From 23d83ec1532dfbff7036ea713b941ae6a2e55eda Mon Sep 17 00:00:00 2001 From: ispyisail Date: Fri, 25 Sep 2026 15:59:21 +1200 Subject: [PATCH 01/13] Add --seconds to spacemouse-capture.py to record longer per step The SpacePilot PRO recording on #599 has a weak `right` step: pushed too lightly to read above the cap's normal cross-axis noise. A longer window makes it easier to hold a firm push and gives the decoder more samples to average over. Co-Authored-By: Claude Sonnet 5 --- misc/spacemouse-capture.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/misc/spacemouse-capture.py b/misc/spacemouse-capture.py index 71d5b573c..caa94c83e 100755 --- a/misc/spacemouse-capture.py +++ b/misc/spacemouse-capture.py @@ -24,6 +24,7 @@ Nothing is sent anywhere. sudo python3 spacemouse-capture.py # finds the device itself sudo python3 spacemouse-capture.py --list # just show what it finds + sudo python3 spacemouse-capture.py --seconds 3 # 3x the time per step sudo is needed because /dev/hidraw* is usually readable by root only. spacenavd can keep running. If the recording comes out empty, stop it @@ -121,6 +122,8 @@ def main(): ap.add_argument('--descriptor', help=argparse.SUPPRESS) # testing without a device ap.add_argument('--yes', action='store_true', help=argparse.SUPPRESS) # no Enter prompts ap.add_argument('-o', '--output', help='output file (default: spacemouse-capture-.json)') + ap.add_argument('--seconds', type=float, default=1.0, + help='multiply each step\'s recording time (default: 1.0, e.g. 3 triples it)') args = ap.parse_args() devices = find_devices() @@ -168,9 +171,10 @@ def main(): } try: for i, (key, text, seconds) in enumerate(STEPS, 1): + seconds = seconds * args.seconds print('[%d/%d] %s' % (i, len(STEPS), text)) if not args.yes: - input(' Press Enter to start (%d s)... ' % seconds) + input(' Press Enter to start (%.0f s)... ' % seconds) reports = record(fd, seconds) print(' %d reports recorded.\n' % len(reports)) result['steps'].append({'step': key, 'instruction': text, 'reports': reports}) From ebd4a57563c807cc107168c6f90a24ea8f1f702d Mon Sep 17 00:00:00 2001 From: ispyisail Date: Fri, 25 Sep 2026 22:14:14 +1200 Subject: [PATCH 02/13] Let misc/spacemouse-capture.py record on macOS The recorder only read /dev/hidraw, so it could not run on a Mac. It now also reads through IOKit via ctypes, using the calls hidapi's mac backend makes: a shared open (as #1028 does) and the input report callback. hidapi passes those bytes through unchanged, so a recording is exactly what QET decodes on macOS. Standard library only, and no sudo. If 3DxWare holds the device, or Input Monitoring is not granted, it says which instead of recording nothing. The JSON adds "backend" and "other_readers" (any 3DxWare or spacenavd process that was running). Reports that queue up while it waits for Enter are now dropped, so each step holds only its own movement. The Linux path is otherwise unchanged. Tested: the Linux path against the virtual uhid device (tools/hid-capture/fake-spacemouse.py in the docker harness). A stale report was dropped and the step's own push was kept. The macOS path has only been run against a mocked IOKit, not on a Mac. Co-Authored-By: Claude Opus 5.5 --- misc/spacemouse-capture.py | 366 +++++++++++++++++++++++++++++-------- 1 file changed, 291 insertions(+), 75 deletions(-) diff --git a/misc/spacemouse-capture.py b/misc/spacemouse-capture.py index caa94c83e..19a6bfdc9 100755 --- a/misc/spacemouse-capture.py +++ b/misc/spacemouse-capture.py @@ -22,15 +22,25 @@ This records what your device sends while you make a few guided movements, and saves it to one file you can attach to the discussion. Nothing is sent anywhere. +Linux: sudo python3 spacemouse-capture.py # finds the device itself sudo python3 spacemouse-capture.py --list # just show what it finds sudo python3 spacemouse-capture.py --seconds 3 # 3x the time per step -sudo is needed because /dev/hidraw* is usually readable by root only. -spacenavd can keep running. If the recording comes out empty, stop it -(`sudo systemctl stop spacenavd`) and try again. + sudo is needed because /dev/hidraw* is usually readable by root only. + spacenavd can keep running. If the recording comes out empty, stop it + (`sudo systemctl stop spacenavd`) and try again. -Only the standard library is used, so it runs on any Linux with Python 3. +macOS: + python3 spacemouse-capture.py + python3 spacemouse-capture.py --list + + No sudo. It reads the device the same way QElectroTech does (IOKit, + shared, as hidapi does). If the recording comes out empty, quit + 3DxWare, or allow Terminal under System Settings > Privacy & Security + > Input Monitoring, and try again. + +Only the standard library is used. """ import argparse import datetime @@ -39,6 +49,7 @@ import json import os import platform import select +import subprocess import sys import time @@ -59,113 +70,317 @@ STEPS = [ ('buttons', 'Press each button once, slowly, one at a time, in any order.', 15), ] - -def find_devices(): - """Return [{hidraw, name, vendor, product, sysfs}] for 3Dconnexion devices.""" - found = [] - for sysdir in sorted(glob.glob('/sys/class/hidraw/hidraw*')): - try: - with open(os.path.join(sysdir, 'device', 'uevent')) as f: - uevent = dict(line.strip().split('=', 1) for line in f if '=' in line) - except OSError: - continue - # HID_ID=0003:0000256F:0000C635 (bus:vendor:product) - try: - _bus, vendor, product = (int(x, 16) for x in uevent.get('HID_ID', '').split(':')) - except ValueError: - continue - if vendor not in VENDORS: - continue - found.append({ - 'hidraw': '/dev/' + os.path.basename(sysdir), - 'name': uevent.get('HID_NAME', '?'), - 'vendor': '%04x' % vendor, - 'product': '%04x' % product, - 'sysfs': sysdir, - }) - return found +# Processes that may also be reading the device. +OTHER_READERS = ('3dconnexion', '3dx', 'spacenavd') # 3DxWare: 3DconnexionHelper, 3DxNLServer... -def read_descriptor(sysdir): +def other_readers(): try: - with open(os.path.join(sysdir, 'device', 'report_descriptor'), 'rb') as f: - return f.read().hex() - except OSError as e: - return 'unreadable: %s' % e + out = subprocess.run(['ps', '-A', '-o', 'comm='], capture_output=True, + text=True, timeout=5).stdout + except (OSError, subprocess.SubprocessError): + return ['unknown'] + names = {os.path.basename(line.strip()) for line in out.splitlines()} + return sorted(n for n in names if any(r in n.lower() for r in OTHER_READERS)) -def record(fd, seconds): - """Read every report arriving within `seconds`; return [[ms, hex], ...].""" - reports = [] - start = time.monotonic() - while True: - left = seconds - (time.monotonic() - start) - if left <= 0: - return reports - ready, _, _ = select.select([fd], [], [], left) - if not ready: - continue +# --- Linux: /dev/hidraw ---------------------------------------------------- + +class HidrawDevice: + backend = 'hidraw' + + def __init__(self, path, name='?', vendor='?', product='?', sysfs=None): + self.path, self.name, self.vendor, self.product = path, name, vendor, product + self.sysfs = sysfs + self.fd = None + + @staticmethod + def find(): + found = [] + for sysdir in sorted(glob.glob('/sys/class/hidraw/hidraw*')): + try: + with open(os.path.join(sysdir, 'device', 'uevent')) as f: + uevent = dict(line.strip().split('=', 1) for line in f if '=' in line) + except OSError: + continue + # HID_ID=0003:0000256F:0000C635 (bus:vendor:product) + try: + _bus, vendor, product = (int(x, 16) for x in uevent.get('HID_ID', '').split(':')) + except ValueError: + continue + if vendor not in VENDORS: + continue + found.append(HidrawDevice('/dev/' + os.path.basename(sysdir), + uevent.get('HID_NAME', '?'), + '%04x' % vendor, '%04x' % product, sysdir)) + return found + + def descriptor(self): + if not self.sysfs: + return 'unknown' try: - data = os.read(fd, 64) - except BlockingIOError: - continue - if not data: # only a test FIFO with no writer does this - time.sleep(0.01) - continue - reports.append([round((time.monotonic() - start) * 1000, 1), data.hex()]) + with open(os.path.join(self.sysfs, 'device', 'report_descriptor'), 'rb') as f: + return f.read().hex() + except OSError as e: + return 'unreadable: %s' % e + + def open(self): + try: + self.fd = os.open(self.path, os.O_RDONLY | os.O_NONBLOCK) + except PermissionError: + sys.exit('Permission denied on %s -- run with sudo.' % self.path) + + def record(self, seconds): + """Read every report arriving within `seconds`; return [[ms, hex], ...].""" + reports = [] + start = time.monotonic() + while True: + left = seconds - (time.monotonic() - start) + if left <= 0: + return reports + ready, _, _ = select.select([self.fd], [], [], left) + if not ready: + continue + try: + data = os.read(self.fd, 64) + except BlockingIOError: + continue + if not data: # only a test FIFO with no writer does this + time.sleep(0.01) + continue + reports.append([round((time.monotonic() - start) * 1000, 1), data.hex()]) + + def drain(self): + """Drop reports queued while waiting for Enter.""" + while True: + try: + if not os.read(self.fd, 64): + return + except BlockingIOError: + return + + def close(self): + os.close(self.fd) + + def empty_hint(self): + return 'Try stopping spacenavd first: sudo systemctl stop spacenavd' + + +# --- macOS: IOKit, the same calls hidapi's mac backend makes ---------------- + +class MacHid: + """ctypes bindings to the few CoreFoundation/IOKit calls needed.""" + + def __init__(self): + import ctypes as c + self.c = c + cf = c.CDLL('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation') + io = c.CDLL('/System/Library/Frameworks/IOKit.framework/IOKit') + vp, i32, u32, idx = c.c_void_p, c.c_int32, c.c_uint32, c.c_long + + def fn(lib, name, res, *args): + f = getattr(lib, name) + f.restype, f.argtypes = res, list(args) + return f + + self.CFStringCreateWithCString = fn(cf, 'CFStringCreateWithCString', vp, vp, c.c_char_p, u32) + self.CFStringGetCString = fn(cf, 'CFStringGetCString', c.c_bool, vp, c.c_char_p, idx, u32) + self.CFGetTypeID = fn(cf, 'CFGetTypeID', c.c_ulong, vp) + self.CFNumberGetTypeID = fn(cf, 'CFNumberGetTypeID', c.c_ulong) + self.CFStringGetTypeID = fn(cf, 'CFStringGetTypeID', c.c_ulong) + self.CFDataGetTypeID = fn(cf, 'CFDataGetTypeID', c.c_ulong) + self.CFNumberGetValue = fn(cf, 'CFNumberGetValue', c.c_bool, vp, idx, vp) + self.CFDataGetLength = fn(cf, 'CFDataGetLength', idx, vp) + self.CFDataGetBytePtr = fn(cf, 'CFDataGetBytePtr', vp, vp) + self.CFSetGetCount = fn(cf, 'CFSetGetCount', idx, vp) + self.CFSetGetValues = fn(cf, 'CFSetGetValues', None, vp, c.POINTER(vp)) + self.CFRunLoopGetCurrent = fn(cf, 'CFRunLoopGetCurrent', vp) + self.CFRunLoopRunInMode = fn(cf, 'CFRunLoopRunInMode', i32, vp, c.c_double, c.c_bool) + self.kCFRunLoopDefaultMode = vp.in_dll(cf, 'kCFRunLoopDefaultMode').value + + self.IOHIDManagerCreate = fn(io, 'IOHIDManagerCreate', vp, vp, u32) + self.IOHIDManagerSetDeviceMatching = fn(io, 'IOHIDManagerSetDeviceMatching', None, vp, vp) + self.IOHIDManagerScheduleWithRunLoop = fn(io, 'IOHIDManagerScheduleWithRunLoop', None, vp, vp, vp) + self.IOHIDManagerCopyDevices = fn(io, 'IOHIDManagerCopyDevices', vp, vp) + self.IOHIDDeviceGetProperty = fn(io, 'IOHIDDeviceGetProperty', vp, vp, vp) + self.IOHIDDeviceOpen = fn(io, 'IOHIDDeviceOpen', i32, vp, u32) + self.IOHIDDeviceClose = fn(io, 'IOHIDDeviceClose', i32, vp, u32) + self.IOHIDDeviceScheduleWithRunLoop = fn(io, 'IOHIDDeviceScheduleWithRunLoop', None, vp, vp, vp) + self.IOHIDDeviceUnscheduleFromRunLoop = fn(io, 'IOHIDDeviceUnscheduleFromRunLoop', None, vp, vp, vp) + # void (*)(void *ctx, IOReturn, void *sender, IOHIDReportType, uint32_t id, uint8_t *, CFIndex) + self.ReportCallback = c.CFUNCTYPE(None, vp, i32, vp, c.c_int, u32, c.POINTER(c.c_uint8), idx) + self.IOHIDDeviceRegisterInputReportCallback = fn( + io, 'IOHIDDeviceRegisterInputReportCallback', None, vp, vp, idx, self.ReportCallback, vp) + + def cfstr(self, s): + return self.CFStringCreateWithCString(None, s.encode(), 0x08000100) # UTF-8 + + def prop(self, dev, key): + """A device property as int, str or bytes, or None.""" + c = self.c + ref = self.IOHIDDeviceGetProperty(dev, self.cfstr(key)) + if not ref: + return None + t = self.CFGetTypeID(ref) + if t == self.CFNumberGetTypeID(): + v = c.c_int64() + self.CFNumberGetValue(ref, 4, c.byref(v)) # kCFNumberSInt64Type + return v.value + if t == self.CFStringGetTypeID(): + buf = c.create_string_buffer(256) + return buf.value.decode('utf-8', 'replace') if self.CFStringGetCString( + ref, buf, len(buf), 0x08000100) else None + if t == self.CFDataGetTypeID(): + return c.string_at(self.CFDataGetBytePtr(ref), self.CFDataGetLength(ref)) + return None + + +class MacDevice: + backend = 'iokit' + _hid = None + + def __init__(self, ref, name, vendor, product, location): + self.ref, self.name, self.vendor, self.product = ref, name, vendor, product + self.path = 'iokit:%08x' % location + self.reports = [] + self.start = time.monotonic() + + @classmethod + def hid(cls): + if cls._hid is None: + cls._hid = MacHid() + return cls._hid + + @classmethod + def find(cls): + h = cls.hid() + mgr = h.IOHIDManagerCreate(None, 0) + h.IOHIDManagerSetDeviceMatching(mgr, None) + h.IOHIDManagerScheduleWithRunLoop(mgr, h.CFRunLoopGetCurrent(), h.kCFRunLoopDefaultMode) + devset = h.IOHIDManagerCopyDevices(mgr) + if not devset: + return [] + n = h.CFSetGetCount(devset) + refs = (h.c.c_void_p * n)() + h.CFSetGetValues(devset, refs) + found = [] + for ref in refs: + vendor = h.prop(ref, 'VendorID') + if vendor not in VENDORS: + continue + # The same test as QET's SpaceMouseHid::isSpaceMouse(): Generic + # Desktop / Multi-axis Controller, or no usage at all. This also + # skips Logitech's ordinary mice and keyboards. + usage = (h.prop(ref, 'PrimaryUsagePage') or 0, h.prop(ref, 'PrimaryUsage') or 0) + if usage not in ((1, 8), (0, 0)): + continue + found.append(cls(ref, h.prop(ref, 'Product') or '?', '%04x' % vendor, + '%04x' % (h.prop(ref, 'ProductID') or 0), + h.prop(ref, 'LocationID') or 0)) + return sorted(found, key=lambda d: d.path) + + def descriptor(self): + d = self.hid().prop(self.ref, 'ReportDescriptor') + return d.hex() if d else 'unreadable' + + def open(self): + h = self.hid() + ret = h.IOHIDDeviceOpen(self.ref, 0) & 0xFFFFFFFF # kIOHIDOptionsTypeNone: shared + if ret == 0xE00002C5: + sys.exit('The device is held exclusively by another program ' + '(kIOReturnExclusiveAccess). Quit 3DxWare and try again.') + if ret in (0xE00002E2, 0xE00002C1): + sys.exit('macOS refused access (0x%08X). Allow Terminal under System Settings > ' + 'Privacy & Security > Input Monitoring, then try again.' % ret) + if ret: + sys.exit('Could not open the device (IOReturn 0x%08X).' % ret) + size = h.prop(self.ref, 'MaxInputReportSize') or 64 + self.buf = h.c.create_string_buffer(size) + + def on_report(_ctx, _result, _sender, _type, _id, data, length): + self.reports.append([round((time.monotonic() - self.start) * 1000, 1), + h.c.string_at(data, length).hex()]) + self.callback = h.ReportCallback(on_report) # must outlive the device + h.IOHIDDeviceRegisterInputReportCallback(self.ref, self.buf, size, self.callback, None) + h.IOHIDDeviceScheduleWithRunLoop(self.ref, h.CFRunLoopGetCurrent(), h.kCFRunLoopDefaultMode) + + def record(self, seconds): + h = self.hid() + self.reports, self.start = [], time.monotonic() + while True: + left = seconds - (time.monotonic() - self.start) + if left <= 0: + return self.reports + h.CFRunLoopRunInMode(h.kCFRunLoopDefaultMode, left, False) + + def drain(self): + self.hid().CFRunLoopRunInMode(self.hid().kCFRunLoopDefaultMode, 0.05, False) + self.reports = [] + + def close(self): + h = self.hid() + h.IOHIDDeviceUnscheduleFromRunLoop(self.ref, h.CFRunLoopGetCurrent(), h.kCFRunLoopDefaultMode) + h.IOHIDDeviceClose(self.ref, 0) + + def empty_hint(self): + return ('Quit 3DxWare if it is running, or allow Terminal under System Settings > ' + 'Privacy & Security > Input Monitoring, and try again.') def main(): ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) ap.add_argument('--list', action='store_true', help='only list matching devices') - ap.add_argument('--device', help='hidraw path, if more than one device is found') + ap.add_argument('--device', help='device path from --list, if more than one is found') ap.add_argument('--descriptor', help=argparse.SUPPRESS) # testing without a device ap.add_argument('--yes', action='store_true', help=argparse.SUPPRESS) # no Enter prompts ap.add_argument('-o', '--output', help='output file (default: spacemouse-capture-.json)') ap.add_argument('--seconds', type=float, default=1.0, - help='multiply each step\'s recording time (default: 1.0, e.g. 3 triples it)') + help='multiply each step\'s recording time (default: 1.0, e.g. 3 triples it)') args = ap.parse_args() - devices = find_devices() + Device = MacDevice if sys.platform == 'darwin' else HidrawDevice + devices = Device.find() if args.list: for d in devices: - print('%(hidraw)s %(vendor)s:%(product)s %(name)s' % d) + print('%s %s:%s %s' % (d.path, d.vendor, d.product, d.name)) if not devices: - print('No 3Dconnexion device found under /sys/class/hidraw.') + print('No 3Dconnexion device found.') return 0 if devices else 1 if args.device: - dev = next((d for d in devices if d['hidraw'] == args.device), - {'hidraw': args.device, 'name': '?', 'vendor': '?', 'product': '?', 'sysfs': None}) + dev = next((d for d in devices if d.path == args.device), None) + if dev is None: + if Device is not HidrawDevice: + sys.exit('No device %s (try --list)' % args.device) + dev = HidrawDevice(args.device) elif len(devices) == 1: dev = devices[0] elif not devices: sys.exit('No 3Dconnexion device found. Is it plugged in? (try --list)') else: sys.exit('Several devices found, pick one with --device:\n' + - '\n'.join(' %(hidraw)s %(name)s' % d for d in devices)) + '\n'.join(' %s %s' % (d.path, d.name) for d in devices)) if args.descriptor: with open(args.descriptor, 'rb') as f: descriptor = f.read().hex() - elif dev['sysfs']: - descriptor = read_descriptor(dev['sysfs']) else: - descriptor = 'unknown' + descriptor = dev.descriptor() - try: - fd = os.open(dev['hidraw'], os.O_RDONLY | os.O_NONBLOCK) - except PermissionError: - sys.exit('Permission denied on %s -- run with sudo.' % dev['hidraw']) - - print('Recording from %s (%s, %s:%s).' % (dev['hidraw'], dev['name'], dev['vendor'], dev['product'])) + dev.open() + print('Recording from %s (%s, %s:%s).' % (dev.path, dev.name, dev.vendor, dev.product)) + readers = other_readers() + if readers: + print('Also running: %s. If nothing gets recorded, quit it and try again.' % ', '.join(readers)) print('For each step, press Enter, do the movement, and wait for the next prompt.\n') result = { - 'tool': 'spacemouse-capture.py 1', + 'tool': 'spacemouse-capture.py 2', 'date': datetime.datetime.now(datetime.timezone.utc).isoformat(timespec='seconds'), 'system': platform.platform(), - 'device': {k: dev[k] for k in ('name', 'vendor', 'product')}, + 'backend': dev.backend, + 'other_readers': readers, + 'device': {'name': dev.name, 'vendor': dev.vendor, 'product': dev.product}, 'report_descriptor': descriptor, 'steps': [], } @@ -175,21 +390,22 @@ def main(): print('[%d/%d] %s' % (i, len(STEPS), text)) if not args.yes: input(' Press Enter to start (%.0f s)... ' % seconds) - reports = record(fd, seconds) + dev.drain() + reports = dev.record(seconds) print(' %d reports recorded.\n' % len(reports)) result['steps'].append({'step': key, 'instruction': text, 'reports': reports}) except KeyboardInterrupt: print('\nStopped early -- saving what was recorded so far.') finally: - os.close(fd) + dev.close() - out = args.output or 'spacemouse-capture-%s.json' % dev['product'] + out = args.output or 'spacemouse-capture-%s.json' % dev.product with open(out, 'w') as f: json.dump(result, f, indent=1) total = sum(len(s['reports']) for s in result['steps']) print('Saved %s (%d reports in total).' % (out, total)) if total == 0: - print('Nothing was recorded. Try stopping spacenavd first: sudo systemctl stop spacenavd') + print('Nothing was recorded. ' + dev.empty_hint()) else: print('Please attach this file to discussion #599. Thank you!') return 0 From d392ab4b8f3dcf8c9cdfe9bf921c1e1941fb7ad1 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Sat, 26 Sep 2026 06:50:33 +1200 Subject: [PATCH 03/13] Let misc/spacemouse-capture.py record on Windows, and say how on each system Windows reads the device through hid.dll and SetupAPI with ctypes, as hidapi's Windows backend does: shared, so 3DxWare can keep running, and dropping the 0 report ID Windows adds, as hidapi does, so the bytes are the ones QET decodes. Windows does not give out the report descriptor, so a Windows recording has none; tst_spacemousehid then uses its fallback layout. The docstring, printed in full by --help, now has step-by-step instructions for Linux, macOS and Windows, download included. Tested: Windows Python 3.12 (embeddable) under Wine 10, against the virtual uhid 3D mouse: --list finds it, a push sent during `right` lands in `right`, and a button press and release land in `buttons`, with the same bytes the Linux path records for the same push. Linux and the mocked macOS path still pass. Co-Authored-By: Claude Opus 5.5 --- misc/spacemouse-capture.py | 284 ++++++++++++++++++++++++++++++++++--- 1 file changed, 264 insertions(+), 20 deletions(-) diff --git a/misc/spacemouse-capture.py b/misc/spacemouse-capture.py index 19a6bfdc9..bd0db5c27 100755 --- a/misc/spacemouse-capture.py +++ b/misc/spacemouse-capture.py @@ -14,33 +14,59 @@ # # You should have received a copy of the GNU General Public License # along with QElectroTech. If not, see . -"""Record raw USB reports from a 3Dconnexion 3D mouse, for QElectroTech. +r"""Record raw USB reports from a 3Dconnexion 3D mouse, for QElectroTech. QElectroTech's Windows/macOS 3D mouse support reads the device directly over USB, so it has to decode each device model's raw reports itself. This records what your device sends while you make a few guided -movements, and saves it to one file you can attach to the discussion. -Nothing is sent anywhere. +movements, and saves it to one file you can attach to discussion #599. +Nothing is sent anywhere. One recording per device model is enough, from +any of the three systems: the device sends the same reports on all of them. -Linux: - sudo python3 spacemouse-capture.py # finds the device itself - sudo python3 spacemouse-capture.py --list # just show what it finds - sudo python3 spacemouse-capture.py --seconds 3 # 3x the time per step +It takes about two minutes. Each step says what to do: press Enter, make +the movement and hold it until the next prompt. Push firmly. - sudo is needed because /dev/hidraw* is usually readable by root only. - spacenavd can keep running. If the recording comes out empty, stop it - (`sudo systemctl stop spacenavd`) and try again. +Linux + Python 3 is already installed. + 1. Download: curl -LO https://raw.githubusercontent.com/qelectrotech/qelectrotech-source-mirror/master/misc/spacemouse-capture.py + 2. List: sudo python3 spacemouse-capture.py --list + 3. Record: sudo python3 spacemouse-capture.py --seconds 3 + If --list shows several devices (a Logitech receiver shows up as + several), add --device /dev/hidrawN with the 3D mouse's line. + sudo is needed because /dev/hidraw* is readable by root only. + spacenavd can keep running; if the recording comes out empty, stop it + (sudo systemctl stop spacenavd) and try again. -macOS: - python3 spacemouse-capture.py - python3 spacemouse-capture.py --list +macOS + Python 3 comes with the Xcode command line tools; if "python3" asks + to install them, accept. Open Terminal, then: + 1. Download: curl -LO https://raw.githubusercontent.com/qelectrotech/qelectrotech-source-mirror/master/misc/spacemouse-capture.py + 2. Record: python3 spacemouse-capture.py --seconds 3 + No sudo. If it says another program holds the device, quit 3DxWare + (or uninstall it) and try again. If it says macOS refused access, + allow Terminal in System Settings > Privacy & Security > Input + Monitoring, and try again. (Rather not use Terminal? The SpaceMouse + Check app does the same with a window: see discussion #599.) - No sudo. It reads the device the same way QElectroTech does (IOKit, - shared, as hidapi does). If the recording comes out empty, quit - 3DxWare, or allow Terminal under System Settings > Privacy & Security - > Input Monitoring, and try again. +Windows + Install Python 3 from https://www.python.org/downloads/ (tick "Add + python.exe to PATH") or from the Microsoft Store. Open a Command + Prompt (Windows key, type cmd, Enter), then: + 1. cd %USERPROFILE%\Downloads + 2. Download: curl -LO https://raw.githubusercontent.com/qelectrotech/qelectrotech-source-mirror/master/misc/spacemouse-capture.py + 3. Record: python spacemouse-capture.py --seconds 3 + No administrator rights needed, and 3DxWare can keep running. + Windows does not give out the device's report descriptor, so a + recording made on Linux or macOS is a little more complete. -Only the standard library is used. +Every system + --list only show the 3D mice found + --device PATH pick one, if several are found (a path from --list) + --seconds N multiply the time per step (3 triples it) + -o FILE where to save (default: spacemouse-capture-.json) + +The file is saved in the current folder: attach it to discussion #599. +Only Python's standard library is used. """ import argparse import datetime @@ -75,6 +101,14 @@ OTHER_READERS = ('3dconnexion', '3dx', 'spacenavd') # 3DxWare: 3DconnexionHelpe def other_readers(): + if sys.platform == 'win32': + try: + out = subprocess.run(['tasklist', '/fo', 'csv', '/nh'], capture_output=True, + text=True, timeout=10).stdout + except (OSError, subprocess.SubprocessError): + return ['unknown'] + names = {line.split('","')[0].strip('"') for line in out.splitlines() if line} + return sorted(n for n in names if any(r in n.lower() for r in OTHER_READERS)) try: out = subprocess.run(['ps', '-A', '-o', 'comm='], capture_output=True, text=True, timeout=5).stdout @@ -327,8 +361,218 @@ class MacDevice: 'Privacy & Security > Input Monitoring, and try again.') +# --- Windows: hid.dll, the same calls hidapi's Windows backend makes --------- + +class WinHid: + """ctypes bindings to the SetupAPI/HID/kernel32 calls needed.""" + + def __init__(self): + import ctypes as c + from ctypes import wintypes as w + self.c, self.w = c, w + self.hid = c.WinDLL('hid') + self.setupapi = c.WinDLL('setupapi') + self.k32 = c.WinDLL('kernel32', use_last_error=True) + k, sa = self.k32, self.setupapi + + class GUID(c.Structure): + _fields_ = [('Data1', w.DWORD), ('Data2', w.WORD), ('Data3', w.WORD), + ('Data4', c.c_ubyte * 8)] + + class InterfaceData(c.Structure): + _fields_ = [('cbSize', w.DWORD), ('InterfaceClassGuid', GUID), + ('Flags', w.DWORD), ('Reserved', c.c_void_p)] + + class Attributes(c.Structure): + _fields_ = [('Size', w.ULONG), ('VendorID', w.USHORT), ('ProductID', w.USHORT), + ('VersionNumber', w.USHORT)] + + class Caps(c.Structure): + _fields_ = [('Usage', w.USHORT), ('UsagePage', w.USHORT), + ('InputReportByteLength', w.USHORT), ('OutputReportByteLength', w.USHORT), + ('FeatureReportByteLength', w.USHORT), ('Reserved', w.USHORT * 17), + ('rest', w.USHORT * 10)] + + class Overlapped(c.Structure): + _fields_ = [('Internal', c.c_void_p), ('InternalHigh', c.c_void_p), + ('Offset', w.DWORD), ('OffsetHigh', w.DWORD), ('hEvent', w.HANDLE)] + + self.GUID, self.InterfaceData, self.Attributes = GUID, InterfaceData, Attributes + self.Caps, self.Overlapped = Caps, Overlapped + + k.CreateFileW.restype = w.HANDLE + k.CreateFileW.argtypes = [w.LPCWSTR, w.DWORD, w.DWORD, c.c_void_p, w.DWORD, w.DWORD, w.HANDLE] + k.CreateEventW.restype = w.HANDLE + k.CreateEventW.argtypes = [c.c_void_p, w.BOOL, w.BOOL, w.LPCWSTR] + k.ReadFile.argtypes = [w.HANDLE, c.c_void_p, w.DWORD, c.c_void_p, c.c_void_p] + k.GetOverlappedResult.argtypes = [w.HANDLE, c.c_void_p, c.POINTER(w.DWORD), w.BOOL] + k.WaitForSingleObject.argtypes = [w.HANDLE, w.DWORD] + k.WaitForSingleObject.restype = w.DWORD + k.CancelIo.argtypes = [w.HANDLE] + k.CloseHandle.argtypes = [w.HANDLE] + sa.SetupDiGetClassDevsW.restype = w.HANDLE + sa.SetupDiGetClassDevsW.argtypes = [c.c_void_p, w.LPCWSTR, w.HWND, w.DWORD] + sa.SetupDiEnumDeviceInterfaces.argtypes = [w.HANDLE, c.c_void_p, c.c_void_p, w.DWORD, c.c_void_p] + sa.SetupDiGetDeviceInterfaceDetailW.argtypes = [w.HANDLE, c.c_void_p, c.c_void_p, w.DWORD, + c.POINTER(w.DWORD), c.c_void_p] + sa.SetupDiDestroyDeviceInfoList.argtypes = [w.HANDLE] + self.hid.HidD_GetHidGuid.argtypes = [c.c_void_p] + self.hid.HidD_GetAttributes.argtypes = [w.HANDLE, c.c_void_p] + self.hid.HidD_GetPreparsedData.argtypes = [w.HANDLE, c.POINTER(c.c_void_p)] + self.hid.HidD_FreePreparsedData.argtypes = [c.c_void_p] + self.hid.HidP_GetCaps.argtypes = [c.c_void_p, c.c_void_p] + self.hid.HidD_GetProductString.argtypes = [w.HANDLE, c.c_void_p, w.ULONG] + + INVALID = (2 ** 64 - 1, 2 ** 32 - 1, -1) # INVALID_HANDLE_VALUE, 64/32-bit + + def paths(self): + """Every HID interface path on the system.""" + c, w = self.c, self.w + guid = self.GUID() + self.hid.HidD_GetHidGuid(c.byref(guid)) + info = self.setupapi.SetupDiGetClassDevsW(c.byref(guid), None, None, 0x12) # PRESENT|INTERFACE + paths = [] + i = 0 + while True: + data = self.InterfaceData() + data.cbSize = c.sizeof(data) + if not self.setupapi.SetupDiEnumDeviceInterfaces(info, None, c.byref(guid), i, c.byref(data)): + break + i += 1 + needed = w.DWORD() + self.setupapi.SetupDiGetDeviceInterfaceDetailW(info, c.byref(data), None, 0, c.byref(needed), None) + buf = c.create_string_buffer(needed.value) + # SP_DEVICE_INTERFACE_DETAIL_DATA_W: DWORD cbSize, then the path. + c.cast(buf, c.POINTER(w.DWORD))[0] = 8 if c.sizeof(c.c_void_p) == 8 else 6 + if self.setupapi.SetupDiGetDeviceInterfaceDetailW(info, c.byref(data), buf, needed, None, None): + paths.append(c.wstring_at(c.addressof(buf) + 4)) + self.setupapi.SetupDiDestroyDeviceInfoList(info) + return paths + + def open(self, path, access): + # FILE_SHARE_READ|WRITE, OPEN_EXISTING, FILE_FLAG_OVERLAPPED + h = self.k32.CreateFileW(path, access, 3, None, 3, 0x40000000, None) + return None if h is None or h in self.INVALID else h + + def describe(self, h): + """(vendor, product, usage_page, usage, input_length, name) of an open handle.""" + c = self.c + attrs = self.Attributes() + attrs.Size = c.sizeof(attrs) + if not self.hid.HidD_GetAttributes(h, c.byref(attrs)): + return None + page = usage = length = 0 + pre = c.c_void_p() + if self.hid.HidD_GetPreparsedData(h, c.byref(pre)): + caps = self.Caps() + self.hid.HidP_GetCaps(pre, c.byref(caps)) + page, usage, length = caps.UsagePage, caps.Usage, caps.InputReportByteLength + self.hid.HidD_FreePreparsedData(pre) + name = c.create_unicode_buffer(128) + if not self.hid.HidD_GetProductString(h, name, c.sizeof(name)): + name.value = '?' + return attrs.VendorID, attrs.ProductID, page, usage, length, name.value + + +class WinDevice: + backend = 'windows-hid' + _hid = None + + def __init__(self, path, name, vendor, product, length): + self.path, self.name, self.vendor, self.product = path, name, vendor, product + self.length = length or 64 + self.handle = None + + @classmethod + def hid(cls): + if cls._hid is None: + cls._hid = WinHid() + return cls._hid + + @classmethod + def find(cls): + h = cls.hid() + found = [] + for path in h.paths(): + handle = h.open(path, 0) # no access: enough to read attributes + if handle is None: + continue + try: + d = h.describe(handle) + finally: + h.k32.CloseHandle(handle) + if not d: + continue + vendor, product, page, usage, length, name = d + # The same test as QET's SpaceMouseHid::isSpaceMouse(). + if vendor not in VENDORS or (page, usage) not in ((1, 8), (0, 0)): + continue + found.append(cls(path, name, '%04x' % vendor, '%04x' % product, length)) + return found + + def descriptor(self): + # Windows only gives out a parsed form of it. + return '' + + def open(self): + h = self.hid() + self.handle = h.open(self.path, 0x80000000) # GENERIC_READ + if self.handle is None: + sys.exit('Could not open the device (error %d).' % h.c.get_last_error()) + self.event = h.k32.CreateEventW(None, True, False, None) + self.buf = h.c.create_string_buffer(self.length) + self.pending = False + self.start = time.monotonic() + + def _read(self, wait_ms): + """One report if it arrives within wait_ms, else None.""" + h = self.hid() + c, w = h.c, h.w + if not self.pending: + self.ov = h.Overlapped() + self.ov.hEvent = self.event + h.k32.ReadFile(self.handle, self.buf, self.length, None, c.byref(self.ov)) + self.pending = True + if h.k32.WaitForSingleObject(self.event, max(0, int(wait_ms))) != 0: + return None + self.pending = False + n = w.DWORD() + if not h.k32.GetOverlappedResult(self.handle, c.byref(self.ov), c.byref(n), False): + return None + data = self.buf.raw[:n.value] + # Windows puts a report ID in front even when the device has none; + # hidapi drops that 0, so QET never sees it. + return data[1:] if data[:1] == b'\0' else data + + def record(self, seconds): + reports = [] + start = time.monotonic() + while True: + left = seconds - (time.monotonic() - start) + if left <= 0: + return reports + data = self._read(left * 1000) + if data: + reports.append([round((time.monotonic() - start) * 1000, 1), data.hex()]) + + def drain(self): + while self._read(0): + pass + + def close(self): + h = self.hid() + if self.pending: + h.k32.CancelIo(self.handle) + h.k32.CloseHandle(self.event) + h.k32.CloseHandle(self.handle) + + def empty_hint(self): + return 'Check the cable, push the cap firmly, and try again.' + + def main(): - ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + ap = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument('--list', action='store_true', help='only list matching devices') ap.add_argument('--device', help='device path from --list, if more than one is found') ap.add_argument('--descriptor', help=argparse.SUPPRESS) # testing without a device @@ -338,7 +582,7 @@ def main(): help='multiply each step\'s recording time (default: 1.0, e.g. 3 triples it)') args = ap.parse_args() - Device = MacDevice if sys.platform == 'darwin' else HidrawDevice + Device = {'darwin': MacDevice, 'win32': WinDevice}.get(sys.platform, HidrawDevice) devices = Device.find() if args.list: for d in devices: From ce0e7e68676535e7fa3eec4fdfe5cc1a736fd07a Mon Sep 17 00:00:00 2001 From: ispyisail Date: Sat, 26 Sep 2026 07:37:38 +1200 Subject: [PATCH 04/13] Add jumping to a folio cell such as B13 from Ctrl+G (#1034) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typing a cell reference into the "Atteindre un élément" popup now offers "Case B13"; Enter zooms the view onto that cell with one cell of margin. The cell is read the way the border labels it: row letter(s) then column number, honouring the "columns start at 0" setting and multi-letter rows (AA, AB...). Cells outside the folio are not offered. BorderTitleBlock::cellRect() is the reverse of convertPosition(); a round trip over every cell of a 30x23 folio, under both column-numbering settings, returned the same cell for all 1380. When an element is labelled exactly like the cell (K1), the element stays first so Enter keeps its old meaning; the cell is listed after it. DiagramView::zoomToRect() re-centres from a queued call: zooming in makes the scroll bars appear, and the viewport resize that follows is anchored under the mouse (setResizeAnchor(AnchorUnderMouse)), which otherwise scrolls the view away from the cell straight after the zoom. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- sources/bordertitleblock.cpp | 41 +++++++++++++++++++++++++ sources/bordertitleblock.h | 1 + sources/diagramview.cpp | 17 +++++++++++ sources/diagramview.h | 1 + sources/ui/jumptoelementdialog.cpp | 48 +++++++++++++++++++++++++++++- sources/ui/jumptoelementdialog.h | 5 +++- 6 files changed, 111 insertions(+), 2 deletions(-) diff --git a/sources/bordertitleblock.cpp b/sources/bordertitleblock.cpp index 4a2a2dfdc..c6913ba46 100644 --- a/sources/bordertitleblock.cpp +++ b/sources/bordertitleblock.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #define MIN_COLUMN_COUNT 3 @@ -935,6 +936,46 @@ void BorderTitleBlock::updateDiagramContextForTitleBlock( m_titleblock_template_renderer -> setContext(context); } +/** + @brief BorderTitleBlock::cellRect + Convert a cell written the way the border labels it (ex : B13, the row + letter(s) then the column number) to its rect in scene coordinate. + This is the reverse of convertPosition(). + @param cell : the cell to convert, case and surrounding spaces ignored + @return the rect of the cell, or a null QRectF if \a cell is not a + cell reference or lies outside of the border. +*/ +QRectF BorderTitleBlock::cellRect(const QString &cell) const +{ + static const QRegularExpression cell_re( + QStringLiteral("^\\s*([A-Za-z]+)\\s*(\\d{1,4})\\s*$")); + const QRegularExpressionMatch match = cell_re.match(cell); + if (!match.hasMatch()) + return QRectF(); + + //Row letters count like A..Z, AA, AB... (see incrementLetters()) + int row = 0; + for (const QChar c : match.captured(1).toUpper()) { + row = row * 26 + (c.unicode() - 'A' + 1); + if (row > rows_count_) + return QRectF(); + } + + int column = match.captured(2).toInt(); + QSettings settings; + if (settings.value("border-columns_0", true).toBool()) + ++column; + + if (row < 1 || column < 1 || column > columns_count_) + return QRectF(); + + const QPointF top_left = insideBorderRect().topLeft(); + return QRectF(top_left.x() + (column - 1) * columns_width_, + top_left.y() + (row - 1) * rows_height_, + columns_width_, + rows_height_); +} + /** @brief BorderTitleBlock::incrementLetters increments string with Letters A to Z diff --git a/sources/bordertitleblock.h b/sources/bordertitleblock.h index 28da7360c..4065bf488 100644 --- a/sources/bordertitleblock.h +++ b/sources/bordertitleblock.h @@ -159,6 +159,7 @@ class BorderTitleBlock : public QObject void setDiagramHeight(const qreal &); DiagramPosition convertPosition(const QPointF &); + QRectF cellRect(const QString &cell) const; // methods to set title block basic data void setFolio(const QString &folio); diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index 843b694be..10216015c 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -385,6 +385,23 @@ void DiagramView::zoomReset() adjustGridToZoom(); } +/** + @brief DiagramView::zoomToRect + Adjust zoom to fit \a rect, in scene coordinate, in the view. + @param rect +*/ +void DiagramView::zoomToRect(const QRectF &rect) +{ + fitInView(rect, Qt::KeepAspectRatio); + //Zooming in makes the scroll bars appear, which resizes the viewport + //from a queued call; that resize is anchored under the mouse and + //would scroll away from rect, so center again once it has run. + QMetaObject::invokeMethod(this, [this, rect]() { + centerOn(rect.center()); + }, Qt::QueuedConnection); + adjustGridToZoom(); +} + /** Copie les elements selectionnes du schema dans le presse-papier puis les supprime Copies the selected elements from the diagram to the clipboard and then deletes them diff --git a/sources/diagramview.h b/sources/diagramview.h index eb73432cb..a03b49ebd 100644 --- a/sources/diagramview.h +++ b/sources/diagramview.h @@ -140,6 +140,7 @@ class DiagramView : public PaletteGraphicsView void zoomFit(); void zoomContent(); void zoomReset(); + void zoomToRect(const QRectF &rect); void cut(); void copy(); void paste(const QPointF & = QPointF(), QClipboard::Mode = QClipboard::Clipboard); diff --git a/sources/ui/jumptoelementdialog.cpp b/sources/ui/jumptoelementdialog.cpp index 9203cd909..118a4c8e0 100644 --- a/sources/ui/jumptoelementdialog.cpp +++ b/sources/ui/jumptoelementdialog.cpp @@ -18,6 +18,7 @@ #include "jumptoelementdialog.h" #include "../diagram.h" +#include "../diagramview.h" #include "../qetgraphicsitem/element.h" #include @@ -38,7 +39,7 @@ JumpToElementDialog::JumpToElementDialog(Diagram *diagram, QWidget *parent) : setWindowTitle(tr("Atteindre un élément", "window title")); m_filter_edit = new QLineEdit(this); - m_filter_edit->setPlaceholderText(tr("Nom, label ou information de l'élément…")); + m_filter_edit->setPlaceholderText(tr("Nom, label ou information de l'élément, ou case (ex. B13)…")); m_filter_edit->installEventFilter(this); m_result_list = new QListWidget(this); @@ -86,6 +87,7 @@ void JumpToElementDialog::buildCandidates() Candidate candidate; candidate.element = element; + candidate.label = label; candidate.display_text = label.isEmpty() ? name : (label + QStringLiteral(" — ") + name); QStringList search_parts; @@ -111,6 +113,7 @@ void JumpToElementDialog::updateFilteredList(const QString &filter_text) m_result_list->clear(); const QString needle = filter_text.trimmed().toLower(); + bool exact_label_match = false; for (int i = 0; i < m_candidates.size(); ++i) { const Candidate &candidate = m_candidates.at(i); if (!candidate.element) { @@ -121,6 +124,23 @@ void JumpToElementDialog::updateFilteredList(const QString &filter_text) } auto *list_item = new QListWidgetItem(candidate.display_text, m_result_list); list_item->setData(Qt::UserRole, i); + if (candidate.label.compare(needle, Qt::CaseInsensitive) == 0) { + exact_label_match = true; + } + } + + //A cell of the border (ex : B13) comes first, unless an element + //is labelled exactly like it: Enter keeps jumping to that element. + if (m_diagram) { + const QRectF cell_rect = m_diagram->border_and_titleblock.cellRect(needle); + if (!cell_rect.isNull()) { + auto *cell_item = new QListWidgetItem( + tr("Case %1").arg(QString(needle).remove(QLatin1Char(' ')).toUpper())); + cell_item->setData(Qt::UserRole, -1); + cell_item->setData(Qt::UserRole + 1, cell_rect); + m_result_list->insertItem(exact_label_match ? m_result_list->count() : 0, + cell_item); + } } if (m_result_list->count() > 0) { @@ -142,6 +162,11 @@ void JumpToElementDialog::activateCurrentItem() } const int index = current->data(Qt::UserRole).toInt(); + if (index == -1) { + zoomToCell(current->data(Qt::UserRole + 1).toRectF()); + accept(); + return; + } if (index < 0 || index >= m_candidates.size()) { reject(); return; @@ -159,6 +184,27 @@ void JumpToElementDialog::activateCurrentItem() accept(); } +/** + @brief JumpToElementDialog::zoomToCell + Zoom the view of m_diagram on \a cell_rect with one cell of context + around it. + @param cell_rect : the cell, in scene coordinate +*/ +void JumpToElementDialog::zoomToCell(const QRectF &cell_rect) +{ + if (!m_diagram) { + return; + } + for (QGraphicsView *view : m_diagram->views()) { + if (auto *diagram_view = qobject_cast(view)) { + diagram_view->zoomToRect(cell_rect.adjusted( + -cell_rect.width(), -cell_rect.height(), + cell_rect.width(), cell_rect.height())); + return; + } + } +} + /** @brief JumpToElementDialog::eventFilter Redirect Up/Down/Enter/Escape typed in the filter field to the result diff --git a/sources/ui/jumptoelementdialog.h b/sources/ui/jumptoelementdialog.h index 603b3932b..4a34d1f2b 100644 --- a/sources/ui/jumptoelementdialog.h +++ b/sources/ui/jumptoelementdialog.h @@ -31,7 +31,8 @@ class QListWidget; A lightweight, transient "quick open" popup: type part of an element's label or other information to live-filter the elements on a diagram, then Enter to select the chosen element on the diagram and scroll it - into view. Up/Down move through the filtered list, Escape cancels + into view. Typing a cell of the border instead (ex : B13) offers to + zoom on that cell. Up/Down move through the filtered list, Escape cancels without changing the current selection. */ class JumpToElementDialog : public QDialog @@ -51,9 +52,11 @@ class JumpToElementDialog : public QDialog private: void buildCandidates(); + void zoomToCell(const QRectF &cell_rect); struct Candidate { QPointer element; + QString label; QString display_text; QString search_text; }; From 9738345b45c5eb3f635aa5d08ebc2b3361f6ea4c Mon Sep 17 00:00:00 2001 From: ispyisail Date: Sat, 26 Sep 2026 08:22:12 +1200 Subject: [PATCH 05/13] Add an option to keep the folio row and column headers visible (#1034) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Affichage > "Garder les en-têtes visibles" adds a bar along the top and the left of the diagram view that repeats the folio's column numbers and row letters, aligned with the cells at any zoom, so they stay in sight when the folio's own headers are scrolled away. Off by default; the choice is stored as diagrameditor/cell_rulers. The bars are CellRuler widgets in the view's margins (setViewportMargins), not scene items, so printing and PDF/PNG/DXF export never see them, and they paint with the application palette outside of the dark-palette inversion. They keep a constant thickness; when cells get narrower than their labels, only every 2nd, 5th, 10th... label is written. A bar is hidden when the folio hides that header. Showing or hiding them keeps the centre of the view where it was. The labels come from BorderCellLabels, now also used by BorderTitleBlock::draw(), so the bars and the border cannot disagree. PNG export of all 133 folios of the examples is pixel-identical to master, with border-columns_0 true and false. Known limits: changing border-columns_0 repaints the bars at the next scroll or zoom; the menu toggle updates the views of its own editor window only, like the grid toggle. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- cmake/qet_compilation_vars.cmake | 3 + sources/bordercelllabels.h | 51 ++++++++ sources/bordertitleblock.cpp | 16 +-- sources/cellruler.cpp | 170 ++++++++++++++++++++++++++ sources/cellruler.h | 54 ++++++++ sources/diagramview.cpp | 91 ++++++++++++++ sources/diagramview.h | 10 ++ sources/qetdiagrameditor.cpp | 14 +++ sources/qetdiagrameditor.h | 1 + tests/qttest/CMakeLists.txt | 6 + tests/qttest/tst_bordercelllabels.cpp | 55 +++++++++ 11 files changed, 460 insertions(+), 11 deletions(-) create mode 100644 sources/bordercelllabels.h create mode 100644 sources/cellruler.cpp create mode 100644 sources/cellruler.h create mode 100644 tests/qttest/tst_bordercelllabels.cpp diff --git a/cmake/qet_compilation_vars.cmake b/cmake/qet_compilation_vars.cmake index 5721e4111..1bf68b48d 100644 --- a/cmake/qet_compilation_vars.cmake +++ b/cmake/qet_compilation_vars.cmake @@ -168,6 +168,9 @@ set(QET_SRC_FILES ${QET_DIR}/sources/borderproperties.h ${QET_DIR}/sources/bordertitleblock.cpp ${QET_DIR}/sources/bordertitleblock.h + ${QET_DIR}/sources/bordercelllabels.h + ${QET_DIR}/sources/cellruler.cpp + ${QET_DIR}/sources/cellruler.h ${QET_DIR}/sources/conductorautonumerotation.cpp ${QET_DIR}/sources/conductorautonumerotation.h ${QET_DIR}/sources/conductornumexport.cpp diff --git a/sources/bordercelllabels.h b/sources/bordercelllabels.h new file mode 100644 index 000000000..d5dbb6e29 --- /dev/null +++ b/sources/bordercelllabels.h @@ -0,0 +1,51 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#ifndef BORDERCELLLABELS_H +#define BORDERCELLLABELS_H + +#include + +/// The labels the border of a folio writes on its rows and columns, shared +/// by BorderTitleBlock::draw() and the cell rulers of DiagramView so the +/// two cannot disagree. Header-only so it can be unit-tested directly -- +/// see tests/qttest/tst_bordercelllabels.cpp. +namespace BorderCellLabels { + + /// @return the label of row \a row, counted from 1: A..Z, then AA, AB... + /// (the sequence BorderTitleBlock::incrementLetters() walks through). + inline QString rowLabel(int row) + { + QString label; + while (row > 0) { + --row; + label.prepend(QChar('A' + row % 26)); + row /= 26; + } + return label; + } + + /// @return the label of column \a column, counted from 1. When + /// \a starts_at_zero (the "border-columns_0" setting) the first column + /// is labelled 0. + inline QString columnLabel(int column, bool starts_at_zero) + { + return QString::number(starts_at_zero ? column - 1 : column); + } +} + +#endif // BORDERCELLLABELS_H diff --git a/sources/bordertitleblock.cpp b/sources/bordertitleblock.cpp index 4a2a2dfdc..46e3f7ba8 100644 --- a/sources/bordertitleblock.cpp +++ b/sources/bordertitleblock.cpp @@ -17,6 +17,7 @@ */ #include "bordertitleblock.h" +#include "bordercelllabels.h" #include "createdxf.h" #include "diagram.h" #include "diagramposition.h" @@ -533,6 +534,8 @@ void BorderTitleBlock::draw(QPainter *painter) //Draw the nums of columns if (display_border_ && display_columns_) { + const bool columns_start_at_zero = + settings.value("border-columns_0", true).toBool(); for (int i = 1 ; i <= columns_count_ ; ++ i) { QRectF numbered_rectangle = QRectF( diagram_rect_.topLeft().x() @@ -543,23 +546,15 @@ void BorderTitleBlock::draw(QPainter *painter) columns_header_height_ ); painter -> drawRect(numbered_rectangle); - if (settings.value("border-columns_0", true).toBool()){ painter -> drawText(numbered_rectangle, Qt::AlignVCenter | Qt::AlignCenter, - QString("%1").arg(i - 1)); - }else{ - painter -> drawText(numbered_rectangle, - Qt::AlignVCenter - | Qt::AlignCenter, - QString("%1").arg(i)); - } + BorderCellLabels::columnLabel(i, columns_start_at_zero)); } } //Draw the nums of rows if (display_border_ && display_rows_) { - QString row_string("A"); for (int i = 1 ; i <= rows_count_ ; ++ i) { QRectF lettered_rectangle = QRectF( diagram_rect_.topLeft().x(), @@ -575,8 +570,7 @@ void BorderTitleBlock::draw(QPainter *painter) painter -> drawText(lettered_rectangle, Qt::AlignVCenter | Qt::AlignCenter, - row_string); - row_string = incrementLetters(row_string); + BorderCellLabels::rowLabel(i)); } } diff --git a/sources/cellruler.cpp b/sources/cellruler.cpp new file mode 100644 index 000000000..299d70eb8 --- /dev/null +++ b/sources/cellruler.cpp @@ -0,0 +1,170 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#include "cellruler.h" + +#include "bordercelllabels.h" +#include "diagram.h" +#include "diagramview.h" + +#include +#include + +/** + @brief CellRuler::CellRuler + @param orientation : Qt::Horizontal for the column numbers along the + top, Qt::Vertical for the row letters along the left + @param view : the view this ruler is placed on +*/ +CellRuler::CellRuler(Qt::Orientation orientation, DiagramView *view) : + QWidget(view), + m_orientation(orientation), + m_view(view) +{ + setAttribute(Qt::WA_OpaquePaintEvent); + hide(); +} + +/** + @brief CellRuler::thickness + @return the height of the top ruler, which is also the width of the + side ruler, so the corner they share is square. Constant whatever the + zoom. +*/ +int CellRuler::thickness() const +{ + const QFontMetrics metrics = fontMetrics(); + return qMax(metrics.height(), metrics.horizontalAdvance(QStringLiteral("WW"))) + 6; +} + +/** + @brief CellRuler::setLeadingSpace + @param space : pixels left empty before the first pixel of the + viewport, along this ruler +*/ +void CellRuler::setLeadingSpace(int space) +{ + m_leading_space = space; + update(); +} + +/** + @brief CellRuler::paintEvent + Draw a cell for each column (or row) of the folio border, at the + position the view shows it. When the cells get too small for their + labels, only one label every 2, 5, 10... cells is written. +*/ +void CellRuler::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + + QPainter painter(this); + painter.fillRect(rect(), palette().color(QPalette::Button)); + + const bool horizontal = m_orientation == Qt::Horizontal; + const int length = horizontal ? width() : height(); + const int depth = horizontal ? height() : width(); + + //Separate the ruler from the drawing + painter.setPen(palette().color(QPalette::Dark)); + if (horizontal) { + painter.drawLine(0, depth - 1, length, depth - 1); + } else { + painter.drawLine(depth - 1, 0, depth - 1, length); + } + + Diagram *diagram = m_view->diagram(); + if (!diagram) { + return; + } + const BorderTitleBlock &border = diagram->border_and_titleblock; + const QRectF inside = border.insideBorderRect(); + const QTransform transform = m_view->viewportTransform(); + + const int count = horizontal ? border.columnsCount() : border.rowsCount(); + const qreal cell_size = horizontal ? border.columnsWidth() : border.rowsHeight(); + const qreal first = horizontal ? inside.left() : inside.top(); + const qreal scale = horizontal ? transform.m11() : transform.m22(); + const qreal offset = (horizontal ? transform.dx() : transform.dy()) + m_leading_space; + const qreal cell_pixels = cell_size * scale; + if (count < 1 || cell_pixels <= 0) { + return; + } + + const bool columns_start_at_zero = + QSettings().value("border-columns_0", true).toBool(); + auto label = [&](int index) { + return horizontal ? BorderCellLabels::columnLabel(index, columns_start_at_zero) + : BorderCellLabels::rowLabel(index); + }; + + //Room one label needs along the ruler, and the smallest step + //between written labels that gives it that room + const QFontMetrics metrics = fontMetrics(); + const int label_room = horizontal + ? metrics.horizontalAdvance(label(count)) + 6 + : metrics.height() + 2; + int step = 1; + for (int candidate : {1, 2, 5, 10, 20, 50, 100, 200, 500}) { + step = candidate; + if (candidate * cell_pixels >= label_room) { + break; + } + } + + for (int i = 1 ; i <= count ; ++i) { + const qreal start = offset + (first + (i - 1) * cell_size) * scale; + const qreal end = start + cell_pixels; + if (end < m_leading_space || start > length) { + continue; + } + + //Cell edges, drawn only when the cells are wide enough + //for them to read as cells rather than as a hatching + painter.setPen(palette().color(QPalette::Dark)); + if (cell_pixels >= 4) { + if (horizontal) { + painter.drawLine(QPointF(start, 0), QPointF(start, depth - 1)); + if (i == count) painter.drawLine(QPointF(end, 0), QPointF(end, depth - 1)); + } else { + painter.drawLine(QPointF(0, start), QPointF(depth - 1, start)); + if (i == count) painter.drawLine(QPointF(0, end), QPointF(depth - 1, end)); + } + } + + //Written labels are the ones a multiple of step: 0, 5, 10... + //for the columns, A, F, K... for the rows + const int position = (horizontal && !columns_start_at_zero) ? i : i - 1; + if (position % step != 0) { + continue; + } + + painter.setPen(palette().color(QPalette::ButtonText)); + const qreal centre = (start + end) / 2; + const QRectF text_rect = horizontal + ? QRectF(centre - label_room / 2.0, 0, label_room, depth - 1) + : QRectF(0, centre - label_room / 2.0, depth - 1, label_room); + painter.drawText(text_rect, Qt::AlignCenter | Qt::TextDontClip, label(i)); + } + + //Keep the corner empty: the other ruler's labels do not belong there + if (m_leading_space > 0) { + painter.fillRect(horizontal ? QRect(0, 0, m_leading_space, depth - 1) + : QRect(0, 0, depth - 1, m_leading_space), + palette().color(QPalette::Button)); + } +} diff --git a/sources/cellruler.h b/sources/cellruler.h new file mode 100644 index 000000000..619b2d52e --- /dev/null +++ b/sources/cellruler.h @@ -0,0 +1,54 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#ifndef CELLRULER_H +#define CELLRULER_H + +#include + +class DiagramView; + +/** + @brief The CellRuler class + A bar along the top or the left edge of a DiagramView that repeats the + column numbers or the row letters of the folio border, aligned with the + cells at any zoom, so they stay in sight however far the view is + scrolled. It sits in the view's margins, outside of the scene: printing + and exporting are unaffected. +*/ +class CellRuler : public QWidget +{ + Q_OBJECT + + public: + CellRuler(Qt::Orientation orientation, DiagramView *view); + + int thickness() const; + void setLeadingSpace(int space); + + protected: + void paintEvent(QPaintEvent *event) override; + + private: + Qt::Orientation m_orientation; + DiagramView *m_view; + /// Pixels before the viewport starts, left empty: the corner the + /// side ruler fills when both rulers are shown. + int m_leading_space = 0; +}; + +#endif // CELLRULER_H diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index 843b694be..276ccc15d 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -16,6 +16,7 @@ along with QElectroTech. If not, see . */ #include "diagramview.h" +#include "cellruler.h" #include "lastusedstyle.h" #include "qetproject.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" @@ -107,6 +108,13 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) : connect(&(m_diagram -> border_and_titleblock), &BorderTitleBlock::informationChanged, this, &DiagramView::updateWindowTitle); connect(diagram, &Diagram::findElementRequired, this, &DiagramView::findElementRequired); + m_top_ruler = new CellRuler(Qt::Horizontal, this); + m_side_ruler = new CellRuler(Qt::Vertical, this); + m_cell_rulers_shown = QSettings().value("diagrameditor/cell_rulers", false).toBool(); + connect(&m_diagram->border_and_titleblock, &BorderTitleBlock::borderChanged, this, &DiagramView::updateCellRulers); + connect(&m_diagram->border_and_titleblock, &BorderTitleBlock::displayChanged, this, &DiagramView::updateCellRulers); + updateCellRulers(); + QShortcut *edit_conductor_color_shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this); connect(edit_conductor_color_shortcut, &QShortcut::activated, [this]() { @@ -1170,6 +1178,82 @@ void DiagramView::paintingInverted(bool inverted) m_diagram->setInvertedLightness(inverted); } +/** + @brief DiagramView::setCellRulersShown + Show or hide the rulers that keep the column numbers and the row + letters of the folio border in sight along the edges of this view. + @param shown +*/ +void DiagramView::setCellRulersShown(bool shown) +{ + m_cell_rulers_shown = shown; + updateCellRulers(); +} + +/** + @brief DiagramView::updateCellRulers + Show each ruler when the rulers are wanted and the folio shows the + matching header, and give it room in the margins of the view. The + part of the folio in sight stays in sight when the viewport resizes. +*/ +void DiagramView::updateCellRulers() +{ + const BorderTitleBlock &border = m_diagram->border_and_titleblock; + const bool top = m_cell_rulers_shown + && border.borderIsDisplayed() && border.columnsAreDisplayed(); + const bool side = m_cell_rulers_shown + && border.borderIsDisplayed() && border.rowsAreDisplayed(); + const int thickness = m_top_ruler->thickness(); + + m_top_ruler->setVisible(top); + m_side_ruler->setVisible(side); + m_side_ruler->setLeadingSpace(top ? thickness : 0); + + const QMargins margins(side ? thickness : 0, top ? thickness : 0, 0, 0); + if (margins != viewportMargins()) { + const QPointF centre = mapToScene(viewport()->rect().center()); + setViewportMargins(margins); + centerOn(centre); + } + placeCellRulers(); + m_top_ruler->update(); + m_side_ruler->update(); +} + +/** + @brief DiagramView::placeCellRulers + Lay the rulers along the top and the left edges of the viewport, the + side ruler covering the corner too when both are shown. +*/ +void DiagramView::placeCellRulers() +{ + if (!m_top_ruler) { + return; + } + const QRect viewport_rect = viewport()->geometry(); + const int thickness = m_top_ruler->thickness(); + const int corner = m_top_ruler->isHidden() ? 0 : thickness; + m_top_ruler->setGeometry(viewport_rect.left(), viewport_rect.top() - thickness, + viewport_rect.width(), thickness); + m_side_ruler->setGeometry(viewport_rect.left() - thickness, viewport_rect.top() - corner, + thickness, viewport_rect.height() + corner); +} + +/** + @brief DiagramView::viewportEvent + Keep the rulers along the viewport when it resizes, which it also does + without the view resizing, when the scroll bars come and go. + @param event + @return what QGraphicsView::viewportEvent() returns +*/ +bool DiagramView::viewportEvent(QEvent *event) +{ + if (event->type() == QEvent::Resize) { + placeCellRulers(); + } + return PaletteGraphicsView::viewportEvent(event); +} + /** @brief DiagramView::paintEvent Reimplemented from QGraphicsView @@ -1179,6 +1263,13 @@ void DiagramView::paintEvent(QPaintEvent *event) { PaletteGraphicsView::paintEvent(event); + //Scrolling and zooming both repaint the viewport: follow them + if (viewportTransform() != m_rulers_transform) { + m_rulers_transform = viewportTransform(); + m_top_ruler->update(); + m_side_ruler->update(); + } + if (m_free_rubberbanding && m_free_rubberband.count() >= 3) { QPainter painter(viewport()); diff --git a/sources/diagramview.h b/sources/diagramview.h index eb73432cb..f7544b66a 100644 --- a/sources/diagramview.h +++ b/sources/diagramview.h @@ -24,6 +24,7 @@ #include #include "palettegraphicsview.h" +class CellRuler; class Conductor; class Diagram; class QETDiagramEditor; @@ -62,6 +63,11 @@ class DiagramView : public PaletteGraphicsView QList m_separators; QPolygonF m_free_rubberband; bool m_free_rubberbanding = false; + CellRuler *m_top_ruler = nullptr; + CellRuler *m_side_ruler = nullptr; + bool m_cell_rulers_shown = false; + /// Last viewport transform the rulers were painted for + QTransform m_rulers_transform; public: @@ -78,6 +84,7 @@ class DiagramView : public PaletteGraphicsView /// cursor query (QCursor::pos()/setPos() are silently ignored by /// several window managers and compositors, Wayland included). QPoint lastMousePos() const { return m_last_mouse_pos; } + void setCellRulersShown(bool shown); protected: void mouseDoubleClickEvent(QMouseEvent *) override; @@ -91,6 +98,7 @@ class DiagramView : public PaletteGraphicsView ///Set for one call only, by the Escape handler, to let focus leave the view. bool m_releasing_focus = false; void paintEvent(QPaintEvent *event) override; + bool viewportEvent(QEvent *event) override; void paintingInverted(bool inverted) override; void mousePressEvent(QMouseEvent *) override; void mouseMoveEvent(QMouseEvent *) override; @@ -113,6 +121,8 @@ class DiagramView : public PaletteGraphicsView QRectF viewedSceneRect() const; bool mustIntegrateTitleBlockTemplate(const TitleBlockTemplateLocation &) const; bool gestures() const; + void updateCellRulers(); + void placeCellRulers(); /// Lowest and highest allowed value of the view transform scale (m11). /// Prevents wheel-zoom from driving the transform to overflow, which diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index da26262b2..2565c41a7 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -493,6 +493,18 @@ void QETDiagramEditor::setUpActions() } }); + //Keep the column numbers and row letters of the folio in sight + m_cell_rulers = new QAction(tr("Garder les en-têtes visibles"), this); + m_cell_rulers->setStatusTip(tr("Garde les numéros de colonne et les lettres de ligne du folio visibles au bord de la vue")); + m_cell_rulers->setCheckable(true); + m_cell_rulers->setChecked(settings.value("diagrameditor/cell_rulers", false).toBool()); + connect(m_cell_rulers, &QAction::triggered, [this](bool checked) { + QSettings().setValue("diagrameditor/cell_rulers", checked); + foreach (ProjectView *prjv, this->openedProjects()) + foreach (DiagramView *dv, prjv->diagram_views()) + dv->setCellRulersShown(checked); + }); + //Edit current diagram properties m_edit_diagram_properties = new QAction(QET::Icons::DialogInformation, tr("Propriétés du folio"), this); ShortcutManager::instance().registerAction(m_edit_diagram_properties, "diagrameditor.edit_diagram_properties", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_L); @@ -1110,6 +1122,7 @@ void QETDiagramEditor::setUpMenu() menu_affichage -> addSeparator(); menu_affichage -> addAction(m_draw_grid); menu_affichage -> addAction(m_draw_guides); + menu_affichage -> addAction(m_cell_rulers); menu_affichage -> addMenu(m_background_color_button->menu()); menu_affichage -> addSeparator(); menu_affichage -> addActions(m_zoom_actions_group.actions()); @@ -1941,6 +1954,7 @@ void QETDiagramEditor::slot_updateActions() m_background_color_button-> setEnabled(opened_diagram); m_draw_grid-> setEnabled(opened_diagram); m_draw_guides-> setEnabled(opened_diagram); + m_cell_rulers-> setEnabled(opened_diagram); //Project menu m_project_edit_properties -> setEnabled(opened_project); diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 71ad56244..41a95fa48 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -205,6 +205,7 @@ class QETDiagramEditor : public QETMainWindow *m_auto_break_conductor, ///< Enable/Disable the use of auto break conductor *m_draw_grid, ///< Switch the background grid display or not *m_draw_guides = nullptr, ///< Switch the custom guides display or not + *m_cell_rulers = nullptr, ///< Keep the folio column/row headers in sight or not *m_project_edit_properties, ///< Edit the properties of the current project. *m_project_add_diagram, ///< Add a diagram to the current project. *m_remove_diagram_from_project, ///< Delete a diagram from the current project diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt index 2fec5922f..4274e13d2 100644 --- a/tests/qttest/CMakeLists.txt +++ b/tests/qttest/CMakeLists.txt @@ -84,6 +84,12 @@ add_test(NAME tst_diagramsortkeys COMMAND tst_diagramsortkeys) target_include_directories(tst_diagramsortkeys PRIVATE ${QET_DIR}/sources) target_link_libraries(tst_diagramsortkeys PRIVATE Qt::Test) +# bordercelllabels.h is header-only too. +add_executable(tst_bordercelllabels tst_bordercelllabels.cpp) +add_test(NAME tst_bordercelllabels COMMAND tst_bordercelllabels) +target_include_directories(tst_bordercelllabels PRIVATE ${QET_DIR}/sources) +target_link_libraries(tst_bordercelllabels PRIVATE Qt::Test) + # contactusage.h is a header-only helper holding the contact counting # rules, so this test builds independently of the rest of the QET sources. add_executable(tst_contactusage tst_contactusage.cpp) diff --git a/tests/qttest/tst_bordercelllabels.cpp b/tests/qttest/tst_bordercelllabels.cpp new file mode 100644 index 000000000..7c4ca074b --- /dev/null +++ b/tests/qttest/tst_bordercelllabels.cpp @@ -0,0 +1,55 @@ +#include + +#include "bordercelllabels.h" + +class tst_bordercelllabels : public QObject +{ + Q_OBJECT + + // A copy of BorderTitleBlock::incrementLetters(), the walk the folio + // border used to draw its row labels with, as the reference rowLabel() + // must reproduce. + static QString incrementLetters(const QString &string) + { + if (string.isEmpty()) + return QStringLiteral("A"); + const QString first_digits(string.left(string.length() - 1)); + const QChar last_digit(string.at(string.length() - 1)); + if (last_digit != QLatin1Char('Z')) + return first_digits + QChar(last_digit.unicode() + 1); + return incrementLetters(first_digits) + QLatin1Char('A'); + } + +private slots: + void rowLabelsFollowTheBorderSequence() + { + QString expected(QStringLiteral("A")); + for (int row = 1; row <= 1000; ++row) { + QCOMPARE(BorderCellLabels::rowLabel(row), expected); + expected = incrementLetters(expected); + } + } + + void rowLabelSamples() + { + QCOMPARE(BorderCellLabels::rowLabel(1), QStringLiteral("A")); + QCOMPARE(BorderCellLabels::rowLabel(26), QStringLiteral("Z")); + QCOMPARE(BorderCellLabels::rowLabel(27), QStringLiteral("AA")); + QCOMPARE(BorderCellLabels::rowLabel(52), QStringLiteral("AZ")); + QCOMPARE(BorderCellLabels::rowLabel(53), QStringLiteral("BA")); + QCOMPARE(BorderCellLabels::rowLabel(702), QStringLiteral("ZZ")); + QCOMPARE(BorderCellLabels::rowLabel(703), QStringLiteral("AAA")); + } + + void columnLabels() + { + QCOMPARE(BorderCellLabels::columnLabel(1, true), QStringLiteral("0")); + QCOMPARE(BorderCellLabels::columnLabel(1, false), QStringLiteral("1")); + QCOMPARE(BorderCellLabels::columnLabel(17, true), QStringLiteral("16")); + QCOMPARE(BorderCellLabels::columnLabel(17, false), QStringLiteral("17")); + } +}; + +QTEST_APPLESS_MAIN(tst_bordercelllabels) + +#include "tst_bordercelllabels.moc" From 2807771200533edc8f725ffff2591d9fa6032be5 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Sat, 26 Sep 2026 08:36:53 +1200 Subject: [PATCH 06/13] Jump to a cell on another folio from Ctrl+G, typed as 3-B13 The popup now also takes a folio position before the cell, the way cross references and folio reports write it by default (%f-%l%c): 3-B13 offers "Folio 3 (), case B13", and Enter shows that folio and zooms onto the cell. Case and a leading "p" are ignored, and the separator is optional: 3-b13, 3b13, P3B13 and p3-b13 all work. A plain B13 still means the current folio, and P3 alone is still row P, column 3: a folio always needs a cell after it. A folio position past the last folio, or a cell outside that folio's border, offers nothing. The zoom on another folio is queued, so it runs once the tab switch has been handled. Checked on the ATS example: jumping to 1-C5 from folio 3 gives the same view, pixel for pixel, as C5 typed on folio 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- sources/ui/jumptoelementdialog.cpp | 115 +++++++++++++++++++++++------ sources/ui/jumptoelementdialog.h | 8 +- 2 files changed, 97 insertions(+), 26 deletions(-) diff --git a/sources/ui/jumptoelementdialog.cpp b/sources/ui/jumptoelementdialog.cpp index 118a4c8e0..65b2615b3 100644 --- a/sources/ui/jumptoelementdialog.cpp +++ b/sources/ui/jumptoelementdialog.cpp @@ -19,12 +19,14 @@ #include "../diagram.h" #include "../diagramview.h" +#include "../qetproject.h" #include "../qetgraphicsitem/element.h" #include <QEvent> #include <QKeyEvent> #include <QLineEdit> #include <QListWidget> +#include <QRegularExpression> #include <QVBoxLayout> /** @@ -39,7 +41,7 @@ JumpToElementDialog::JumpToElementDialog(Diagram *diagram, QWidget *parent) : setWindowTitle(tr("Atteindre un élément", "window title")); m_filter_edit = new QLineEdit(this); - m_filter_edit->setPlaceholderText(tr("Nom, label ou information de l'élément, ou case (ex. B13)…")); + m_filter_edit->setPlaceholderText(tr("Nom, label ou information de l'élément, ou case (ex. B13 ou 3-B13)…")); m_filter_edit->installEventFilter(this); m_result_list = new QListWidget(this); @@ -129,18 +131,13 @@ void JumpToElementDialog::updateFilteredList(const QString &filter_text) } } - //A cell of the border (ex : B13) comes first, unless an element - //is labelled exactly like it: Enter keeps jumping to that element. - if (m_diagram) { - const QRectF cell_rect = m_diagram->border_and_titleblock.cellRect(needle); - if (!cell_rect.isNull()) { - auto *cell_item = new QListWidgetItem( - tr("Case %1").arg(QString(needle).remove(QLatin1Char(' ')).toUpper())); - cell_item->setData(Qt::UserRole, -1); - cell_item->setData(Qt::UserRole + 1, cell_rect); - m_result_list->insertItem(exact_label_match ? m_result_list->count() : 0, - cell_item); - } + //A cell of the border, on this folio (ex : B13) or on another one + //(ex : 3-B13, folio 3, the way cross references write it), comes + //first, unless an element is labelled exactly like it: Enter keeps + //jumping to that element. + if (QListWidgetItem *cell_item = cellItem(needle)) { + m_result_list->insertItem(exact_label_match ? m_result_list->count() : 0, + cell_item); } if (m_result_list->count() > 0) { @@ -163,7 +160,13 @@ void JumpToElementDialog::activateCurrentItem() const int index = current->data(Qt::UserRole).toInt(); if (index == -1) { - zoomToCell(current->data(Qt::UserRole + 1).toRectF()); + const QList<Diagram *> diagrams = m_diagram->project() + ? m_diagram->project()->diagrams() + : QList<Diagram *>(); + const int folio = current->data(Qt::UserRole + 2).toInt(); + if (folio >= 0 && folio < diagrams.size()) { + zoomToCell(diagrams.at(folio), current->data(Qt::UserRole + 1).toRectF()); + } accept(); return; } @@ -184,22 +187,88 @@ void JumpToElementDialog::activateCurrentItem() accept(); } +/** + @brief JumpToElementDialog::cellItem + @param needle : the typed text, trimmed and lower case + @return a new list item for the cell \a needle names, on m_diagram + (ex : b13) or on the folio at a position of the project (ex : 3-b13, + 3b13, p3b13), or nullptr if \a needle names no cell of an existing + folio. The item holds -1, the cell rect and the folio position. +*/ +QListWidgetItem *JumpToElementDialog::cellItem(const QString &needle) const +{ + if (!m_diagram || !m_diagram->project()) { + return nullptr; + } + const QList<Diagram *> diagrams = m_diagram->project()->diagrams(); + + Diagram *diagram = m_diagram; + QString cell = needle; + QString text; + QRectF cell_rect = diagram->border_and_titleblock.cellRect(cell); + if (cell_rect.isNull()) { + //A folio position then a cell, like %f-%l%c in cross references + static const QRegularExpression folio_cell_re( + QStringLiteral("^p?\\s*(\\d{1,4})\\s*[-/.:]?\\s*([a-z]+\\s*\\d{1,4})$")); + const QRegularExpressionMatch match = folio_cell_re.match(needle); + if (!match.hasMatch()) { + return nullptr; + } + const int folio = match.captured(1).toInt(); + if (folio < 1 || folio > diagrams.size()) { + return nullptr; + } + diagram = diagrams.at(folio - 1); + cell = match.captured(2); + cell_rect = diagram->border_and_titleblock.cellRect(cell); + if (cell_rect.isNull()) { + return nullptr; + } + } + + cell = cell.remove(QLatin1Char(' ')).toUpper(); + if (diagram == m_diagram) { + text = tr("Case %1").arg(cell); + } else { + const QString title = diagram->title(); + text = title.isEmpty() + ? tr("Folio %1, case %2").arg(diagrams.indexOf(diagram) + 1).arg(cell) + : tr("Folio %1 (%2), case %3").arg(diagrams.indexOf(diagram) + 1).arg(title, cell); + } + + auto *item = new QListWidgetItem(text); + item->setData(Qt::UserRole, -1); + item->setData(Qt::UserRole + 1, cell_rect); + item->setData(Qt::UserRole + 2, diagrams.indexOf(diagram)); + return item; +} + /** @brief JumpToElementDialog::zoomToCell - Zoom the view of m_diagram on \a cell_rect with one cell of context - around it. + Show \a diagram and zoom its view on \a cell_rect with one cell of + context around it. + @param diagram : the folio holding the cell @param cell_rect : the cell, in scene coordinate */ -void JumpToElementDialog::zoomToCell(const QRectF &cell_rect) +void JumpToElementDialog::zoomToCell(Diagram *diagram, const QRectF &cell_rect) { - if (!m_diagram) { - return; + const QRectF rect = cell_rect.adjusted(-cell_rect.width(), -cell_rect.height(), + cell_rect.width(), cell_rect.height()); + const bool other_folio = diagram != m_diagram; + if (other_folio) { + diagram->showMe(); } - for (QGraphicsView *view : m_diagram->views()) { + for (QGraphicsView *view : diagram->views()) { if (auto *diagram_view = qobject_cast<DiagramView *>(view)) { - diagram_view->zoomToRect(cell_rect.adjusted( - -cell_rect.width(), -cell_rect.height(), - cell_rect.width(), cell_rect.height())); + if (other_folio) { + //A folio shown for the first time is laid out at + //its size once the tab switch has been handled + QMetaObject::invokeMethod(diagram_view, [diagram_view, rect]() { + diagram_view->zoomToRect(rect); + }, Qt::QueuedConnection); + } else { + diagram_view->zoomToRect(rect); + } return; } } diff --git a/sources/ui/jumptoelementdialog.h b/sources/ui/jumptoelementdialog.h index 4a34d1f2b..880e4efa2 100644 --- a/sources/ui/jumptoelementdialog.h +++ b/sources/ui/jumptoelementdialog.h @@ -25,14 +25,15 @@ class Diagram; class Element; class QLineEdit; class QListWidget; +class QListWidgetItem; /** @brief The JumpToElementDialog class A lightweight, transient "quick open" popup: type part of an element's label or other information to live-filter the elements on a diagram, then Enter to select the chosen element on the diagram and scroll it - into view. Typing a cell of the border instead (ex : B13) offers to - zoom on that cell. Up/Down move through the filtered list, Escape cancels + into view. Typing a cell of the border instead (ex : B13, or 3-B13 for + the third folio of the project) offers to zoom on that cell. Up/Down move through the filtered list, Escape cancels without changing the current selection. */ class JumpToElementDialog : public QDialog @@ -52,7 +53,8 @@ class JumpToElementDialog : public QDialog private: void buildCandidates(); - void zoomToCell(const QRectF &cell_rect); + QListWidgetItem *cellItem(const QString &needle) const; + void zoomToCell(Diagram *diagram, const QRectF &cell_rect); struct Candidate { QPointer<Element> element; From 0e02190eb2a439b43ad6cd5f609c6f8614ce5407 Mon Sep 17 00:00:00 2001 From: ispyisail <shane.ringrose@gmail.com> Date: Sat, 26 Sep 2026 09:15:35 +1200 Subject: [PATCH 07/13] Add a finer snap grid for dragged texts Texts snapped to the folio grid, so the first drag of an off-grid label pulled it sideways by up to half a grid step (discussion #1020). Texts now snap to a fraction of the folio grid, chosen from a "Textes 1:N" button in the View toolbar and a menu under Affichage: Off, 1:1, 1:2, 1:2.5, 1:5, 1:10. Because the step divides the folio grid, texts on different elements still line up. Ctrl still places a text freely. 1:1 is the default and matches the previous behaviour. The setting is stored in QSettings; nothing changes in saved projects. All five text movers switch together: element texts, text groups, texts moved with a selection, conductor texts and independent texts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- sources/diagram.cpp | 30 +++++++++++++++ sources/diagram.h | 1 + sources/elementtextsmover.cpp | 2 +- sources/qetdiagrameditor.cpp | 38 +++++++++++++++++++ sources/qetdiagrameditor.h | 4 ++ sources/qetgraphicsitem/conductortextitem.cpp | 2 +- sources/qetgraphicsitem/diagramtextitem.cpp | 2 +- .../dynamicelementtextitem.cpp | 2 +- .../qetgraphicsitem/elementtextitemgroup.cpp | 2 +- 9 files changed, 78 insertions(+), 5 deletions(-) diff --git a/sources/diagram.cpp b/sources/diagram.cpp index 01a6e63d2..022b0a9d2 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -2684,6 +2684,36 @@ QPointF Diagram::snapToGrid(const QPointF &p) return (QPointF(p_x, p_y)); } +/** + @brief Diagram::snapToTextGrid + Return the nearest point of p on the text grid. + The text grid is the folio grid divided by the + "diagrameditor/text_grid_divisor" setting (1 = same as the folio grid, + 0 = no grid). Because it divides the folio grid, texts snapped to it + still line up with every element and with each other. + Ctrl held, or a divisor of 0, rounds to the nearest pixel instead. + @param p point to find the nearest snapped point + @return +*/ +QPointF Diagram::snapToTextGrid(const QPointF &p) +{ + QSettings settings; + const qreal divisor = settings.value( + QStringLiteral("diagrameditor/text_grid_divisor"), + 1).toReal(); + + if (divisor <= 0 + || QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) + return QPointF(qRound(p.x()), qRound(p.y())); + + const qreal x_step = settings.value(QStringLiteral("diagrameditor/Xgrid"), + Diagram::xGrid).toInt() / divisor; + const qreal y_step = settings.value(QStringLiteral("diagrameditor/Ygrid"), + Diagram::yGrid).toInt() / divisor; + return QPointF(qRound(p.x() / x_step) * x_step, + qRound(p.y() / y_step) * y_step); +} + /** diff --git a/sources/diagram.h b/sources/diagram.h index 198323bbc..244299a04 100644 --- a/sources/diagram.h +++ b/sources/diagram.h @@ -233,6 +233,7 @@ class Diagram : public QGraphicsScene BorderOptions borderOptions(); DiagramPosition convertPosition(const QPointF &); static QPointF snapToGrid(const QPointF &p); + static QPointF snapToTextGrid(const QPointF &p); bool drawTerminals() const; void setDrawTerminals(bool); diff --git a/sources/elementtextsmover.cpp b/sources/elementtextsmover.cpp index ddf2f235c..f0b61139a 100644 --- a/sources/elementtextsmover.cpp +++ b/sources/elementtextsmover.cpp @@ -101,7 +101,7 @@ void ElementTextsMover::continueMovement(QGraphicsSceneMouseEvent *event) button_down_parent_pos = qgi->mapToParent(qgi->mapFromScene(event->buttonDownScenePos(Qt::LeftButton))); QPointF new_pos = m_items_hash.value(qgi) + current_parent_pos - button_down_parent_pos; - event->modifiers() == Qt::ControlModifier ? qgi->setPos(new_pos) : qgi->setPos(Diagram::snapToGrid(new_pos)); + event->modifiers() == Qt::ControlModifier ? qgi->setPos(new_pos) : qgi->setPos(Diagram::snapToTextGrid(new_pos)); } } diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index da26262b2..1c2d1c410 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -20,6 +20,7 @@ #include "scripting/qetscripting.h" #endif #include <QCoreApplication> +#include <QToolButton> #include "ElementsCollection/elementscollectionwidget.h" #include "QWidgetAnimation/qwidgetanimation.h" #include "autoNum/ui/autonumberingdockwidget.h" @@ -481,6 +482,41 @@ void QETDiagramEditor::setUpActions() } }); + //Snap step for dragged texts, as a fraction of the folio grid + m_text_grid_menu = new QMenu(tr("Grille des textes"), this); + m_text_grid_menu->setIcon(QET::Icons::Grid); + m_text_grid_menu->setToolTipsVisible(true); + m_text_grid_button = new QToolButton(this); + m_text_grid_button->setMenu(m_text_grid_menu); + m_text_grid_button->setPopupMode(QToolButton::InstantPopup); + m_text_grid_button->setToolButtonStyle(Qt::ToolButtonTextOnly); + m_text_grid_button->setToolTip(tr("Grille d'accrochage des textes déplacés à la souris.\n" + "Maintenir Ctrl pendant le déplacement pour placer librement.")); + auto text_grid_group = new QActionGroup(this); + const qreal current_divisor = settings.value("diagrameditor/text_grid_divisor", 1).toReal(); + const QList<QPair<QString, qreal>> text_grids { + {tr("Désactivée"), 0}, + {QStringLiteral("1:1"), 1}, + {QStringLiteral("1:2"), 2}, + {QStringLiteral("1:2.5"), 2.5}, + {QStringLiteral("1:5"), 5}, + {QStringLiteral("1:10"), 10}}; + for (const auto &grid : text_grids) + { + QAction *action = m_text_grid_menu->addAction(grid.first); + action->setCheckable(true); + action->setData(grid.second); + text_grid_group->addAction(action); + if (qFuzzyCompare(grid.second + 1, current_divisor + 1)) { + action->setChecked(true); + m_text_grid_button->setText(tr("Textes %1").arg(grid.first)); + } + } + connect(text_grid_group, &QActionGroup::triggered, this, [this](QAction *action) { + QSettings().setValue("diagrameditor/text_grid_divisor", action->data()); + m_text_grid_button->setText(tr("Textes %1").arg(action->text())); + }); + // Draw or not the custom guides m_draw_guides = new QAction ( QIcon::fromTheme("guides"), tr("Afficher les guides"), this); m_draw_guides->setStatusTip(tr("Affiche ou masque les guides")); @@ -956,6 +992,7 @@ void QETDiagramEditor::setUpToolBar() view_tool_bar -> addWidget(new DiagramEditorHandlerSizeWidget(this)); view_tool_bar -> addSeparator(); view_tool_bar -> addAction(m_draw_grid); + view_tool_bar -> addWidget(m_text_grid_button); view_tool_bar -> addAction(m_draw_guides); view_tool_bar -> addWidget(m_background_color_button); view_tool_bar -> addSeparator(); @@ -1109,6 +1146,7 @@ void QETDiagramEditor::setUpMenu() menu_affichage -> addAction(m_mode_visualise); menu_affichage -> addSeparator(); menu_affichage -> addAction(m_draw_grid); + menu_affichage -> addMenu(m_text_grid_menu); menu_affichage -> addAction(m_draw_guides); menu_affichage -> addMenu(m_background_color_button->menu()); menu_affichage -> addSeparator(); diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 71ad56244..bf6de32b5 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -28,6 +28,8 @@ #include <QSignalMapper> #include <QUndoGroup> +class QToolButton; + class QMdiSubWindow; class QETProject; class QETResult; @@ -244,6 +246,8 @@ class QETDiagramEditor : public QETMainWindow ConductorColorToolButton *m_conductor_color_button = nullptr; ///< Diagram background color picker, in the "Affichage" toolbar DiagramBgColorToolButton *m_background_color_button = nullptr; + QMenu *m_text_grid_menu = nullptr; ///< Snap step used when dragging texts + QToolButton *m_text_grid_button = nullptr; QList <QAction *> m_zoom_action_toolBar; ///Only zoom action must displayed in the toolbar diff --git a/sources/qetgraphicsitem/conductortextitem.cpp b/sources/qetgraphicsitem/conductortextitem.cpp index e5e2201ac..624b5ea77 100644 --- a/sources/qetgraphicsitem/conductortextitem.cpp +++ b/sources/qetgraphicsitem/conductortextitem.cpp @@ -185,7 +185,7 @@ void ConductorTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (parent_conductor_) { if (parent_conductor_->nearShape().contains(intended_pos)) { - event->modifiers() == Qt::ControlModifier ? setPos(intended_pos) : setPos(Diagram::snapToGrid(intended_pos)); + event->modifiers() == Qt::ControlModifier ? setPos(intended_pos) : setPos(Diagram::snapToTextGrid(intended_pos)); parent_conductor_ -> setHighlighted(Conductor::Normal); } else { parent_conductor_ -> setHighlighted(Conductor::Alert); diff --git a/sources/qetgraphicsitem/diagramtextitem.cpp b/sources/qetgraphicsitem/diagramtextitem.cpp index 4587ab647..771a3d42d 100644 --- a/sources/qetgraphicsitem/diagramtextitem.cpp +++ b/sources/qetgraphicsitem/diagramtextitem.cpp @@ -370,7 +370,7 @@ void DiagramTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { //Set the actual pos QPointF new_pos = event->scenePos() + m_mouse_to_origin_movement; - event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToGrid(new_pos)); + event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToTextGrid(new_pos)); //Update the actual movement for other selected item diff --git a/sources/qetgraphicsitem/dynamicelementtextitem.cpp b/sources/qetgraphicsitem/dynamicelementtextitem.cpp index 1316d992b..fda123da9 100644 --- a/sources/qetgraphicsitem/dynamicelementtextitem.cpp +++ b/sources/qetgraphicsitem/dynamicelementtextitem.cpp @@ -639,7 +639,7 @@ void DynamicElementTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) //DiagramTextItem::mouseMoveEvent() for independent texts. //Without it this was the only text move in the editor that //ignored the grid. - event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToGrid(new_pos)); + event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToTextGrid(new_pos)); if(diagram()) diagram()->elementTextsMover().continueMovement(event); diff --git a/sources/qetgraphicsitem/elementtextitemgroup.cpp b/sources/qetgraphicsitem/elementtextitemgroup.cpp index 253c10146..9e4016fcf 100644 --- a/sources/qetgraphicsitem/elementtextitemgroup.cpp +++ b/sources/qetgraphicsitem/elementtextitemgroup.cpp @@ -688,7 +688,7 @@ void ElementTextItemGroup::mouseMoveEvent(QGraphicsSceneMouseEvent *event) button_down_parent_pos = mapToParent(mapFromScene(event->buttonDownScenePos(Qt::LeftButton))); QPointF new_pos = m_initial_position + current_parent_pos - button_down_parent_pos; - event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToGrid(new_pos)); + event->modifiers() == Qt::ControlModifier ? setPos(new_pos) : setPos(Diagram::snapToTextGrid(new_pos)); if(diagram()) diagram()->elementTextsMover().continueMovement(event); From 95f3ea2f6d32099296eaf4b1ac13086e7f2d2a83 Mon Sep 17 00:00:00 2001 From: ispyisail <shane.ringrose@gmail.com> Date: Sat, 26 Sep 2026 10:11:18 +1200 Subject: [PATCH 08/13] Share the text grid choices; add a preference, a status hint and a unit test Drop 1:2.5: on a grid of 10 it steps by 4, which misses 10, so texts on two elements 10 apart could never line up. Every remaining divisor is a whole number, which tst_textgrid checks. The divisor list and the snapping arithmetic move to the header-only textgrid.h so the toolbar menu, the preferences page and the test share them. The preferences page gets the same choice under Grille + Clavier; QETApp::textGridChanged keeps every editor's toolbar button in step. While element texts are dragged, the status bar names the text grid and says to release Shift and hold Ctrl for free placement -- Ctrl+Shift together is the pan shortcut. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- sources/diagram.cpp | 32 +++----- sources/elementtextsmover.cpp | 19 +++++ sources/elementtextsmover.h | 3 + sources/qetapp.cpp | 1 + sources/qetapp.h | 4 + sources/qetdiagrameditor.cpp | 49 +++++++----- sources/qetdiagrameditor.h | 1 + sources/textgrid.h | 62 ++++++++++++++ .../configpage/generalconfigurationpage.cpp | 11 +++ .../ui/configpage/generalconfigurationpage.ui | 20 +++++ tests/qttest/CMakeLists.txt | 7 ++ tests/qttest/tst_textgrid.cpp | 80 +++++++++++++++++++ 12 files changed, 252 insertions(+), 37 deletions(-) create mode 100644 sources/textgrid.h create mode 100644 tests/qttest/tst_textgrid.cpp diff --git a/sources/diagram.cpp b/sources/diagram.cpp index 022b0a9d2..e8c6b17f9 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -42,6 +42,7 @@ #include "qetinformation.h" #include "qetproject.h" #include "diagramsortkeys.h" +#include "textgrid.h" #include <QTextStream> #include <algorithm> #include <climits> @@ -2686,32 +2687,25 @@ QPointF Diagram::snapToGrid(const QPointF &p) /** @brief Diagram::snapToTextGrid - Return the nearest point of p on the text grid. - The text grid is the folio grid divided by the - "diagrameditor/text_grid_divisor" setting (1 = same as the folio grid, - 0 = no grid). Because it divides the folio grid, texts snapped to it - still line up with every element and with each other. - Ctrl held, or a divisor of 0, rounds to the nearest pixel instead. + Return the nearest point of p on the text grid, see TextGrid. + Ctrl held rounds to the nearest pixel instead, as snapToGrid() does. @param p point to find the nearest snapped point @return */ QPointF Diagram::snapToTextGrid(const QPointF &p) { QSettings settings; - const qreal divisor = settings.value( - QStringLiteral("diagrameditor/text_grid_divisor"), - 1).toReal(); + const qreal divisor = + QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) + ? 0 + : settings.value(TextGrid::settings_key, 1).toReal(); - if (divisor <= 0 - || QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) - return QPointF(qRound(p.x()), qRound(p.y())); - - const qreal x_step = settings.value(QStringLiteral("diagrameditor/Xgrid"), - Diagram::xGrid).toInt() / divisor; - const qreal y_step = settings.value(QStringLiteral("diagrameditor/Ygrid"), - Diagram::yGrid).toInt() / divisor; - return QPointF(qRound(p.x() / x_step) * x_step, - qRound(p.y() / y_step) * y_step); + return TextGrid::snap(p, + settings.value(QStringLiteral("diagrameditor/Xgrid"), + Diagram::xGrid).toInt(), + settings.value(QStringLiteral("diagrameditor/Ygrid"), + Diagram::yGrid).toInt(), + divisor); } diff --git a/sources/elementtextsmover.cpp b/sources/elementtextsmover.cpp index f0b61139a..f5eaad4c3 100644 --- a/sources/elementtextsmover.cpp +++ b/sources/elementtextsmover.cpp @@ -22,8 +22,11 @@ #include "qetapp.h" #include "qetgraphicsitem/dynamicelementtextitem.h" #include "qetgraphicsitem/elementtextitemgroup.h" +#include "qetdiagrameditor.h" +#include "textgrid.h" #include <QObject> +#include <QSettings> /** @brief ElementTextsMover::ElementTextsMover @@ -80,6 +83,19 @@ int ElementTextsMover::beginMovement(Diagram *diagram, QGraphicsItem *driver_ite return -1; m_movement_running = true; + + m_status_bar.clear(); + if (!diagram->views().isEmpty()) + if (const auto qde = QETApp::diagramEditorAncestorOf(diagram->views().at(0))) + m_status_bar = qde->statusBar(); + if (m_status_bar) + { + const qreal divisor = QSettings().value(TextGrid::settings_key, 1).toReal(); + m_status_bar->showMessage(divisor > 0 + ? QObject::tr("Grille des textes %1. Relâcher Maj et maintenir Ctrl pour placer librement.") + .arg(TextGrid::ratioLabel(divisor)) + : QObject::tr("Grille des textes désactivée.")); + } return m_items_hash.size(); } @@ -112,6 +128,9 @@ void ElementTextsMover::continueMovement(QGraphicsSceneMouseEvent *event) void ElementTextsMover::endMovement() { //No movement or no items to move + if (m_status_bar) + m_status_bar->clearMessage(); + if(!m_movement_running || m_items_hash.isEmpty()) return; diff --git a/sources/elementtextsmover.h b/sources/elementtextsmover.h index fd4ad61af..a1b793a43 100644 --- a/sources/elementtextsmover.h +++ b/sources/elementtextsmover.h @@ -21,6 +21,8 @@ #include <QSet> #include <QPointF> #include <QHash> +#include <QPointer> +#include <QStatusBar> class QGraphicsItem; class DiagramTextItem; @@ -55,6 +57,7 @@ class ElementTextsMover QHash <DiagramTextItem *, QPointF> m_texts_hash; QHash <QGraphicsItemGroup *, QPointF> m_grps_hash; QHash <QGraphicsItem *, QPointF> m_items_hash; + QPointer<QStatusBar> m_status_bar; int m_text_count = 0, m_group_count = 0; }; diff --git a/sources/qetapp.cpp b/sources/qetapp.cpp index c57a907cd..48d9001b6 100644 --- a/sources/qetapp.cpp +++ b/sources/qetapp.cpp @@ -2231,6 +2231,7 @@ void QETApp::configureQET() // affiche le dialogue puis evite de le lier a un quelconque widget parent cd.exec(); cd.setParent(nullptr, cd.windowFlags()); + emit textGridChanged(); #ifdef QET_SPACEMOUSE_SUPPORT if (m_space_mouse_listener) { diff --git a/sources/qetapp.h b/sources/qetapp.h index ad3850c79..5c0b15106 100644 --- a/sources/qetapp.h +++ b/sources/qetapp.h @@ -260,6 +260,10 @@ class QETApp : public QObject static QString m_interface_language; + signals: + /// The text grid setting changed, see TextGrid. + void textGridChanged(); + public slots: void systray(QSystemTrayIcon::ActivationReason); void reduceEveryEditor(); diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 1c2d1c410..f90525a58 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -49,6 +49,7 @@ #include "qeticons.h" #include "qetmessagebox.h" #include "recentfiles.h" +#include "textgrid.h" #include "shortcutmanager.h" #include "ui/bomexportdialog.h" #include "ui/conductorcolortoolbutton.h" @@ -493,29 +494,21 @@ void QETDiagramEditor::setUpActions() m_text_grid_button->setToolTip(tr("Grille d'accrochage des textes déplacés à la souris.\n" "Maintenir Ctrl pendant le déplacement pour placer librement.")); auto text_grid_group = new QActionGroup(this); - const qreal current_divisor = settings.value("diagrameditor/text_grid_divisor", 1).toReal(); - const QList<QPair<QString, qreal>> text_grids { - {tr("Désactivée"), 0}, - {QStringLiteral("1:1"), 1}, - {QStringLiteral("1:2"), 2}, - {QStringLiteral("1:2.5"), 2.5}, - {QStringLiteral("1:5"), 5}, - {QStringLiteral("1:10"), 10}}; - for (const auto &grid : text_grids) + for (const qreal divisor : TextGrid::divisors) { - QAction *action = m_text_grid_menu->addAction(grid.first); + QAction *action = m_text_grid_menu->addAction( + divisor > 0 ? TextGrid::ratioLabel(divisor) : tr("Désactivée")); action->setCheckable(true); - action->setData(grid.second); + action->setData(divisor); text_grid_group->addAction(action); - if (qFuzzyCompare(grid.second + 1, current_divisor + 1)) { - action->setChecked(true); - m_text_grid_button->setText(tr("Textes %1").arg(grid.first)); - } } - connect(text_grid_group, &QActionGroup::triggered, this, [this](QAction *action) { - QSettings().setValue("diagrameditor/text_grid_divisor", action->data()); - m_text_grid_button->setText(tr("Textes %1").arg(action->text())); + connect(text_grid_group, &QActionGroup::triggered, this, [](QAction *action) { + QSettings().setValue(TextGrid::settings_key, action->data()); + emit QETApp::instance()->textGridChanged(); }); + connect(QETApp::instance(), &QETApp::textGridChanged, + this, &QETDiagramEditor::updateTextGridButton); + updateTextGridButton(); // Draw or not the custom guides m_draw_guides = new QAction ( QIcon::fromTheme("guides"), tr("Afficher les guides"), this); @@ -3262,3 +3255,23 @@ void QETDiagramEditor::slot_runScript() { QetScripting::runOnProject(script_path, project, currentDiagramView()); } #endif + +/** + @brief QETDiagramEditor::updateTextGridButton + Show the current text grid on its toolbar button and check it in its menu. +*/ +void QETDiagramEditor::updateTextGridButton() +{ + const qreal divisor = QSettings().value(TextGrid::settings_key, 1).toReal(); + for (QAction *action : m_text_grid_menu->actions()) + { + if (qFuzzyCompare(action->data().toReal() + 1, divisor + 1)) + { + action->setChecked(true); + m_text_grid_button->setText(tr("Textes %1").arg(action->text())); + return; + } + } + //A divisor the menu does not offer, set by hand in the config file + m_text_grid_button->setText(tr("Textes %1").arg(TextGrid::ratioLabel(divisor))); +} diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index bf6de32b5..487ee3e35 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -166,6 +166,7 @@ class QETDiagramEditor : public QETMainWindow void subWindowActivated(QMdiSubWindow *subWindows); private slots: + void updateTextGridButton(); void selectionChanged(); public: diff --git a/sources/textgrid.h b/sources/textgrid.h new file mode 100644 index 000000000..10e77fa76 --- /dev/null +++ b/sources/textgrid.h @@ -0,0 +1,62 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef TEXTGRID_H +#define TEXTGRID_H + +#include <QList> +#include <QPointF> +#include <QString> +#include <QtMath> + +/** + The text grid: the step texts snap to when dragged with the mouse, + a fraction of the folio grid. A divisor of 1 is the folio grid itself, + 0 means no grid. Because every step divides the folio grid, a text + snapped to it still lines up with every element and with the texts + of other elements. +*/ +namespace TextGrid +{ + /// The choices offered in the menu and the preferences, 0 first. + inline const QList<qreal> divisors{0, 1, 2, 5, 10}; + + /// QSettings key holding the divisor. + inline const QString settings_key{QStringLiteral("diagrameditor/text_grid_divisor")}; + + /// "1:5" for 5. Not meaningful for 0. + inline QString ratioLabel(qreal divisor) { + return QStringLiteral("1:") + QString::number(divisor); + } + + /** + @return p snapped to a grid of x_grid / divisor by y_grid / divisor, + or rounded to the nearest pixel when divisor is 0 or less. + */ + inline QPointF snap(const QPointF &p, int x_grid, int y_grid, qreal divisor) + { + if (divisor <= 0 || x_grid <= 0 || y_grid <= 0) + return QPointF(qRound(p.x()), qRound(p.y())); + + const qreal x_step = x_grid / divisor; + const qreal y_step = y_grid / divisor; + return QPointF(qRound(p.x() / x_step) * x_step, + qRound(p.y() / y_step) * y_step); + } +} + +#endif // TEXTGRID_H diff --git a/sources/ui/configpage/generalconfigurationpage.cpp b/sources/ui/configpage/generalconfigurationpage.cpp index f5689046c..06816e113 100644 --- a/sources/ui/configpage/generalconfigurationpage.cpp +++ b/sources/ui/configpage/generalconfigurationpage.cpp @@ -23,6 +23,7 @@ #include "../../utils/qetsettings.h" #include "../../utils/qetutils.h" #include "../../qetmessagebox.h" +#include "../../textgrid.h" #include "../nokde/kcolorbutton.h" #include <QFileDialog> #include <QFontDialog> @@ -68,6 +69,15 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) : ui->guides_startup_cb->setChecked(settings.value("diagrameditor/guides_display_startup", false).toBool()); ui->DiagramEditor_xGrid_sb->setValue(settings.value("diagrameditor/Xgrid", 10).toInt()); ui->DiagramEditor_yGrid_sb->setValue(settings.value("diagrameditor/Ygrid", 10).toInt()); + for (const qreal divisor : TextGrid::divisors) + ui->DiagramEditor_textGrid_cb->addItem( + divisor > 0 ? TextGrid::ratioLabel(divisor) : tr("Désactivée"), + divisor); + int text_grid_index = ui->DiagramEditor_textGrid_cb->findData( + settings.value(TextGrid::settings_key, 1).toReal()); + if (text_grid_index < 0) + text_grid_index = ui->DiagramEditor_textGrid_cb->findData(qreal(1)); + ui->DiagramEditor_textGrid_cb->setCurrentIndex(text_grid_index); ui->DiagramEditor_xKeyGrid_sb->setValue(settings.value("diagrameditor/key_Xgrid", 10).toInt()); ui->DiagramEditor_yKeyGrid_sb->setValue(settings.value("diagrameditor/key_Ygrid", 10).toInt()); ui->DiagramEditor_xKeyGridFine_sb->setValue(settings.value("diagrameditor/key_fine_Xgrid", 1).toInt()); @@ -287,6 +297,7 @@ void GeneralConfigurationPage::applyConf() //Grid step and key navigation settings.setValue("diagrameditor/Xgrid", ui->DiagramEditor_xGrid_sb->value()); settings.setValue("diagrameditor/Ygrid", ui->DiagramEditor_yGrid_sb->value()); + settings.setValue(TextGrid::settings_key, ui->DiagramEditor_textGrid_cb->currentData()); settings.setValue("diagrameditor/key_Xgrid", ui->DiagramEditor_xKeyGrid_sb->value()); settings.setValue("diagrameditor/key_Ygrid", ui->DiagramEditor_yKeyGrid_sb->value()); settings.setValue("diagrameditor/key_fine_Xgrid", ui->DiagramEditor_xKeyGridFine_sb->value()); diff --git a/sources/ui/configpage/generalconfigurationpage.ui b/sources/ui/configpage/generalconfigurationpage.ui index 030b66877..3bdd12356 100644 --- a/sources/ui/configpage/generalconfigurationpage.ui +++ b/sources/ui/configpage/generalconfigurationpage.ui @@ -784,6 +784,26 @@ Vous pouvez spécifier ici la valeur par défaut de ce champ pour les éléments </property> </spacer> </item> + <item row="3" column="0"> + <widget class="QLabel" name="Label_Diagram_textGrid"> + <property name="text"> + <string>Grille des textes déplacés à la souris</string> + </property> + <property name="toolTip"> + <string>Fraction de la grille des folios. Maintenir Ctrl pendant le déplacement pour placer librement.</string> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QComboBox" name="DiagramEditor_textGrid_cb"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt index 2fec5922f..63766e0a1 100644 --- a/tests/qttest/CMakeLists.txt +++ b/tests/qttest/CMakeLists.txt @@ -91,6 +91,13 @@ add_test(NAME tst_contactusage COMMAND tst_contactusage) target_include_directories(tst_contactusage PRIVATE ${QET_DIR}/sources) target_link_libraries(tst_contactusage PRIVATE Qt::Test) +# textgrid.h is a header-only helper holding the text snap rules, so this +# test builds independently of the rest of the QET sources. +add_executable(tst_textgrid tst_textgrid.cpp) +add_test(NAME tst_textgrid COMMAND tst_textgrid) +target_include_directories(tst_textgrid PRIVATE ${QET_DIR}/sources) +target_link_libraries(tst_textgrid PRIVATE Qt::Test) + add_executable( tst_qetpalette tst_qetpalette.cpp diff --git a/tests/qttest/tst_textgrid.cpp b/tests/qttest/tst_textgrid.cpp new file mode 100644 index 000000000..a58251c3f --- /dev/null +++ b/tests/qttest/tst_textgrid.cpp @@ -0,0 +1,80 @@ +#include <QtTest> + +#include "textgrid.h" + +class tst_textgrid : public QObject +{ + Q_OBJECT + +private slots: + // A label starting off the grid at (-13.3, 13.7), the case from + // discussion #1020: the sideways jump shrinks with a finer text grid. + void snapsToStep_data() + { + QTest::addColumn<int>("grid"); + QTest::addColumn<qreal>("divisor"); + QTest::addColumn<QPointF>("expected"); + + QTest::newRow("off rounds to pixel") << 10 << 0.0 << QPointF(-13, 14); + QTest::newRow("1:1 is the folio grid") << 10 << 1.0 << QPointF(-10, 10); + QTest::newRow("1:2") << 10 << 2.0 << QPointF(-15, 15); + QTest::newRow("1:5") << 10 << 5.0 << QPointF(-14, 14); + QTest::newRow("1:10") << 10 << 10.0 << QPointF(-13, 14); + QTest::newRow("grid 7, 1:2 steps 3.5") << 7 << 2.0 << QPointF(-14, 14); + } + + void snapsToStep() + { + QFETCH(int, grid); + QFETCH(qreal, divisor); + QFETCH(QPointF, expected); + + const QPointF snapped = TextGrid::snap(QPointF(-13.3, 13.7), grid, grid, divisor); + QCOMPARE(snapped.x(), expected.x()); + QCOMPARE(snapped.y(), expected.y()); + } + + // Every folio grid point is also a text grid point, so a text can + // always sit exactly where an element or a wire does, and texts of + // different elements can line up. This is why every divisor offered + // is a whole number: 1:2.5 on a grid of 10 steps by 4, which misses 10. + void folioGridPointsAreKept_data() + { + QTest::addColumn<int>("grid"); + QTest::addColumn<qreal>("divisor"); + + for (int grid : {10, 7, 5}) + for (qreal divisor : TextGrid::divisors) + if (divisor > 0) + QTest::newRow(qPrintable(QStringLiteral("grid %1, %2") + .arg(grid).arg(TextGrid::ratioLabel(divisor)))) + << grid << divisor; + } + + void folioGridPointsAreKept() + { + QFETCH(int, grid); + QFETCH(qreal, divisor); + + for (int k = -20; k <= 20; ++k) { + const QPointF on_grid(k * grid, -k * grid); + QCOMPARE(TextGrid::snap(on_grid, grid, grid, divisor), on_grid); + } + } + + // Separate X and Y grid sizes are honoured independently. + void usesEachAxisGrid() + { + QCOMPARE(TextGrid::snap(QPointF(13, 13), 10, 20, 2), QPointF(15, 10)); + } + + void ratioLabel() + { + QCOMPARE(TextGrid::ratioLabel(2), QStringLiteral("1:2")); + QCOMPARE(TextGrid::ratioLabel(10), QStringLiteral("1:10")); + } +}; + +QTEST_GUILESS_MAIN(tst_textgrid) + +#include "tst_textgrid.moc" From 2fdb225936ad41411ba5741bf67e9f7d347db2cc Mon Sep 17 00:00:00 2001 From: ispyisail <shane.ringrose@gmail.com> Date: Sat, 26 Sep 2026 10:17:13 +1200 Subject: [PATCH 09/13] Reset the element text mover after a drag that ends where it started ElementTextsMover::endMovement() returned early when the text had not moved without clearing m_movement_running, so every later beginMovement() on that folio was refused. The dragged text still moves, because it positions itself, but the mover no longer tracks the drag and builds no undo step for it. To reproduce: Shift+drag one element text a couple of pixels so it snaps back where it was, then Shift+drag another text of the element and press Ctrl+Z. The second text stays where it was dropped; with this change it goes back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- sources/elementtextsmover.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sources/elementtextsmover.cpp b/sources/elementtextsmover.cpp index f5eaad4c3..8835dc9a8 100644 --- a/sources/elementtextsmover.cpp +++ b/sources/elementtextsmover.cpp @@ -137,7 +137,10 @@ void ElementTextsMover::endMovement() //Movement is null QGraphicsItem *qgi = m_items_hash.keys().first(); if(qgi->pos() == m_items_hash.value(qgi)) + { + m_movement_running = false; return; + } QUndoCommand *undo = new QUndoCommand(undoText()); From a08cdf7272d3f7455b0870aa31fa74533d105304 Mon Sep 17 00:00:00 2001 From: ispyisail <shane.ringrose@gmail.com> Date: Sat, 26 Sep 2026 10:17:13 +1200 Subject: [PATCH 10/13] Reset the element text mover after a drag that ends where it started ElementTextsMover::endMovement() returned early when the text had not moved without clearing m_movement_running, so every later beginMovement() on that folio was refused. The dragged text still moves, because it positions itself, but the mover no longer tracks the drag and builds no undo step for it. To reproduce: Shift+drag one element text a couple of pixels so it snaps back where it was, then Shift+drag another text of the element and press Ctrl+Z. The second text stays where it was dropped; with this change it goes back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- sources/elementtextsmover.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sources/elementtextsmover.cpp b/sources/elementtextsmover.cpp index ddf2f235c..36037459c 100644 --- a/sources/elementtextsmover.cpp +++ b/sources/elementtextsmover.cpp @@ -118,7 +118,10 @@ void ElementTextsMover::endMovement() //Movement is null QGraphicsItem *qgi = m_items_hash.keys().first(); if(qgi->pos() == m_items_hash.value(qgi)) + { + m_movement_running = false; return; + } QUndoCommand *undo = new QUndoCommand(undoText()); From 0ca4b9f6c3549cb16263f0bbeb5e3d36d048556b Mon Sep 17 00:00:00 2001 From: ispyisail <shane.ringrose@gmail.com> Date: Sat, 26 Sep 2026 11:40:25 +1200 Subject: [PATCH 11/13] Put drawing first in the folio's context menu, rows and columns one level down Right-clicking an empty folio offered Paste here, Folio properties and four row/column actions. Four of six entries change the folio's layout, which is rarely wanted and easy to hit by mistake, while nothing in the menu helps draw. The empty-folio menu now holds the "Ajouter" submenu (text, image, shapes, terminal strip plan -- the same actions as the Edition menu and toolbar), then Folio properties, then the row and column actions in a "Lignes et colonnes" submenu. The selection menu is unchanged. A submenu whose actions are all disabled is dropped, the same way disabled actions already are. Discussion #1033. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- sources/diagramview.cpp | 20 +++++++++++++++++--- sources/qetdiagrameditor.cpp | 12 +++++++++--- sources/qetdiagrameditor.h | 4 ++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index 843b694be..9a5a27154 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -43,6 +43,7 @@ #include <QDropEvent> #include <QPainter> #include <QPointer> +#include <algorithm> /** Constructeur @@ -1299,10 +1300,15 @@ QList<QAction *> DiagramView::contextMenuActions() const { if (m_diagram->selectedItems().isEmpty()) { + //Drawing comes first. The row and column actions change + //the folio's layout and are rarely wanted, so they sit one + //level down where a stray click cannot reach them. list << m_paste_here; list << m_separators.at(0); + list << qde->m_add_item_menu->menuAction(); + list << m_separators.at(1); list << qde->m_edit_diagram_properties; - list << qde->m_row_column_actions_group.actions(); + list << qde->m_row_column_menu->menuAction(); } else { @@ -1318,11 +1324,19 @@ QList<QAction *> DiagramView::contextMenuActions() const list << qde->m_depth_action_group->actions(); } - //Remove from the context menu the actions which are disabled. + //Remove from the context menu the actions which are disabled, + //and the submenus in which every action is disabled. const QList<QAction *> actions = list; for(QAction *action : actions) { - if (!action->isEnabled()) { + bool usable = action->isEnabled(); + if (usable && action->menu()) + { + const QList<QAction *> sub_actions = action->menu()->actions(); + usable = std::any_of(sub_actions.cbegin(), sub_actions.cend(), + [](QAction *a) { return a->isEnabled(); }); + } + if (!usable) { list.removeAll(action); } } diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index da26262b2..f1fdcec7a 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -1044,9 +1044,9 @@ void QETDiagramEditor::setUpMenu() //toolbar button has no key, so text fields, images and every drawing //shape simply could not be added. m_depth_action_group below has //always been in both places; this brings these into line with it. - QMenu *menu_add_item = menu_edition -> addMenu(tr("A&jouter")); - menu_add_item -> setIcon(QET::Icons::Add); - menu_add_item -> addActions(m_add_item_actions_group.actions()); + m_add_item_menu = menu_edition -> addMenu(tr("A&jouter")); + m_add_item_menu -> setIcon(QET::Icons::Add); + m_add_item_menu -> addActions(m_add_item_actions_group.actions()); menu_edition -> addSeparator(); menu_edition -> addActions(m_select_actions_group.actions()); menu_edition -> addSeparator(); @@ -1056,6 +1056,12 @@ void QETDiagramEditor::setUpMenu() menu_edition -> addSeparator(); menu_edition -> addAction(m_edit_diagram_properties); menu_edition -> addActions(m_row_column_actions_group.actions()); + //Not added to a menu here: it exists so the folio's context menu can + //hold the row and column actions one level down (see + //DiagramView::contextMenuActions()). + m_row_column_menu = new QMenu(tr("Lignes et colonnes"), this); + m_row_column_menu -> setIcon(QET::Icons::EditTableInsertColumnRight); + m_row_column_menu -> addActions(m_row_column_actions_group.actions()); menu_edition -> addSeparator(); menu_edition -> addActions(m_depth_action_group->actions()); menu_edition -> addSeparator(); diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 71ad56244..c0495b948 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -177,6 +177,10 @@ class QETDiagramEditor : public QETMainWindow m_row_column_actions_group, /// Action related to add/remove rows/column in diagram m_selection_actions_group, ///Action related to edit a selected item *m_depth_action_group = nullptr; + + QMenu + *m_add_item_menu = nullptr, ///< Submenu of m_add_item_actions_group + *m_row_column_menu = nullptr; ///< Submenu of m_row_column_actions_group private: QActionGroup From b61193f66f47d0774d5749d2c2038287f2fd06a7 Mon Sep 17 00:00:00 2001 From: ispyisail <shane.ringrose@gmail.com> Date: Sat, 26 Sep 2026 17:50:02 +1200 Subject: [PATCH 12/13] Revert "german translation qm file" --- lang/qet_de.qm | Bin 392827 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lang/qet_de.qm diff --git a/lang/qet_de.qm b/lang/qet_de.qm deleted file mode 100644 index 61dab31c8f97b28d77f472415db983f6463ff9c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392827 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%0DPc5*HPVqf<Ei8~ z9C!e}&oUex<*-(7&zDQ>aH<afBu&>A!NM2KN(gQ_QEoO%l}0&Izq_HP9vg>HO$!U1 z#lRXfYrAG9NkheL9fQ(4^sV4=K@2soFor6ALm@~`<<rB~0}r&DTxPX|2`f;3!^yUp zIy7regJA<UlH89v0MSRTO}XgEX4QdeWx7_TM=BI@D1hKPcXds0KY_yQs-uAYTZ}9_ zgjXA>1hFyl4^9DsY0R!}tN5v>$8oAM-G=ANp8akhR>9p=!y2e1yXlwHTUoBP(=kBb zhpxQ|BK$7KpoDciWZ7XTKSm$zo_5e4+LYJtD77bMQrBOA??t6LN!sCk#qm;O8b1D1 zoQKx26-Meo2bJ0#D4eLzdPI?i33?5P2X5gMwvw759N~7D6{m1|Cd%m$-IX{%XjPf` z86vfm;VY-ZiKcZEr~64vPoINhce_W`J{J2`h#ZOtp_l}2Cd$=nyUIX_rTDbPEflr~ z!CU44`9;G9qqcS7=UV=0OoMGh2P2>Wkl8Kj*N&CXawsgdTpN;cBN5e2kDIziBQNbd z7OSHXdm?Tfymzz&8^WNKal7qVe&Mx~I2)0_ryH1q@BvcC78xdFO1_rtSW0I5j{dGT ztQ9P74(cr#`#9W9KuWV+nJ*azwUG>}+?b_@c@&P7xudP}tS5q2!52vbotl+@$|Xd` zJ?b^UU^3HmyXCP=QYQC~<F1wO$w`TP528YFFCgN!$3^z?1GQ-^R#?DFxQa)B>v}_? zc$-85GtNYI&9jp<z#1I@h=SjJt^~CqX)L-gxv{D-%!vqyVqkVnE0v2Q^u(2P07C~g zIXAfny-+Hnz|B03e*o*9z3?a`0eD){AcJ_Bh6DZnG|tF?eEntB48jKI83C&%u3`<G zc4VOp(WtA;kxsuvnI=-++$;M@$1>x4d|y;|j7A<yCm|PQB%26Gi<e6gHLcg$vk0ry zT@dIpetV)lJ6>*7YSV}jJ$P?ra=P4-ty=|wVN@XJRzvKw#-Ib-YQ%8n2;DN%dIc?D z98YAX9?s11Zcke#5J5i>Pj3~-AX}<|DH=)LJ?nLD){u<3ap6%=Fc|dq5-<`j3{i!6 ztk*7WIilPqLYBF%ey2g%mzN%)4%idLYebo#K|>F?=r(qU{-d=C_`Gs~@MGQMNNo9D zj7eIhR;wCp7%|vTT;k?Cy06<Ze=03v1mnuS-%3#WUP~C6s*KJ=?YV+EC+#|px^>`4 z&LbX&uwaQ=GlO(c9VhCua}q1O@U9SAJ*+_0q^V>sY%6P^uqTB-Fi=i_Lh!t96wqBp zg+Rfkrb`b!^}5(r$l}QO%8^Mxbn(5;CEkKq0wAxzA0Msnp>`#N0aa4}{6lS7>U?<u z%0w%y<loqX!ZfHLaBfO9)uicBGc4I4p4-!aX30zsuBkKfxb5_X$6yY(Ab~1?Ed;uu z%|`$`=G~KMS9f5!X}5a$s7lD5L);uK<6$g=x>!2Z`K-Yy1XntJElwh!r&jM{x57|` zg?!l=q063t|0)2d(BffHGm<ps9|%$&_hu3)8KH#9H4a5Pi-*M6+`60o!84R<o^XaM zN8q?m;(uZa3nl1yJlYyzssNRw5Yj=2X9)vo!;c`1={iH?ceJ6_ir#3>-*7kz-&my~ zaV4>3`9MS;AY1%YnFQU;)p3A9IkWZ2$`qn-V$WuBNZoEyvC=Jr?Ti3uzJiI(k(Idk znXjH-b^uYXb0Jv!NUa46I+WPmgv5k5#Dw7SQVnha^2~ch3huY(N0om)%W43qbHF(Y zh`TfhHdqKo%M7F;CM_IZ^y6$0_VoneBsNKbNt^zP?&*)!5rBcck^_P>k(-OB4Mr=- zgRH|z1fnKMFCjuwG!tx~JB^of3qq@igl-dfp0csiFN%MKq-qc2l7q<Z>iz0Q;ln&p z+|?<ebv+->E?;`Ejm)LqV<l@#D<f^GF3M8&Lbd^^#=Ai}QZ7M+Q_<_zVU{08m=^A# z-mtBXD<~eKd=(`dx^*A{s=YMOlrMnuScI<_Ig6|=9Gc$1WGg$_K&%imtr5)HiI*Iy zH)eZJx=bVG-fN9|@7I>TOGJ97m_JV1g_xwG`7QiJ7EDSv>{*opCaak3<Q8&s^*I%@ z6vRne{0yBfz(ay2)2F9`1P(SH^aFz$q^7xS{9xmFPE{JUtt4L(&y&sS8Wi#!Af)3k zi?7A#Ca53JbJXV;SsKUa6hvgxH{yTE*w_b%m=s57<P3|}X@r^+V4SUk_~b1@qyAQC zj2J^%a1vfyB2Ev3d<hYclvCiicSh*ag}}t4Iea7TJ;54bWX2SQ^$E;F@y*;z^PS?w zVMSM<;()l<Js@@oVG_>hGtRe$go7w!DlVA$N?aPH!HE7cjxJ}XTA?^MuqTa|wYH?a zc>1d{Sj{&QRTb`q;(f^Q1+0*|AWxVIYMwc9L|ebSk7MG7qf|tFX96Bw1M1Z$4hc(d zrcBB*7&Rw8gMmK-6rK+zlf+GW=ZU1`CR}Y<rSo^D)2i><SMI@cs$K>roKg!Qr8qN) zxoYm@D7CA<L$PWUN}i&l$Zfk5UO>LDr!q~CNYWxW_OM~-eeXC5KjuuO86JlZJv>*3 zQ3%gl6H4d9Gv(F{lumy4Fr9DsEsX0MO)7@t<*+?BiG+?x<bA?^Yz;#}YlM*v-|>cw zHdC4}hc|}xInkoR`c!z23=oO~`rN+$A*vz!;QVXNgeS@mBU5ZLG=kC&Tt(JSwHZE) zkcbDva5%=*;QtBkWO=I8uC}77hWm%2iB8s_)MDg)VVytKFvmorENh71P8hfs1XGRr z`Espe67y0tQ#lg%W)%t3aKT+bl$uROX(qWU*a=e*-fb8H$kA2=0PWE(U`6nrN2>ua zk+QQ8Y;rKSs}7@LhH!2{n8ezeAu`+^hCMUff1=(h?*sPBO(XzETYLCqc;e((h?K4R z!=#S!DqLk9B+=ZZo1iO;QG(bv*_zEB;aTKGn({$uL=LuFG!V)vDuPU_ilmaE`~Y5_ zCVY*^&Xovq_B5MtXjF(LFnv4ZfY6oM^4{9jYCCGg#O+8c42AX{WSb|0)w1X|@S0wj zrx=-V;VAr>?WQ=4vlmZ49r=Bv(^w#vo-Wli5}f`1GRRcu4feghF>w@RzqBb5BO}0( zUq{p7p1r3=!}xGn>ST<^E_>vCi7J%}KN3=gdTEz15Tn!Ho76KVQ9O9^_{dr2$#`)C zZta{wyKDgkD=|QYr~&cG|6JD1+L2nLJWYe55jN}X=J4>ac;XWWUj^Au-G*9^b5k!H zX*41ib>drFAOoAwVTTYB;F%&#gu#wrCjimETx*fE?g(-P;HE$zuQ?y?*g1?3++2tf z%B02agxkD?I)pkFsPdN8KdND>YfTM0%xP!XMk@wvyTKgO7KIdjm@Jeb?+@iqm9ixB zCC=H9P!SDT>aiWO;9JHSXs5)r8Mgspur;_Ie<jChc5D^b;OnN;b+!h3E$lZQokb!_ z6D3uEb$dD5xdzq(#$Ky~mM5w>pzygM#jzP~y?(fV>)urCZNLh+7pf_f-$j_T^Q}4# z-y`va1V^!b6ETuxWg;-#g!59fa&o_Qsd<ahTM-tiz;6TdrdmQY^8C>$!ypfpQu5s> zKx3D3#q-+O>k8c1#s|p&1nP_?)T&Q}@kX24qtPG6dl&{+T}!oA{R`==EQuP<)3P3} z<0?0U(T-S*Hf1uh%rrAm6+34nQY~!;FS6?!@VEa(sc74e)OPCHO25Y5jLMEMphlUw z7R{%jG&IiBTJT&uU3iEYzUqCPsLxg8>@-VAshKV{aEzWy2v!{|O+471^SILrG3Wq* z9cb|hrIGGumjp=ibkCh^SCYp(14{UosM%&?jB`LY=;<zX_h`M1a6zklerO&H5_;0b ztbCi~v@m@@_mC`<OoGfpzab?%ybNmE6pwZ%^$en*0ul@|d5(p0<)#-%WFaL}f@ptm z0x#Z)>PII0N9iM3gRF}&1_nTpfn;}L?O{_r(2O0^tPv@d9IN3^vRV)vjlhyQRCW&Q zYRVe4AQ?uqwc;y9Js9-f9P3;HRGqbR_RXCofo09u=RLlt=hJ5-sexxqeLR#Hda`Jr zQ5d^$fFso-K!+w)sQuU!Z8a$mCOlMSg~)mJ@lVVk9XpB#Ow^GAqe0`fcxd85`Yw;o zf{7oa1tiY)Yv5$$OiX)FKZXfq*bFw0dIn9R1<P3GON|Og)R;TUYAKa)K$yb7d<5^n zKMI?Z>07$p-54-)>S3TS!Bp?^8@@%40)u1baF5}4%@8ty!8@^rs(9d3m!(3c>{3@U zF6-18I@io2D7d#|a1>Dsp73zKj>H7b)R3rWy$RV-nW*fdKom|;szA)PBn8Ky1V^IM zM8-KqG^r^QIlDl>*$d`Uq6J$33!0|GKoCLdIm?ZHZh<T|@$6wHFA8O6yY_e#I1)ZI z2cFZYTzCv(6f511gvN<jih}dO3yqx?X_Gb`eOtsoeH>a*O?!dg91}3P;|z!;1GYB< zFeU@Fn-v@ZuxksT1YbHJd?XV>`bZcEQ+tqt<cz>X+l1ad^~xyB&M%|3R6U~D^K!ye zFEyp66!OuTu!z2sQ6rvb<@hm7Gx!U2uUVcI%@4fITNSldnD2A2rJ>-c=6bn}g*YkU zoyz}6lIQ`-{|`x|2gJ9<$TL-zfmrDBG|ap+OKwM$C70`1^?+zypxQ7G(HssHl~I?) zHn8nD{8<S8R+-OCc9Arkr$bCi9FeTYNhKC=C<iw5%*DmEVm%F-t3poCxA{(&k`psP zcUnb<>CsV6qoZb+9`s!yKS%A-9<UFJjmcte&P*?kKxI$aN}RG%19nm#MBFIB;G|${ zl9N=I?-Z`&G_W4<)510+<Aws$5`nG)x5p40V)V&$KvgH)aO=%*u(BK@$w3+Gj4%RM z>>d`a8x%^D;3$5g9?))t45Z0xNF{0c>&(E-GQlMo=fcDqAd|bo5S50P91i-A!0AZ? zHP=YnVmM7b^Onr4{@P>pgC0T|bfYNr6CBsjSplR<HnW_KJUC?@RSEx5@KU5w$EIt6 zxR66^;k@)tmp}=vX1pXavIo$cQ--f=9Lx^BCO-HKvVC&Un3jXnpF<g`X*)_Bp2z7# zxgFIH^ni5((pG3-P>W>wJB=;LVzN*ckqJLej|oKROi9bRdJMV@gN_6z>=27jjhx7_ zvVI4PeRb)noO8YyFW0dQqC#oe1#AysXS?e)oHFdIQ)z75os1#tgh52dWUx8{q_$yI zs$7TXE=3poe?B1e0M22LRj#n9QAM<NN*(eRb`zoxP0PEL7M!1O1N0h{O|>cr3yr{y z!=MjHq9lI19@}?K4339@JRTF3Wpt}B>)D}W{it>yA_m;Tb8R;rgfvauV9Q5a=ZxLd z1Il$VC@Ie{l%<=sI?zI4T7?`pQ&HrgS}~?YLV0+LsYjy$%gS)(xoJlrH{PYucpw#Q zNhQiK@3G!BmKEBfC%f9B8PLm|?=hScRdzUUA1s8?fVt>+Cv+OEIi`bAv$A%BMl~^x zY687y<X8?B>&LXwLb#i0aIN}8J?HkX0EdzAxkbWK6foq{-yA0C9p`~}bhDDiqc{O_ zQ1A+~B|Z#M;X)7e_nTKeTr5|^H4l|-7FUVNEn~hX*}?-l<UBkdk-^;qu4^R8lVnTJ z2PdGwRW0=xzTx?It}d2+gM8@#uUBAPRnammkA&Rj6+ci2vwA_TU~0qN^RRyg=9#OO zwK%!QBDMfKZUL@1gABHF39Dsj_@6O6*N_MNW!SuP!JOUoC1dC2^61N}#h7MIVy6w# ze@|@z2FT{f%qGjzvW*biW%L*q6kLPKUpVkfRc1#|+KRj$*xQsaIxQyZi78`G+j6}g zW1o(tWQ1t&rY4m2;$ZukK})95X;5v!x0;DaL8uNw@L0PG+mQwgaR>Lnc8!%I^*1t@ zXe0Hs|2+$D1){T5862NlJl@Vj8LQyZG)1rO<)srQH?jwMa_M&HNs~{vOVp?G>Trp^ z-yYy6@MOdhbMfS1v8fZPhOp`6(8iilP1kMu#tV;0F`c*xV)YeywrgW_Aj$7MYZyPf z8M+H;2M<Y^&?r)Fj@3(uG<cLVC<;UyM|>_KQIUj}NLSo}9t(2^>*^fO7^p9}+P<{t zY6_z(@HAT)$_Sdc4fD+NTJ3<wNL-N>5Kr{8C1syEE%DMFsBwD$%t3QuE<7fo<en3~ z023XS<uS5oO$JP-DOIMgAQMGsTk<>;#Y}CR#b-S9Yn*<{2^?_Sb|7RISsqX<x%4Ko zWT0e%r07GQgzux758_(@@hAjYDN>;q4$YN282uk=fzw|s5Vrvcb!eOX&Wl0I<vZYB zF10Qeh&9-;ar|fGg-`0Jovgu_mi+LZM6gP>UN_un1WS?4rU$;~0PAD`6CVC9C<I2R zrTJy-il!|KdycePVuxD(DD-AWSrMHXVFo?NS%ZcSH90~iNx|jbFGt}Q!h=#1-*ceV zQj$aMsR^RPiL?N%Jj(8!Y~7jbNUsY16t1KxK;;jz<^)qTw4g7XLfNiHIeLP{xFvz2 zG^cZtM!y3sHY%GxG{hazbJQh}>37=&_MN;t*UH$gk|&-gG0q}ao@%4HX(@6+_MG1E za0ZF1*gVbK<j_v5Up88qh4PpSuvI`(8{@QMD&9&2x%Kqt8sz3ku#odPzB2?Rm#G94 z4*Uy2O)lZT+LeUWB#R(KH>oyQk9rq`7v=)wJ)lI}AwYoP){{}|rw<%W-%j8dfi=&% z2o4Jj{WnL1%ITcrAxxG!@ys1^zD`^4E`QPIA<+{SO-(jR+?1L>Rv_9=#bLRL{2q8b z#DwZeIaK43Yh+1x@z~bub0Kvzc5Yl;yfkJ_=E=7rf1=|VXc&MPWTV2sXrqj1WUkRS zVRXt=rj4hMy~Z0GPK0@QC~}QXpS>BKg#<i%>}E=-K&N%~iZ*u78g5&_+EOj2o}0B7 z1V^z+4Pr{5c3x`}&Q@7M!loMJRJhB~B^ccgCgdc+joGNoBKK-u_`!xlXa!TBjk1I9 zXq4t=Dif#RF_Qr8ybbke{{>n><CtApJK>R;BvIjh94Yc@DquDF<{-Y&`Xq8WXHYw= zQ{GTN(twP8!jj}|$I30p(`Jay4DIFwgfmimkpMU~g)eu7EFXmVjXY(hY&M}8A#uFM zAgM{)ydt)|qqV6z*XAj#dm~MbvVeU(lQK_2P{p@!VAUPq@Os5)dydEiUU3eQALs>T zl^A{8CQQBq=;f9wM<N<hK(Gi|3!U&qljRpxOE1#N%GxI)=Q`>0uYvJ!wW=z+B8kpq zL$}UrOb)1I5~43@X^vT?WX6*fwl-|S%I1PEgEk)h+B}T|AIm&tI$>w#sbrhl#TC4H zkZ0O+#GdJ<neg0YT~I7}AQkfDFr7eCPg{~ka&2%c{yQLif!pL#RNb>qXCJcZsT!$7 zf@<q*>)Kmy9b;w~Gqu?3O7d5C>=e~K6U6(inc=1l!_DN{;U)lM)U>!k!Hrd7<$*G- zbK~-7*dl#6mNSaRRt<*FBtH}qC;~V9*v}(dH2l~{dvD4uI7G@6e5%$EgsTwe6KOW> zpv&AS@kmX<)QJ>E)LE9M8>LxcP8k)5>!RnV{=%W@o%eUzBgdVdlma~REdHkYh@wt) z#K*DkdO}PGnrsfJ1@JnWkt}SKLWeLDwMb(T7r}gdj$sT+9nzmyL=%i11F_(+i^+$} z8s?F_!T17_IFQ7}lw@}HsV1;T>2egYNb*MhE{sxJ1*fBi$(O>7ENvk9QYtgE-iZp` z?K@uaeb#I2@sn6Qx;ff9ZCrCF>U3a{jaJT=y-lPM$EG5twHeyR*!eFxRY!Us611WO zzdYkD!%+`?P3UYWno$0CT@Lo*v!SF^=YRJG3p?Jufm|=oyDBM&g{a*hR$wxwhGTkN zzsb#0^={B0m?VY1N0I2~ky>=Kmy*b0G9KG0e4Z5PE$zF7T3yT}1W%909m#TNU4xqO zCiMo=yh(91r-ErBrVNrZbw)4UC{A0Tg6?;_^LpFKT&FQ2PZwQ3588P-`aKY`VekXN zp5TM{oD}%91d}jQv*L9dVQ`)NHi6$%IcHdLQp)Nw=e8U8Q_QABV-(4Egm;R@3p93Q z-<v*r+w~%Y@^F-$*%+EeZ2>!Y#NWcfZTNk-8}h=0y0Q6e1^I_~3o`fz_I&Jv_-m_C zy>1raBPt^M(37R3#h-9)b0SBgy_cL%+4(!Yog&7FNw(nD90BeRcaA#eLUxsJvkS|2 zMQ>G2FMTZKz@#_2RmhQzW~je87zkmUPaAq0k?(gy2pP?i&r;m*2_2U!NT(G#Ec}F0 zH!GtITF@~KqmltW;)e-}TC6HCSX%f=(gHUXQ5BRMPD6QZpY7Uq^S}i9aEvQeOrSSe zgXZ5{qdW^;L5J8Uo(?qV2rs-A?P=zAM|r6G;NxfGGX6!VPXZkv0QF^Y9O%Yuu&?6? z9Uw<r<fx&8Q>E67$kfk7AtE-Ni65aFmTc61)l?l~ZUqt!<H)FCU-jM$@vU)+#<xTb z1v*99i;Se9xg52Cqg~wgsJW;WG9uLNW=soeG)^NYjhkXxz}*^7*4u~=4o&d%qBb=` zEgm$u4Q~zQkAhqtuN3T(dv_kPQS4S(4p}V~yLVvy8UZx!U{yf$J7SRhUfF0C%cb&4 zW~YZk6^jt}5V7@aTbLPHn)Z-#Y>$7Z>>!h*y3*a(%_v98BByW=R9)_7-1L~3k*`aE zg^Cc5r|PH7<)Fse2_seSEJ`@t>oD5ge{<*VYwZ!aGmgguPAJMtC0jb&alG_E_#9L$ zH<0ALOSme2oh;A6DJKs@XhJ`}&a!xvhQUd%PhRK044Y6g#jj1FoorH>`cEX4yQA%G ziWP4*Q_1K*n@ngTJNW)nNu=CBZP>+<h`ju?NCe#W7|yDMr9F;IamOvw9H}`gwv&30 zkXyvJH|u0OGj}BOJgLN^b0BIUxr4e1PLa`y^vH<$o60ML_oc3ma%2*#Hwp<=0TtQg zDhpgw4<6G~;9DMZZw{PHvA<}Tf{u$}6TvGouw=5FeaVrHsbt<yj-HP$PG#dDQfGwU zIwVjM3#%+ucP)%W(#7crI9OA}3JJm~Do=}4>{cJlwM;z*Zk;M~a?ySWpogRv4{L#W zqS=Xn^(2&%e#P(VaA=60nSE^FRt~kAcXg!QiFVIUwxWFSK0I1gBmoW+S>U1$sEwui zIq~*g{EsD7bTLuTYeDE3uu9)NJ%wa1JZ|R&Ji4biCOy7Y07_?*G>*hi40NQGGn2IV zB-I;*it>d#o+=O35gPhb=#1{Jf8i5UA3CAo3b^AgOWY_fEE_|scl<4_8dO`ux5TZW z<wkx%>pKp?877tCj66d#*YG=Yzo3ny?Y0<s4U|<!^#j<F>h=n2>a=&Ht;S~USWDXV zJ=ESVpA2Xty$eAM9EIw3cvqo^+FPGsJi<7TMw<w9MB}$;D!>~Aw>Xp-sisZbbzI#U zv%oD4F9!{?n21_P@|#=YZzhnT3msh=jb`ak+$YK7?u6epdFT9ni+hGqCYOK#brC1e za!`EvO1Ej0;?I{L9xbk(h4=|rcf5F#sjGG~(y@39r%q||u$-8gnBX#J%Rf8j9H{L} zlZ)p=T&fnL>s&;K3asj+IR7pk8?|@kP{=PGwj+Q|&uyoFhXrhUj(OId*OHMPpI5|p zX{+bIx5PhbJRYWfL^?df9{*U#yjLX68#Sv)pRH%~Aepc>M}*}wJI|qHx9GAXQio#v zGAhKh))#{ic*UusywRP3b>n4zE@33AaYGG9g{w0!1I)Y}p;5i|rz$+ItyV)xU z1+;0FC&dT6tHDihz70X&BuUfqQ!BF;IK6VGgPOe&=+rO<nWQkHF%XFS`kOxXK~Wx) zH|V}Du+7QSbNKYZ^pI<|H!>UZL-~O&D18rOKE!HbIsLEN-Gb$^x<+yfZ9C^j7ktxv zA=aGRpi#F$aqpzrCPXOU%aklsIN%wgL=X^;Py}luBcRiiPT$Ez`#c`*oF9pVFVe|7 zhEIna#UwDCnbsz?3~ClBadw%Tm^ZQGr*RZyZd3F^EywAu$`Gh^#brn$J}evh3A1BT ziw#GIa~-G9Y<O!p9Wf8QgWD1&@lLPfh?i8~MVbyYo_%8bT@=^(RKlk3j%`9`=pgIh z#I4(W&I=xsWFOi>51czVFYefe-4R|pPf^Mt*@ZT|;+9G~Ug@U@i(zBNQ((PLJJ$&J zI5g}zkNsYHRMgdj$4{}d()jFL#;Et%(I#;|cseMA$mn(KIs8oDIGZ><fLZ*X>FU(K zC<OX5TR=^F(CkuZj#L;n2Rw7N>2T-p19SRsnI8ZV|2F5RGXUL#HZd&6yCVSsNr1UM zyIcXd>(s~{oZroyF&hu;iNv`SA#U^t*{4p(;8<MdsG}%KNLoQB(xOpE&&a6Rm^p9N zKSvlYqkv40#um4gCL@ip(GF!$1y4NtfFA2k<&B1<dgW=>`C;yij#ZKIgzy=Y+>l8| zcEY?KiC`qle%9VIVyBd7j=NhPg96O|R3NE{Feh4_>@Fo@v!4<H^;+yZxQZ2`jOmkf zLr*YRro0Bpw5r|YPz!gWF((lnzvM(iFhn#rh$}!}D?7oZ$15mzX@u_nlXNxjNXq!S z-EMTF^cl(6VYAq|uk4yzI)U`GMz%!RetuO?+WLyo98A(>flvDC4t7=ZP>z$37rwG9 zI%dtcu5AehLst6B8k_!-gE;o#409p8oWKRgQ?>|Cd5Wdounn;bpS5RKg_0m0tG@B0 zcB*s0#%;oNr=yeW&QF%vz9j)!9TQl%*Seu|VJcmEs|$*3gMF=aK8my`B57y5{B#-p zJ<+m_aif@en~tg%*d0orKYhRQLbf#(vV26kBLVMB!BzWGd6=+Oi;LB#>*%7Di&{3p z)=3x&ngRZ^1FqBoqr|^t{=PE-%&si*j&U!ywL&p)Gv}e-Q8&L=#^3tX%)aCm+?eS7 zI*+62H<DIDw0U6`M^~U)(|H(c=uQzCTyQF;li)^3M70|z7kA@-Bsh_JcI4HOCA-^b z`su@Mit!ri30@+O9k38rZPSO_AkYw|G>Nh@$ML??9<$RJiJ2MnW19f8kzM+&`ubAz z0K0&V%(K8HKkzuPxsrB4MF;~LNcv(H+Q@GGsaVG>udAgbh9cFG4`>@dc=d5Lt)yw} zK;zHbAjRk#WW&k*pdTJrDruB0RJJ<yxBs?LBn7tiv%mIiU6a3yQJ{cT(k4y-_0<_o z9D}r@Sua%Me1C$Q(}jnqG#*TZ;M(K3Q%TboCm0Wun`dBQ8vhg#tI-jnHwm;wFG#!t zg42<_O`;}=ob7%2tx4@Po%N1l0eqG!0M$P|Vskj`l#FEwc++1+UZ)zbO4oRW2j3^^ zwUEHiz$2kC{1NYDaURf+^f;rcrU&qx{$2%gwG@e{Q)8YfNV0ukWsKhOU>MRRyW==a zJ7UR&Nl>NL%GsHcKO?Kr^d!PMhVj@FFAg^e#=-6w@$VigPgGD#g54;ExINEg1M@O3 zxkO01T(T$lJemv6*PCGz7d}5W3-27FA?NfuFw^+X7N_8kQKdX;n=~sGyeqoCj&Cxp zf>DlUbVK8Cc(f`|;M#Lj?1c!j>252RjzRuNdMjJsG~uKmEg>?42{hUDl8C_1RLT#_ z!C{@P-WU<zBj%Etu8K*$6n7np+9ygQU1Z}D5hg4H4#EEDb~U8mu9>&M2&eHun$&bL zhP+5ab`LD;S&d$tRYs1`+ox5DDz~~u+z7>;)JZo{+DN$450Ez4moO2k+a<-bDb!}x zt#pz^p@u#g9*6>R7UpXXG2IcDDXDG*|AySM>8@gBN^T+yTcD!Tz%iznpZ3?OfvvH9 zWf4Q8NvP!yUAXD#-0ym0%nA@M*B;?dI#rGP&lk}=pL&8-$dK*w1Si|MS08h^^tJ6s zYsX=kYlpb)6;v-t_iEO5fi-Et>O|7RIKI*WM7CeAwx(rE_GVb20vV6skc*R1aGM*_ zK-$IeZUUGHBwu(G)LjBxY=>+`AAUx08M6~7CN4aRQ%^pyuV1r@y8!=>>>=1SIU6x% zk(8@ZTMKJTmg_AukxJJg37S{3DL>UZd{<%FKMK7JY4+I8#J2~7`@~JGy}h3w{p_;F zFS&0Y!}!m~zmh%PwW1B;Z_|(oiA>XbKyvl~t~rjJq6*cOImC{^Pc^v9OH`pY+=~b^ zt|bsAn7;u`!prR3(z*JjxF=p0p726emzcrB=W3<d%0!fd9@9e(Td_qUuF*(kb4F97 zC?pj#R!I@bBWT#Tg6Ocb$@EjSO))07TiL`d%K~Lthe@$GG9ET1gRi9vg6eH{5j>c# zx-^YnUtx0f0j4W?m0}`cp1o(>XlG293ah<YWNad!_t3YQ0ukU^jb&Ob?y^z3AUc;w z4kWD6(&<$r6!nx6tZ!l4EV-Vr)Q%RM50+yPT+BvqV|-(&jp1iib10su|LfmW`&ahN zCtSo#6-P%UyY#*ULdSM0s_#IsyPM=aeIp;B8C6QXF}}}krV>o@n%Gw&eN9)>o7tdT zrWw__7>LoRV^eQv4zsKTd++dUNbF)x<Yw#V0^?H(hp!@bCVPXl{}}@2DhrIKPc9gm z+blFs2QgP#Skib^Z@g?yII7<9w1;s36<$1o%4_mb^yWxsbk%&x<*}E!@>poiC<5nQ zn}`MHo5ghq^O|CeiK3rx0Co;l*}#)evxujM?h1FE@!A7YCL^Y&?@PX{o3Ue4qR!~O z?sD&UcexYN%&}IX(t(L-(mTNJ%F;unNtLIWFRzgmQj;@&4yV^F)63U;0&u68stoXO z3>ud1N>TD{y^bxOL80ICUt>V~ddMai0wxEb<T8@bgAMGoCp^3qF_PgH9m}KaubwY& z05)9-*f=a}S}AaK*`bylwr#*NQS10huale|e&6g8wbBlACLG5+jzXd4pkZR8+F(@p z)&K8=Z#Gohlc1sk3mDOb6()(}2btgvdg;fB=)S{tM(Z)oQ7lF?Fj-B-7!V9EyKR@S zc%IktMC>DTuxp?y`>G-FmOk`GZ)o-P#Y9l%Osg=Hnp;pcEU?RuF&|Vr++@CfCm1Q6 zOwJlp9fd4`TkEu}Q8|g!XIT70Lz(%xYW(|WZ-eu(X}exE2Q-wE3Cmp(Q}5;is(B<y zc)~+{i@JAGU}={XWYDInymUhtt=tPB0>4w<XF|B&aR$tH@lfq_P`S+7i-hTRp8%dY zsH#dp61q{<XhE2|GjeWnFX<gtTk+}O%)8|Qz6*3)hrjD0QMNx8J-GO7jDcjUYcGn) z-tG(Gr?rba9Bo0>rVzhaG(8f<tvv|~$c)uR_wvGI_QfOmR)0;i^x@OFAgt08?-xl8 zH;Y$PC7Z?@wZ#n?p*pWzF)sa_k?CQ1ErR8y$z|-qlPvwsY3X?#3tsrl&b;YVRDpd_ zBxhQY#g3>Qdzsu?DxRcFmbebtM)BhNFu2c-(tj$tV=cU|r{<J2((@BWdVbH51|>wx zy)zLGxxUGcb%_`8>N!{e-cJhH8Ih4rjazZLjvjz{lmXZ0SsQtaufPIRL|d~4d0Euw zxhFvVj(gcbmTC9tp6_Nk!ZNq{nY#xl>sZjk$W5b9jRm?|mJ9iA7ka6fUtt@Kj&a?6 zE02n^LOKCrC_9MPA0%_p>ja!Mci!^Io!1lTtTs_CCGLQu^^!LD6`rp!$qAPU_kXb4 zG82{sTB^nc%56S^n}Q}iN9KQmotOnqFEcUg-5r)B9RJU@mo~)gCFBDl?^G06l3&(T zo9t9Z`(ou&r@4RWNKJGF@rmXdH^Zrz1<o^S8D&k>+c3&{`*1E>#GGrhiD_2IHmARI zSs@G9%A32kQca?~U_8qMqvEVtPe1HMO#6i+#>+a?wXKRF5pXY5epZCj@tuZ{s~sdX zfW%qjstvcJRf)C=&Dx?{QjM{^__!txg_ie;7P){;dFJdd=Z%K1vfKXZwKoTIm|S@= z6Wbr(*jfN$_Da7G7aH-^e*;GveQfu420>m?kfNIocP)Tkc`3GKb{%GwfuYyo-Qr-0 z8B_~E#a#e{z4WbD2?xV(9*~5ZUSJLTVA*~LvFb~vjpr2;PnWmEup|ORw`l<&Y_{yp ztes3nb#LFpH0YT<3m87Py_3asa#;ge11#Ja$Qtb#Q_Hg^xmc|{Ys`I7KQvOl8fw)0 z(_8-}(ZSWodqsv%gZ^UtM0Y?FrZ_A9;PlXn<X%j(&ofpRiH({Cbzk5N(nVs2W<9;Y z*a%f#W<VY;S8+piOWHLB7ZpxO9O)wb<cZ@vqY9ic9TI1H#)vy}mW!qC%t3jTHXZ0B zX$@HWd0Wh_r0dKD7Yc{a&8yCSd!<Pv;gD+kM<&l7XrNQ;yi!6<xTA@(KPh~X;`0m! zYKXP0u`^D@@6*%9_`HkacNRvm#uFf0V|gbdUz13XK#LTBht7WJBq&X_OO11AzS}@V zwca?#+@U0}_rQH(iu2+L<~;V=Mq0A^O>UB%cn!<$WZtPdnk%PGz$>hc{M0Hw?F_;$ zfoBohsA4_p+%ulbVLU$xj19#=>j1}sarKEh3j9!2-5NeSTSWs7z=AZ-W(Dk~HB%0U z%aiAm7CvL)V&{?X0uF67rz*RH;S|tAWtsc1Lwrp13z#Cf7JlY#9>AV4GRk{*{6NyR zUiHGWPhgKqxca(UnG~>)g@t>yk;A#8jok4G6iZZ^<;k$5R2B6SxmJqFI;d^Y#wh2H zWEujKNf<Nfz>0mA9lDih%=UgHOS9_ph-AWPRE<f(lX#M=VjpNtB=(Poi$#%2T^|@G zFf-ebcv7r9i1cF~GL;?l8__|V1g$=yP(2$EvCY9;2V|rZbH2D&>VJx-Q~LOx8k<2w zHtv6jPvj|A=7ysFED_>&g%6{Z`3(Qe^K%aA$4&I>W-82NxT9XHo(rEnbbn<|2f_8X z$RM65q2ig9YWi5>_5h(H0Fc~e1cb#raW0S~q)|uq(Nkqp^FxVhrsnfG`g{2=-mpZz z{X`o#SU`D<q$$IkQ44bhWMkpT<zBbe;73v~H&BeT%8m5FUFM`(u1OjodsL&*PjYw3 z@txU|)R_H|_%_qeHD7?U4cq0M)KqEoG{qeT+r7F?(^Q&i<a$9mjEfoMCE`JweF+?x zi`6x~S5C-4v}~^g;x#FYHwPjf1LmR~BT8QMVJvY<o?`N#xkNK*=??>yQD(BY@Kdpc z+ihFevXQ~gRx|W%r>*=*%F4~bW*jBN=9r69G)sVG8GcmUZP@iGaATi3w+YvxpgnjR zU^_(cl50*2t&!AC|0R=L9;cO!-qezvRzk+{G+N}A)8^<-7Vp|1ONp0_*s2{Szlr2D z8RH2QwWR|?Y+cns_IBtE9YfpQrZh?zTXm97)TEEUF+M(RUxS&H8P1A8C1a28GaZj- zLCs|6j;&J6naqVIm^SNSl&1MSM=^a!d*!%4*W%=cV=j9yET643p{{_Oalh7Zc!vF( z&JWE?8+<%A(ZE%@QRAuvbnT5ifG)+%$UD=ItaF);oVOnHlg+}~c2=@5-`?k?Y2>x1 zYvLsAIf3b>y`pPc#Q<hbn{2N*^i1{^^V4RrMW*>GS4#OB>l$y7z0_XPnSef4_Uqy6 zWaLS!>86FW7HPa*m`A#kHpp{1ir+Bp29y$*5{;)x4ZA#Dk(qoHq|W6T7sBp_#w#VY z(Uo05Wvn^^O+H17?pnxHqBWn06dx)z@#|06cul2I%9Sa&$zcfhI6yYxrx(eM4phIO zWa0N={638G3`!*`RutJ(la(B%K_)~()UiJu9rz1t+gM>n4TU?XN*|R=Ro1Di_|j1| z8{-<#^Di-6ykXP^a)=JZ;~Ost$dij7$=nF^ig6dZ_}9GP%84P|II)X&PrL{}uzn0b z4)aHM$;)s*=!|*fr77N3ff|+gKBM^_D_U^7C>#{hj}(<^lE1)wH&eyks7S4gw3qUT zB<<kt^zc3pzDa$8iZGMWiJ_C&u}S&HT`x8mW!jo#_eqwrMI{>D+RZL+24gz;GsMod zWeS&d%wf)7GO-7nx<rMiG}uAco)n=UW1lGlYO|zHDVH?pdOK(i(YCXTDLV$Nwsu2= z8R`Kn)ayqflB1isQPRvi6H%L%0{2F1F7iwrz&`R?GWxDvh0kDYKoM^!GfW$?N0m(X zhCcuStju*5?9~;7Cabf4TXlVcfYa^KiF~Sju{+khgLx06GD)6goGv|EtK^;8!G`E@ z-Av2CAWnJiq>MMmnc3AvY<Z-}Ad0Y6Rq&?JewPVy&$Kx0F8^BKT%PEX-kJ$>WrSeY zN86il;}dUw<~EB53R^aYpP53LcE!{hmqU*<m6oa1$e1C2aaYD5r$saIb3w?2jB!MP zq~d1;i%}1<FD4R;qwUGu=8BKlNEQBKWxgTG+~Gn-hh$zDCkN|N50T#WFD5>$Isk>^ z@rd$iUbCc|MbYYIGxmqVr%m-AC!4nLY#cc|QAJOWD5DKDT}F4FQVU;^U8KNp7tSk< z1LZspl4KWviUq0)aW{a3Z!IKY2PBbOKx4D?vuD7QL5?Xa*eJ#HzCTM%ULQBByyR%9 zKT8>FizK3vCg=#!J)mC8-$_MKUF<41fRVzZXCuzBi>Xt_UqZau5f+EDaxKx75qY>4 z37W9tkxE~1oqcW5b;Mt;mxkO+Lpfh6KyGNDM3}c7VEF-Lfx;P*bC`qR;=D*>DpK^Q zLQ<t5U74FvsBRntjg#A}+sRl7au)5>TMvj%1Urj*PPsPJLcKA5lIulExKE^w8|(7| z_7g(zwk1iI4WOyU3arssMnM*%aP*A<RN4ooP;UW?!BX7~A}Y+rF%IY9EbbWJZ5Io9 zg<b^kUUaS-n&Cvf$})9GJ!JgxR`OCiJaz2Q#i69%sSOtAxBz&fUCX)Iz3vdsL96|; zEp4L2!hpMj$I&}AHxO#52xqcmEa&~hk$##3jQx?;<QU=o9X&5d0e*!)y>Z>053Y*( z6}T>;2q)t749%710FCgV9N?^xQ>46>90{3zc4e0ws?X8_V0+%2D5BJ6X)Etv8A1ac z{>G$KBlPt8HaEpOPSHk&DpDlF-RNfl-kp~wwqQf`)Q}MnM-;JiuB%VkFN?VprB+^P zDhN5}g6_v8Gy`Ml$2e--5Xw`^wtPpO*#eZbJd$zlGi-q4IdoM6F;3*2$fpT8nE{Pb zqfqH@&gDxUdOw~qZriMW-@B6`k8*^KKNrygbOC`|D=$&96+3s7<mj6!C~uS7-E(4q zE&)nvtk}}@(!&*$C*~aB76{W4w9aAKXr4)CKMvspQ;dk!gTD}=zQX78+O5ck)Q0F< z#LZjkXG>?%G_H!oljs)WylCOgwhoB6Q^ELo(g3;21ElFp76?1N2{|W5uCe`kL{$MH z`Kym&0T$VpN0ZV=Po;4p*7zj{cOuV@R%{1dKC&Q)*I)?c65T^x5)DPcmJ<R0p&E4# z46R0xja$JA|9B<fiX&(|WHSGAj6_7a2v}SbU4Eo3-Gp)?X$^A!sdrH6r+EPeYPau_ zJ1#tiOD7u)+~pi@Fjk*DgMbaAbnYU{m3I!K9Ttk_<TmddOT8$CKF7GL5pU9}+NQ91 zC+Aikt)XhV85IKL7;2SRYHFFeVU`~+UHFBlfk=))9POK1QJj~iABlNj$qOKT)xjdZ zXZLgQiE(lM<p77?sZPd88Om>s)fsto?C|{<K5BE7lUlZ=%n}nRo<vy18NiuZXk(F= z6K{mmkxoonZfZr-w?wPX?bWgqWflnMggX67*&K)+&*g;ZR##kzV298v&#Sh(9~Ie4 z%YmgIlU}pw8|gWXIUpi;Kx8n4JLZ{lf;+5A$aRDCgE=k@n{%w=V9M4h6jYk@Ku|SN z6Pm6(PgC%=bu-|kv{kXg&E@U$xT>xRjrPK0Ik#n1@TZXNQ_9OMQLZ_`66>lK=}zHN z$=u_a>`ryBsPod1Ol(|4kkQRBC!ExUsivBeB&u`dz5Fg}Q(&QAcd{{EVy`-JDz#jz zi5xqWVuzhXijiE9lVgZ}h-21j!m(#TT6$^*QO=xey(L;}r%Fyug!KDGv7nhe<}2>L zR<=&727v+3*v~opksh<>Gzjd{!z5UgYSjSG2^X7D`s-y8m$?GCCuU4m8?c8vvtZJ= z@W7Qx@JS1<t$XM4lIPA2;K)?yk0D?kwunVc(M%j!6FKofCE3SA=TyeDA^*@8NG=e% zsbfkZkOkT<olAB55Tz_8;CMsFybDF|j*f@{g^`$;(HXEYNsHW#UTrCf&5If2#PjON z5+Fy8D~l^n;RaB&uAInwp!b3sP=jT7P*cPV!H!~+qW)x2!%sF1gi2`_a>eO#ZN4te z+@?@%Ux%L@ITIHin*^87xspAYeq8WHwNkxhDl2<Uep%<_(LK32CmxJSPZ}v}TY4Je zGp};hYp{Y0hUD0~4I1QN)|4xAIIL>znJi(-W9kk(XHE?-jzZM4H(v>R@Mtr?GCqPG zRljT%8=-LlqTVU1%SMrCnA-t62;T<XPV}hrYGx)Lg03vh48X50mQjs<&77O{j5+Re zV0{@D;3qdP9@DJl9Ir0Ht1c_LZ%neCbG)}%4gnjkQn}J1&+`x<WFvl2^6D{3swNFl zpQ`88m^Wc$?r|F<rjNeH8y&aC&6g_D2Pp^qH%6)>#~%WVCBZTW_W&rW_o_B_&l_%A z(E3&&$%Bfrqq3!AWrWgmQWtmpTrg)zbjjGcxr=>w72l;rgGBheJdhT<p7KfXb3o#q z>w=62Au$deEzEnY*L7&-GOAr)(To`xUOCa!T_nH!4D@icLe4n=Eez_&otej)A(R+& z1Q9iX4;}+yDs~M!&R~P<5*cdHZ(Hk%LPq(?Ibpj73FEw1mMI(bVAGR56kIEWZL*P^ zUbf;4JsvI1tH^OcR)dopdw@*VSslyIR2Jgg*$-YyrHW0nYoa*b1oWH@cm+9Qq;%U3 zNpoK+Av8az_>AK(>`Z#AMc-Ak=-pGP?F(<3J9{g#{A;bDhs%}enbtno`_;)?b7D;| z-&7XQxCvABnGmRKpF+Ul?9vObtwu>r?7EykXtNQ>bDq~&+NfQRH~7MQs+)XQ4^Y>0 z_}K+Hfi`s<L~R~J*E%?)g?{yg*CGnTVBf+{Bo!t7ufq_JQvOa_(}IcRCxS!K?|Y?z ze22R%`r8fiH>TNYZ&FoeReioO=(jNM5AlD8BF_!7<4&B!KU=Tg6`nZ6ANKA-0Zim| zL;K}$>kYfKXPf+TV?PP(vaZ0m7ZQJ6?zQa}vnjs98xa258r+z%&YR?kn=@AXY<c1q zZ_RfluX#6DtINJ&_tqObSANs(tvCCNfA;RJxAa~=+gEmZ=InmDeOSc^C`@T0zxSy0 z&+#@hT7FHD(`u?1^Ju5w(v80Ma0NlgCPD~0!_KXHdrz_np&w20VgU^mfXM{FFCB4r zW#xpP3b8W_n6aTYOCw?UOOA*|k`FCwfEKD=L<W%q=4uIjW#lv0>zguZc8yJkH28Fw zTuIkmK4`{d>*Fyl9(7gSXoRVqWV~=bdrV>ktS)qbT-W8BvvDXSpG(sm_~~+j`a)r! zOx&kjBHLGwavXR+E+&3jJhd>O_eMZV_^yp!u%cs$*VqKnkSw9$zPzx{{~v?h&-<h` z9b3O8tXmhjCf=hHEwT3*+z3ZsyysRoNfvD9t$cKOV_Z676RCu7E43S1HDV~#+4S}g zP^w)n?DZBjHpm1MnueFU7WG=qk_4<Xr1BSa*Rp5*gC0@inkVhFC3O3-5B5gTAi!>e z7e)#<mJvTD?77t(YEhfdhn>}GMOg6MiR%}AJKrcQk&N$Kng)DXhXxFDQ0lRIO4iQm z?Cg&8YfYD_4lh+EBV64<DGnDap#_TTzV{Awq&Q=TgfZhZeODN@Bdzr&R}+Q+Y-6v1 z^O}gTo`*E6bDnlVM<F>8Q{jz+g>02|qsPI1M<Dw(bnULfTzdfdF|aBiY<C<#FtU5} z)TqQ((&pFz-Ou<x_-S%I9o#FT>?JXv(uQGgemd+8w>QSMdRobJg{8W4c2M$oz|>KV z?Gk)4=U`?z6+SYmv@D(hD0?o8hg6mZ@ijmly;EA2OOaq;J`FTbmG_;9>mwzSh9qHb zl&hsmCbR`?4-FmOAB5H0m9OAP?E07m+-=xhFL55g8E2a7a7#K+VcV32Fcn$~hwN0B z9fp~KD|`^+%1v{tk;%$!WD<25|2ZRY#RzJ@7`e*=e4Txrw<(dFfMW~LDh?r65QP`s zl{HKOISagrLglb?Ag(|uJzFY^iy>`i*)=iiVuB?{5Sz=IeNWVjK+mw4!dOa}Bgc1x zpW}<30?oO4tpX2XCZ*hl<ONolGTP8}^#C147cn(%dM%&Ts|vDKx-Wyy>Pk(RJe$ha zp=~J3t#gyuCQBo}3erh#g%h^euouy-Mh_MibafNlS~rN^eAR>QHpUMv)^0(xL|i<f zYMpd$MMYv3em8*0@DM0l^lSk;+Ulraop!Z^C$fg)jd<i)88KW;=UDf8jpIV;><r|l zot@hwf}o9I%8UuTiJ~X)Ui>YoDrsv}l?1Yw@OiQ)`;g?5wc0`Odljak&kii=22P<6 z6)Qu#fhdb2ZB?r~^%XnD3Zq?S0m2-!Xcz5^mzo!IZ5-*~c?gFwF_7M7=7bQ%j<Xd` zmmg{~r92#c-mz@{b{q5-ssV-y#Hk!t-|=^9ya`j<1t2WuO&Ckp$mH;(kj~3uQspwB zP|v7K8*|jT715x1bO>rpD))$!iMcW+YhyOyxKg`k9cM>i$aAwV*U(VrL479f;Yg!C zD)Ej9FbR(*%7v~9a^q7jI$8nbOV+L3#wENnH48^<3*-gNFgJboK9{&uJ?*ZZH*>rl zd3?~Z@mCr@bmq8>%G2dYXNh*xu?dTyqHGa#8L~*_N^`a*Agim)!phKlIafu>^(ZtU zZ9w!Rm`Te6<84<cX{l71I$-|H@0flN$Dw|wc4a4II*N{@kx`9;>Nm>Ic=WZ#d)RK| zVJRR)1)x+A&LRHDI$MZUEy)F+^K2V6PUot~xfG4Gibj*|vKGg8FZesD3pV9*T%x;o z)Mb9V{&fnjVL3JNNYb-K6e%)I*o0QF{@wiL7@pt}<w2zf)D@vTfNxd7(Wt%Zdt_d< zNHJ#`6h&UT5~Me$CNLVWI`fS_a@BnV)bgT9X)IW+Fb_<sFImk1M<NS1S?Gg!wIDc- z{#{`cjV;l*9~lh0SksBNZRl7ew|z9=iA0bhx}U-J{dk}~U2dQ@l#^>ij_!TBD_z3` zMoihITAU0}DW<b6<E_>*#%jD?sZr(9c3mJDNH;w3qd*E^REM9DMq`N=v4KhSo>83D z>a%jvy9eA0iLO3Zzp05;v9L&1fb-sP2|ZvUCoKjK*{&T}N33ReFgoH*JW@u-lXG6L z<vmdzrm8UAlhd+RvsL)2H{oV`Jtj{ej-^~vYJniivL^0%Yi8EVXCT-*-~w`ZQs`p! zi`RQ0G<LDA-LEaY$IM*+ic^4$7;YX^wcP7FEu|AgYp1EIE(8{nE4NEV{jj__4sxPv zgGb!)!ac{fgPQ0-oh|Vm+F0WefXi)WUz_m2IQ|}W_sPQN{-+15#oJX8V16SMfd|$F zJMHu$imHV}6>MIrq}IDpvb!nNpfmHBNC66U%OrFTAM-cXVijb)J!&n(#wxjy`6(<y z36T;|SvE=1u?zZK)rml6K{iE(K_O!(f@EyYxM5>Sq^#*6v_*`lLVGN{dr(GHq!~L! zC9IL{W+qDU&Y7HqcQn_GdSCEfZN#cV%eiq+>v_ltBt=!^3T4nE+VI#Qgk&*y)bv~K zgl0Wj7|O0((IC`OR8~mhRu<WkdHF3`dLDjDsHR~Hj`T(FuFWEd+|F`d0|`9zc9sHy z17OCAuzg`K>OYb(Y&yxLi-aru={vTi7cAQ{VWHl`JMEp@Zk<0DxY9#ybgbw#$$ens zr21KKIEFF}{cB7j8NcQkG6<(9#+&y!s@>|hop4HH)K4PXnx1s_8LJ>t@~W!mxjq25 zQRUSCpeLHF#@rC6x4rucVH1B#Zll37Z8Z8P!9i54X`%?TSoof6k*Ms^%t(yrH?Ex` zzjGc4w9B;g*%s{Jj%XfX@VKZ)O=Z4Pz3}KX6e4&aCQuT~@>Sd+&EC6Ff13uBLuAf) z@^CmDp#p$TTcr>pX98*;qC|KE2b;cpc0EA#PNdvro$8lbY{%^npJSQRM()Mz$~r#d z)`TlCHG7l9KXpt;M-Df)`6_X<i*#6<p;krImBbezJqaqgdtH_WiRL7#LB?5WuM@T} zqK0((AT=EXh4`u~J^ikU!sRkG3lKZEve)c85RT&x#jQh{IBFI0go_({F_cASEp$Ju z2dCq4OTbrd^?FwBXkNQ3gr>$8u9Y%=BX}FE?#s*RC1=%(Anh>z0)XT-Qo?T(iL}Y0 zG;llPMqBz1n??^z)Llt*`t0d$gp^=Tn&B7Z0bFvvsW;oHT}vw3XkK@x?CIIek=sny z82!OvxDJya1^YE_bvD{M1wY&Y02=R_y8~*4_J(z_v}YgS2}h>7mhpV~kvE5W|8LZ9 zV>{R^8)eZ<A31gGz=?1No2cg4mtjDmDJK*Kw4z-yN)rwmwMb@7nAYyjwTEWP=<8); z)6H|u)`drBrBWw?goy=F3*&5T?et(UmPKcfJPOC#`L8tdOGF9vToK9Tos%hsu`s+H z8Jz^oU^xhFL)xy|@mA?h>Av(nD69Md?I0_35G`EF#^x=NE0XLcjmEmW^5S^d$u2jO zsSm4i;Ze}OkX3K+_xa#wK;Th1o*L$VcK-O?)^pzc5m|rvk@xk6<Zu+ERl~ri>$pOZ zhzrnrKQkOGOxuYQW2bJfn9H|SHb)@t>(|ux?ER?%Lo_nkPf1lApGm2RpdcmRQ0}3u zi=vZpCBw@2H)f5q?Ev{F3Zd|p8aebq@n?tAYwp@!s)W@xL&gu_7W9eo9F+<v8*p|* z-Z5oOglRVLw6(R-^f72Us{bf>Jh;>=;}VG97z@m4Ol0<|bNV{cwJ;9Z%bBe~C<Ei3 zE_8#2iZoMiUwAABoF`J@G@bq8k{~aP(uUNBv2BFH!r)^McePyOa4@Mx-Do5L5{QPL zo%%lr>oAf-tY5+I*%*H2)-B&+QDWpvyo)&9B$UMzlXTN_>#|(R&%-mMNYW(Vp`=ib z%HMf@`ok^wo`gZUlEjN@RvvPp%qC&E4#zQalHU_vy&sn*_XJeXS)`g%xiOth_!i+c z3Mhp?@4M6U(-cD@=}Z}E<HL3cGuH9uB;@ivm`PRENRG>Ix+S&XR&Rw=HJBmHey>X0 z#(dIa!N8PCe>y0XCvk&G1isggzY!1Tu~Hr;{;R69j&o<q8_tt`MxOBd&uT-^7G~Ai z6nAFrjvAcg*B#}`XM-n$$0Hc{yF#DNrO2Ha08`@T4iGa6lV&j(OuALKEGErL`A!oU z^K+_6V?NEXjcPx>8Nqxs{<z{gl7G|?RPM^`5#Ra87PySgt0!Oo(h^ECl;h8!v`bjX zG&nzdsT&M*%MG$LKIQP}M;Ocuq*X(=#HgVr?g!tdiI7CAYOE5kem`NJ2;zao7^X^< zr|oD&ZKihBIIXxEA3p9Bcj8I>FVevAgu1SH!U!!L1~|`hn)NRRGYYZN<b!hBcr&r$ zoSa1eZX}gbg)!7Q8=vKQp(NvM{F!<SzcHto6vY+YkMWy;#?)P^YaY6_%&X!=v8Q3K zsMJ%&QED_;*PY<Faf;%t5)0iA<&ZAP*yjp9&g1(*{>r{@+M8cbxH(-s|EGZg;^INj zol6H(teAfO+(~OS;U{8D&l$OR3yzCAXvJZHIAF~S)3)7-Bjkn?q@N{ss|2w|IE*pN zQ)lu5eQH;FROboLnL1YpquB*Fj_*(AirvNToJH4UFl@Mo+e4qCIX>xvR5*@L{*8EL zwl#Gw(i=z8L<K(WJ3g$ow73o-8{Io0mr=~2JqEj4&X;QyxfN-$+&+t|k$8(5GCwL) zQ|J<dcpZM(*Wdr;N8S@+046=5C@?a}4wqUb)X(FqYPe$(zsR4f!)1hvYs1Jqgh`D7 zXL;`h#&%j6Fa3({X0=)o>WC{1#s(QAj3zi#t+yw`Tg~jqZiS*ChGA*EQJH{~kQx;x zf*y-skd=vWp*(=>uvVioE&;}C;cl*kv(OToSd6vg1PkyrOCp&j&f;h3zDp1QdKn!6 z<Q-}L8P_ZO`=1Brzy$J{$I7_7gMo2DD6?kJq8Uvo5Jzj!70rZEdrd}lJ0ck<yTUq< zk`$S@)*Bw_;OBRRH7K^R31tn<?dMS4J6Gj!wbpQd|41#m0)(i5MH7v<ORqzaoR7vV z+;f~E+QoT#9`KhMQY?A%1uw%gFabr{c#&W?q{tKqsz#fI<xH{{H6y#sN;}&^e74j^ zx+c?1uoJ%Gt#D4T!WaFn-i4Rw@l*1Oc2vL8HLKCj2KeQvDLVWRGvjOXb+``Ys;*`T zfUu6HW{5KRuUQ($1;6Mf5)BBX`I{nG<d(}_;7CwFda3=6D=-8CSEXzpj)EWn&c;@` z1~fr!*J-#2(pA~sDNMR$IzDlXj7M=2$iV?-0ec?9V>S2y`5Dt;g;QF~Yz3MFU3e6e z_BIJOz}e!Mm8W^z!HOs7OvOIscJ-L{ItkW~9d)&gT6L|=dV{*L!&T+n%Fa%|>ZJDY zhBMe$1kw_l`vBsTpg^Wg08gN=`8vHorO6KbeHaMi%}&l2wf>YC<jsif?AV#p)3hzN zA}6`ji0p3rFc@q5uz(%88H+NiOvm70_{sL4Z|Yy3JaH~p*3Dh^Z_LRAWK!r*d@}Mt zVivW}Qp)A0!5~p<${09~k@IWipl){1vUMcbINzl*z;VmCrK;Q*9?oGu@9bEI9|ut- z$yoo+GTkU$trLy+-t@jBMjd&k8;ni20Q%V6wYIA7%dmT~-gW8r5}tZ5g-R$DJgTJh zxp#B{58T}<mnF`ijnK0X?xqfOC9hzeH@@W&y%(@KYj6*IA3=6_>8zd&{6^6rSwY0Z z;IZLgnBj>{segvCV|Qn*h*v}<BG!i}L=L)sW{P>Tm$xOhr0k@qH73~PczEyqxgXY^ ze@mCK*UYJ59}%^1eH)5)MGwOCD#UKS@H%L-dbLmU!bck+l}D&U)jAa5COu%Nbd}ho zlWO5}rAjFqJAZpoz;_Z#*O`I|d;rU)E1+|k{KlA|_kiToRHQO7DV&%_f-&%&SwWN2 zC(Ta7!Q@TSO<@d2%M(31{lD@d((OO6h)mj+@PB&&l_+weSm^~Ls#H?#GFqn501y_2 zwq~{nrKvei#f`$L=y29mwFF1R6G@APlj&b((lB8{*^{{b5W;}<He?H+oE<MUkj?#= z$SZTfLh}?W7Z>4hFLGBUILELeT~q7n-Jp;(mcA>JG+UGkkZ_YBc<qee(%6hDbdBdi zeGK$A_(=j83&oSZ&CPlsLRrH1&L`u%S)7fd>)*PP&ShTp-0KtciufU6zVFyv^H6z0 zvwfHoXCqViaTevExGj{K0T%s3Ly^vnTe<MO<Pm5}9W1m~ed0kJS=ud+X@uK17~CjA zFbP}7I(6gHAiCn3jXOix8$<)2E*y3J(A7(15CN0;md-}%Zp>6shgO<XVi?buEj8YI z)3#dOJ#?gTTXY5|jg1C4>V-EQhj31C-z}kT9+xB1=}2%J_ERYv7T+k`dCHz1dgqF7 zhYg2EYfbnF(EFpzEPxh`Ra&Iha1TwWH8Najj?rj24-?CEdXyX!P=LFA1DYR2OTxx# z?`bt)3@Q!9GwFlqY(nDHtXxTF3`1Rn!HwcpxH1tkbF+1wr_s&pECh3YQy39O%Q}aQ zu~96D)re<}D9Ao{=j}G?#g*RCi*PDgxba>6KY9FcJPzaN%*lRK;kQy5|6sIwiYwRt zlNfdp0X>j>zKr9g*reG(jo=jawjMD1okb3=SKUpA>utCrh9<;+f}AC$Bq8NvvJI~f z6V2hcK_YT}4%ncR1Ad1Gw1ZPOfnoS(7IedfD7icMkd;dJENlUiV&&Ltd|$0pleF4| z1%5DPfy8yUq%jhNf9;lY#v7Z?Mh(3yQ_`++>XT*0iNEviTu>I8psO!mPA&vZIYdx0 ziwWMDf*@VW#Sm}8-ec)oQUgL{Olb^ci=~>ei$_PCWPF~Uf|IvBqc|~)lXyvH*~)g4 zaL~oHEk4dH1Rwc1WeP^lBFMwD&9G<<Ed`iH?pU{fkTl$zyrUYvo&p}+Q8L7D(#_fu z1~5ShC%uo}fqSap=^X-lgP$Bi6}%0Zm~=44bS=4ChFMqI$dlZ$>N%X#WGx(!qxK|* z67278U{Qn0!fjGnMa6|%r>DIse<6}6ziM`)E=2(XA#V_1TfV#2<m8D0?xo|6b%3!4 z6LbQi(_RcP>$`vn&tAWWo1O~LnJ$2yS&#-3LCS`S7ecDLm}16}5buoF{*W5c_V;16 z>8)XCBXiX^Mw(09?2OA~H9ScVjJ;L8J-_T=sX2i>UtF#YH7_oOQxUyW(xT?%oH2Aq z(lRR1h%78&QHSchr-!D4=t0sxJ9UQrUOFEU#n3GSfl9iZQB^W^<TC_EwT2`u@K};w z9nFf92ip=MqD)k>=c%vCFqllFd1{Xv`3OQzoq9{^dRRYYTR_+`mTLouY*hHUcs>Pb zM*}S{W446J@#seV6)*=FTa;Q2Wj3Yu5W+`IEw)XCdY^c~>1mD=FZY@(CC}uWx+jN8 z!pWmj-_+T+*rP)wb2LfvT1?uQOT=e0xA~chi=;x{c>}H~cBG*~dUF2mK`_;t#ERhf zaGsh>@Yy%PFcR)fN}R&tX1y1SfUn2v%#gZ(9UTXu_auI#MJ92|eCjO6yoL0ZV|hDx zTza}Z%V=p%DYicb1nqp4`TRV9-<a4e>DN7k=f<vS8LFKuBP5==o2O&*UmxTVS$R>h zz8j`qGPGN$Ka&6rCIXZ#LD`Gckb8&A){=PqGSuFxi)lU5>5@zv-wT2`T`qH5cL8c1 z_3jxGd<JeE#+9FQ7T%gei;T?Jb>CQV2yt~-*wR-BmS(jw*DQNg#2a8VFsF|2nZA@{ z=5B;lhbyJo3y)$DB%^Sh38U=I43QeOnVEGIpL5ha>^g1JqJ(h=gF7M2iMR9kq@ZE` zrU%=d$dovb6OJU9G}zWe89&TNqchHbzaLH9TF7Ndf4eWZ&qBKBzLe$n1<!X6JwN54 zUd@}9jYwM~zP(z1JS5#^PL-y$yMswtP(1_@K|AO21Mr$$cz>JkuF`k0Y1R5PUF6_Z z2e8HVuIh-V(XKP*d|G!V@;!Ip_?yw}bW2s+qg7={hksYcnA@b|hor<*5?&Z`kR#a? zC#2-Vz%**Y34}t@sIOC4s-WkoJRtq8ks0K=peC<z1&F^yXOzWBziXYE{K~G5aE$Ms zRW|RHDcWHN4@UtL=AW42GVS)$jrm?%zC!m(t1!A>_r;MBMF~DOY)fK;EerFNW*UhB zMd*j@cVfAF?hjz&sY1J|0z#nIozr_uenC#`e7Nx{2or-5s}jCm%?35L=V`nv$`3xB z8LrB`dDCT&n5!3*Ty<`$_7$~Rz39e^j#iN~HVa2%qf}8pw~!bLCC`DtY@sAG#H1)7 zsZbJS0S!7OB@zZ>!DNbUy<QyN-MD%I{LxhC^-yp<W(__~F~66&viCv#9|FI0hmQM4 z-saNtiEAo|a46Va+<J5toB#lW@Nic>I;7wig%QQ>%>D}x-*+UL*4+g;4r|?6v1AE8 z)_v%cyDeN3t73^Ej&1`@u}cJL5nY_>b)or7kz-sEF3d)9aVR??qJV)iMoU-#cnA)U zJ^1ftr0)}nn$D$dMdOLuBZACvMX7Kx#)M1=(BD2dGw~Pyo6blrJxJVOm-x*MH$v2y zUZEuWQ*<%indE8+o;}+624hs@l`hn$>+1BIkf3-&f!=7u-{K8f9apA%fp94oW~KmP zHOE9T<P(`D?$<$hYS)o~NqT1WBtY}L^J)F{F?xg$8WMtY?E)$YEbcgP==wc-ZoXEN z`d}0z&6Qc1+l69zs8H(!G9E@kYZK{{LeWu(*}tL;fAmTvS+WcN2h&5*4k+@RLF&^> zwgYZ8DL2}M*cNZ9MkT3fMvK`wZ-wcWnl6Z`=9wYL<XEOt(icDjp+@x_9ybLpkz#{2 z-r=Cn0W!}XPU#nb5wb`g*>5NGH9@k`iqu6(?x7trco>`?ZUd_Gfj{6Q8XA5X+jp^> z6<tI}uI@qDGE7q+C~cT}MCIX0kOIlc!FGw{6-?Bb1(uAm?iMN>Z3-iG`Wp)}7F2<( z;ogNEP@&}5RJ0Q@lrCJanMD&Ko>QfNo|zi<m&&3>kB#2rvqU08`4->f8}5wUbB39| zlVyfcMFAHAuA!-fBNE}{a$z9oRH;3Ru+Nkjp;hk;@^Fn_lp=oKCO3|%pryX17&2$s zmE)Q?bvz42AtzVi3e?`EpfV!N@PZh5;_u427#UDM1~HKy#eR{852H1~D(CTw>V9p) zosqjh0fo6_pOkCJb7odKTce8(siMWOkQB@;fvIuUp3%O!v&mGtNf=&BHhd0C(>zrw zwR2vcYT;m|HCvhsk)S$0J13>kgQ{53r$RfT-1I!+JMC@3#0)(L+F*(}<~N3~`Uh$o zG=6d@!3?uC;f!TlUX$J3o{*khTt(K@gE%JCGR#UQp=(TeE4c)E0+%s)cB<zxHlucg zVp?5%G#Si>Q)D<^u;wrmHKn;&DMSk+FydZd?u8%M4W=@Sl9G2zYtl~obeFp6Ktd%n z0`4{24x9{1U`k|`bC}Gd^f}hY=ZKPGdd;I(u&R<;wOl2AmbKn2P4BkXtPQ>$K6i2- zQ@X^n?{AE=!i+ZJ|JC2NO|jX*pOn~mLyRWCXMw@HiOFnO-`D`dAVv6|gQBsOL}ICd zo;BXihy`^rD5oiNwzyM&gSBmpx*jF2_1dRla7~(d#Efs{5@T5tZnhJGuOoB4p*1t$ zWY*P`wMI5R(i+Bi?j(W8p7>dIVrj-Al{#dFaZhp9-0VHgol+Ir8R)nzTeLaxpkxiO zA-D_9;1OWXu$BkFBBwppvg)o=BX^LuJTN!ilecUFZ=t|dO^87oT8Z@Y_$0de<eXHK zQ*xpvYErx$Sx^oF#uFZla~RNv@sd*~1jM;oZxG2!jb`7(Pipo$wzu+BsR1?(d$AY2 zQ8PQ^LDhuy5rb;<j6l_#?+w*$(O7I^!Gbx`F%ttRV~9}0tnZWqrN8kmPSIklJY0_% z_kn6_lOgV#t2LozgQR<{gPH<KSa}b*DUYP#-f5e7dFbt8?6NS<xAq95-Um?kgg=d! z8<pDhz2dssg{itDrYb_WVOnQ8`4qG9&^B%R2a1s%VJv`Cw@21&%kD>Brm8?(6qP!) z*m)%xc^pkfzrN2`w)jRCVz@C>nW}ioR4kItS+-%kO=Rh;rHnHqqm;2hHPz3E1Hw%0 zm)z75`9A;b6c!xGDIiqam>#JoQE^IwGQxvnpAq6BCe)}jvv+<^XyZ82#7nNKDr4S_ zdA<c=r2r0P1wxki`8xbhapV%8X~dp~^)ZaUxi~qW(%5E~%GrgLP6!j*AxJ+O#S0Hm zh`Mh!6DG0y-`<PgRLwOoo4+!rmp5*5pH+DwFLOsjtEz`Eo-tu`2AypSBq`M%v9GW) z$E6ty+ahpeJ+nuia*lxPXU)^G)8nm_0d|GPxG9JS<<bi8D5#XohE>4^BkJEeg5PP& zGIh#eYfJRDPr=+blN)MqX-p22N3C<2QPf?-6Y0;9jdjjUx=z{`r5xs7PujDTjW_PZ zLUFA4F~*qUNEK1?lon`=MO&melb}p$Csp~BKPhy@@2GL{Qg&jUZyDa93Ld!!Dea6< zkolY2XXPzq->%O_9Ky6SMgxZLkSi!9ko$F0fiW`uJu*8;>~S`7F`i(${QUKp9t-|i z(WmsRkfz4)9<Q$ESh_B)!ZtkBoJZn@^mbO}<9XKiI5ug<7`TSZABomS2$d$3_PJhv zEqUl|8sqZ>>-m=*F+z9oD-X%#5A>DM#ux8&lx_{@$5e&&;7E%^A4btFQH{jn3$=oc z+%!gThin_}AG!z0+vX`()vKxAOaRw1+WAtW!rI^vIWU#k_AFi$^E`s1^Z?35V1gnk z*A?cl{MNolxf;9hlMXtJH(r6GO{~@N=n|YE=J;F}L6-hLA*61HZd>s4@z$qZ_<=Lh z0OlC{4Zb|cbt=BHHk4owQ32-T&2Y=18I;Y#!+8CcUGA4X*Kgt5_K$n;1ssHB-jv<M zK=^+%W3(iecbj{@j4J|8iqh;{xJB<<#Q>~nZ_=k3!6W6;c!=*tyAru?fGTWfv<}2v zqLGf;S7j+%fFTECBFu1LwxlMSt?=g6=y2;GNi>-=h%)bq86XL%`q&d`D}eQ*Ql1-w z;&;^P+g%@JojV{>yhY^Kv1VN|{8G*4g-5ZN**ao#RK=sgxMB>#J-|q8CA$lk#<wd& zAaIZ^zyOMPCpikm2@$rJ$=+;tuqP~m-Z>Uay|FCN9Nn}Wi+g)48g|PVtKH+<CY#2u z;TAoMr}1nGX8jJ!(d~M}QdX9#bS~4lfH|^3-(hhsq&~ktV0<<CUfof!9Zi#F`;tVh z+0LUAgfTTZOJ5CE7<<kRVPom3zz!yB)OG}uJe5abhTDt=T&G%V#CVRid!hVmPQ*Bh z*SmofA_jtb5K@=MdmHJhCOpPntpd-7L>=1QyT$Nj=l(!cS;X9s1)mLSyX();h(K!A zQo-E<aQ%xQy8P@OaxNLQ*Q$w;o;v6<sLN2REYy7$9?2vjM$zc^R#l9mnQD;{rp8?W zmCla1?g0FJs3-zA!oDyL1Sciu7^D}WT`k$adnpJ^c~qU&A8NV2(ev#!R(c<Ul&1aS zz*$M=aI7@07a3;3aC62ny&GflfckDSHEErf<ch-=9)p7n!6dpP{N^G`m+Q^?yUo~) zgPQSHZ=_|se8$H(w$ue#H3HKeMW>F>E@A8urrj~wo>y<rJd4`uD*iWN$zUr|IpOoh z!IVu8@5CJtVR?9Z822nfl!Gg8t!|wlU8Doq_e)k4Q#H>c5&#o7BWV=r4Y6vbcAKPB z>NKfcl}xIso#r9i$f?n}6{@#e9v6HEo^J$fT*cxgC5UnG1p0iaYAWfu_mN11x9-Q2 z4F2o$j)S=8CgeHxI98QE{mCQIlgTo}jmTOASB|w6^G|lY$%c14*T$vh-X`yh5~(oG z0U>*5?&(g%Ii{K|@qB1r9i>i>_&$-mh%q&@HCviIiCj6~p0UKKA1l()%`Cp@)a}D3 z)V`VHr>#)sH|jrOFy^K)a=9Ni-2y+wE3r8;O*G9auo1pRyPpp|23?Rs<Y9!Z8FBws z>kq?qW%XpJruFa~gVa-cO7``KL(%Ej7alH8mD*KwTha?T!&7o<_(XM|{qh(>D*S4~ zeRZf_ZO_*D<&k}nTs%>lm8YiAOeox1nKa)YJ<P{i2!~_HF@A*gsmK%7Z{ROgoAs~+ zrald(h6><17Sjk@l~%PpUPXzoT~65FnnBDT3&OP;W!zLT9FqCsrAg|}@Y_K{pKC+I zgd?#()N$t#lc%jA5xR6%fSB7EAl_saaqCS$lUA%d&`uy<ejsYbBw8=@OSvbB)&aTB znj?*Jc}zM%m8xF8<FY{PY|F=%pcAsNsk9fgm{m@jeQD|8N<F$QGG&@Asmo!!n&-m_ zmemj}(H&0`!w?Cd2F@DrbrP`C9Na+tN6@`pgj41an>wOLOh)2qlZ$uk8m%gs2FXUn zBn}LZD3`?j6RBwjS$+ifIAQm*c4Un(UX2}54Z%qE{Y#?DziE_Zjj;m3))9Et94?j~ z8#%0UISu|h@rJS``Z@`}?HPnM86SrWw2{RdH7SIcFmVe<kz3I@O0Tw>gh7hzIyALF zJ2Kj4P?Z={L(z*Ug=sLE=1=O>S09a<53W7JvJ>cart!|SVK#`WWAYgka7r~d$kJ0Y zrDhM5MtMPYGnR}ZNRYJ)gJ821snn#jid2FGc7Ro*v|ZW#tOrS~z}7Ul1@_gYILg^; zUV+K!vUMb|Y>Y-}=22MPd7A8mh>7W0;({;rPdPSOdrv^DbnBx_tuC7K(qPndwBhM0 zzQ(@xG~7Va{SO&*6SUhkyEJ9EWx8w&_Yy8T1LkFVQtb1KtL4dz$5-GeNNB*mu!Q~t zzOmsBbaiW#s+y(TZirfJla*fzjvkM2c2*{<*flW_iddexr26KM+q0%RxxT4MKBk<8 z<CwGo*IVq49jX1V;0tq+Q_Z_E-Tf#~kbN<OTr=^rME4P7t+(%8@OB@7IeY?Xe+)iS z(L4affrpPJK=eX81;t+nRSQ<p!y6iI25Tml;cD2mlg}}=5CP0^6TXS7TCB3C*=njg zJ5^+=HS}vzR?zzL@x}xyUu9B=n&Mg3IE4C_lT<%75SdEB5v4OT;tyfC7V{at*=>Xy zFK`IV?6ps;l4p{Pln<MJD9jYoMpOzNgU*vU;uT5v><?~;MmY#LOnMEurFojL(0?0O zT=|XKKrXh!r~>s2g<kP=2smQ~kT%|;ubSgdqKw$7-brw~SV=r1+EA+TJTum%tXX9z zcPood=$AI?t1xpse@bBD{%XyXLKqUi5qmLFGN-s+ec;T<>9M1uqa(*hPK=>5B{T0p z@Bf><ca5?8KJ)uVwoFoEilQirqA8j_qRHV%OAaa8mbElZi&u$WlA_76EX(%p9?lGh zW6jOy%+MkeY>gl&*4s2#1dDVVY>P!vG_o5ci=qWm<eixpMG*8wTcmFSqzH_nH}pjj zEQ-QF`~5u6|9AOc&l!q#8nhBf&YbiA|1Qt(`91fG+bAWxS+hUvdjIk#e|obo-t{kk z^6&Qtio=>;(obG$bFMG37yII{2VwRgC3nx0Rpyc9)Ekj|*+mj@Ko!A!y>}wBhnB1* z3%$wH`c`kxuP?zcDUvoP$8>M<OZq(WR#_X1;W2p1p6Cl+8_c7cySezJWYpqiLccLq zgxK$uM?YVIJNE}MtHrpr?3$8XU&mT}+Jx0^`gUB3-=<E`RS^`jfK!zM65NqUJolZS zn|t&zFs34Fxh+H&c~K2B*V7;lu1Vd}gicTrSKsY@Mif-rdpm|;b?@Vzq&Jj7Fq=Ds zrzs9>y9!njrUgf*wE$0FWzTo?3ActDv?{3xT=r%0tdEVKFwx|<VlxyO#ywKZZPns? zI?CR3L55{8?i(hF5X(%gs<v}RjlBs;C$t8&O=1367C9N}Z^$cGi3PIp;5vIU+dH4O zCp25!R9kt&HuEVwq5bWWs7vSoo#%3KdB=I76paN(^XJ{7HH5_gj`ASe&nv`Qew@)` z5FFFMMIyF8BMpt1k~tGdy7BOR@lWXfhguDx)j3}a9Fb3N*v7#yW`^#CApVxZPH{CS z3w^N-uOK<qDjVHv-mOc?Z84K;=^#FHejt<NXb6TIbV??VuNXSQ^NK(nP&BUoi|3sJ z<C2qfNON2lT29S;1)4?2+|lzLw$=8OGI4z3t0QJS(mvx?w=m_rQLdp57t-JdhOkpF zGgD`f$qE&MKOnL&a7GALnH)@0=e>Bcc$4^qi~<kW6mu;)BAH#0)M73%O0WBD4~m2k zi3X+xk~^zu@jWNC<XKHeUZmAy9s~Yfxe7C;6CgTfu#F&jr1Rc=VPSa@wfDpoUFoIa zz0rqzKmxZDZ)hE%I?%cD<(|ACcicl2ZeAEehNn%vchB%ORtMXDQDw(Pmq#w`ssBoW zgCxzkJXY2VI84ue`lXf)g5YCEmJN}LF(y#o<w(MNo?+nftxH}mC0*0jA?%R%Ah~(; zL7`9EcTgE`w+FzI9QKZWbE^}3M(X1Cvb-3&N<06{V_WVBYC+l#I77q+aWNPp8QtW4 zliq|+Hg+l$=Td0ko{2MK1#_C`#!*(rWvI^Kp9UvRDCFa-cP{QTmd}A*GIPEYPQz#A z8_D{S9{sC}?(L2`R4CP`Tc-<A>&Hy8nz$d5BB?i@q{p;-s3rKh$Jbh1&rIeK3|WQ& zffmUDZ$9xt&Jejr!#2;pRU<10)28qYFL<a#4l^Zmla0Lf7z!$C1B_`_|5gOU2+A*9 zEK(pO@>Xjyt|;zd<n<CcPgx#e)+<6XE)d7oUXQ73Zt6jfp8Ise+$dytQ)!t4%2rhW zxbrWz?L0In5W0+B!L*2Id9PgLs*gbHi1VgqZ&LG9wacOg=I9x(RQBu_2Le&uc~_ON zMC@OQa44;3OHeqog*AD27)0I3K_gsN`Z7KZW6AxoPGYYzGLf_~U%>Ipyl1;2bXH~0 z8V%pQ)w=>d#Z}fC>UHV@d&R`u_|e1<w_jWnLmY=0?$J2Z1A-w|ced@~U`?v$=#3$` zV>zx3aH&5YWR?XPu)7>Q==rG51X0jnK0JkfaMEM}46@EDf^xT7w7l~1xGj{9fY>{O z>}8o#ugjIcD1F)eD7|SVUMg*i)`-2uzWsQzH!oAA!f{^heI(U$3<c!>?K^q3H||b; zIM$im6Yg*(Cv`fQX<++shgqFvP?$X*xBWyO#5-`j{Y37eWS;EZ=?}Gq2jd;azm6^Z zR_hiXX9sVMJOre}cF?9Y!57Nw8WWvA>HO(vEAx+ef)|YSaD7wycQx`ppc*6$(S+~? z+5?`@pD#_EipbRq4oS-~lJYdS+`mt~wllJio#=hZYV>r=L6k%w3TrFNNn-kWIVq5s z!h%)MCR^%n$AzA5Td3M%&ml||gzEe?**R_Pzdf2pW7WW(>>k$pB8Mh*$4Nh{Nr!!c zFx@fJ4Tzl*{_4)vZB9u?FNU_V#EsNh#*WKM*jZd%TOK{gjMhL(8~ebXk8lS03Eqi{ zM>+2F^T7wU+V@UB3m=*7!6I<Sn71SBsT*kfB+;SCqP&p`Qe~IVT#;G$(cc}*NOf44 zh}D1%qZfw=A?KjxDu^52_qLiKc~h)vUfrk#Q=kD%85)tVF8JxURl8vHK^>OMCvXFJ z!&G($ic1^Uy4x+hz2E9x^xHXlc=GMi@cEU>Z~t?}z~f)`Ju>ltO9+!-mjuAL%x4M@ zet!&n*(2W>Hc7PSDg<}Dv$nd3H+1wi_sM{Oc@UKzRId)T{i>`MV;Mm9$ZSFD(8l}s zO?6zOu*B#EeKgVR!343<?y*9+s+i1VZbN`)K}7MWqhxS;_yyA`VnM7>Dm}rL^H#WT zUF#Pf0VNb5rY%qt%!ru0DMTm{`%fzl`wLB2#S<0FFlS!fqUS@Wob8l~TZ@#F%j?^( z$&sqwVWR=HQ*<Bk7(_~@hRJI>`b`X;V<_M^tPs>kva?h}+uVYK9fPZNS?G~6wfH?! zX?=_J$b_<p$FE%Pe>8)iLQW!iBSO$tArW6wMC|D8{k6h+O`N6YIF&t<!N|$CfFStp zu*{T+Sh7fk{Zxz#dc)&!u#Qt~pjvO^@^$ruBV=<mCMOj2P^9*&@Iu8Ha(B>w^!Fw6 zn?xW_*`uE=N^ctDNcZYIu%j;OZ!V<K#|YJJ*LAexu&{rwVTk5Lie}3WLJsn_&_CRD zm#j(CyrXAGmkLt1JLlY)%ynW6*Vo|*^S&&-5iBNXQTOzDa5hit8va_`6Vk#GrvK!+ z!iDZBz64){jJ}puvV4qITXO7}Va>go*3}O&nGaPfjW&FGWnH-t%WA}UPaf1)M>^7Y zBX@YbI?nz2a}(@{PlCA8oj8{=L)fgl)CxkNV+cN)Di(7DepL8&P}H-+y;7AfYZh$5 zzq0$l(~xslZNr<q9~9!8?3}+LfXIEV`aW`1hngA+Mg&CID5L38B}LX^l?^LQoT?Ic z^ZmWL(cCW=bgS6C{l=Q+T^z$Mfc}+-2Rp=oNzz!#MJwF%N<GfTv;}=Wt+NRpjNoT_ zJ@dnUJtQ=kuLL-$<EE-UfELjxMjJ?oo_8rd)ti33rz#(7t7AA}VF<9{XupoPe)49Y z&;h)?qlspSWeXV{+}j!ckHhWMaGrx7TG4efs{JJ#YVx%`Yf%r!ikOGdOFSqn;5Ild zUY>x3!A;7vZpY33gW(C4*d9F~wE{qLE*Zz}uFga!cHC6Hyo}dl@Wb6Q3qpD8Vi1Fj zDZuQvL2x}dV``Ad=|sD^IF>lXlJd&h$(^=cm2}kgV+;uGmXd~*>z-Bwb4jq7ycMc{ zjRBoKlBM9pO*Xk5x70nCN|d9|Yqt#(@@RB&5jQ_`Yg2VEN00DM#d-^8%fxA+lGPj2 zUaO)&n{EAw;s~iqB%#jO$z!?}^5W~wu7xs9f9&Oq=WV#q04FRBxwqj&MObQE(sU<; zwq$&-IzgHo0c}S2!{ucRd)FVs@?N+8kLeT1RJGbdA{T%;SbMP1i2S5oBU4rAWQ*F; z5&c|BDpml3`Z627a0iv@yooa9YG&LuC+XD?Lgde1qeK{~$L#IC8gbF!S<0FM8;WMu zCcStJoP@m*;Zm^kl9V_43~|3u@5D9F8Xvp8ymtT5$K&`V83;bcKn)D>w)*->9UX(f z?$kgJbWj*^Rw8(I+<q|Jc=Ykg81$98MQ{pKWrFs+mL`gF60+PP6bdr<iruG@n@YYC zr+;(S>P`A-c=(`TEjqhsv3CHzFeRTT)I>L_d}Z_raEscPTh?7m=^G_OX<F*}(Mu)T zk}iHyvrCcDW3QR$f0KB0MjUz#Z)TO4{&A7W(JfYI`C1X$+bj!w3|!e?A^+e^Icnzx zAF8y^(PwhptW(I{_a@v(QH=`<F&?ro#AWX-=2}`+Fw(k894Hobj7_XtcquXfk`m$J zy;x3#pUZ*Z!JOb!%#HgGGwO9-$_04s1<*rAU@43{F8Iyawcfp@#e0|qX!yROpJ^W2 zSCyzWB_#BR^yO3<898r8d)!7eM$9aYcthDJ*GQVA@0S&itO^uT$O-|RV3H!_ZS*M} zs?5<APgkEM1=fw8Ww&tsS2~&xYgqpD?B-x@^Z<K>OcbT*Yk<0F{>-;ORQ+mY3ylt~ zn)o{+6(wm}=kBI1%9ezrgH$Z$p{&Z-MvyMyaK8yYcJ<p<d7%gxzq_zH_2}moH}`8` zUVqvOk6X5H$UzQ`c34aqZ%FACJV|5&9AnF2sF~vZb_p6XfGtbq>Ez>6W_H^;Bfnzl zAF1vrW*AnF#GIROhKafA+u$JqKg>=RX~QdV<(425%af{5%-Edxtfl)oD+m9=nr5{& z&m6`Of>FF`*w%XDN{*CPqO#~@FpzlAmsd`Opyi(Ptix_b^EV||aI7Fjxj+X?!*<~d z4W6=K$I9QTCR(TR3FV9F?yMZ$+5!E|()N^GEBdEk9ASWkuVR&voMB0$d}u{-LLKZ_ zz{MrR(X{BV6=t@yRoAJVK7=qr<Tp6aZ2>DY>gc4fPE_AblCy8p1%qHD;T8elS^ZmP z&0aUTC`2TV=>?H2i0_z~jYpGXk<zv;TL43z92Iv}et`T955xr~xy(Bn20L^w`dUk} zBRsv*|7Z*g0xv=q@)ws@$9VBm6Mqr0`BT66i_uHmrTPoOTYq%obbNXHQJnHePcy<! zvwSVhsgqQZqj;`(>w8)ySHFytWqWEBA2%j`5NGLWmhaJeV6!NqQ$e#IG*ADhmLh<L zg*Zq!X`rHQrp*&Y@v;z|mIw8^6~8=2xW0Z};cBk7K)I^ntH@2@ZeFST?bw)C5v6i^ z)jBhJwWoC@-S&)YxzIyTa;~9XvMXugPYwJ}dCmCx{yi!b7u1|q3IFCUAU2<<91*%l zg4t`beEz7|*(L1-!nLGe{=oBtzM2y#zV#7+4(9T_AA8w+!wu*5Lx0=fDO)Equ~%;~ z$57HHZ?hk`E$0xNoyl(diyZPrN>_eskN4)Nm3HFMpP!h=hy|#<?6)L$YCp;GA%vXy zk<uSj9(=I2DI1b!LXaL2YVxQ9_HqhNmg7n_#f+a;TwEHZIR3H;d>Bz)pW`E&6UnhN zceiNm(6!kFehPJj_6oBC2?v&{*X+Jx?LMs)fhsO|hI4(u{gpdGAv}md>NC4j>2Zd+ zhmXE~xcMr!6~L}uxWr^%ECwyZqj_|41sq{Op@^E1e(W-vI_0`lZ>(q+P$O1<XX31I z2HpUe1`|})x~OpZ*_c#&R!*Vv6Vx?v!uWwLfI9_m0V_j6O>TfYT+#7)qAkh5o$Ld1 z&?cUy5#vVgoSma?+~C~#*;(aJUVZmQ@66eg#b=YfrDbaOkv%DbxvZKRLKZJ`cC3Gw z&EsuR<v8=87GX8jfO#PN`L_rC^?OTm!&#E$Wfw0h%)2GQisOz>zp@FH4LIh2=LBf< z+Y}iDvCOd<Q+qO=@GZhxQD`87=;iZ2+>}6ODL5M}zrRTej@_9tmlC`_ctD^cA*na9 z+0ULAbp0Y5w;cmuqX*r|psQOO^$$&;MX*jnbs(M~v4^php^8=t!wSfV5aoW<Abx)+ z*#1h;#r+e6rTlDye43bDLeUFFrW+?9Yt*Bkt*H--QpQ9!MMKkxd=!6PR-Fp3VOZ4e z8}pdf8}}aAblM-*AYk$2_IR#skK)OS`tvRk#a2JkMSQ&dO(v=qvHLUUH|I7@F&_iv z_E>!==$Sjr#S7y=+pRU92N8}j6y3nM3T3BYH>SBK638d)IHb%S6*e&3Sa&~Sju&H| z{7%c#D*W!*mb{tHn1k$>-z-I{-x0#Q<8(0&xb2dKm5({zRE>aDwGXag0>$1CKWcg8 z1-6Vi7x@5$E8Mjl7otd#A9KfLT{8)b;}YK2OapU^jB84HDVh>dj*yA<dB#AUeHPH< zIRK4Ne%qq>$K3gJ<E0N$BcW4Rv`TPR5MZD|60@8wjy>CXjfaKPgGwAq$hqa(Yl$=L zz2<CJlpwO)aaqI;VI*uVwO#wn_5NUN4mv9Ybd?qwNHdc%`%1SJm7sL6n$#Otlce5U zU+ARdF|RMQd`zN4U{qezSAkrHa_GKW!{i$y7wz`MAl@~xv?fAxqGh>~h=Q7)@uM-( z;hQ6<;N!sccv`58Dv2a65FPiJK=riehe9TV&}0q)xj^B7%z?X?h1acu`b%jC3o1ao za;Nb5gCoTykh+T5Bnbdx0{paYL^|EHkuvf&BWzx@L!JaKl5~l!ANsk5H9XEiXBer4 zWb64PCyg=KgELxy6G^r=iQC-b^$bqb65o$wZu3x}F%R=#jplH*Yg~NRh4wKArPf^t zGG&pVcZImc<-Sl19m_%&<@&~8Vn;?#lUd<jY?#R7rN)@*kd8DjWzx2r=fWhz&87RY zJ&Xyk@$1=+vDQ>(Dpmd6CKs9v;$tr7>5|>^)9;TBrl;jLNNo4h-yQo!ijRPJF|ae@ z$M*AHe4eH6d)tbqB;7abt~QxG8|mGP?vNPu?%t-R(s7i@)KYrXK>IADq{ijrP@jEQ zN>@>=e$-eVr-zZOaL>k36sPA6E=LWqOHy8FoRUjl&)nWzS0%y~x4Lvel@8M=3oOB+ zs?#DuqwG<O_#dV4ApBVhfXKjY`why-r{2iaJ6KRz%L6j_Jk`_+PhQox?kI4hEu7LR zETkVXE!2A(ngP@eJP3y9#uxN20fH`nxp5dFGP76MTRe|IgJR%~QnOfMeU5%T(CU3u zB5KjuXCh!exS~eGVkV2rYA9?b4^{hF6W^7>sY(Z`LseLNykv`9RMxHTxMyATgQ29~ zQx|jBz(csQS(Kl<N{dvb7q2UnBsBDX-+}`MQkT4yY;gbMonmzuuAF5jH*cs^mfItN zk*gaB>@o_+UA=ZoohxZYAsM=8ifSQX%jyHK)(mE^9IP#_7Ph6vRZd6Kf0~<>h8cmk z!8Ojh>z0NDhTeu1RBIf0e`)_i?ZOKUB*ku*qQ>Mu-w@0cMQ=3(8b^9sCww%{|Eb<l z=6um$-bi+MKDli^-E+T9#|t~HtPyCQn|(h+i6v7GJ6`>#B9a&m+?YPFYl$;}A}_$s z??X_#-qF?P&Q(K0_`Vvm;!aoY7DU+89sL|aPLr@#b)U>=^bd4`9x~<mgsg@8Mhzr) zEBIZbybpKJGXm0mS(M7HSbQ1l)gn?d=^2@*Bo->_NQ$9lG?0w6ps+WY^4;IEVp<RP zNs%BSie?29{)}?psF9;L$YF}(E)4AQbO5&_HL>%p0?ZL*w!cFXhF7WRcyW*Vah|ZC z0d6E`l1v=WsuxIXQT+Z01l%+6-SGzc?udbQ=6IC0bIlK9#LH)Owf)#B+Erk;kiZej zBPzqC_umpyrAvA+DJ{ojks`rGs=<PHg&whjb6SBj6e2MqP`A8>!`T|t&Ly71_$zrc zt|VQ-t-;|7X$}2&1;$?hhvA?oQ-)8lh;SvxUj*^TcrgivaQUHV<ERty!j;Zw-5=QO zS^3;8dHedCgTO__^psQ}7oQ2T9k&awcDdL+?#7HhMf`qAVvLg>CPCRxqE-6@PyN1G zywZ>x7H0V!y8{rvs*qDYh$Px149V_;i6Nd{hSxQSKZz^{u_?r?a`T)mKz!ZD>K@x* zTnIwWMoBR8<k94sTrDDf2xp}5mdBw5Q3zIzP?U>9FaQc-C&Hfg9!&hn*A{kiJ39)P z1I`ad2N#$j_s0K~ctFM*ob>xy1*AlzO83MiD2WWB!!mjpA1G&h$+H~rsKPJAOSZr= z5RO6aV4&TMShfAUoO6%<t~Dlo*@TDL)K638`qu_Yczf#mtq=@u6P!VaxPgKuh=wce zWqm!aiyTL2Fc9TW)Tt~5_NI-6h}49q#9ZMGB@WRGrBPDYZ)$mt;JD#C*nb-ihIznB zh!W=umU^jML=0xi#r?9Nknkx$<G;^v81;zTz&^to@bePSSH`11a>3xCH^p*!GKk#X z-3(4sG}xZ$xx?}yh_$gMu|&tG^s0F)4~8$dc(7-6CFoH#r}zS~eG~A-HS~;6_2}R8 zSv1gKL0NN!Br*ysbZTw)D!^f@SiyTkgH)C|7g6?jD}20(7ly*PZFup>9UPHq$?*s} z84BRJkV+A1!`3+e-a=Q;JI|UxJaV4B@m~B$J1kt)aonAD{nSQGQMluc_gcX|xg%wq zcO1{~E6(!bEk9d@f@~-Sx4@3Ez;sGrs$RNsh+SnNanjGvCd_m)x8=zX=@b@qC#Nl9 z0=l9=GP_?#RRAWH=zVUmcxU?P>&F#Uraxb@WY3WY^JN_j1PT%X@d5!keshiK6G%Z# z!;ZWAqV#Cd@42;m{X0^q#hoz~(<UyZ=>p&vuC74Mi~RdUR}~Rco-#<IOzVnCl009& zTEt&?u@4N=ahA?Wt_WG2I74vSdiRdMkVC~n*st<0M0q^YSE&MPMcx0_4gX(pE!Fvc ztd+UV!l54YMVJb#0wKe9QH=(427>`NfsOu^)JNcL>XzOSI3eRa0YP^c>x!MWiv~3R zaYGUW+jEf7dBBFiKOy8`3S*;0fHN!7VLjL*uo3?py9S6GtV-XASo628Wl-x=@AZeW zSXj>u>54^_f=Z;Ky4Jt}?ke%<I0RoJfW?tP=dB$lO(8|jMg4UMI+@|ZiegwS%2b?z zFK2q+(!(M$s!Xj%PuOdB4S~PWi9a{&j^yXj4Dp~s<##ARx+&r#3y01CQh-B%P;{Kf z8MI>4_aip>xw0;V%y5mWI8ndjsWz)iNWM!(OBe6Rqo0yNQb%`=%@1tEI(HhmCbC5R zxFa5Hb3y>@50wZ6**7=)BGQA^j8=?qfFEbHvv#Pi)418wN#LxuZqdyGVkleN4w}y= z(1`LC4$_5>yw#p*K;x`sS8i|0jPq91J0y%>RV9A|OpGeaEbDJba@){V#AzA&v3b5E zm)A@eh7?@qCf@j3kSqw=Ha^u~T~&)fD7r$x2FhWS)v$MOW5p{1buMN)x~7@R`$~6* zbnL$rn<<H^dv#X>Cb+S`bFvPbQ1^@fdmam8?38LyL0to6D0a7vww1hi`V`uRKpl{! zYQGDWfjoNKt0I%a2!#mIKm~i_rfH<hnvJ^)&Gc~Gq-<6#dY=B{Ej)R5^wGbX*}ngs zYcOn4m(@+9q#K?ONrXr8qi;Gc_asg>oAoF*Q6PqNK6%_h4b}5qz(OcG>;dNm$tW@u z`|`G_sjTCd`px#u-q(Ff7g|ohDX>%Aa0&t2pnnN^iH?0SH`!zn16xD5wpa!t35oOK z!a0wvuFF4dT3KT(gFvtH@E#OxSE3*=qwmC<vV0^|{=}dvFa*2O)<E@EX&p}tKw&+P z51{TYVvhr`BMG;}2(VtHE@BosLFoJFlRFeiN<ijjRDLN=x79N_Z8ez^q9!61W^^?5 z=Jm!IBf~y)bLsvXV*cYIX4CeXCfXM!+UoAc4!h{4Iy*DOO}_FSMLxFY360=N#pRE% zQ!li!FreA5-@V*sm;R`C*0Wl{pIZNDG;%g2KXpRkR3VGBvp$$z#`+?(c0c-QnQ4q( z9gTOPz-AhY18uu(jgENzRjF+fsjW8N^|kv8voy=RK(ox*g%xGx$szoXy0A#-u|WN@ zX6#nPklqB>MMiGdj9+QhjAb1q=fi}<EiUPY=Ex(M-<|QnE}QJnL1IPJK$Mu5aDgU` z;Qu>P|M-cbZj8WZSdU$Kb4AWu%jlB`z!@ZS^%*r~>R4Z$kbX8V3V@4QW$*iFYimTQ zTb7@bxGnDLz9|Q+=6%toYx0y`(At8a<UkG*EHXMcQ$CKAAy(cIQ20y9yLSsHlmY|d z4!=^`;o2QZM)IL+cgpaX8!WAxx#9im*UYl03U7XXkAYEVDzZ!<xYb;qpuK@%RU^oh zkeD)l-p<-sa<L#=UMP$I7^}ld5|E<ZN>T;9^U9``e!f_#>kx5~nUQ2`cw$+3zQD3j z-VVn9@0e8nL_&Q4@sqZwkiuIy?6+=I+1eTF_H*~gF}2ibfUB4z3@r&v$<E?sF(2c~ zV199o<N`e2ssqI?)4LY)%M)Gw8^%onv2hR4Wn-U6>R1Y(rhO^9c<R|FJ51`-zVous zEUnIal4rDo0>>A=xw*1FyH>aN-icwi*s(cl52=O+p)?a_o%@-t>XWvnLim$V!b@xJ zO+~u?TQ}BL&~Q~cl8COXxecT;v)um6pZq7Ci{53;Uny^Zt0cu+ZM&#iCvN$gq~&*( z<wpvV<3kqTd2wMd=K)03$9HKH*c)JiujdA!E2>)ix<_bsy>q(y>fN4rv~2$#=C6 zK<><xHZ;)jl;OJTiekoS7BO6sWMq0vb^61?ecvJ8Y)Y!YZQ;%J;r52%l+Q+0VKu7r zq}l4AQ$@-P$cEtJgHq3d)yDLic*HTCraI7AHHoV)?ayX!R=f6G54jvT+ANs^%&88v zQ&^6SMRkG%R0@l(D2=)4jct;B@`Hc+{gzYb!ThwJe!u0Yw<+eRG~#z#NBnMi#P7C@ zIIXjtE*uCPjT@S)R5x!Lxu-W>P}xv_z?@Pq>9Txydx_wof<k1L%(sMB!ING#q=#Ar zRay()-7(t11xobk^A}~)ie#y$FqPnHAhD2B=v;`Wih1QDh@qUJ5%1K@#zNTw9(N8z z9+$(5`@z*KdsSZyURA<O)vtAPF2tsF4!cXH0wc(FQ_{A#%a*D_=@vfOIlz<xp;x1p z5NNN*%eYp+deguMF0U$KU#4w~^^ugZG|VG$I_Da*Wq0Qo9hTnC_YM_qEswFdWAKO2 zURGB6`HXPxy85o~X%%J1l>E+dPaFRVIih0~RgMUh8jg2PfjJ|f4sq3%u@VQ_WnIf* zW-&>-bF{j%)h{nmpw4~LVeh_1>yV5|j=V1i1&;EC4cSuprF=oP!ySQ=%WLG&6hT1s zX1P@-HE|`8QAE(Z+%SzO04-6B{&vC%J`kWzkP2c3B2l{klQ(|x7Y6qwbBBx=t$c>{ z(RPN>C@V1%7-QxfbgqfYj9#`WKbvQ0yDk~!-e?g0!rCFGW{ZS4U)Kq_KW!i#z9f|i zc*uJpwrokv9MXl&f%-kTNpKGG2{b7s;Cb9pI(>I-5?0LtArv5`A{xLIybXOh_#c!U znrw2%W^hE$+bsO<Ep^`=;7C?jvy8WqWsq$4=<f?#hdu8`jZ0GgPOsclB<!i+(2}@1 z#Z4T&hH^3MnU(&KYBOGKr1LNilrDMVr{Z@JpP#$6Kmf(~cYVraRtR`$KmjYiOeuKe zkYewt*GJ!9)eDrHo!tBBVo#&l_Tkc<@gScNHBik{c=7f^(OrB?4DXFXc*QAqQ-8oQ zDEJ9s9?_bcI$yVl4HdomOJM~Vl}Or4w{@~UGx-WKEsNmaymoQqjXR>r2#)evW2h)6 zi@;g@b>#mle<L21>Qs7(o0C0dBW$dxLi_0ZMD6fEau7C<uH-t6gYJ^C(z8RyBlY7E z<2~=uJVfD83Fk)w<8*PC+(F8nYYuy8qRKDYd>K=*5)UJ%+-WsD0Z3l4>oY3K?pn_C zBzvpmH~Lo=FR)ALMyXCgGUIQz>I9vy9;l?QHu>zHXF4-(g``wA(y|ux5tuCf{L)Hx zcm{vxQYI(fEofVMZyWgwop1f2YVriP@HzXL=2-JWTz<P__vL~8yl(Y+0*ws!24F*L zt1KO9hhyN>S2fZ}T?|G%SsL?Xnmc0f)w6hr&z-%enxrSsoxQU*|KQx&^>c-=noAlz zk)Ci*AN}m?$@Oz*Px|90Z3w`;?|PqFHI3;$f5Z0c(GX8^?=@j*OZ&gly#K10^+`9s zO9at9YF6JTf`9vY*=dTR_Fcf+YYf=+?PUePlt<ZiVQrw=NTW`G3Q%Aa93K`$0ur(E zJ}j66zYflnV1bG;&~edUP#88bDDw;Jn@bdjkz<ujoLKME@MGjUwxYsy0p(ElJ&5al zp#hsm!RiTXVO`r8Qwi%DqC*Gkc<m`Vs5&Clqh>*qF4578f+1L<=)=+%jX8Q&D#-M( z$oE7P3`PQGD+`GfKyl)go=0q@44L9%)Zu$l>u8Q;bitJvUp#+F96cd3ACZz+2PjhB z(;pIQ$ZQ1lF;CXXMv8>|E7$0$y&^uM5^EnJafKM+#F2v#Y6gr#0+nQT&0agBf@QDH zOwvbNQ8ymas6t96D6TyE`3goVT_9vS38gBq8kC@(g*<kg*~FH0&#u8fvFh11_;|uj zo95Xy@@pl`th2)=A*WIGEEI`R#NdPIP<R~0D0g>N@qZ=~slzghQ)#3@aVfCN!m_%+ zvcDv)HYvz8m9}fRF*Vw*A@((^J8{#b7T=wTip{8Vm~I|Uw|TmR5hL}d;@nMt>R$hr z<^QhXw#hd5U}8OP|LNHW>!yTsy|iCjLq=T^G4pEl7={$S8Hd^N9;Iod1doE>REx>2 zEKa7<Tl*gUw1}ct`T%A{Gr^7I??*(^OSWJAR=uQY62+9nNw5Hq9R7@nG3a>QMwGH3 zz|d<jsB1yP4puZXq(+eKI<F2OCq#T#6&1X;3gC8M-(22UQf1AJg-ly{GfqazaWoQX zQm%5a&IWlZn?6o;*rqDVPHz+e0<v8so3ib=dHS<kn!fEEUujuFGO4r!;IPooBPfG+ zs$DSLjbKPX@(Q3VJXFma+ZB@<IKqb!TF*#Uo9i>klUdTUcB(pQTUh&;2L$Nc!sYeo z%;6Q+_FO@tW!arulcd`|+SAg%QWNYVimMqAJ17{V>(PtTJpGY+!MBgSgF-Ro7anxJ zFfz)2*Ny(l0$n#Vynju+1Up^`vCgA8@RUG}3d>zw_`di0awN(~PqI;Jd&gFqrZ_0| zgWHPi*p5@r7e#C=hc3GI;&_>h>a0bMCv#@Ea^v;k>hAM{7dcufH=%>4sWytE;?vSr zvZ*`d@1~XR5^&cA#KPMf0l3YZySC3VD^Mv5BEFEK7n`QRZJWp;KOw5OyKN^gmfT#s zZY=y*7@?r1m7BVc7JWBW5-~;(`5CLp>>H|&w$IGf%W}RAg$2&!w7|H%ZC<pf?R6SP z5)uXaL_Qr~e)fjC@KP-|n&z4|bRdp_!c$7&iX*Ain2)6RVRh7NTh76>2m!fl-_6*a zn~d#>bgpcFi?EZ1+LsxJ#ZL<BuyK>7t?p5?64LD5h>7}tE^cvh>b6(i>YZbIyLI%@ z2mDYiv+VFMm0(q7He6r~%Vr<7D=nj-rZ}(9NL=%8q>{xcr!Fc;Ll;d3-&Nqdoat6) zdgm3}r~(FF2CR8GBO^<jU;C?tbP|+CNPt^JP$Kbivj>ndbqVy}Jy#m#k?YH6Ay|Vq zkpaLVY;fQtpOs-W%+fvHCPLRTon=0e&w_p%MLF+4di3qGQaCc_E>D&rWjaCgKIaR& zyssqHO~7TA$C=;A_L<B8&AxtzgM0QFH>oej^8HX%Kukc}GBnRD%N^^T5q9OJ|3<(v z;?Yau%0RCQnsz+?W1U}gv)O4n4*2fChNhTY_gLXC12>WlEu?>jbFZFydlmmsry@b| zcXD5dvUNxsPqDntlKS9<kmm6*<6iXGl<^b4AH>1;2A+GRfq>`iI-C(d!;Ac8I~(QA zQWQu$qm$pxl7eMS8E~^P9J(<C{I~2pC5BqoY5Uo|qqFnVS_x)QJB@I5tgGt|N8F8T z`=X3Apy_?3M=2kbC<-G<LaI`Q{pMRXYCT=J6s-E?n>3xRCo{R*vT}6jxJrM~0;D{w zJUD$5upr<#X#;-<$_;HYu<)%IYSc)80h}Yj4(A1G1|o*;@~dlULDJ(O+_aoKeSct^ zUp+>>XXWe2m9%z8LZ7nJbQtSm7;}^$lUpLStaxo^VR=Q>t1fdX^ku)-r|cnCJGo;* zn@6i~)s9xV81Q>#vK<j+ms6PETkw__?Sp|6L3SokoZ!KestEu;3~{Awe`F>=ocaro ze!9_LU+BGl@=NlDUrZz+3-52n&*QbVoQ`WrM_=%|IN!^~e5Y-`g1{E+seRw4YIA)l z&Q+!~)%kkGd|wLlRryByq@S8N6_@?gDW2P<Ufeeoaqn@T-!ajJZUxI?+94z%S`Fg6 z&z@giSGfeGyTg{-#=&LcRfxH?c?fK8;*|b>J&yO;i}%z?Nd~=Br(SOx?bN8zgfJ)c zr!L&Skd59u(aWUl`rZ$9&XQI<8OLm0@J#nmt;^k$h90$Aw8AzBr?oy425epG@vd=N z7y5i0chow;ga`62ptrdF$*qtf<RRH0pTGFPtJ?IYl?$-Byk=&{CM*pR4HS@qmWF)h z(&dR5wyTiPd$PK0u9yw0Y0$%3C`8-U?Cv3Vh9QZYZo}FmrY8MT*uNwJVC+@i94yG0 z(l+R11Cr;;V;!w=n|U-Z5hi&UXbeAY0LN2L7ls}{;yfsX1bZQ}%laHq&J*^R?HS*r zi$6>TDETc_@Ce-0O|`BH;C;$XN***tMORXv;I@q6pH3U~=uLcGpPZWbs)c1iPfqD~ z|BO%Zhq;ZDxBVMP>4w<KK&uLZ8X~BB*&L68YGT%BVQUgN|N0dxBA_rSukMfW?u^Nu zs=_Sym$>f3qFo-gQbaZhYv!j=Nzj!|6O!hf(y8s@sZ+hL_fCEFxQL$pbn2_G&h*|} z(kNe7#J`uOT<veDEFH{RLi>gc;3mj49M!~5JF3DT9npU0)m15mGUt&1)`m{o6rQ2d zdGV#~*Vg7%`g8YMo`34Nrt&^AKpaV?sDf%I;mIqUmaBLuv@rP42+3t4a3;_$4}SBY zHg0nsW|!W^MZ-A~BsC~T<gA$KpBJJup3A;4EyzuN@|-#=fCD*>7LlTQ?qP*4`FJ_r zG1fqDQ{@!#WLoclSr_c@0+)M-CQkJZ>Qhs9_)WX`sy<1SZS}gm4q|c2Iy~hrQc2DQ zHuQe9xzt-dX2k^-^ozu|z67@gmGbhCIZs=69yu2%WKsKD5pFVq>fytu4ugY-PtAPw za4Xpy?e}_yP|nQSQl}<6LWXxlncTKkfBt_kQwr4?Ia;)yCH>3cp*JPRG$@fSeEF!a z>Y(Xc%R3wrLJ0@s2gX<+2Navb;<sSItB#6pdRNbayyV}6a>fw2fXp0p&^S5rKw2m& z>l$rfXvB!5Ltc1K$q_0DYpJD$?up~N5N`$x_o>V6IG}<PD*P!i9dWx*@xp^9y_2P? zho_+qNcTEh&VHfwY-tGzOHCx}Gh(7MW*={&88oa`F&piPOVkt~_FR@MqOQnukc92X zi{}S(CM!~F`GH=?7!i28-}_k&OA(sF7#>k&zq$aetg{)bj?$Zdu-ab<V&q=NzGR=w zk!*ftX<^yzX-~KyOZ!BJvXDDZ3u*=pJ?gwCith11F_~6L765(L1nTAGrS+j3f*(66 zX9pu8UKp$oN|r#+^e7ES#CpKd?&JdynNg^3T#_0#JXl;?wXx1NjOEvnil)mtQ&Ox! zi&W&XKGzqjbAj0chYFK0lSxGejeKghQJ$g+^Y-T8?HunwX)DVj)WOBM8j)^KtVB;7 zNjq5HER7Xdm0P>>HS<aHOuaOd0fJa-OL6Yp!>n#1*CuGfG+zrQg?ttG-TbL#eQ$wn z`Ww0j#q)2Vixx>9cYjEJLTlM;JjJsKy~6GtV&OoLonYGR!eC`-wZCi_l8S1K8h%e2 zUR#bej|_Ra#5P=0*^H)h@2Uz?9&uWhg0C25zNAyTDkw|~istQ)kRX38QRm&Sf8|u~ z(#@;AY1u|pY10Ym&H1~yY=)Ub?~n`-E>EVRNfpEp`e8QU-Y-dXvjLT3i0?~MR_mZM z6K~W8y{DT1x1uZSridtFDJAst47B}kgh{MQxx@q2mY2z<b)vmd9tzTvr1gjl&lELd zJ@$52!|vZHB6whij{29RKAg~}M2h3qcLwYd9iDCw5tez>C`Q!4KP|-i=93yMb9H_3 zqU7PVxlJosc=OT~3k);HdQ`MWXE{A=1rAy{<rB%*NHwE_B!L`}nGiCt?Eyz1Z#rq2 zWMx;g?5ZaC5r2w^;RM33af1J|azqWKgjz|4)-k4|Ln2>JS8Bk%+#HTs79r9j1DX~& zPLS=hH<#zgbIhE#d!%}jxWHw*DVOQR>^4}Oh^nk9vQH@qb^;9}j2)fZ@a}Iiv9e+M zt;FIszW$!ji^NGpNYh=?t&}@?RYHWj%^O}GCsnfHwK3ym8{XU|VtRezcj5|Dx?jV? zq3q_5MGV*)#K8R{*l`t}8i)DpHH9td9uf5k<7pUdoXoC<*Z%)}u4rx;C!ebUf~_HU z4bP4ju-cNH(>UH^3%Ab}(xuz5f5YN!!{j4<?G5jA1jRHw{Rh!0Srw(Jh6^_?E6-d- zr#K<BfG0eL992Al9`*-i!d{6740`3tFh3d1%GAqK*AS*%))z-!+7KrW>`}oaD^fpD zTUAThL~c(cY}n5yR0$eJoDqbO)yln|Sieg&Wnn&X=e;*knY8H5v@v7S4RgF^!4W|m zrw;@Y6ZX*B9FhDzSKz9=r4qJ1g}-6wPoUE@jP@JSY8qz#)WrL7>rYvWnZ}2{n;x?E zF%1tLS8Br*ahK40ARJ{LwWYi?p>NJ@URIcvvI=C8(Sgpzh%K3Io%_6WQ?&qB>DF{x zp31q6ykWw`0h=;t++I(*I>D~VD{HHs2|Cu8`!r@A8e1Lj*-1I%Fd~n)M4*yGpfPE+ z0V<8ztK&_1T2oeYNqcf#hJdgvpR_jdOOr)n=}AS0d0OdslMbXsc$7`mh|9Djt8noi zieRBbC8IQ?D=0xhcn)ex4mY<14)t~@mT?B<W#iX8E%p^mkfn*^T{tOiCgChW(3G*m zBq(F=x+AWlo`M<Jt37lfG;TiBH;mUz+GyOV9on8?<Pk-`vpF0K&2iTHOhgA^jo?%o zOi8ubUd(2jd-NYs#bS)R`qckYsF|sBv`-macp=~jh&LgO8>M4MQY{$Nc~6Tkh3}Sp z6M2M)3%j|lR*PyBf>Pv<NPIG}F<=M4fTHkcGPp2dc*Q)=#KNBeax*skIQceuHcsF= z5X9>4Q-~UGCVjqsVcf{X{5T48FG&*={8F)E_jokz>Ws!ZYI8!A?oRxkp5^MXiXUl* z)lcxxglFjG;7?yE{=HuOdu`%+ydVFEGS8^%Edn27+JvL&X6W*4m{~wo5PSDyytS<E zx=C`0S@gAaRv`k<eJy5YH}6MQ33}LH8Y;^iojOdIhR}rKFJ@LWUb3JX($`887B^I% zSy_eh{AVVQ4i|p3dH45vJ$~2-Kisn)mge>G75%xcKi96KF?I5+TP7Jg#<*k>D^3Z5 z+y*eI9M;GuIWgq-Cez&MXp#k7qTpG5U=gHL=sEIP3$N{5?-{LkSr~y$o15lqP7+j= zuxDXl5f6@)EgvP~XjvO`s@YY<sdO#|a_>g)QRKp}3v`sFvPi2kYyvWL6(1A-aw+jk zU9+w6oD+Nx9W!w;ZsYs0@ObKklOeMwl-ovdo~X8`I!wyeGKtB3W69c0Iw}eP7JZf9 zg^`H!e@5~WY{@C=6R%xT7Q*+~sv#@v(Src$gf;9pn2<BmhY`E)2+@if7n&mwxDX(K zEdloEE@hv`|EBU$@bA^pJdr(@8Nz8ck^bZ>`?oBdjw|dvI4tY5P+p3QE#e>_toPy= zDge@JNoIs1oLuFC=(^~XQVmL-Oznisv)_rHlS0qJ1|5-RQiWd&!!t+x+|7a17uk~T zE-hlPG-a5=4InJ&m+Jqh{#U5eW!H4S3K9HJA~5Msl0hqD>=vqn)Qn-_F>wXYTn-s& zETDT7EIVN($vLylBC^I<#Fu4Qg-`@bIc$^r<tEm=9Wr)wS6|aKlh^ySjm2m@dZia) z@NT-q0ga%KxeQ-jgm*Pag-?1G6KGe~qawMWF6DcQ+vw#SHj^@<b!%o_Jdizw22rHX z5!X3-0>TmF$!HQR*yBz2`TBICPeYF&7~@d)SY;F>A-u?x<w%hzJ8qL$q#&Bn8yGVI zcUOVsmoA8zEx4zvDV*y0n?-|0B#RUb(eU;dp;d><ujx0n?UQ6O%na*?Ox56efnJVk z_!y~pqR-;#T7fH~gDk&loRO!pk)1DLrG@G?v-usjB#sbM4A94!;1DXek?##Hc1AzZ z+>43`T*5?PKYR4`-aU2p>dDE-*e@1fx!zw|t&p2PH%<)aoYf#eh1GieJjE0U;eyM0 zcv)HO_6zGK7z!ECSrDq>e3>TIb&-}OlVs*k&*^Ez^9_v;2Xl_+?(aLAb&zf9+ww(i zSYaazr%su_&WlyZfTADaI>5P+6fHMO45Vj)9|Zgywa?}@G}f|5d3AtikM1X1N6tf* z6Py!*y#45B>H$9JTUob`K_07_b;o%Bjm`{Gn9e6f_S8?qWu&{dg~Z=EY2tO96nW@X za4`DKn9kyI9Gjj0L-7|T{)K=N!p&&ZL<4un9Bx%w57?6;y4$i&lIQsS+sgP-@Rlg| zh6?Rlw7v2TtjS|K&*{xo<V<r*#*7m^rTY8|3$l+bEk$n>@!{qq>wxLG2n+UlS9^E= z%6KqNX3c}N2WVNf*$q0@fGslI4DONN3~po^|M{Y}m$WZO?Gb}M<)Sk&eI7eFFfv!R zI)e(Ab)0S5%!dl~2xXicRa_M3X4Guf8Y_sGhz+j0K0YC-lLS1X8;YA**XTiu2{|GN z`bBJ@lXF{59_$fPh7o60iCvBN`Oi!&m5xcyjWT}jDwcH6n_D^|CaXqp=&KcFOw2`k zrs6oP0N&7o3q_o$=$FWo-a&2cq)*d|IE@Hxk3-4SHA!!&!s75%lUX}Zhi(Bus^G$N z3DYN3p-U}(_!hfJVb6&BfBF1;e;t3j?w&DXL}_V1!MVMs;36jZen+*u*M4kL@3gLt zt6AkaeH~3zPhL2Gmuso1T<VvwX!1+@3{HhP+k98;GaQREC{RW@D)jD!B~b20kTtDg z^sL+o6eF%6nB@$zeb$$<S;_jrUNQ=Lr%eL9TiMwiomY9jrW2FFaFfbrrlY2|?rmT^ z6{lJ>6k%gIKz(CP6FrwrG-^Yy<w}q!Y49X~l3cp1+jK;|DM=-|IO@}AM^kiL^&2-= z)}Gon=XF@2an9Nzp2SIZT~dp{rAHr&yNuey>4F<TI3S%|AhaH&IS<NdM}p@s5uQZR zNS*#%UzOAl!P=Hhfz2lJ)IR=;<?#y=(KUxx4GY}6DAT6X@T=*2%q8C!vKfXwi(Kox zo^L5L75Ob#^ieVLu^oOcRe;ofrCfSI{!Sv*!P3l9M;rx4F9Eg91<soiH?C-NL(w=U zV|zyHBOW|=`J*DRNMhmo{M|0l9Ts2wNFx#K3_E5d-w5K4xxwPNyW_aVEzVdpaND^b zC`m=r6Qnb)i)G!-!hD{)A|grEhw0a5v`!OY+Quv2V`ANaY$nyGWttJ7H$>qxdAe)= z&~}2js1oQgdF&oVDW5Q}w7J)93`GFfU};6`HyNdE<&=BN29N99fx(5>yVm!P&YjB{ zO8UCd&lM904h2&@{LB!|XoC|X&@f~%<S00;L=H9bF%fi__kjr12-lE;$UAQYryKUP zrgH^#FbL-p$x5=c>TI-YhXaw*zNDQsli-kjxK7YGL~Hu$avp2qz=-}q&I-mmzYP?> zO;}uRdsLUNk}!Vuy7F34o}ib#=~Z<_PjU^-afdzMKq2Fh0BdO!3Ki_c)^XtT!n@u~ zX<n_}bIV&B9v!rBaz{?2=w_%t7e-x>8$xEeF3^v&%Dq0GkYmhcQeeKCI+5L_i2l#t z1m;<KLMIy`Q}~xg>s&H#8u3{hF}O&&Hoi9&`M?S6ttpbNNNEWVhFV<r2=C}kXm8U9 zJ8mklbD+k`T|?{>(uUd{P1})yX<=n7cK*~6ON&8+$yL*yvau49z;IEzmSlu*I*(@K zh7ip1DM@8sPjc7Xf5*iRhKnR+dn`{XZ{fF$yi8|+++I)8ap!HguV`TIqvnSDdIKSG zgNT2MJH#bKV4OUa(1gHZgFcr5Pv5#KkFg(G5wZqnCJsl;`=i@SGM%V!TW`&8Ak8r5 z*5>Xhd0j1Xf^y(V?W)70k|DIrQGU&arNSd;-|av8yP_6SAaqD-2xa<@MwB`++#KBP zOEKqGs~EamgBG?gI<w&^eo<_mIoyFCPkr!24izv4;Jei#2iK~;O%6KHVNr*|l}IQ8 zImU?^(4u^VsNdKY(dL~w5fzZQgCD1(M{b>&v8R{?R7=Pg9E(?V>>xmOG!TF$>#;YV zA&RSKs4!*XpI8ZG<5&8F_?%SY|6&9xgkshlxsLX(H}s|60XlF`1pwEC5>mKywx)VX z?1%_p2o!p~h}5AaFK1MArq{cuzQ6Po-mu=n%FL3rRGfLZxel9=!DqccP)Bz@E6_<k zCDWDLxWpk76uE}LHCSn*Z!BJd&(2a96|C<TK&T~z2QpcD-F}47X{Po#;w~Fec7@S{ z61g1=uEBVggyh`}R4B3YG@|UdC5rlZ+xAMljVne89|@dyrU715aWGBzxo-!rr=MXu z>8_dg6}9xrL@$l{><4Qqu%f0|M#H;C+FOj2lh-uPq>rO^(Vgrhzt(|9a*d&%Mr-3i z?Oe&Ep00K6D%<Pg0NdO&*Y)a~MWW`1rYLRNb%kyR?wtrkn;^4&V{L8uLcdcwK4_i+ z2#;ft^BRxTNhZbJkAA}C1(oo@bW7_P#P5^_OapyR1L;C;h}t_n2t#(t|36n{^mV(7 zSd^i!U!ORvV}UZdn0vUWLw|1KpNVOCe@<tOev8XiQzeqy|6XU_E7%VdHg~RMI&$Xe z<3nF_KETg@5N_Z+qZOXi8dG7i{@L}OtbU8DUq3vD8+&kAMe5JJE6d@4G;+XLm}ezC z%bGD5&dkiHFuk4{oIFQ~u~cz$jn-BK!Uo2AhAQ?T&u0sR+j~n3ZfSc>QeLgJoIuwQ z?iG<S&r*!;wc5xjjI0by4gvP)`ZV_iZA+iV@jrLos;;}KP$tu~_r@*!Euo@wH9x!L z3qtq`0vFS9G5wV8*p&WB<WYL|vYtwBl!L@_4#;)qNrawWF(yyjMlx>q&5H=!6w|Zv z**ZERRXI;H<<0c2E-QE3T7xMRRj7{I6T01+%Yu5hYY!F%#)4`<u4icF*8Y&MT@8&3 znb0MbJA(g}v}Ve3g*dGK=9~<l?dN?+m!V=G5on?~5QpELxA8*ZYdqAyZuA8Zm$8S7 zMcTJxkTaMhPD#+v8{JjZdlUb-z(Azn0{8S*&AKy@>ZHGOEgqw=Qc|hpgcVC6e)Ka% zkYvTrqwA=!JNi>|b~lG!^t^V6US}jZJM-dV5vd~l_S`5i0=YS{h1#gCti(t_ky-3v zBas@sDJ{)ox^Sa{O0z<AuFZ+sIk<u8NBTZbczoGM?|n-JRusCmHmjCS7@K~yuwm+Z zZJA$=)=HRF)4gn<$PpMX71LEORwGWGHOo^d8IVM0>^&Hj!3DST)bTF0LOO6u71VI! zC=h6V;SRO#18HuYHLsRgNj%OlY;Q_Ej_Qz=$gctHlo`WaS8FP|1{-TmZ~j6)2fiSo zu{F<DfTc>8G+)GdW#^(1RIedd#{)my4G7;uAaWW@C5Tu)K*-|;3bYodkZnsmS6-rS zkM$~tlSS8+ENDT*7mJJ4YeU7-8o*{-c92u|`c5h#Q>{S#QhCLx()3oBd0Li5*R$)u zhRtvYV5*zJ%N+AXC(cd{dS2ni^HXZjc&(VEMEf;#D73=Kz>?J|DBiN&i)%eq1aO<( z^1|I_;&FWB$nahlj?>uB=VK3+7Vk9=zE`v;7@%(mjm%{d7q}hMa}jD(+wtENR=P<O z{6tcK*e5eSrWn_>x%S}+*WA%>`7}4oxQ6G1qUmOoE}z~-clKQ)`Xr|E+mHT8nwIy> z7(V((CgI)}E1@UWQ0k}~x@Fcdo|~vl3m2IdcI0X!xa613#he&R9HI7k5l_ux?97Bk ziR`HmBgE_gPk6YKC+J;To69qb|3KTLa@z@Q5UV&POjh+9-c65gLEs+h6Tmr;7=B5Y z@s_>Co325*i2$sJ3S;;H-!VIsFJZ{EpnL+fdNS_h-Cpm6N}sQ+tgW6<E)dZg!xQsM zgRft@daK8OmsFAqnvG=$`AXc`^$F^wi%}`}UnZmQ>Lh#L_N~ja=hxTGAN@zR*7`m- zL;^QDcISKK@A}@_NabzA?iE4McL}nlDott6KgjmHac85n-SPKq9lf=0JO4;xhcyU1 zEI|N%33j!gYub7E3GZq9N#j)sqjL71W5H)>$CrG^#K+cm+kVQDVD-l4z+|x6#?TWT zg`okIGTX|gc(;9HP9tE*(d3eC=WA?7`fR^>Gi^xA8?{~hB<=zp%jNiW>;eHl6mxfI zL1dt6>5yjG)w1g8Y++aE7z?XjMoH0j?xHLxlG=4I)V51Wr|*?)?JVL4_Gtk1l74r! zU7eL8rTAR$dv1ar{-F20Vx}KRlb)>2u}@XR-_z!T;!Z|tuBGmnQV%#qjG4J4Cl==# zU&JyP3~*(#Mif3_AlQKO366ycQlO8jN~u_#bbk@6C}~uQ)jK2SZzDaITUIjNxspsY zt1jizm`edP8$vEe-Zp?tjabGIf5J+?x`=5lA{aU9OeLEvBFVw28=?HT!@CRIGnL^T zxUD;ile}D?L{@?3E$r4D_-DX!b1lSCc1(Rs^$UyA6FC;{(kmb6g+d63FHBC|lDVNT z6GRPh-zdGZb%cF24ZTH_eXDimt)l8{Bi7J?tY=3oqV-5iw|08u0$R@aKbA@Gj!cSf z%);+p&E-QhMUaFhxoj{LHo&wv=CWl3$?vW`<*umXHu^y0w^>IJi4l$eQtt(W=r_zv z$*NeJ-i~PWzKoMHiWC$SVM>`Spp{!8LtbmYFqX&?uzCN{&yLGjc`i4XEFaV73XSM} zqcCNfl`_ZUzc&IbaMy0YaA|Vj@Y}B&JU=k-lzCYrfbeLVIjI#w63s@z=&+e>X2tWH zuZs{S9^9^rF$7dbn%O$BydpfnKM&Z(8E{WFpe0tWKBx|Q+=y2mFg(t{`?7&u;g>sM zvr4s|I%2(5xD(tNSM>bI%c@*R%s`>z#()NH)PVJp1?%jY5wLyz(vSoZE*O`YfiaO{ z{r=79lTg1D(dbuNL3M8b{i;R{VTvf67##4LgfY2!v?XU%+-3rMP%iy8G6o3^;r{c~ z6+PkUcV1Q@d7gsV*OMN2cP1YHzk6|EPQLhH)OEpMF^md3?yV@wkO)?8vntCEEDAYz z6$=0T&<mxh*sanOD53ZeoyrBc%^pQit@ooo`=N?)C{huJz3j#VCD6&g%FuT<7klfQ zs&+qTHtqbf@3P1wD3(cXan;YN?xfOY(CZ|tRnhDH_?C8R|M#S2V%{P40<w)4j8jCw z3MV>ByA<5w{1-~|_pYukQFdZ!SO7=mDO7S-s-<9;6v~p2X2!LAtH&D_oqSPAV=(zT zF62mgA@3&lkfsiTa}_>!;#2`Tw-x=hA{+$g9U^Y#;B&tnEBe=sVqSkYVHW~L;65Sp zJ(+X9P+s8D+@t?oh9g->hYyB|^y({XL-?8cR#UMbJ@=%+zgYn7wE+-l$UYy}E5 zLK~n2zQ-I3Ub<LllCmD;_U$UXcNaEv+)u#m!+3m?ZWRv+%{e~2WyZY_ui=wZS+Ln0 zk5K?o0MsUPCSPXnimKDdcXZ5hR^9c`xn4XsfwDA67IF12T`7V`E8M=i|7|+c*@;{6 zy-#18y;XhYQxo5c-#_)O>bKjRp~WXY-N3168`TJ$_}0#@L+X5eZ-K47B~doXvTJnt z+a{yX;}5wf3@IYENtEpJ!l(hC`ulBL6cNkaU|iHtl^KS@rFK&b#6QH7zz*<#2HeW+ z-!P(iJsU1I^3jS|;J?t@jLtZaWgKji8N-FFhFB#qu|D^8eY&i7<8>;P;Rq~{v0--? z^lzApm3!n1tI4CkSw{{5J=uFfpMb`!p`2Xgq@Np8bx*>G-LM{>$yx7c28$Tb#AN?z zj(Efw4b8=ich@UNiAxM9JM4L7%WEj~daAF#Lq5TR+A+^b>{(mI!MG%*-OQ__!%>wf z3;wH{KNu*iNro6jGAW|ANI+tM__%0T%nIsa)m3i$)IV%RO2Fv=43ZV$HC~n{fx1fF z@!oQ10F(EFy~U+5xB{KA-4f%#4pEEcXiLzBicFLG;|4u6C3>Oo`_}$XigS<_u)+3X z7r%u#%Y8#<EW_@L29dB@*5?bhr0_jvy3CgoM?7If-Gfzp*7{h@pIp=2jL5iLoyz!u zE<Uv*N6+IHA(^uZsJo&`l6Vu@se<KxW^P>=*ibgJ7^$3k=Bg&tBqqRn3(M<fhHm&P z<}?XY>6xJTO~dZOGROP(k82FYzEG97HbQ#8-z%Q6IVDn3*P-@2ALQ@Yb8~gGB6-{h zj2@8*@S%NC^a%i*c=1+}X6My7a&>LEu{2j@Vh6?1@0dV=LHl9LSTAH_sm`;i$$J=d zE*qR_y>d`NXdd)4)Xq;Lj8Gx2d0#a9bjkwD9aBN-A+kwE1U$iU7{R0k)g?qPDGJM> z+LBA+X>mty$+EdghD45<(Yf0qJ2vJ1Z@Vo)ylw;BUl5S8d?j)b;j`o0=sv>U>M<Uu zc%hmMhA#%$vn2CZN22QuLK~1OyT>o<01FdvT#$NFM`Le?)rtdQ&{peI957#Gy3*A} z{!-cWe$4q&$+*MWg__`>L+I}mTz%Tm;8h_9YP6Msuusa7!EkXT6Ydo=<PmaT)9(;> zq?e>{lWXLS2q3;GV%eWy=iYh-BN*~aSet{_*IbW6l??Og|6Bh>z^ojV^KXF^9ScrZ z0cyChYGaC=C_0O{V++jMEMkS1Hz`ux`x+sR#Zv?gli#a?9p0KPL?|$hRhUv{6s_F6 zjOK31vqi_*RQU9%zg>VHAt-Dm2eX3>k*V!~cmhrv0OU6|7i#VbP>5O(3`R-$1nF>p zY40xzxc&^z?;>MEZ@9>oLOGZ(38Q|nRg%QfC$i*GT0vOL(I8kZ5CvB!erc%Y@A;0a z0vtPK<REY4<s$OEBm99XlrVA>Ox4z~pSl?6s|;vg1Y1{;<-hDg7E060L1P$1V2TCI z4OCVeBcIY5RQZFv2Bbe#G22v7g?*!Fvcfp1$acN#J^qFv=v~~n7+B<`JgiKvWIHGn zNwFVu_muvXNqAngAOt6wAlHa^$`qW6W-JbN-6Z7@rimOJ6ysz^+%a{rKb-5&Th31N zuzNKuE<^ASs6zD<&EGkd1p-2ax(4C(CS7;?lqtJr6l{Kfrxp=ig7M1lm@0JH_KESi zPyo?azMQRma_YMB^&b5L2|?|z@6hY!b;{;6uTtL<#F`h2(<T{#60EjQ$<iY;dHZy% zwiKcjr`<lKAdaG&bMvfYdY77CKCFp95Fbc7r(4&P8zH56y)Y#{Kew=Ah$*ACB1_CJ z);#h)G2SU54Rjph1cMYN#*IBQWgJohVmnyQ8JFP*;W}Pg0!0G?<Alu7vhb2s2}zvm z;CaP}+_!*ST{OaZvoyN)>CbdbU#D-)=eNH$b>UoTpElImDkq-7CF`WJr^t9p0HtKD z&($XU#eb?Yp1oiEqxKp9M9AmmA0VcI{SdB(LInKz+_iZp+7R@s`aVc5{;8Y8!&$o$ z<EkTK<{dqax=1@ZLNz%-PV#ob4&h47sE?=jo|mD(QvHw&5pnmFP3F;ZBFto><i>0n zEj{u|c5L-vQEF%3F;`!R@Oct`GwS~CSm1!)ur2i7Drj1^WKX6maI&(og^&8dsNg!4 zFBJQ04BT#BF*JbViW+GI-lS_z{VCT=nqQ|QMbpdA6fbwZ`;pEM3~>n-NiX2fJ38l( zv4JT88`8Yw#6S_6a0a|`){kJZWEQL><hVfsfQtsiEq=974iV^zLJ@`|DiaYwN6zvc z>1T5=aQ(bESn8l%vzhNb;d}Fbyb6SiIWGUgD9c!FHzBTfDy&yaS+O7#R<0FUvq3xo zl3mw2miIwiUVdF!-m<_uG**kQ=JFqwgtDXvu@448WGkL@98R8qgAI$+(iS&EsBtqU zT`Mguom?=lzyk=y$roP2J>x`0+EawsYuRGRITyI@$Vev7gdEUHMH?3OfkOFiUfSKq zSXz$SA-?5AEmI4KgRF)GanaKw7cFHsM7%UFxqQ&$LGv9WMx-&jXr2<vnwR-oBbTWl z)7819b=A>o=O8y81GxXVK*C_tcEl|M@zwh3WZ5DwO~_cv&S+oT&Bs_<ImW9Jx*Cu8 zi`CT;WWB1w;ObMlE~RoosM)?Q+TFo*xf4(fE@~v;nWVI*m}QX2MEjuA(aP!IEYpFe z;ZyA;EX<=W_~EjgT2PMWh3`!Z*T^n;b-?4b!ph@WonDN})8+$5iEK5V!1L!l-`rUL z2qt-U<oNH%VUI-Fz?tHV2WvCJPpm(fM>jNI<@e?B|CPiZ2p_ZpnmntYvObN50=Og+ z3-t;Fn|dw;A4U*_apJ;`d--;>R;iMCpT|O&aB)Z?#^!<*C~RKn%}VW_K=zW5Q(aV< z+lB2#&q`e2iL^jWrSNF#_z=y#r4=@T@|Hm4a;o!}wAz3>)m7&lx>$2u>9MrZ*j{pL zYy4*IxWOu1B^)MmQ&kI%hTqU>s!)t6oN-kz$5j!sv22ZwWjYvv_4AD@xiIlRYgRYq zp3sRiKRh~zoBQ;ta07Akd<sM6xW-eZHEs^>K&g8d9{ud$6F6p;ciC>jlE62tEH_9o z2p8ksn5k^B>hw(0(5;>F%^Ga+fqEar9FkjK+L3H&s)-@f_Li>5Y;9q{4iA&_gD1B* za-O%ixDOf^7YY;Q1TNf*CLGM4tKXG$gNwW;dKGR7gx_yjB|$e2^ykTdaymO_+BrQ2 zIEhzbF?E8w-3RZmJJJ2gtD{8_HjJ~Y7zfrOIJOHPhZ|U$GrRiYK9>zz=2z|GKe2T8 zX4ZGSmGyN&C*MfU*E}P$d8We>{i+PB4N!YCKt*oU4x=|pcA243b^MnM4~K*RU`J}3 z?uBf+p>neN^6RzF=4s=JlZ`QIWM1u~k{FvfQWx-Jha4J&P*>qj$71W;W31&Ctf76m z_!tAxZyWLX1l9$Wrs>pF4;BgwT4nn|l}0qW(Z0fiCEDMx#%C@K`af1%i&YD2+RD(E zw0R<WaEsz}8Jdfj>P85yuJ@0Refx7TDJ67ab#A#&#fA30k$+z&$_;y*AYv;vIkGOT zf#SB0PI;hYz(y(I60up^VibHndwz9wQ%jXSyF<l!LjX#i_9W*g^E)Sg-V7uu(&SE@ z<)F=C(Se@znAx#AK(trn=2vESSxgq#IOujCw1Z8&A%yhs9vF?wg$QE&geeK722&`7 z(y;DU0|fS+SB{Iv6N`nEQlFaXBLu)t5O`D#1)4H0{)O`twy-=%#WQ=jWcz9E5wD!m z0voyI#VN8$+rjYEnIgNxB~PR&SKjFcMYV-I65W9SU?7fulXEMvEBs|y7125uYj}Pr zfRYR1!GByTo@#)IBCQBJc2V=Zy_rf-1z1A(FWdgPu!PF+Ng6$2WYY}zcb$14n1yG7 z24?*7xIw9Lw3~_N^)cm1`f9i<&BZM_78n<MyU0)=4V7EeTey3dYAaSQtR%WY=M`!* z)4RA#D3hy?Ac4QB`e2HnwP5u@QS5<YG)lQsUk(dqcDq~8Y9*@}^x)CQ^47|(n8i_b z_*>z5sYB06ZJ(ewkJ-#obI(PU3Zq=uNh^7$5_j#mHSvcgd%&VCPf_p;9`=AW;S9_4 zAw}i|MHg}$Ozcpp5HK1lXJjNmv-nA_=nd#vzWkdG-G?SN=g=i0A^=vVk5I6yi1!hg z75GBjmlQv*#FnK@HDC7w=Dq;goxDP0XhfDTXZyvqsZE`1`{h0?P6V*HB(UR()vh#} zTJVI-@eXqBU8mQLWK?OI*0Vk(rM7)Nw=AB9qV&95ws_~M{=wrB4v^yMT(japw5L1T zjn&?W*XXx3`w|XK3+j^<nVk77{a<Y;if99Q&8%4J!in|1Ug=oxm(6t8?Xd}7nUf+N z5RlEdq5~I0yH83U$n|3GmXqC%mOqwBj_4HJNA8i}=*vCP@~D!V1_*+qBa_k7;bu5> z%h?j2I7;AZ^sICTET1E+xJX<_w{K}X!ZyWbY^*5)B-Y{w;)*Jt-;}40Ox}f$WR4aw zQVDsB16I7ovTnKuZyXzs+s%sOgSOQ*0*P-6E+8~A$Uy(H-f*KmY%oE~KcCi9>SGWO z<_J5XW>vNo?q=GBVpiI*_-4oAt{Lckc`oU}AUMddMAzJtCp*8<Q>pCP<1OvW;yI9B z766aUZL7i51_m^H=3ip^1$5fj5Nt%G#RbFFd2P@`*u#Y_h1h7mU+Jtkv2rjD7?<Rh z-X(%=WpDza?k=oa9ZR8;jJKl#bKV+r8JvWd7;;LYAQ=6gFXC|PB34F+$Q+S@1i2eI z6(|Q6ACqxAfkE2u-b-@Ab2H?{V8<g|oYTez5wyGLX6^<4Jx!3xpGX+!rj3#hx}L_% zn0>FI+i%EQatM08(6YE!=0;rRaAC_rUJ~z*SNEWx2JcM~WoA+JktW}eGLqy!Xy9Gr z@8wf@u`=Pn!YJCex?ij?uN)q!aHKZRT%Ib5>9>zkHGe~|HncwO40kJG%?p=TmnFh^ z|Ifna-9GN2ir(Bd>ht-iBQ)pV*M9SHa&!c$E}w_qm{1}vS^ek<cHx^E3Pi}wXjP9s zwkV}eratoc-;}cdmj!D}BoX{8dmY-Baxg3fv2T1=!$X?@Ug`uVTwV`csv2=CbXm)T zX*e@UJRQv<$OiB~U>E}e^;@-;)NiM-L{Wgk>1dWAa$BwAtSG+tjToZr3oybW@v<GS z?mdBhQ5Pv`f~X6wN^>auY?u>q;biA7M7xYID4TaAA^k*k9h;@~og(}(c{wh5+hql0 zba_C3zp!hx`DUD5Ib6zT4tFU>G2=I__27t0IZ^c800G?TS!j$g{?^Z*hQfU-Sk}DJ z`-M)+)k(n@m^@%iP%FPw@%;20m&&Eix^7>RL+q*UeVhvW5XLH2D7E=@?g=L-!WoPG zwWBaig}fcgMIqdKN_a|_h|AUm&V8|siFq3>Ao}9%_u41>q`g;~PveXkww*q>mJqf; zDMM()hk}3iRsv>ND8-$=#4p|dd3jQi1l7J(`Fr|3fVF*xZ;8Z)Q+Mm2YZ4(h#Km8y zR^2OlH3C;bO)0dc=ya0_=^X;dmy5uLd0`~slR@Vn>W(0TLNmeEBq?iU@wOaHD-gXb z9P`%yz0*id^UVc`1NGSQ$tw#}g*@91!Pg1~h5SegG>mFgM(|jv(ap$nR#*>H^69WM zI3pj6HAPUpRODt?`AYjXznr<0P)vi#km4NI?P$EFCg#9t-O0;3%A~p-dRtXlWJ+1Z z2?MGY@e;${^rg%1btr8+RpgzpDoX{3%is34>bR_T*oogXU9T?Eq)-(I9-6-oT^Ije z@hM!$_mr8j<>-GH&6nX~lNId^P91JR$ym|+sh|dVOU^b}T?-Nk-evMTFX%%|mdtP( zjBRwS^tK@Q$-o%!1QTo)5wB13w3nF(;3d_A_QuroGEw(Gw2&ZQ5QHu2GF;O)BqWKb z7m`Py;(7L**OnHd(d$4IYOcs$^0@mB>*TEnMK|rGb-RHj7oP%jAyE!tKT-Ca_Mi6m z?x_8-W6N2l7Rdv;CWZ<@DwB<+L>to93ue}_i~o8{yGW<To)H-#&j?wNzO)lJcXFEG zFnMMu9XwMyPyG(AG?jw^K6FW?Kz|s42;k(*O(K56;sn9J*9pN6@MVb8pPQqM3z<VQ z7m(2_>yF_|tVFKf7kM4>;t*8!#rttQ?5UcQ)qnAeiotwILt=GDz4Ss69mn&}MW~Q+ zh#dy4%2&`yEkGg3unZi04G=r7A0xCOY5B6IbdR75kXeq;fiY5QAzlsqFb_=*0}%pW z_O)>I{z)hsU%%Yxuzu2bScS;-IA`T~VBxf^-HBaoztq`j7WL)Z`O4Wm(Ma12x?IA! zGTxUuz(jg==xT;1;ie{v)js{Qt|v?&gmNeH`)iPs<8n`Fxs=s~bbdm4c&r|C&7wrz zx&q081-VwR8rQq;>MHr|n7sNK7i<OVr%p$zmo)fbNli2^r)OAN2gaw$Zo)D}^Q6+g z;fYf)49<CvnsE-W+|v<}5_O%N9!#%3hmRf%pj>`;0K!ocv0zX0>Y$O3#mPWe1q33W z&C|~rqpW;Exi7n+(N^P^`JQ++M8}IyT((ta#wEQIxP36-h9Y2Ty#ea=l~(IRSH~)^ zC)`WSZcdy6&vCw!@6wZhoqqu<I8Ajnhf`J|B_iAZdQCV+-DxlJW&M$m9lSwO^rgzY z?C7Yf!9@sxIK`unC0t_cDP1e?vZ)m4RXQdtY@F1$7S~>sd$rnNE|glKuvO*QNkv@Q zq~4BNsZV0_)yuj7{&K2|jd9i=|44G}u;?j@x+4p*v@umdr*nwJ1<^)IYV$&Tz4Zo7 z<nlHU4hj&`A4Q>vP5^6=|8bI*%`UHAQ-+XPs8O~TeFbxJ6T~uVK>%-G!I@TN4Bf+3 zFqidR{!GeilKYQbD{>rqK@aOqSG3hGm(Bh{j1Tr->Uu*cQg+X->uZAT?SKRAyJ4t2 z3$Q-a9vkYtrQv3*InqAd6X})FOqRcCn{IZZ-O%Q}7cDXys&Kg9;eM9xVZ2jEZfved zP+C*m01oZ4mntA_`)>Ega7eB)+BrNzXc;GX;oZTKwF@%*c73URygjwdqlGxqws$QN zs{Q3_75yg{o3<<@#c7Ycn`+nvvq?>kX<yV^nHU3kcLv~AoLnK{DsxmwdnL&*E@ZzJ zA{|+hK_Q<7$87uL`^9a84j4)`mfa7}GpLA9Qq|f=BUT_R{{vk(IdkLUK6_J2k1ibP ztL-BkkszD=NOc#2xf|k`Q#WIjOXjFD;+4A(+Nb+d!zNT*6eahbI&loLdHL!S*jLaI zWA@=$kNyd)G+DFD0w@eHk4kY5YOZ#nLzwa%xA;cd;{AfYIB|BPt~D%9{Gmt(>xyvr z8z#1L2|>27<f<&>92j(iQ(PCt2+@q|MmIwCB6Ose8(M5k|FqpTG;3HQTTtBQ@84Wf zoQzBbxsWJUsB~p8Z_$i4Mtl@_BP=3Pi6&zMHQ%%-ss-z0uOMo4lISV4xE*u3w&MV| z%BfNgknY8ku>?Ky^A92$x)x^)gQH52Hx~qe-?1l=kC)??zZ|wKuHI-RD(a4^=7!V} z3v%qr*FD_0jncWssb{jOBdmtjkJ2i<WP&<DH0`k48IdWc=-YkxjxZZc@nzu~zYvry zv)Spla5DMm&ljU(R&u;(U*G$sK=7m@c7zvcR?eObwEQ0X8P`MjPv69$Z>%eWq?ykp zgoc14!$XuxT>kCLJzZF6g9$xKX9kJ}(w~Vl&)>9aKW4me^4~tsJ~3rv05pP=NqdO+ zF?n;aM*LEzFY8K~3u%dNrgZy4xn>GCiyHyw@(wA~xjQ;>I;-n@LX%RKLMFmk;!i?w zXpb~lkcDPLV(`M5-qF(?c9|m*K0TfaGUR13+Ign8L>;pjMz7LPx_wynVYbbTEOfEI z0!8>vSs>r;Lv`H3KOEcO3(YEZJ)8KN{(oNt{#wZ$=49WW{7C1vJn^bMi31H2er`Zb z&nDshYO&^WF|?wI+Sk5zCG^L5|N1prt9`Vx{OZ@fHX8yx3fr43{I7M`_o>Xotu$!a zPhcK`I{dueE9gb7DeDz9GK65dax%=-J;T204C^C;sos~7E)1J^F_R>VwQsK?^681d zeDFX;|C4cR2@vrnpT8;1ZHRbnBx*j!7{^>>sk>Ii#xELrC>;$?#Bi*3D)QbFSp6;A zKYJwX#a!NT?O)l#+O_PWWoY|)JL~0IVnnSrZnK)zInW-3LT)HxNyQmLIr7FTxy?iW zK><@xxEf-IJ>StCnTu~XO$beG#ey`~9Juaw69klCk;1~_{+$A~BkZr<TA1rE&uxll zVRfJ);Sz>%e$FC4P5hK4MEU`R^S4%$;Ep(t3sBWO3TG85v<_QEfCvPL-&6Ft2hDhJ zi3=6=&ednMACE*w%E^@l>bk3*hXt!j(u_=ej2N?hCfB9Xl|%ySGDaY7zqN3;J9X@q zHUjd8$jxwo#N|Q;FvhLf*16<d`f^?jR{t<R9dC8Cadvfiw00Ic!DB^IfN~Btm*wVf zzawvnsFo`dqK+gyag8}lX%l8!$Txp5O<&Y3$|?-DFW`a};79AyxO+&-ieMmp!EjOO zHx?mq>ehnwqyPfxT(iT^#0#rg(Y~xNSHjuC5-L-dF*7dYrLYj`E}`2aH8R@gn<@oY zloLr%RdMg+&_1NHWNHuRHT??(IJ>Cr6NQ2k9~$m*9U%|7CKS1B+|CP{Y(soyPF~#6 zLTxBH(LTdCB`4Tmbxw>dBa2S#6+*c{fO=opLgQApkE}m)p<;z^_Cau2lbssyWomt# z&D)n2#%XD>W?WV#WN=ir9}{gQLOf%B?$6u~Z5G?#_3CK3Is>OotIfxIA&!R}?lD&F zBOefK15aujaZeg?G_K^GX4@B8>NGn#{O^Lubh0U>0K_s;fw(4ul6GZ=fOvwh-WDNo zr-3{Lj~ALuI;D%z=npo2w0h-du}1=NnOAja)bBUMp69o?s&5C&mAhCv^x?SmbF)e~ z8{U2Nu}qBJapjT5;fDz-a61;=i*f+6Eb&Q@ASf)%F;9K@XHp(RW2balxdqczP*>o& zllYtXTX4-(%`@ND;VoFKrZqKJW}O-$6RA?vvA3p9scn6TQ91g0hu(S5Y>6H?Q*t$% zkj9dl4fDBJ*PK9t$d+0UCHdl;-&WnPrNXzGTr_19eI~C_)b&T3edQ(1Ey&PDq{L{- zL-1_64g7>h3APL$N{iX~0d)!c^Zj)>%GwWmU*Q@mbAvR@vp&o~O<jd(?c?k%#vugd zFRgt@UYT{$N1>Nb`w-r47DLZf?Fp4JPoHVp;|n%yk%uYvD#^E_6zU-<&dF}dT`%cs z@nRhi8}nkzgl8jSkD+`WtPP&2QgP`0wV_99N#`<m1SA-mShI83C)_WW%L9H$aEMcX z;n7beanE6_t=y(jTJgu0O<y;Z2jMv3Bf?6HQm&OxTXZ3vW$??p6c8+HSib1#kz#<| z^PFGC_OWLacr%m5C@y)Sb0dq|UERvio1Rz9#;QdZ9aoU8M_q?lBe|o+Nd&FqIBv4H z%i5OuMs=7&4hd?Z07Ko;kS^GBzE*jYkBun7aHM9W?Hc!BHm<sY<T_RtJ=oeLpHGvl z-N9H`66V{l`jMLW-nErIX%@IWs$u)kQ_;a0aLPGW8GjS}KNkmAT1lx!S^FGkOWHs? zUUtu1RL>`lAY%&cv!-4WgjD0sI3Z5WErgLJMRTw3sBp}9UU`SL@|Lb;-cFpW=~9Sa zaM(&NtOh479K+2O6;U&5NPco_4avXJzWMbLs|<o0L@>E5;nTqmo|CDq?BU{Adq4t< z5_<U>486U2vw>-^*7v&pd`Cx$$<2ZQKCPl42W;Uizx0*1mvDD)@2DaGFc&IP((Xl; zHmk;9+?3P}V1l`h8bmU|j=37Yh@9hDW^w7PbNDF@|Gk0(A>|QhnRrqNZu~(UcX#i5 zMWCpM7XBcdetqRTG_-|1#g{)VyHWe|uNC`rVZMqJu+Ldr;IeA*YyaJkr-#)<FfQN= z0*Wjs8%tK3zeM+};C}n!s2~51phIEY<Z=DX)One`+TVJN()V>ZQd&JD8G?fg3?bv8 zgj_`-eA+b14CkFg+SfN`Rs8yz#wcrFe`(yZ_VqVO1i~uW6DV>`C0Y2>{rcQg5o|HP zu)evJhsU?WfwI@lwt>m1sCu`*PLJ>l!p$~zRWDIr-{OIy!7a+ySveHxwp;l3BKq!9 zJK3YJ(;`<5YL1?6UC>i+hDN=`pc(1N20v@2(Q_rfh@|T6Q{hlvI>-s~yaimtpP_FM zJ@iW`1`;Hnd6)-wA|m9_Z7`=|hUNR2%9<SB9zT^f9M*&d)lIrSc3^M8ii&m{qEUUO z5NvW;vzO}$jla?)dH(}i6bsy*jOZZeqibRr^Xl+oc0vnt&*gw3SW<ehYlXUjvLpUz zQ}r7ZZn1zTz|2)M#pt)!mZh|;t)}rqKULl;n_M*lil#+a)<<l|g@YBiH{(JtK9#dv zSEaGSVMlQ54q^AdZY)Tv$@3?g&%11a+8So2^Zv7r^Oo0KJ!>uS$^(Yx*A$>yI^uA? zBae5X$d(xMbbY+m!=3m=Jhpdr)q-~;_-~hWW!=OOW1@5=!$qkBE;zDMm^6+HH|Y5_ zEWhKQRTcDH{R@d!-Xe;TAQYKdH)GBZID*ScL^;;KBX6q$LV|Voc**x*7h!WSP*d@r zlYKo{SYDD7LP5l;mQ6l(9<~O%M@u7kSRt5d(^h1_WrqD|kE&B;Vr&vL15wKZ=gG$} z)t!mddiVLtHrkKzF{gR<$9<JOUR_LmM7J>KmRdd3Av1ofhx)tM%vf~SAQ!6XP}RV( z!(FUx>38Pd&Yb3n@y8PHSbs|90gO#~PF(vz+#I<wnBKR<oKBdjfPzXeNzxY<EN_?_ zlL8Xb>Q03c?~SXICGn0Dv6j|0?mhY#+VHIoLHV>9Ne7yaiHJoX8qW(+;ast{W$Xy0 z)Z1ZjAS&a5z1JhQc8Btc3evK;yY}G@3Q%iB&`0}#S-nOT0yB%30_f*btAIKdQAO{8 zpp9D1))741%!Zy&u7~boN_`)_un&2y-H>3r>CHb_?XQIX%qW5N>4_%6S^YqJ^O78G zljN09sm;5%w%VaHJh76l^(FtgjHl(=@l8}6!3*ex!*aG8+zG^=xf#$+y&*9IcXnaa z&=WUwk1k4Kn$^#BD-mPoJRowXNITDF=Te+V=6$B9jwv_R^{nueDCVYOHmL*PPkv(n zc$`gN>fAH|%GkD@>Dl&^>wTQfV<oKfvNohGm2Nemwf%~dJcTnZRa0*pHM<H6y-GdY z`f-h{HfsS#rInVd@YF}_E?_!o1xzhRqkXfVq>$@Y7gVjNT7Umw%oad8uf#0H>(o`; zv_9spvh^yC^6dHCYSj)Q(n~VKn8-<DgS$#&L<?tq5nHLST7TPXd;|&>s2ns5%!E^f z?;=kycf?HA3U+T%$F&GI=_~7^i*C<~9btlXJt?<R1RrduE<kqSuXJ6|uie(x%fd(3 z#Mj9jV9`lG`7M<@4IWgbz~goF)c^UlxlN0^A`JAtQm4A?Q3oczD_(^Yb<@Z)9UG7o zM9SkS@486;$c5f_<v8C=Rj}(Yew<>P^-&HLj_Y&|!76MHqPVQxR%nyF1*|%9<8<NQ z?`W6fRokpD=wqEDZxejIEL3rW`G;n02pJu2Y7eD^Lh?B@pHmBJ&PgE|4n@#y!vvJ3 zu^c(ESrCr|^F@BUsS~0Q4XiTcwC3f*^i%}RjZ15rO5#5;r%tsWlIS>)Or}KqRbrU> z3P4d6+vC)@)wlBlD;vQx7Rcs#FxGEgKd!GyQECTlJ!9E}1dzMT$P<^;T@S7f^fx3^ zl%w5UuUa(pq{&}0N^^q&Q|>7J+~wpaje+kar&E2-Qzq*NI^gn6er>6G6Q~8>CV;=3 zs%jO%X!XRd`g{~cDc5qsKvveMvF%o7%{()Q^Lg`dyah?GI?~K(QJ)^MtvWRJRPfBe z84quFJ`I7)?HDmeRj{4XxtG^+9d-QS$Epxk-)il(=T{U&L-Uh6Yab<Lxl(CtjB!lf z*zPvL4ye#W(KB%<k@dDtxx04LbFp%g4)XSUZ@0sH3nSOyKK?AobGbC%?r(U(`|ghE zZrEqR8zE{6UJT_(_v+azqFE<y6=|~VP}r?%w)C#9kMQ&rb>C@!@!!OnHg&Y*CWBUP zf*=ATB&5)#V=;@Vc>b!j{1Hl#Au_zb7-JurM!h5{<ch|ku>Fc?1%@qT6c?M)F+E4M zj{({EB75^6-ED{WTOzUbkz8HKZS-(BS1gGPg-cfFJeJRy;*e$Z8!W`I5HY;=wY;Cn zXHA5+JtnnEk}K+Kq?<=rV^L6N{@B9mU|~_|_XAjLQeN8^_!}+7Qa}Go4KYg?yK<K3 zk%77SvmB&16Jc?<1PiIIq(2k8>RC&2yLSk1*9r@ROY0_CXd!`aGz;0Si;7DsACHyL zp%@ym<gzsv3u`}~4+{J#L8NzxguUKDEw34WSiF-@qNWNlNl)kIj|8=u64Xjd%wQM# zFn2)kK)W3?!ei&vEQG3k-*usnyZRVqYU(KW=QWXJEU9nem5IrC7!V4#B)gx&MQr0M z0`mod98N~FXm>Tbc>QDjHqbZzTaG(E9_pDCv<R!K*RuO;>Xs;v&gb5m+DaUswDcaO z^jN=wp-9q?q@&0Rjn_{Rj;5=*Zq^|+{B65xkftW0iBjNJ6;_BmOjZkld3@ufI|brV z@Gc>wzvs#(MaNu%4mZlJLhBmOb4ENZ>Yfgnu@iEB_nLy;ApG*PIN?``w&hLqjLna{ zzMP82tg0h6X+H{ITOal&?}tKR>oTjzXC`7eZ%sFF%GhX~s@$oXd^~Q6xzAloG`E)* zjqA8IL51&4ghD<*h4O8VJNV85^{KNEK0!;tkKvac_L+i3PF(AUa%tXP2LG1FX(*q_ zkgDHXeDpJAiz_dr{X+gkr|qZSs?2L8+$1og-H+l4V%1b7LYE*@o;CGjGiQKrO`#T7 ztjrB$eYJmoX|Ycy19Q0HA(tzzN7X7+P?^><lLGr5&mHq`PrR#5aHRn%=v}goNLC0j z3cr~RzdhcD)kUbUNcd$dU}Aj@$KLV44%aVuIVg@DE(x*9O({bvIIV*`o*d~UCuqTX z;4nnWDyy97f`9EA(Uc@9_U<nY=<cdt*OrD$(6PBSh5D=0fCAsKJc;~?21G%u<5GoY zM<u=q*VIbJz05CbWl3@v_d1{30`^SXm0C1hbAFu?v7ftMKF#*4x!V{TBmzR9J_(V5 zY`eZR7_4=Or)MR4Bl`N}7;~Y^5A_-0Gzq<P8-DQar)dt{SX;RR0WJbfaD>{)&2^Y{ zwoneJ&ci=R@tda6;Mk<BV3wSRehTSj9E*V5e$(RjI{4^hj1#oCp50hmTPBfsV`*dA zy3&mvVyiWH>KkDZ;DI7#;?f%`LeyV;vx8!vs9oO7>lUZ^VoqCoCweKeIB~>w6y77> z9ZqH9gZnNa#gU&O0k}U{>{7F;&68Z3XddsyINo>~(pGbY>(FhkwX$Qh$zfG=+0$s- z7;3dHFv3EpshC8!V1;ulao(x`r1yARG4}}a*KW%UZ@J;(vYzx&;+@8Bk;c|m+t2j9 z4xD-ti~M}UB8j^hwXP?S#8*G!-z|C!!Y!e}kkZTg*~2pMx)dbEEc(~<4Up%loNLwv zIS<BsJ)X?*S*4jkXelKs!T<ikP;p9DZx8=;6yzwi@_PH(?6c*#%$TvrIL+j@V|nNH zK@P-0YWzJ8v{M5`e%(IQYZdVzMB-PCAgh^Odip(Dc0D}d6`Pyw9t7IQRDt@b{crJp zm8BCj<)Es;1QD%&X{>>tHsrK(CC`OfzzC_i7D$(V<|KnU=;C|LPpT&nm3{POvwQIg zW4EPQc&Xq#onpSA57qUDHAQlo0q#E(;MAw^z6xBcux8PvP&hR#YLK~}Am_g1>XN1~ z)4RRo1+qmJ1_f1qcw7(FUR@ZN2D&hq-&`1~a&vZ6_f=io^o}q>$x_vIT>nIZ4%aIW z@GW1U0P5T3{tA{H{&jblCzRz5H5{jPttz;`sz<+S(b4`!s@v?+Q<#mT_fJA1gQG*z zWrRTSf~?wMtRA!DK*mL@*X6#yq;@)sX!BC|@gpdLP+#CeTUk>v7#h+ShhrWmtDrr8 zP3HPt*e^S5L2U%!o_w~|K=7UKLsWXb?{<cPPkf@Z)B3s|FYUBG&X&_on}+zFUF@6` zq$HKe@2Qrk4(8F%I?_`J5ooea56y5AY|wB9kdgqGXt9ncQ<yN^5*~>w%F(!1=_4{V zOquf(ov%f<i1QtI^poBc>5Xd^jhqX5?G$}?v}R!1SL|XOZnuU@qfK?i9KI$9q~0#H zdi5;xbj6@=#x>*cN&(EgvewP3eU&#Wd?$2dN`+~HO$IuFt30>oVP<X1zBrX73(~1c znK9h#jX|I0i=IDP3bk)v<Tu;Rsye-2#d9QE#q#^KEI3Qo@{XqEHH57y7+UgQYKK(6 z3g;?-L%OkZC`ex{;x%F&$MSVlQfS8$&kvSw$>>bSar6;-q7!A1#5OofIeD^3$`nDK zPeXQSh-bvT;6m+u0?vjen&Xt=TSRV8L8Y3ne72>OxOVi}Ro+V+>zPMCEi8cT@767$ zxwu-3LeKb`pcCwiGQt&YMmr5QEo8_Xj`>*xw<BUUbvl#DL`r8d=di4<$PKx$yt2{Z zhdk3p1;?BI#NDOkg^dU6y5arh<+UF#%=dnLPe(MAg;J67eVv!*SjwQ}=73MI);}71 ztss<_0*t`=HI)s#J__`YRXVUvcSdDIKC7td>oWU(NB!E@e*6?En-B;Tu_=)z?lV4? zNX6rA*fn)=ZT0TbqTB>fXRbuUSjUUXg7`r^u^PfRYV7@SZ1L<W`)ruyhA2f?DTdXy zn}II{)r;gRVr+S5pie@bW6!!t>E2Tz8z5f;ltdDxOr74w)tvwhtGZD5a27Ss=rz5k zRRC#P>Uyw%Y-<tPF>9i6C91wJYcP(;e%nD@DJ|xzw*Od(9rXn@CQ9V1Y{86gZfQX- zcD3Yl#6>+;_C~|W5d)Uzha|f$UYCxPj<}Li0!PCPj~U|GFw&b+$(MAu7PVqJ^SbjI z&z5U&O|fd_n9XB(q?e3AsuJk_Lm8--`irY;YDzX&`2QLf@J~c81{tXU+5M8cR0V_1 zm*a_OTs8mRHE-m1t|M}omwZQf_^`MXI61i#kql*Vo=XxDcnh*po|$VNYAhk!<*R@} z-Yvvao-#LTJif)Zaqv<8DT9YJ&N-7wi#SZ_@E)&bQvMI6X|Bee2r6%a=1EH1+%ny` zEr1~#4AcMSV$0pwW07ggCLppfZ7nYC8C%-V27N23*Ki(xkVS|jDF4Qska3|;(Cyf; z%Rj8_(yhKX1gb@yCf(v52pet*ctl8%kL;2@pFUBiYuxX<<9Z$Cc3ofF=-pUaytlFZ zpws)<u<<{xY~1ZTxdXPBN+3uWgOZ^X0|381zb*hgNw;gm#($lD!iMSgNdBqt<apEv z)!>0zWRe7?OcWS{0pBaCc;&VbuBV@$lf0^w)F6M2M&G!~-%kA$6se%f`ck~|qR9P0 zf927~mWeBBGzQC_s)NLq17*doP_2`8@V3HG6i}u(ld-|{Z-@t{0b&02yKfp6b+hmj zqS(A=ED%!YF(;VYy)}-@!O8TE5_DN~V?$<r<OmGtPCJtBI6Z5Yw8GOUKB@2$>T55{ z)J;GMI`{Pa!hO>r8&>v2O==C}Z_%FCFao7(2!Gg0;hjCQ_coN?nUt1wlM3l`8>V6% zh(luo%1J^pk3P##Zn`ckq}5UWCmj-2&ycx<Z=<a!qx(I0I(R_p6(;%CErqCRK^m(@ z^Y9c36UdX~Ek2#qXDBaWmcVC&71E9T%i1q0(Tu_a$w1?2;!}ge0VyuHEu3Y2Ba*b` znaQ5IG?G}QYz0Lv#YkSS)Bpl1B*sH4RA_F)I-FT30zN>B6@)}A4+~V+vTrGmTP%4f ze}Nih;_0zU*6vrSg8a`^$zfd!^zdh7?ypZA*3uDN{T3ZoMHtGXj9XmLWO2RWwPbj6 zpr6kP1kSTvB+dg-0eV^B=I!-~a}iA6KD#dXD5UA@hv^)%FgQ$+ly?(w^4?9Bk|Ob* z>L#k~aPr(maSQK&g>L7CanGJyKZmedg~#9fjlttvqCo81Jxss@w1=)$VS^$78YA`a z#Hv9zhtJX{g3omYjl%k^*^apZ1+cpc2c#N?qLh`prJ7X>!xor5^|9qeaEhQlmjt~Z zUhjke5tg`6wUn}OF@on%Ux+XAFfpnza9!9NdEd!XmR}w$3Es*mU3x;NfSkV_RIMNC zGf!g6m9q|4hvdpCH#wyX{ifEENP~ZJ%2rtSOQ%a72$IV{X)SOZk|vsW=g<QqT!BRG zOshw#;_TT&d8Lm-cK+M*MSDVX<67+OhSFaO3nlFUbYE!D8{=q;P<j!Zl}A5UV<%ba zsp04<WIr;<Q!{TKheYY$QxK?J2(#+_ecjo`{($;K8on3>*GOpJDkqln-M*SNqM*vh zson$y2i_ue8$YGEN(XjVl8Jkf7L`+pdrd@ysDf}{T!|{jDMuHqNpFXvcqc^;I2=2O z4Knaquqxm@;8K*4009T){;Iy=`6Os>C~Una&J;LMA~z{x)Onwm59v1TRcBQjpa_`% zK)J$^8+jXXogmFGRsLNy17c>1ezucE#0rwt(bp$cdTPlyq55yq-dXM^Ys;zTV)`LG z_)2fm9OhniR~%0L5fn07pl%u86i`|SZeF#la>!5pXEFLCK)2#?736?Ts7wZAfzR9e zcT=Q{yhhF<$OX4WjQU2<$#6y}C7=*O#B*F!Y)5`JPV5*R!jay)Yy{1$H}+nY9pvs8 zcZxt(JtEoV5htoJ3^J+aH8YOO8JowIvlaOa3*APa29+(X!X+4FFIW`BoISGp5B1rv zv~S1P<RlGaly{B#m%|BSpBSA(WU@8Z#qGHpnu}mm$NMBX{i|z1K2PCAu|%3NF>f$t zwk+yB3r~hZueoL6-f(7;ifYkyp1$Y>PnBm;6j3aS%E&5nd(6Btt`_OAX0a{IqW+B! z<$zx%FvA0}3#7#D8zzPbO4lYj8wxlq+MtzIIWq~0$H*oYzofYCL9+z+-$f)Y^BeeR z;6&l_JGU+KA3xZ<DGP4~5ggP-1Ww16$kWy0Sn50}L~n(Q(eA%!k_vQDB2ih?F&A6{ ziP*$h1tx9?)boL5cv%9<YX&lqaWJDaWfCGiq{5nJCY#9k-okL3IJih`T-h_G|IqWS z>D_v#*wpHW5MAJ!iXS{*jO9IfmPGHG#;i*>-X5X|)0sFN*Y-j&o~LXPt@De2)HLE7 zx_rntOGe@z>R%^uE{l{e^H2szCtayA=;v=g7;ZfJSn>eMNVsG{$7`DLhlMZBeOAGk zo$w90(0y8$^)F5xDhD~4bv6a-gRns|`Nr!u+_j&ZTLygX+hR0D%YdO5u^6n)Z!XdD zC?*BbBYM$Yf7o}lhesc)2XxaOCJSXZXMUd%QaO`(S*r0YG2a)K*XBN)RX)<PGE^=r zNo#Fjy7I2#b;7FiA+~FX6XOoD#S*V07d1vn){$czHV+u=!q01}U>eBng|HDZ^rfjQ zo0wDr8B|w;Wsy9Ko)|gNh%&Gv-yf$U?8reVWCuHEuV7~KXzZB!mXJ$YD#$Z(oI^FJ zITmC1$Vc5bbz64!zUB3zm2CxJ`?S(2jh4ri<YSjB#g1I^*fsn{jx=65zmdZbVRqYe zOAoXTW}HYpBHryy#jX~5Q*&#}px_qHX-PAI-|aK(Da{ZILyg=64SC$9gNO$mj?Tfj z`p>3HQRCf|PgbXC<eJB=mNasptrqneIUuPt;}qi=InbLr7K{t{TJP$BkbJ%SM3oI8 z%B&YhmtU?|E^V$aQ`FBg6AH#+3^VkO7z_X2kmsvh$ED5*>sE;*Fu#&}#ie_Pg~;%e z6>%8}kC__#txuZemqgSp6|c#r4~1SvPCQ1<7ps%fSVrbaj9#m3@^~{nq53~)wm9>% z0s<p9Su0Ru0L$vpj2z*RavZ3ti3d99gg+Krak86O;BGnf1E*3Ip0)9))$bN|lNw@= ztapGQSj9s$_1u&?6LIlGsop`fOPEF$??tKH!AQXTLoFSeO$|z%4dM{lqJuW&6g?GT zLvp`tZ=tDCQ6Q<~sJ|XDkqkASLmw=q<;(|>9FeEc3W?ts{rmbuK`?%PO@F?jKZo__ ztp1$SpT8P`f~G~Ba@aTNu0_2!uOXn~?@P<%<f;y}*A_tHFOtM0kjVWyCuM*vg`#!x zP_KNycT#`9*84{9aPMsIT<@=rMeJ^LguIPMkFm=T`Dj+LxXD+qyIk-3cA&qtV9}$m zo0o6ossCB)GEa=jHcHF<HHBurH}<Bt9HTiBLSrWRjvVK>xSzLT$c>_xbZgu~QL?JX z<K8b95fxw>doqli^Ko;GM-F_j#zQlcOkDi){||d_7hBhrrHRqDeke-T4@JqcN+ln& zC5v{6lr6hl)oPX6lqlJ%qGVc>f6C=*&n0<DUYor4`u^z0JsmVK$U_B_4v@@4(8xn0 z7|fJAz@Q$2APDjhv?h578hM<jMjB`o0_0^L@=(Y_0m=8Rb@tCWXYX^)B~{&>jLRsI zy!V{7*WP>W^}p6mkq47cWp%BiGfEM0C8nRk*Xg>)7&nsH0urzBobq?W`uIClZ?Z$* zGpO28syf?wUR`2l*_u_77-P^=dJ#Tj_(HyBsDP{q-k&W*`uKPs-5omJRz21Im5hl+ z?A4{9{!&}1U@<xk_lbX%m-LcQd#lzKT#vGa1c4^{d&3%~*Z$1naw+4|_RFg6GL5cF z^5)pA4@ENr@*>o)w!Gl`BqK5t9t<hAtfH%Drm+U<i~bVfu+-GG)WSd)^^0{-5O<5_ z)_we&ZLUpMk$1JCmqBT0jx0k>Dn6+WQH93(TgE$>6wA+DkdMwjn)9kVsH2WpkkYlB zk2P8*+;|(G7W0n%njGhX4ehxJfEE|tX)FIJ7G4VfSg)CeJ$elNBUNR)i`rjyUXVjU z$F%2D(Gnhrx*>(Lxuy;$2Q4`n+LcJ1Bo*LEz(BmW-=t?+9NgC3`o$2H_vz5;5UbkW zG1`Un`IzP)SZGVoh07)@p^aVuSP62ZTEI$Z=SE7YIr6hbq|Gq6C0DaZtzhL4Qy79w z>(^LSk|zUEF103Cc~}YUl+B|0Jj)5}E*+NKr^fJeuwqoM)M9(@fz47z{~EY`4c)cs znDF?O7pcAK7l&o;R-lJJE%lMY*uQ@S4?UC$6W8D4DI<GsBr)ODqJc4((_U*;ro@dI za}AEm7Ni9+m4x*-LITW)Vti5MtZDt_%oct_GQNU{s7l07p~z`4fF$v=vDYCde}C-f z_WPfJoK)-Jl`e$DP=vYTiElLU#@F5(bf%g7cz!>N@5t#t#K=?`HAe0~@j0Gw5lz1n z^3M=G1uph*{4)j*eS3$&!5))jVEVu&g26M9%u0A~brTt?G>Lxp`t0xj+<b~&N5lRq z{oTpW8na)gpM#Wo2oL^j_UF8LX4poOL?2yrn#s>T|GAcrg3Y5-a`LmepG&~%`44WP znCxz2Tfz$xTsVs<s4O=EGZTchQ#ipwZZASAw;hO;zW;;waXn|6*Ea)jy6$S+>OSy3 zNgiGgv;}-p+q5ZYY9`XezX+Mes4}tyt~%~+0IE*L!hV6GEDt#iz-7>m-vO9;>?Gg^ zmdTEHoDLQ@p1pA-17x49_j&u$bLZbU&vTb~NV7A}dvm5<-3Qe&FOey7TxHOu1#=i+ zI9<@rAiWAX194o2?T$UNZ|ph$M)y%+<db-gXUfbo^<V0>k-@KkimMo#I-lN9!V9Re zo8dK>Ob1ys(-`Y<fWXHV+oJ@GwqB@(MxsZ0S!8C0jFS=bTcWCN`vB9AFq+dV4g#R` z94~{F-m~k&N<YfX`T$_b4ZB6UJ(FUUrP=g462fI`PNH3WfU?_d@G*>m&|tgdj7+7V z?x&niLTenuZK|@sH0EX(_j$k`@RpLsFti$G4%rfCP#-mHe-6P1yg9tUahi_?a<8RV z1YMv)Gm{KJe<qnPyb+FI1e>N2n#=20qb~kWKE<H0wx-e&MV`6`_{O9moX2T%3EwZC z@1AG>6Dng!Nt!wTKpLK$-xl9bjuhv?tawNzZN{$i{&}>WMCC+bz9%8Pm+*g<tAt)W zn7)`SE#4@+Y_w+^z4C5{7&p<S!dr8gEVH|Px|;#TF(qtM1TM2bEKEBGdyfeOLWEbJ z189=8cf9eJ$^{FMyIJc&JF>le342`53eII_Wh7h<0SnjO_QLC}Iz4zSHAf?}rLS2P znD%(eeJhsAUOz>@dk5EM6*l4Z45AqcSpoYyW@9rVC$b^eGbw0}z_X_)J<ymOH!rqY z7lH$;KHxVtD9rV3=}KW7&g=os6R25))X*5lq!k|<*lrVM-0y5}Q;#nU@=jiGS%B&y z$j-QIxHH~7Wp<^LJDb_a_$2J<VKSraR$&SYqF<{vN?%$ZT*xFcZ;iZa_Rwg73QTom zw9%R@jC)2p&6rq<>RPI?LHD+Y<>Wj-Ao9^*3O$-|;#W$g0<@#4p=f+&LknU5e7D(q z@~?-5SD5aYUcqJ`er~?ET6pjsEVfb!{VYaP(N8qxhyqT7Cra#@s}H@V6R*w>SGh1? zC$5y=>Mebn-KTzx3_}Q+K~4|aH*fo)WZrs5{L*wXWs@*D5uX#&#l@~uRGeva@L!pb zU70f&p|g#=>(%rcl?H+>!|fGZ-PxA9+RV8BGMAss_>OTkWzR%5*?1?Z#YTL_v-s$l z$h)xo9#?-fk8q{EcpT=D*O@*^aHD2*g0P<y3_aBMib|4JW_8|5JrRr!Fsn_SbTmZi zpU_Wf@UjwtEycI6dM>l?7&EtUARe{0^xjU%@Z0qOE>pTNfZVCP>jB=hv{V@2&BB@6 z$r8O4AK<OR0Id1W-TP)=-+P^6x$Z0b*-CZL>h6Pv5q<L~vaRfZOUE`2m>q25MuWM1 zFwl!5&LC`C>oP|R?Zgf7x~3AuzppW~f0L4xO9{-|>6pUoSnhXjXt!fncc!~Ae(g#{ zMPW^T2t86>mjh0=VQSj4x9V^xig_CnvlxH3IGlCgYp;(C<|`fpHcbe~sc30z!m&f8 z#sp9tvo>ilM389s`NWri8r?10KMQDD)LsK>Jv8g;U4rP5@*~FT&?JjCMITLs5x7HZ zci6v0L+r<pE}8((HKyWkureZw={mY7rPz4l<Bb45bkbmNym*k;?5W6l-pgpoPXnnp zYat~vFSVxoA+(&5tKpU%u9n@qi#5>-E6QwHt^IRS!EWJB$c<~#A+2y2&cYeMX5{LA zVvIcuW75G$Zm^oE{kQ<@lmzMSgH~fu4tr3L)LVe?iZ~M)hB9{^kly0(j(hOfAG?jD z{sK^K0OsOaJUHP=p7g+JSV%hI7a$%@gE7`pvrD~CAV`{Oh6OOKoQIg{ChA%!D8Rn8 z=N>DwGp2N~gvOr6QbXpv=It3*AYHsp2Rn$ZWN0dAC@_6eEp8_Mg#jG#00b@X)3`mB zFEdch{Br6CEaQQ8Wfu)pvE6M!=Vn3p6{-KqEZ*5T3@oXGgPR3?I7t!Gw8x35!{k+A zpOe0DBdqZjsNo{?c(P-%a%OEAD@_yc`LD6)eDE&<JQ_qmixaOl`5{{&;KRZICo>F? zqN~ShPk;U3_?C!2d!ZHHXUa~V_{it!c~P^HOqJ$Ln?!iA@Hk(NykL<4F%Dt1R1)J| z4wEiDFFtXl51=Kj9YA723w?45^C-GYG~{58l#_y|`~qdq6H;7T-akXCge768vS$Iu zzA*YHI1X6_f!2Y%iRCelcdIPmGt)_o>XX_sl<xQ8!n%Y1X2*W4|JiXbb6nWaR+rGQ zv8U9~8{5FOEo-xP?#w>M{|Z>%+aZ>0mQ0>Ysn6{;{$R||;x}6tKPdZw?Rz>4m@b-K zL@cO9u=WCS>9~YzYlQ{m#eBXQ!}F`hL?a4}mO){&W1d(*AzH8173M`POG+mTU~km} zi<PfuQB4PjEjO{A4i3)fs>Y#cg*_b{oLyFpL(x!sIygAftr~}-EvNThNs^2urM(L+ zqy`j7hiTdr+l=p$^{;{U7xCL;99d-J*w<fJXyICyzFb}9U*1yy_%Ffp9>D~<4ARzq zp9~w{!e6F(jJ^*JYB{U?t%*JiHEZCxC*fZrMM>fk(|jJN9(2kVrnS+~a=E(vdrdIO z-ghOry>?nx7apx&W~)(zfN^1Gr*|c})A$mp9?bU`Z1O%CB(uTQ-a<*KUYwlF;W9({ zyfAl@`JzXfGvWbvlH<SvN`kf;t6FN5QA2J)E;1Z&A1^R(is+k(ar#-~iJzE4P%c+- zsF&<e#6C69%0fP`<osV%15CLAXaYt&->+q$nn*x7>bw;=H7?5|0ykyjRh%$=rBk^o zlMZw=CUDK}!R~h8Y-X&~0pV=X0`cU7CgqEC+=m`>WgmtqL4$xk4cPOR>i6H=!Ud>- zI2g6FSWt?hTkC1G<%J{bV>jDdP3oHQkW{{JHwm0%Zd5<F)O47bL*OMW;L|On9_q>R z&(vizI5xDf$ob?3JqLxQf6X4XtQVMARZcn{NzfuUo?^q&sQggEbNW4GsqjB%VjRDj zUW$RGWStF~;uNinx4=79m*Sx}RcC#1I<ek}`k+}&`gyY)=*&%K=+Y`cmmvw|OIQUy z9n@kM)`i`>Xv``v<!B}WlD|9qhN~nRKE5}5r_9SelT~cK=kQ>rFg(P(|1Dz^p|i*; z8ruYTrCxePbyC9>L`!)=dJ(uK^hpi_7-;Cs+of66RhZ;71QwkujPa<78i$7xB89is z+Gw!>O99%9I2l@&I~ySvhlyQRn8P-1hw1f$J8>^H1AWQD)8nVk_EA1#?g67jRJ(yc z-^1h#(G^2Vvp3sl`_W`ep+>LQlD4CaDRE2C8-@-wq)M@QdC-6~ajWt{j&P92pu7gW zsK_HJEL>%=Q$}2_WHbuRN>q!8NyI!2zlB(&QqB1@BEr7QOCXt{Y&Adq3f~UKKF9x8 z@Gs8_wFvf!mQ!Sj=z=H)SdC#D>0#&&{#A4E`C#Sq4F=*G$RtAqZn)7Z#^A0>#MN!m zr`RB>AIc5XMeEAqWA%t<?X};e4xU^D{*c5l+if7BzUU2_!glA6r*q02xYbzcwN^tZ zN^gZ;#5&cp8BSWj<#xhOMsZd_c$A_gu#-`o-X9*NsO#@!6sOsTM=5Ialc05NOQXCU z*S=WVoVb;8@lUQ4PE`IqTo6-y@2AE0jMoAj+&;hmmfpx*7~~Zkss$kEE7^MJw2yrk zENb1$;+aYT^^>KATfA<(yS83T;9*NUW+?bjO=o=l#^nV$h^zevgoqzSh}o=>vgRH~ zZ!uK_6)U*$8J7VDBK1cxUy3t|TX8trWg5TLX@_0mry#b~-x+)Nka;)g>SVb44wUIx zjIAyoNESOTaPDoxO~(wxt;R~T=-!&Lf_c5-ebJE$`#cG&kO~I_M`V!@CwBCMx8PfA zx4@J129gY?zFd5<HcvU_0WRk%qmSZvN^F!OR~da2$5UdX6uHXiqd1-t8>Prqcp#i& zD%u&2+?SA$X=<<C-u-O-f#k#jO}vs?3)z5z+AX0bA}6$m2(>*}3Vuh748_dlj9p_Z zsD)3Bm#w^1`vt49c%FT?r(R+&Bw1$hPD-(y%KTI;TUZCvF6TjwG4kTeq7eA`AodOs zXbx1K7!fapd>z^&)fUalqJn2smw6~D`IHT#;!(G>ZV@|$m*10)Y$YDw!iIi|m1iVn z4gXOKq7I*B=8Pt@GI?(73+w@ZcYiUMuYavbOh$hv8{hB*0E)RA8_k57@O|O`P^ey; z`=Yy%$d4xfT0x!EYjgbv8$~|utn;9O0R*T9vgf+`S;?(91v;Hz+uGH+z?$+NFB&fx z9w1LOB+ZqK8R~ouOZ`bs;6(<tgS}t}qt`(tX#y`&VFUimYpx#LU7ZE~WpXH0+GWuu zjrUkL%kMeI&bE4AF}2P)yy3gzxF(nJ8RIWyEtzg*D)7_hlC&Yyx!^d%df){hE#|ge zH0_(tUuKmW>^iY<iec`n;%hXfqoH*}gr)a~d1(M=ee9&pj+f8!@&l4uaa4DKdr^1M z#;1%Sk^HkI`!o@#uN!>B-3rb}uyLye&8LXerkJ4|@?DVZZ^r&shUZW`-Ud;Z6+lEO zhDj#=hVywpVUbKEjOd$LMAwkj)$AcSre^|STei|x%e>1Y8$^4_UK^)&O_mZ3`j$K8 zkj+x(%WxFCs-4_Ax{MP?cP~#!T}|eEeqz_L{+f~7^>9oWjN!J^XBJ<#m$T~z0!LOk z*+_hq&d5y=yla*YZic8$O%>c=mQ5VL-CjefC)XTKiwC$;UGFu@%uoBOm=+$!(^E_q zc;Pl9z!ErGLva%GO>Fa|48SvzH=rpwad0Q{;B2R)46rH5B6CLV4Ej?$RsAS{z-y8Q z<7a+UWbbz)vfpGjDbwdExsQFK2Qlj-)bER{@is=*7AIjhA(ef6lPex7M0B6I4EAXX z<(1i*7{hH(>=0X0k~966vFXfjqKAe@gx_SNBwTuS6rteKV`C~ZwGpXFLH2Ik1{CUW z3XMORvz0AoRvf9i(_CR?0Y`BzNLN6|CkGIm?Ci`OOY#*1oy1DWS+CM<A!Bu#amP*e zML(T`YF2ZWy#IVLy$F+{&s>wru6{Vsbk41!Atb+&c+A|yN6jHQ(ANpF0Z}??8vR3U z9JXdx(RvnX=)=|ncrpY)3xDHN=zesaruBE=X<xUx%p8#WZ^+L&=;q14aWjsi#eyK_ zb&2#2Y3^@630&95+|Xp)IW$n!NOKgwcQI&<-6}9CpF`?an2ZlHdPnw70H7bMUD^wa z8R^2VFBH016SObY6l*f4qSX0cEh6STIn7V~hm=0=!Vml*`qI1$IkYGNLRXF-lSAaD z>q2QEacLSWC|#NLRH`%7MmnOyjC9S=jwXpvmeJcxm#yClz;(|0V{b83k>gr4+d?U} znm&2=?uVD&U0ReD#;DSS?eKslSSSQtL8j13W0QQC<@Q+G#*=^DX<tmQQWi&byFq*R zYYBy}c9<W->%66#LWUv!Ur%9y4KtyBl+C2)0ys55i_5rSzCyr_aQ#a1V(oXi5&zkU z8^KE_(Io>bi)Ka?r^w_SCQts7%?_|TkY-PJbDlYCH^)DI+NE_G%SdMjqt;wB*K)#a zhrh_Qn)@)($lV$5Uclen2<G53C&!PY7*5R~?)!LZ4co=1`8S=wWy+`Wc=Bdnr~3o^ zO?g8eJP_$2b#H*g=a_-XKK4c#^T(tUTH`y^B}po3dddYEmc9IQZzFBLDY*n=rB4=v zC;?bC^c9{TR0}kv{fk_ki`G*(MpSB2##`9gt>HyhVaqFc)I2BP*J)s&*blKF>Q@Y% z7kJn+TXq+VQdZahbBTl6i<!k}a-kl#LJ}*(VWA}B3h;QTnROFX;NGV!qyffN_hWJ7 zOuLuXMmlr%R3CNC$NAYm4r%^xK@(PLBi;7%^zP4PWM@IXa{IiS&`raW0naime_JGq zU$MD}i)#$>A6V`mmJ`YIJ~Q?`Uvph#)>*5sX{0mXD{8K$;L7N}&M&nO86`b!sh1HA z3}Z4@<)U_U@Q^$39Bz4@t*JXLT<XDGdoL1K&{^1|hx(f~_bczzaT-0waP|4B&Zpc! z(8OY6An=Tk%kig_z<YR}3P26p3Cxn>+^Jtte{y%j8C8ee)955w9iKG~%FEmue@{oI z>3TtKo=LMCVfj=l_0kx)2en=mUn=2dg2`BDunTT5>H=wcEQji{n*??#k`1#o_HP~T zn4jUu)TE7D-s#b*4LPR>^&eWN+=;w9Yu2HJ!<A{h0(AWHt)Nruo~XNK*1D~UL@#4# zQD|s@mF5gLE5{<O@OYyXHH1!~j}H;pbR3~T*-z{8a<&r$)ssrFN?w%+{>m;>0fo1~ zb`8O+kAsKQ6inHkWLSp~#Y6|jxTG5>sA(-oVc@%x+7KJeoEGX1*$v<)WoOkR;_O<a zC^6#C?EL~l_ev2Wxl%}F=|jbqTR;9CTBpmg4U+wFwBpvQV4}l0%X|)s=$rUiwQ!`| zY~g1$vzg0diKGcuM5Zg}oCpy%a0rn+RVU$Svgc$!pt6U3VZl$QrSG&x$=#`m=n-{c z{e5?v><LzQ_w|hCsRz|?Riz#0@sb#jMdyXP;k=x}5Ps=gs!m!UhXshOn=8Eg!vK2R zv3#V1Y>zZ!)pR?;>Ffyb3iO&Aup{6=D~vWR&Z)1lh*atw`}J&U3-<`%vQZn@LbxL8 zqyQtC^O_Y|J0fWT?7iDTO<Vzo(|FC#0Qbs_?W@P`4!7Z~>VP+(GgNCeKoeKuU@)<I z85?H{!<5HZcRr?zwU&=rjJWQ6Oc!}AAF~*L-T9a<4qHBEF&cYX1h6}cA+k7b_lw>g zG+;ovWr4n~!~xYNj3h8n6=__TQ_FKo2IZk&F{&ets!>D4vC~l<aa4^OB9EPp>d2#N z)FOc}f5fnTItXlY0?Rdydb<{8S#N{e+V?#EXZ%WJWkzDs`J0YsM>u0gU=AOXWV&Fp zt53dJ3+V}$Bcrt;`Kj_Nv6HJ8M><s)DRuQ0=$+YzCbf}n6n3?>bF`QrG4SB%YlceM zHC2z~tI5q7Fcl>1g35M*(qYOE&2GkY$EIw|;*r_SnC{S&jafV}yBX6RnX)m9$K^dy z{*)k$;;u4U{m8`*Aat5q!Vv|MYQB@_Gbsr%Wq|zy+4=+N#8i<PIdU3lfka=2tfs9? z#pWT1Up<N>Ri}wj8R2;1>9J%x{XUu?kYdGN(d2c{1HkLd3ZtFL*#Y5B+g`KkG)biZ z=v0b!pUV(bI`=MZHUdQihoGhv=dypPg=@V6`KoNdmalvXEyl4FfU9RIpnN7p*?Ck# zfTj!}xD=6Xt$EF(!#aeHj~%p?l;S*Q_SA!WTH^cWn!WJ8+o{5ns@6mSy~7B_@WO$| zAS+m0mSo14I$Mu7I)QE-*%nFUyX<3VydDn1cb6C~(Z&vHz(A>nZ86Kl^di0Ss>-~e z01{d$RzUlVdm2Q=G#y5J@@bUE%=^q|49l_!93EPEaM9bjPb~F1%q<V4AwG=@-ZI|1 z8EgPcjLmIxT!WyoY0*0g^t`qd(H0{ADvcVHd9CUHnGhfJPWt!KlH}4czCm9aT|F*o zN^hVDRheiy8cD}brCKO>e^E@=Si=o!$X{q|`QE6cvBFESkuKDd^sD4j(x+cF&@qV@ zO%gk-sa?SX9}E%1Yr)hm5Y}t%aiCYv06J;Gl?&?nu$@>A!!8Qs`mmk&4Z|)9-ukee zm<_`&3fSEhq<n;f(@Wi->TdxV+HIb_*VumYOT@6jpo;}4*eg~*#9N<zGGeU^Pp)bT zH^pP7ztfdLHC1U|v_gyEOZOUGcn=Y=2%}h_P73AFAfkC&uoD(+uK?kCn)l6w7y3tt z8nt!3V4En@;kOJ$gWvGrT*8<PDi+)LoW0is>e9#u2hb%}HIPgJZN4z}QORB+Tq?-$ zl3R=q0212WZUj6Od4D8hS>fo$3-_7`vqLMV^WJ)alVV}QTtU23Ve>>hR$vB9jfpc| zFL>h*0Fh76W;jXzBsg#2mUlbd!}oB}`kcLCy|7ScB|qW@;=Sc?CbMvY3I9edVw};4 z>Ck2#1FTjXyq4i9EMcH`=DAEtVHLpd<^a-FzSe@C%XGA&{GZM^#=lC}PYIL}auBFn zzhzx`5$l0oA}1l#Me7FnhBDC)rtdRPqp<i#p>~qi8yJ+=*}GzwW6MoC@|e-sPeAz1 zB5A#r9#9rq^L5HZ##<PjQ;nTRishPfb~Z0A8|9It%M?4!H=Qelr~zyquhV(!Di)1V zAc1!a^w=^RwKPXBSPX+Zl7ib&y<!;TWD2sZT#;&?ABqf@?!LG@1RF)d76?n?AoOd6 zlN3*9k`%+>UMPYK2Op=g$>vDW;AiR`eF#*C^0m$16`&x0RfrkjlUPK=wLfj?=oYq` zjEI>_VSFbYXc&-TH8)#7Pi@H5KhS;*!}U-G+{$RgJ2`{IL~ybl2gv!gF9FrR@W8KT zCgcWA4cD?-jDcqhQ&2ijsBg7rPb0H4O#Le(sZ58@BF!_bSuG}Oj10o&#Mnc3ec8%{ zH2WFme6S%Yauph1Fej{M(iYNNEeh=D9d!J3oWtc(I&H(`C)=O~FjJnB<ufm3u_LXd zY4^;?4se^xqc5giidXZ4@k|ESqA+8&s8shaX_LEX`aQVM`I%ZDbYkMz*?~DrT$h_k zNPxx3qBdl92Bg}vUT>af?ia9eExqq!RT&AD$eA7Qz<tT~3pMoSRUTTamw6Sa&j1Lo z5bk-}#Ze0=nR(D!YZg;OW>Rjbep?cxnpkQ;(iO$DFFzJ|{Jx4?sAn)52OY4*qQKKz zVF;9(6)Bw_EP%IjJZiwSwdqw6#<(bnI6d~Az4v+bc40Zk4NdtEqU&SfK{d?DE?j7H zFD}>)z&w>Rq3H(5zIa4lq`Clg`-|ovKib}3iu;$`LL;LtdqTr|REqtoZ~k3T_l?|& ztKu5b9AMXrlD9C@WpWKa8-Szf59`QqzaXkHv!|hUK=HnW-yY-tE$9pUjrTk<EIx;S zS!dwBzm#G#i)U7#H>wAL1jd>0=?fT7F^)fT6%ZSOm%;D4{PiLJr5>)m8Vp}8t`w<; z3r|tVUSg}rf?7r(op2S>CFK8d-U|N>%!GwR3W;mVcSE`B<k8u2>9nDa$Ngb%AMTG^ zp=9h$z<vY&&0=KYwI)Z7{*LNZe+X^uVRX%zf8R~l-t5RFJKh`$p>$u&ce9!AX493S z$BOuIXTQXLaew?huJ=}c$1bNUYPuG<)uA7ThF%xgbFJueTF2jHM040FZJx-}?{rqP zPh4RKN#CUgp$#fcu?LkO&2{BDA_WpQ^B?t_B`B}=(HlT>9!Vp-RMzA@YPPo46p*n| z630(noQ7#<lQMisJ!dISLvF^n<^8B;j@4Ab)5969Vn$p&&WpyZJB>=YG$t<r3sUGq zJk`OPGdqnty@~(-q5Qpu^Zxy@x5s`k_SV?%;S=*a>0ll!$&tv$RBy@eGpRcfI9*Uz z{%ln9CO2#UgqxeDc^<XIh%2cW_zh?L(;Yk8W!TN)RMK;;G{l{*jj<6M&;Hr{4m^TV zdLa$Aw0B0Kr^eNl-nEaAQ9MYJEByUxBiZaV*MD?jb1>-kuUxv+ecWx$bsrBlJMFnn zZ$tjRgw7nZgOyp^nd8E>{3lm0HLeM~>({P+cnxK!JtV3cd|-xbH&)+Y{^aT<e0}Ld zdGd|91jR!vTe_IE*5NMsYKWT;)-EPGc=G1l8@P!B!2oC~o%Yt_i%9|3hYuh6sICvX zK$n<b;>&ZF)4yi*uUX*G>ErY6mm3$Z>4Sl<%uFsP_n;C&O<=3Cxim2VZdJAo<V;tZ ztBqlwT|+t>y~cLJ-!~h*wN<o(TT7Pa@4pAz1FjcMaBXrYGHaN2H%SO9(Jcw@$X8+x zLtTM)Nwx%FhufDPw3-hGxchT;uDjX&!)|NsN8f+@2XFmem;YY4w%Ng#b}Dm8x7B^q z?nl1SinnnecGuX?GPq+|AhWZ>E+)PvGt2aCA-KFov1k2TjRL$Q&$kTUxry(5Ij=G) zFTcMJzToO5Hjz<Jmn0ir8945z&&LRzGAOGt_&S}hsc0Vj5N2tNm#LoeH_%!*dKdry ztr+>#N;>#7&g)c5;q0{9gZc-hfpTr~LDQa1%Q?+_e4WVEhm>hSDlN5Qm!nYMTmyEr z1u64YCsa(-E>^9J__%d{6VEAr1{2jNZbKqD?Kq@+Q6f5>Ad7*Uadt;)bA8dEX!}w> zXWCm<?<<a7rJI}Cxt~7$)R%+RwBz<6z6wu69*&JF55vrNx8e}2@SaLGBu0yDf?)f8 z0>OZg-Gk<wuwFcLH6k|`aYf>zoY+K=VfD-8F+w<-jRz1w9&2x|UD3a1XW7*X4nPiY z8)cy#CypPs2Afw<<cTmlqU@0B?kh#{%~`<Yi<hm8R-HmcUHYy+Zcxv7b52Ak+kK`& z@=EYISp%KF6F-HC3%;2#N0UH%&weX`z$@|+=;=uwpJR+BaXuEwMDF|$T(w;4_>zFq z$CsMa(rJN|$%Ud-9FwYs7wT06zQ1A=E2-Re);ZI<>41~3VfL2_manm=@;j%JNV(|W zzr|B;&wN?Rl34nZV;Jv(>%&I8CSfXC(X?slvE!Xbq!7Q9m-5!x=fvi|JVQM}14*>B zDbE=bq`jT>6X^S-xh=8i=^aoH`9}grt2{}A)Kd7qdY=8hiH>>_+>vl)>@(oX(Ws++ z2Jevm_Zh5S_G3~nb_3tgJFp6PTlhWebKrYEU1$G#6IM07CztUQ+u9hf2eIRSDV<wO za_Jw1<gAvO5sCS++(+Hd$;=8<(@A6sqf&D$XLPQ09=5kSjkW$IV^h*b%UWKe8D4=2 zq?*I*Hif%|RxbapU4up1LzH2-wT5&GHrd3R=(dd@i(J(Jk&cRRHE8*b{J91jd=<Sn zAIm!2xbhi+^gsIq|NCsd+r?!9jnAZJ^D|h+w0rxXEs0u_{&@54**7nLwk%e1KS{*8 z&D(-wr_$6!dWM)&sHe!U%shO*ht?syIRR4$1Szt`MP-4;<M)y4$wW^n9^|h9aQnap z;8-?CU~JF*$K9d}{xFV@iC_3nkMrqZvcaF@_>!6UDXB)~r}NC+=64mx(1dl!%#4Ag z#b$Ku()q<BYqHACveErLfh?`xi0CuU#pQHd)AT{vi_KXXb8Q_y`cS)C1mkiDaG+$S znOwb!WlOGI)0+bk^?&ls7f=2IMa8Vr{Cf5QTZ160$mP5gJ2w287s7Q->$CIJR<mSM z8U$#GiAk1CHcM9S2lX_+l?*n}V++sT!aGa~);FEO$=+Np-QWYxpRpPAnqYM`TGT&i z;z}ZTZcsf5_l6WvYXdG#ut2w3A)|}twW@Yp>=({$r?rl4v}CsLLnN345`*Tl&tod} z67P;Hyz;EO(SW<my8!TF+TCctUFux`crov8G~h1xE&#lkcsC>2p}s$xngI!sSBL8H z$u=c@;Ul%MNF)9|j0JXg2BO=9N;Pz@YJvo%EHO+rq$>kEf<?QH&LLdD;1%1%Fz}_} zIr10HDd9InIdzj;*e4oa4ABEblIk~c1K`(4w+LMJa@GVRQ>`Ti?zmqHKGd#$fmt*8 zwesH829UyOYE&d21}{-<1TImXk?dWvin8)kKhO3g#&$^+X=-*rNW3Q7NJd14WUkvT zzg+vYwpWsc=RMnHw`=n@b0+MQN3d@Fx2j><O+0{THCsRgP%}wws%)AhF#-~FeGq!z zQ}HTK-FuCH(OafEY!SpH6bfnl#Oh|2Q3i6?UrFbnj5oRu7OfLftexM30!1-jGECnG zRBeH~qwvy<6&+DLWH(*4(McS?JT9R{uez1w5QL<(R^jd!@Z#n3+->9U<a$$8pik9h zZ&(<?Z9fb-K_#Ma4+RoDg7;9Ik%aWB#`Q;<6+PvrfNOyb+1;Ed;V`d--oz?=&#nZ$ z)Di==@J={*$@dbrD?)#bVkhPa$7SuSd&5ne`6$mA*4uluwGpW9$US;2t?CidPugH! zavN(nA8s7O&<WhJgX}?Pm*Q>d@1^4X*J837CkDCtZD9mlYIChJxxO+W5=yqSgd>}| z?MxdI9Mw$g3IwydX?_(i5iBO3K7EW{&0ti-Mr2bM8P*JHHzo4jvS}a73<BM?IJ1jl z0&9*p6Bn49sA;KXfKMo3FkjdatKfQ_A)K&<GwtMOEj$&RWbqY1vFVH`i?Z9?eQjJC z>h6$u*!eldqOG!?Gyr|kLZ_%KoBK%%9pTWDa=dY~O_ti9!wwXNrW7?3({48^Yp82* zLo~Wh693!+I^G__4(xos*8H5oSQvEu&kKN~m0R6d<yOt=fu1Q!C{_=YWbo6B4rlQ5 zicXW|K?!N{34EPo3XyP=8{SsEEg<%<M<AJ0Q<X3pCE`_}+BeX)*C%P&HJ&bx2)!0Y zA4;pXkp}-Dz$V7Q-stIaTyziH`xmw*RLi!nj}x@rC_H-@^bxv`=wRO^H5Xo*N`+}S zfA)~PD!ImiMXXF{97GcuC#}BBNT2i;w(EJsH2RI{$AQehFe`W)8jN}*ow3XlL~fY% z19FG0$!jq=BaR(jwAQA<iqMlddzgS4Xmn6;g$zQj5Tm84kCc`Ylb8)N#iw@k!{i$7 zuJFLtnYnm;!M^=`InTK$tb_}pp;jhvDLYZbs2<t&au(<mfEqat7gl#O*p2>F3R@wW z@&$it2W)LZVOCn0Km*U1dUVW?)qX5Loe$vX1N3!+>p`tQ_*x3EMz?6b!`L51RUI|< zq8LnWLrYC3yN0J^2rOiNhywaYQx&(U*o{YZxw&wm50<W6R=xD(7buSux!Py1=XLfb zZlg=$D*C+j1D=*ot!?l0Z{`G;{C730UEQ<ND$xknv{8rGoKMGD&p!FZR)@-E&7w9_ z>yRJCD=@O#aKOMW%BG#|>q%td*V)z4ko-m$poru+h>!PD%-I<|ck_|d`JDXVKJI1J zLVZbI|G2e=NcA(k?D(j}czDzqOM(Jt-`;=oQ3JZI9HJ5k&-^deF-tcpSJs?UY97YM zFH^tiSk>H6%lqYgGd@E%t)U>QZjbORf07v`UO_G6l;$}jvpF`8U_M2jcxL%YwpXc( za^*W^T2BI?8n>{cW117J%`1+mw9K{fvyPY%@4BEGc>XN1t#m_>ITy~I{(m~eq=Epy zm92MZpB&Zv?~7R*hgBrXQNaw*1(j~yE|@{u67Mf~6u&Y>&qz*ugc7qYHq(^8*V-D_ zaAfI43}z~NKx622(ljM2I52HC(uE@_eTen7XqZKJjeAp_=WLhUSceEk7b@}i@fmc@ z9yB3~w&)LrLosWx$$^;qpgDL~q}6I)N+WK=p~vI!%wPYbCT2?KEHU$w|L>A>d_GT? zr2p=BPttuuu8&41YWME%h^$c*lqVaSsm5BQA)NMyv)up0B2AUF)X5%LY9!IaGxmC6 z6mnT+|1(%dtCSopWOo1F9ozM?k!(EqrnB7~fWc_z$&?S2kNw{RGK-iv&IV%ioG-Hq zIU?t(;jm8y2Q5CQqT7VbFlCn1RW^l#@-33)kMRF>e9yNDhwV%#tEhg_dBjhR%}IiF zSGEO12zY|Nmjtd?gPUKZwV2G@81%q7aal)tW55RLrTc2K{s<g3z1n)Kg|2^SNX-i& z8mmypU=twH!5+m}ydG~PkOHqm;Bw2Gjc(I$H#7oC#@LA4lo(JrE<tqYJ#kE|WN=I) z4V;=12&c&<<dRUNQY0_Pvasa9yv<L)mL-wpwS+XE`~gr0PfpOj9%x=kbXGlzh#ok* znU|C`LcNquE(`=AO<U-X8(*9YW4xTp0M323H>3*Vy5dq47iV`JTf|Lw3gsz_9WDj> zY6#7i7^cCH;-K7R4(eq7Pq3G&rE>Z1$~PObD6YnhgFvn!9I^)Bt@bLqiJ*hLdf1DD z%#0<;6oApmP9MEqJwWi<lanbf+4d$UlfV1Zf05kSqVd(k5O6cm-w<B71<@Dg0h|<1 z8h;l{MUT<Cx1FSSB>|oW)hgOBKhpo~_MW+z%x?{nAEg)JioC^kZ=ms$dO3>oyHY@a zY76IN`UP>`dc0z#m}kwfyb`FvRuL@0q<hNxkBbAJ@rd2*q1EW@jE>Hy)w9?#A>8mX zUJU@#^d&P3>3W1&Ipwc7*h~4rc#LIW*CMGnksqf)Z9S9j1e=!chCJ2&WOD|FM#?cc z8^(mLjbU#^tbigS6F`InioQa2{l@3p8|*jzD7<c$t%jwq>Ku&9u5LC)c$KkcV{R|Z z!{>qvh^Ptnff$NnAR=OfK0U$-I#%=Wus`dH@DPWe3K=^ayAX$O2!gn<m^h0ouegHO zQ+FE)-q0ks>iXFKnX=O!q}flvQOqXBGkspZ(P@hxfDta92i-dI((AlsMmw7oakv`6 z!4R^49OI+Em><33G-}Vi-Ol-}8@2v~FN%2-<~Q*Pp3DqYF*}mEl6Fy4Rz)h$E;J?B zsUeb@@^HrT1WFD^E*cc2N#4VMzU-S?fLBM;!svY~JLi)rg-~0{cK|$ki?JqT(@F2V z60xIa+tU${u<0}jT`b;Bz71JG7ZRm{5m9fTi1AlmMf>!-q8bUIU$L4(GIOW#1!U11 z-~X#$MO2`F3KfS6jp~3zz$yj!ow7V@l{=lXS|6l#P!Ih-Fz7?qkaQB-t<XAB6|ku6 zRnF_P!n`a)l6hqqDn1!yUhb}_w>-RytXTEeJo1r^_%90x7pYbg(rG@BIgWxdx58I( zXbz~;N0l|d<djR(6pG_GZnE#Y$wJFWPYP7*l&gkkYxEM_V9u0LJkHP+&Tvd8f2Xhx z3qqhwW9F=V>0X}Ta3+Iq%0b|;Em2~=2n=3x*bz6xE$f>hG~wA%BO$!1VO64Cz&@jY zkBDLY)BF2w2A(p%^RxTE73M*W+}y9}*~@_$QE{Tdb_Ya*K2{)_El-OlM^kfwSs`V% zY<%__7wcjiR>!I3t2Cl^HUBltI(vXVbnBFfi1zGKtu?ztMANYQsoD2EkU`eWRnCW^ zC*Fl?+Itmsm=Gnata2u5MD7MwwQQvvCExVtXYh`iv3Ant$wUnK2z%Tr(1g(=bnQoF zhV|sq+un>)>pOz>#iUXs{gG9H*sy?Q9&`g4=Sn4C6YZcxh*>@RqCwg+kq0d_qZx=H zpSKr+oaC8jJ>|&^c?oKivF$Ui4MFT_pU|gw{_>))%(&JdfA-XN&2qvFrHOSZ^;^_D z!iF%s6KiB**jA4mfLnG;@=`FbLAJnt_)NKUe94=ZiW<2E4mhc#3=#&a2X2CP3H>Ji zr8Qb41@(xPkN%1qy$L5T@BV;$74Zom(O?Nc2@=m_d4aQ-=rRfUZuq&YZ4WyGsQG?` z>6ofNr)2F=Z5pFr%)Co!<LlX3ob`k`zRZq9;hBWJP#ozVaHo;LLXI!NTGUZSICt<( z8%{yztn}OY)BQ(AByK=?lIBty>!pmzWn26={+5Aa#HA(8Uabmvg*%rjhBN903+R2x zAJ9eiy^YjjF>WQ~kf@&oG_VSKfVRkBl^Lmz*Wf5zP1X=^Coe<l>yT+^?f?0|7_L!d z@~$CP1E=Y8MVUC2^+#ew{Jf}xx5W{OVPg)I2~d~bn(J~b_Ab&T9X>3tU_T1EtQghA zmUZo&^YvJIXPiq)4a2>hTAv~4q>yE3JhbT)zT|*e;qXFX47x*NGv0#z)`mXiUr4Wx z<m?!vGrG!2*UZ+Troj`G^8n*-y8P&d)2J?$dKS}28mh(dT8bkZPNUPL-cadlmbm$~ zt6bwRx2Y(@Z@$_b@YYwF@8Lz8PWhqD6~Vx<jX07b;3tt3$!RX#2IX`PZq*i?$U!gL z0OM%zlwP|`2W^ljwtZKv#-Sy(^qg;D-i8H|F*<Xfe}%?*(T)R~oQ;Du3>6IuIFIH} zu+_f>A#8&*w1*zONv0O9Vyu*_40)qd)TepQ5D%bceWoGkC*4dMN-HIxe`ps^3ivR9 zzib&E8CkgRxZw~nWFemvBM8F^6X`{8s9y^oXRI#Io7H`7d9x*isk^mV;A<ivjVYB~ zv7EEVf<Jc8PZ*7}$J1CaH8Ch~E?H)azbve&d#M_INx5xl*vA?E+0a$2nW@*EwcN~K zuv<HdD2xsJvg@IWvr%6h{V?Op@QKSfnl)m=a~aM)P29*<iVBJOdC5h_6;~yVb!?Ey z2Ta0fyc9vB+=t5K*vG;gOf+2FoR(A$E<Z+nD8k+d;)PEO<#9eYcHe!pjMgNr;>0J@ zBkXZKJKR33V3ehq7s=XFd&s`HKeY?OIGQ&-$CZ6^+-zF-)w3Cfa}R&1g2$g<dTFq@ z)dXQ<FD1M<@hJ<+bB0?yCaT=sNA0?$TEBhu2w(N|_wY<k+Tlr1i()}QL9tLI+qE=M zX$Ue9qp(nr&`V{YH00^FV_BRu-8>e3CJ2OQaXK@Ln>dqHv)Mq@%>;Xa%!6-SjZ|?j z7>2Vv9Lqs}QLNbJxFnrQuWhKp!dfD6GnNZb$gZWL*0oYUkOm30JO2^e{{JS@Svx&R zdYne{P@>Vp|H*4;;Zawx#O`%wKgB4Xm-3cuG+3}w0-Y7)T4UmnI<#O)5c;KWz6aHl zp$Yfqf%kBg6SJD7BYbc=hoRJPD)azmUR`YTHp*W;>lspd&cZs;2`k$3hcAfHvty4e znLZ<d;K*Z--D8hQg~7)rCFq)Q)7#hf&$ru%HcL9}p?gi1ku9_us11{i<~>g>YzBM6 zxCr$=eL|?d@XCLLSG4JCzEStI=)cpT60LtXrJYO#Qf(}ot~rNKsfUuTXi^w%#-~lP zCp8i#ESZ3m>m_h)(Yt8E-Dv*^7l%Tx(w+gy2dJ&@cZQn{WNN3a1J)%PCp`m->v2+) z6um#f)q*)<d;V^kdx>%*CAcDtDT#6M_%O*P-y?e*3yMYuu?=x$9=49#Zsh@HDK9ow zno^Kh9QgFu-=wEj<AX}_f{2AN{^S>{J>2*ep@%74q)q<-i`MAT=FxX_@%$@yhFb&N zzP!aXBzc^?r;%7hetG$Er{~euVcA?|9JuY;q5z7d%^=6M?ERBMXxdGXW=h(?!ooR# z9w7}$xv#?Hkn}m$3NVMqfg9<y-<6o0%G8m$Bq|5%gn<SB!>X<Y_(~OCyb*!Da+NP> zH|9K+QwDOsNx(w9l?YFYnNDV>CvIzO#V*^vo5-|kh}0-s{i9X{XzaoP*be}k;JH<^ zo5ZS90=XJ6w_X#sI&HbXr4AX~$2_#;N8AGV%O|JFTd?ujVjfE`MNQQpCsWT}$Rr#$ zjJ#@kXTd5=g}Cvph5#P93niq{w}q2ca7Vl<x@-^GoSnO;p;DT2>BY&G7`!WzyXGRm zGKl*C@#ffF`~GuFH}6(WXu@G(-*eXvmW}pf9S!+Ci}sXIVVnVPGAWwu2;EB4w^VOp z?{D4&$yx(?o+#a1OzISR38A|!iwu*SsIJ{i<l1d5@-9P$P4UyTR6C7{rD1>b`fxDN zRK>E_&t>Kiykp1Xkte)ccIxvJ);@AI{Nu5IdGNRnw|zx40lMlbvs@FQn5mhyt!*`7 z*%BOb=9xFuaW&AYPi^@1W9jQ~S`K;;^VM*su#w78Hb5Qf`f!}d!mG_qUK9T+Pgi<( z16J=6{;zRi_8?EMhVUjmWo~u2L<hB84pEJG*+ma!>t0`{D1$=!*JX2ywVxVE4N-o@ zzN-QEbu14H-5R3VQBN_tAH9M8VRvJ_tYe{Nk|$vk=NhkGzaIv$P;zH`{yI3k6vV-J zg{v_*D|)TYbp^BMsAOpA%38kiypHn#&C}CsvdVUbcZ2cZY6$_MQ$h~#Z^*WuLc22@ z6C?vlln>64^a|RtA;=w=GDqN4#@P~xKgnf7gB;XBP#xEjHYsJW*?z#G?xJ4g`e~Z8 zU6`W+x1S(*E!bD8F@+Li(`~H`qoZk1v#0@2pzBpl^|zKBZ#ReOttw^s1SM!KdA$dc z(pj3%cE!{z8!EtKP~%#y>_0p9E4xY0{?)Ilbb>>kS?wZ<2cG<?M)N9d3)3pacYE<| z^*vOLz8lqTDz$iSZb{vVXYc$HZS@#$-NxbLJu5th?6Z1F{#wC_S%ZI*-*oZsZIQCe za-vK>3RBZQ3;mR;E@O*&%E&gg1c1Gu_&L+`jM}Mb^U6@zxs~ww(;xGa!_96~^Xlec zd+XZO&1Pfm5-v*UtUbPVwR>%$)yExa5@rLJKziN)^^1rJA_R|LCA!A+^6k#rlV9=| zh+f;L1idi3xOPE7T@vuzjmdP?Zm~s(S6$0{wP_#F;?^1pI=8j)o`!}vQ+J<;3mlw= z^_SLjFhPJ92{cv*Ltb!PHsDFPg7WUQo+p^c=RIdq3~PE#*wLOCIsvs04J%Vw7<=(F zOd{pfniCNMb5Ovnw;ol%`X?y~G3SCZq#h~xghc1QUX;W4HEQXRk|mQULBI%v{H>yh zvhDb6*OOS2ouCwoPvB~dqJ?ZK2)YdYwOylct^s00U=5JRr}0i~8f;WU$KEb>;+g;9 zDNIHEMZEW*FbQcK%DBGY%a|E9RD$S%T){VLc~Frt?moH_sS@(oXzQe9{AT<mtQRNg zeuU4Mr^7CG8d$!9Hl^qB+?r(0xOY@XX8>9cjXOLJs*b4IySW*h(5T4|fGMmij5!a! zlv>mHs|bfSR1A_HJi0}Ng9tPpMP{n%O&RLIBUQ(6r`t5Gt+WUA-$x0AY`2O!CRhag zpwVlw2MwC_4qGfx=WncO9}Zf`&(W{0Ow1<dTddVXvm{iycWn13$^E93K!v8Ht-`v& zoo@+W7$DNS#dkW}sLxFFPsk3rH4{>#_y+h(2P5DeksAqkb0@jW{!F&+F~(_ke=@0h za$6r^nVTT!08!h8kDg5Qhi*RVH6K*1eHoKk+4ae!cYjrAi~4)nME)>FLAY87R~l{Z zW*&dE>v_<(F%UjcHisX@=73x0;R)FVyEk&5yu!)-1GmzvJjE>=BS?1QGCU^Bg&d^) zO6H|-#=#544Qh#R4;`Ro1T-niHgk+woK3dlhMc&K(mNza+-p84194dRozX|#>xa`` z=UN9}f%yA4Nds@}L(<$EOoeIdWuxy#Uytp_6r!%&5AtcNhS@bexCD<acoP+bGR!WD zI_cj4Fe|pBYVFF!8<0$tXij%MvV@*VopzhoeVa1i7@lk*NU1|+L|M58Z|F_nT|UCW zr5^I*T3z&e5)(NF{V93<V&D(Kv!TK|<C4@HLCdJ+nSY1w!z$v~Z00wZz6R4=Wbigv z89B42VHsxxxAP|=NLOTY-NjR?Toe_KOQubhz{;j0GTu!Rp?l)jvgA(GE71_DG22w7 zP@x~z#`SILe5N@9-=71{rmq046R+72RE-I2xyDHIxF=)GVWdh$0%6>hj>c`MQVu?i zM7@|w$EGrswgtm)(`XCJOAx;=Z*O6aY`4RA%4czY?2o;X{{+u7%|P8liG|6XVfc>e zJgl$8Ozi>tYjksGE-yOSd@V`Btv0HbTdS?)K}V8yd8v5P==VFTE#VKyc0iBKOWMIq z-t3803XX1#Pdc^GB)E-~3$`5{H0P3=kDBb!lw6rmSS&e1P8OoK(+@gZgT^#nNiZPO z&S=wb{NSzcPrKgojpY0v%X5Dsoq71JRaES-(lRG@1WNez2^htw*+D=8O^$)LXBRI- znv#)^Fcjv<(3dKzb!$Ws%WfC@lmv~*&w4T<e-o{XtSyekGoOI>DCuR7AW765xTFG8 z9#E=LMWUY&Nmj=mAUX49)S^|Pdj5Jr%ctj#!j2jP1s?VHTZN}o|5jUoPu#JZy^(bM zbTR#0#TP$O3*b}CN_$vm<vE{NO~+!bth!<|&zPNg=6k_ofD{sGCX7}mo}6%+i|(Qb zDA~rji5r?9j|yW}8iSyyV2f`aM?!8)Xtbnh3Nz?KI{uZ3^Xt&FaT09x72>G^-4eXf z<<H;ZlQ>02`A?~7;`|+aAq}SFu1z_&6XzHCDFCOpQ>LHN63D`ke6NY~tA#JniyXpI z<Zzr=$4-MlekS=3+2pCg*w4*!k4+>$d-4s^oSuC1bCUka<t8%xHs{-Gse8&hf&XG8 zZ=UL8nxU&wpH{6Y=HeN6A6_{_jVg*L)5#XiSsKN2cPs3<o3~BAu+5#WlmjLWm~pFA zGs3R9vPBrprD+oWvpk=NKO56=Q_d+!crL^$Mp>BE@WL#h3`HaiEn7JsEu@kn@WFN> z?k17c24(9E$!9?h$3N(*`ON)yxoUs(bXHB+#SRwiFGo6SWn`93N&8(c*~-&dGNgv0 z(hcSBJ6N{=YNTbGhlbV{vHcKw9`CBr2%*Ut<6`MWqtyLOg@&@KydF2oiM$tHsC(4Q z8mrm@V6}q~6N3&ofG|d36m2m@16&_`Yjn0X>cVK_0}TSRJLlie!rZM~81Sm>%JA>i z&7JY`(>ByXl|+33+*j<dlaKQVq0lPT{J=8Npl$m#a6o?qqg|AFsuw0U6){X!+FOqA zxWO;X%atSArY$>fu<R$_K!&ZcPehgEUJzr7nEAyVO33BJ9>VJPO0Y66(khImO@QB; ziZrljs#*qbw_xgqYhazx)5|u)rL=gqs0DdQK%$8v6~Zc9dGXj#qLN%O=joZafgWPg zM@;PYGHed{85|aii5pg?R^bo^aL@tJuz!j6Rz-hqUPo_ac~9l+*brD9_#|xvE$j>r z+%&wrYJz9sqhPp00}*X#tzn4AEJSmoTovRq*ghIBG?iwfn0j!V{nahp>{|u*EQ}!6 zl(81%?Z%UT19PMbGBM^#ii<2Y@rowwi*6+XHf$L+nwuA>Y9kLeveHK#{65M|)2_}X z6c)N?VDBw+14bD_hx`d!;@KzfRuXoJJE3e$O$cTxIB$cXE$S+k$5D9)NvlOwWk6WB z!6XLg5f<$|NSCeL;*&^FGS&{=Pm~wfZVTkloz4I`J#F|vdX+1{VvZ*M)98#7ANxNT zwovk`N!KMC$K;-jg<{b-V0Drznw`wU@EGMm3nk45E5YT*DIcIPm_@<{%hx)%eZ`oN zJQpiiZ>^Q(_L*j^bZ%%KSt@evET)#5ZLN_`B`F+Vl{<9ZXW5WTWJgTWb5+@tr|zKY z6MbZ6s4D5p@mH6f`X=tSj5$S_1{F_Cg{ozK$I4Bbkh{U@ToEUchT=o1i_Wb)Kiwr# zGexAFIWWpPO(DR;-nt}@Vlv@`CKImo(v<xYdOQOi(WT)KTpvJF@2#b<!}mMGfwP*c zcJVAINl!d=LqpouJ7U4^PaPFi@W=o>acSS@{RC=DRYCaYBN<M2aTZL*fERVgOdbFa zKYPJcgli@OS=1<o(w(q9;M$Hht>=!!k$T^>1#s9#I=qalM^*<6o8#$^rQ+*9`JK%@ zQwu!O%-;{s+^-^j8gt+OKiUX1_mQN{aEMm{hrhC(ZsY$pA(%KV(2yd1vz>woB54gm z-u)GJa`7gGS-g7_j9s&8>y1UBz&BinF%$Ap0jb$EH0%v^5}$l1$&8-=oHj~!MKqX1 zWli%DS-bih_%>;H@YZ#097u0Hd)(-Xm^+q;*$V9IhZ6E~ZGZWco*6zt<&SYro*#pk zTa`S9rh9pI1(>0u>q02xiMT{r+A8~>x<Hs#%DQ*-ehBplFh0N#pnvv>m+lv-hcnj^ zbhK$$pbc@c@NeaQn%TqP*tFnL_RQ<@lv~O2XU)^P)5^X%XERd<7Zn>)9yt~}U~zrL z_{Z-WVWv)|YtLQK0HDjenzms>1{(8jT75%9hh{C!nbAB>-A_OG$j~LvpFhTJtXF*1 zIWlQI^n_AQODM-sP5HWUCq`XkpEk`JEsG+iaUPSK>w>PNcJ72v`PwCxpRorN`-*cf zxM$Roc^XVyU?3+zvw_WbZlBdpMLywnJ&R%NjIoB1?~p4fC4{LUv_~HcwgXu`j>b?n zai;F!&qr?y&>5JsqEDIrDb6p#ozQtPgW7RWL&IDfMi3v#cvi=e)gjGr7CukEmCldc zL}`LgXxZ|p^tJ)`)L-=cm(Ry($eDPbtW{`!=8VMN^LK}9!5t@c&jTlOg53$y)y+}> zcSj8c6F=2G<J)!T65E|B?4K&8M$g-G|HcL0oz7eVrlm`CGoMI+aN~BP-Fos%HVcv~ zd2pvA(h`l*#K;drLFrXGkNkko+{EmM$RIF}O1x5TYiCYD2fk^5yuh{&CXSkHBeb+V z+{TN3IJc3u$;b6PecmT1mjY(q%WHAw_Mep&+TcLP>%;3q-L0R@GEL!oDQ0%u!u!M! z717MhL=2f7hA!e4Vk-B(0S5m<W)R!!!QPg+%}q?qaxM6HKbgL<*;-%6vb`~V(f#rI z8<HqtzkD4ZTx2!@0QKpVWrnDZm@XW<w3x&W8$s5~`KCV-bO7M1VJqq5J|csUT+)Gu z_^!F-$c5sl^}19IR$7azbQ=B(e?HS#CWmMcami?9#6b%|xfI@HNE|FPLwFh&M`EQA z6mPKk-0%^%0nNs^JFSftoECQLms@;(HC;Tmy#rC?Ca&{lguVadmzd19^uNb1DKJhO zK%_I&>Lx~MU0iK$4O_Dyb-3h#M(PGfUqoVr6$fz%UazP3JTb*XrUlCzvlLj|;KdZ| zv>1cgy_21jWC2zk%pngrwz5fEjvmXIH6QrNHyPk}|LRw2*)xU4(gx?$#y2*h067Wl z5#8rdNb+F`6nq5SOq@tIY`}K-W8gt=2I43y4uF)NT?{~zF<>t3|DXQBOop2f&)PJP z$|qG!vg}YA&9`QQDt{DzT%&Kz22GbLSAV}X8%QtTnhk2QW|hWo&4zEyhX22r4Ilh2 z%!c%8XDBG&+6>>?4By%e-K1cR{Rd|=?ECZ|#Aa~LL)r}+sm<U!mcF$hz70IE=EsBs ziopqE6BrkM`LpI}=a5!i(l~9u4LtB9<^w=x)ka(6tbXoSXMG!Z_zx)XV4UF3{l~ux zZB~+UzSU*_arwVxQ@(Y5|D$w$N4&<UU7kl!Hr&u7me%1yeT$G98tUtr^FDUQB|l3W zj7)SYhQ<_fTb#={tv<6L52i&?rushM{vLa$WFlDybvv9TWk*8-uU^!iW+Sm}h`YW# zH1@TUv3<3+YUCFrU{HV6j+zb&5?4pQgq?%!v=Bn~tZ4nA)C5X;*F^b9E?gDcyzA&M zYkC6Ft4%3q5{ek`j?qycPo}9z7V+dRqazYMldu{JEwb^=7!ubqy>*y8P2jZ#2eK~9 z{>)vi71bSQ^vtvvOWVDNR&)x3=Sxdm<}q3vJTWyPG4zjOm3}SZZ`D!V+xwTby-n=R zx9Y4f79x}MX4m_)OI<_2vesFRHYyCQ%(zL$u_Nx&*kWutdw{BI(Dz)T9r|8g=H&+O z_8Q&I)@uLupt)^p(feL0>>-S%X*WpvvLo)5Hr^btCYW*4al->KTpdd1kD4G@GENdi z(whacKW&gb0wzbLVWu8csrRzL_TE5nSDGZ&#OSD`4{Cx155^l7)Wibwuz7{u8zZ5% zU=ub7?{Wa%<z2vgGXU?+UBG)Q0Pn3`!25mx-uHI_@9hA*w|4>W2LX6L7y;h7G~HBh z@}cdPfS!K~9`z+sm41!iabcew;~3gYZgkKm1~<|4B%5V~p{4^vF`ug!80fGYh)utC zISRAELZ{13hZz7Pp0smlsLWm`kKx<W8znTAoVAQh=I!HOR}C_GtBIT6B!|Pl`>5ur zE~&Dq31K?z$xF___FE}_B0TdAoStU`CzM10V<Z=iu=bNO2(u`e%Ox3VmUIrj`{bLB z-j_5A$Z_bda>I%Rv_HLHWdyvY07Nt9*e96j3m|k0aN@mAuk|%@JhbO}%>_M#tbghr zq8M9P`_mg-MnI0OV}DJJ%#$JGiyhoGncmn?6CrmUoF^S|nvM61`dYfv_>Ci~7UyX6 zjJaxnciY>0^jI5{URpQ;CYpq7XO_dmwJHf?k~mD*r$g5w&2qEXFxAB7ZDBi<UG_4r z95&^va@NOXAeVQgn2fqEm$Cl8#pz2g4jBoH-*Z?nr3w{+xYo0=VN(A_MP&{|M-@u9 zsXmE(*GEJ9+iULOs0e&2g#~2HECnD}vTez7>%wPzmZDFqXSaOkE_%r3x@>qzC$7G- zCPlqoU~>kisuSjJs$|}ytl8+pAA%`BZpI9L$Hn&D#VH+$gB_M>u+D)b>FO`{E}1Ur zHP?gXl$3a`X*!EB9KeYs<Q1Y_C#s=F;ETL4jP0shFngI6{)uC<_Zp9pO8Chxfc-QN z?586DJDfeo7L-<6>bV>N+_=;`pmf^;+ADWti~xcqyms{+nESXDX%yY*9Vum{|3XXb zG=0ra@nhm2H^UnabjS_jH_kJ0NQO>Uhy6iEdO_ACCDTV8e94;zF9;Z6HF$BOT@94k z(BFZk-WFi6X@5-w&t+iGLI+HtqtwX$Zb#C)4cHwH2f+LoVJ1-{ye77K8=>ELOz#w? z_eP3sET%7fgs%FXA+M%{lIpr{jezXY)Hg%F9;><?J&yzUptU*@cUqK%ro(9)Nv39z zwR;-nRZMiS{wy`g@f4{N&M7<1SLMFKv<f)WcS$7zv*KHF7taV2pGa+P+(>8#nt1Yy zE|TW^qv>$GO_{zlZ9*@TeU5#>iXU@ccCbU|aW$y)r<v)$O2m&ZqYwIEbvWq5O}pOO zSc0aI-mm9@w(svlo0YWXY4puG@qW^5P!och!{36<Yg(46<>0Px2OMrE<_EYUb!EsT z_F<b@_{?rEMe@^BW1|ISnrVNDb@{E7^@;ZqpSz4W7T*#ngM?pD!q23`EWY(GQ=hp3 zHL9`7v~MJ{vwov7#8uulja>5CucY^mM;C>6YG})E_V{FEl?%cP1RNzC=N4=+H^1ie zFQ(@xKV_k0Nx0TlNvP0DUa@=l;;q&e^44i#_T9|-fA^>Vs&uVivor7ubJ)n7Tgf%n z!c=&A-B5QSeH$ZhtKJIvCAP7LdNSEY3-Z7{vlpe<zJjtw)AfTq-E|ku^i{QBCoEWL z;}G3P-a~F?8mBlSZG0o7&3qmDckVs;21OPFTxZFSMQkfzNvw2Q<2YMVF=r9qgOc`g zl+T%WL>^b6c3ey3Gx(LFbPC|L$P|nmYr|Ei!QkQshvuQvVWy3KtGz*32Ssb~Zf!k< zRV6D{<-plJ&JBOiUYV%9DGDGajE~kMzrFLuOI!8$RGJRS!#qfEE5Q~}-3L@lK&UIb zHTJi5FZN!?JtM2Z8D<`ik5&fYI+hm<%#OC_I!dD=gL%(J2aCTy1?^78l3t)5tT8Uh z!RuS7_PLVqM{s!FRHCmZDEZ?J)fVw6GL=AQ3>d+QOq6w}D*(+ZU2;7B?yt{@6i>8C z0$c4oZ1$oUj|4nAhY<#}iz2h(4OL`PG=}oCIFim{q0##?ihnI|QM_vnF_&5Y`@#fS z{YxF64X?G&L=pc<gMYKxUH<ZMbP79wADvL$F|*sggxP4@5LUnn3oGo#F*BRa+D2`9 zssJ3FM$N&_WOn8~p`zkG98ED_Y;9}~qPtKDD~fDA_}N`HxK>lqaUc8oWK?T_=#**? z%3k`8UuFlTfvG(V@+aG{3)zw7L9@9P-IkFDh|Xz*L9?gh4o(ES0y8m?1|iRVI%_MD z48h)MuC<2S(b<dyI69M>gJqY_%z|^^#YHp*5Vk6ubF=k#T5Ijn12Z!C=zMAqY1dt3 z2b<e5e!>KcJcSvddbjaFu3#@{LA5|dF&+^-74ji)49RM<nM<9AYbAU&i*E#A6yF^U z@)NnjfnJ0nl^C9Puk*MOKfGC_Bk-a~?_`WJd3-qKq-9Jri*W>66yrK0oHe{dXgJOz z&FstBV-09gZ0n6cxybvNsi(0+&vl%*J~Xx=xuWHNhp+cK58G6YTYb1Mg356vq$s9! zpik%UBzMs8-4;xAdc&Nxa?)Z;t7WsfHovuvMyElnYr>7<KFV09a&xdNZ`b*Gi#gXj zh;S*8D4I0@bMJjhU_gV~){6PmVtLGBIqYpce%R@Rm$nwbD8@Ahp_p>iyDW0g-0sZK ziSp!hUd0*Q*zDjcgY-tBf)t@r=PyYO@YVAvACe}fKP2fKC(>em)T}*?zkX}$%OH`I zK#3w)5AqLl_!$e2+7rXeOb1!R3>ZJ*+Ow-sHaYBsnE?&IcRO2XAl-{l(5?oHPILqW z$bbFa$j#60iY3<a`P2Xx#k%GYJP$s`Kf(Ib`9y9>_nx;So`>3U;5&_8M=$;=9EOo0 zN2gL}v^-yC;w^hSegO*0^ZVn5qM#0<!_UW?E$yjYm_kjUQN(Kxls|uJC_4|=A%ih) z9SeK9N+3khtA<Jg#itJTD5X=Aj&8Mk(r=5DeXrAhELaB_&Pafx6R<R1KG?b3ES5nR zdan!RRelC`)0P`+Yg^6u9BPA&;$M5HylCVMsLd3ypEQ)R+-R?rY(OoDQN-(xl0QJ& zi<4fZ1}I2k<(6{nDPQLGUyUHy)PxtsdnaSO2V5zgtYq@|;6bz6_ZwmDE01slSQO#P z0ba?`_QzP)mh>JBb8f5HeT*B!C8k*5dLw|0;$35y!($)9S4xYW5mFc6IDp{a05Qf$ zcw-#3ua8OomT>mmcpO>%%(GEk<L{qA?2MteF9k`OJ0D|Y%>#9b8wWW)Y@PY9hGD9$ z1QSKA67*{Y4Clwb0=Y5?z_>&5&X8jszT3DfSg++Okim$cqjRV^+)QC6R7I$en=82T z^EjH$<3?kx8F%E41UEW~dSewg+M^#!uVz!DWLpU)ie@F~;%XR$T=LHxwOeeDq^nHr zJBsm0V58VS{h=gGH|5RX{;>De5MBAgE{Ufzjr!xAE6}`gnGXUxVQ5g?<k79D4Kun8 z^~Sjv#a&fHmiMuSjnRL{tIgV|tH0TJx7TcjCFjWSqw}dh=Iezy88^A_><^vklPQg< z!@r!$b~H+KcB72UT#&3h)4&BKT8QGz$}OSUXZf5)fE=Ak{n3iF@e@%bSb;;6Rb2^r z+B3}Yep9pR3KDN*u+gbh4pqtGg>#vcSibg^u%c+zgU?DDNq4t0Vb86Y(!eWq=sbYV zWS_>BI=zU2eHtDhwZEubsk`i<y#BR){Sb;9A4`@+V>Rr(s(=!mel=t*fS~?Q{CrVK z;=<<^%Ofe4;-mt?LGz^+xG1`{hIlKpq6TBKFU>(_oR5AT?N^?k#gsRTWx6@}cW^2@ z9w$1z`eVPAnIrwqYbegymQ+U`ea<wcE4x33&CFWc(K(F>H#(C#W6c;0g|c|J5+j$4 ztTCUbgVgB!434HVc(>7N_g6Z-PH<mFf*YMdy|JbYj_Dk-C*q*NH%3Cy*Q01vf;^MK z$S6~JDmSweB_v7>m9U~{)`NdJh-<xbdLmt0RijD|>JEpAPHu#u?I{%cpznwNHu`<? zJMw%wpXJup1HJyMAe?Ifi(*}4fODDsP+1h`lxC01xnymaQN-(wqnrzhwyg9GDGg&8 zGV@bdX~K&H$xnP$d{T682-X{$NcHSBhY_P_MA*@p)E!SZ+RVjBFq)^N8h-}I%nVfM z#w>|i0HbKv9OR-|U)ceJwUN8;1N#=@5&0RM^k?w?R_g%-ZfqJOj}V>GD5GX~KR>UC zk>}3}SCz%*G$QoqjG#MU*+9#rgwhd}s~hT~JCE_l{JtDF@SwV)&>=p7N^nt>YY(Af z(qNoF#b9hY^Ei%C08!j(0L@N3#R}^vIRIAcvXd0-e%jnZ_Hj^csRS3rwe}EaGbi*O zcAk8ZMdT5#ve<aoj<0GBa8aBsPbnWFyC}Xk<8wjFS5tK+#y={dMbWK0!l}#(FM{K3 zLzDH(U|?}6wJzc&l^`LM!iZv64VTRvWS@mUd$^TS0I-ZxKuwTQq#YHM4x<X3IsYMt zRKewM&)+Gt-s+cPgrdabzr&HD6C7>yxy%lQ<{6eYR+{M?OS%6J#)!^tlyR?A&h3^^ zCmW4uzJ0&ImtM^7<ud9n+Z%D}+~ttbX^)6Tmg~gyAS-Z02MRKVN<dMJYXDb0UC)@0 zBRxOG7`r{Vg6%@Du@c1imCUA>f{o%{bEvE^a!%c-Y@<gvPCGTgRbyN}g!=3ZR|}tP z*gh&PO3!o!q$r~Gpl3I+`jlFAr0RT*0602@+Jj{ekIB@`Q-=koidvjLD#2A_Ts6eF z93J1py64?qOX@odu7S+6(V^q-A4T03^;Weo{V^vvX0p1~Xvv-Ag^`1AMlq;@Mnyf_ zxTWdkMLh3ygNo!v7#BJnalDdJ>#XSnNXt8{VsPZW#_HyfcXq9zhgZZqe>U~VXThn2 z`qIlWb-*?nL*!2fxgj?xYaHzTaRV(~svnN7X9<9FlBv-UgT&3BDW_EZ($q$~8pokJ zx3Lzkt5q{hY13E{+6>wmO&2u=^jHeiG;)Z5JUqsfT^df(WXs~T{|*`uputvfeF85< zSE&@xgi9Z?Bkw~}CvI8{4xD>FI%pY;!;wJGp1YmMF$=sA9XSq#wbeWk+%~Q^8=J|x zyP3O&K!u|oZXvW^-w0E2uoC<35dA`eYkO$yePGALK49f=dcTLpVm050uFAd=C};g~ z#XQoYV!B4)z_OSeRv7dcc6yNzY7JOX9P7ZpSim*!k_xTiaf><qLnTWwGWh6ZY7cp) zFr&~6j@TKLU|$I;ift|M(`A@~aywoD&}0tZd(CjoM@^Vf#OsbzT$=m9mpO8N-x0SA z_dDB-K{&!z2`Y+gP4Jpz-H?-L%FDUB{jr8Ui$|7P?Jw!?L@_yk4KkE7Xa^>*#X!X| ztpomI2K*v8s`ix8><eb@F%X-gU@<?Of_|?vh$22R<mg1|jFw#{qYCC%{Ah}|c-f+u zSHg;7S`YqPW<6y~Lr#*9px<=Jw?Wwq0Qsl#WI6}+lzi0cY&8e5ley!OqB9(2^w%@< zbOx=`RM{M-(mB%nET7?y#)!_Y{<u?_x#iEtL4$wnR7YQrqE-oVQgn0M^^LS+&ugv| zVL>mNLF*--;<PAKn*coUzp)UHFAaNLbg$RODY{2N{xuTl=<I6`$0kzwnHcSYmJ6jt zQBR+;v!QNLrnHX?KRTuQW4>N8C-R6yWI8qCmgHJHZO<*6>P)y6J1oL?G(>c2wTHb@ zF|$y*Q$B<IWM=OqlppQYu*>nH6CMSJDhjGPZ`{d}^ENX0=%li{STZC#hvm=QtyGU- zp_$Woj@rGt1s_Ad6*i1(!Hc3@Z;Z16oNvQwW8YQuHMe~3h{gDJ8@I!UwaFU5qUhEd zU^;;9A~@Ltoc^>R-eP>rV!YUR&}^dtMUXGo1R2G<<}jhX4EsvlzLoLcTJWMs*Bj%l zz-s5Uv^dW_Vb@<ZwD)^auDj!bq7!_|gOmSe&bFnp{6ISCAf?rrWpJR{vn&~$7w6=8 zQ+_Y&NSRZ)T`iY0Phr&P<VV9Kbj<0S2x$wB6_wCzO@LAKYYmd4I<b?M;0src6b<q$ z9X@aOWoc_D9hVErZ7pC?e0MlNhUzS~Zt^808^X5$E{bohAzlldihQzUUeB7eD_u_e zBf^eOr0#ej;mfY3tcHQcZ`a=O{`;G){vhJNtpP2HalH{j2k0YU%EVfpN=S5zv)jxP z^{XbpDB86KQ6JDiP9keM*@mBXJmWA~|HSifM$o;Cj?(=|0HPMKD84lYP!En`>sx<8 zOsP=E94M85s<12rt{$>1mTJ#Yw<9g|!SnL1RF3NU67X_^J&uAxcVyVniPRg<Unn-` zVHKC2Kv0OIXT|*%`tz^!T9HbiN>EW$kJJHwRy;Sl>PF-5%W7w-BLzmaztN7-M-5<A z*p?44=V5ESn(9Bx#CHm(Fx@qAbjBk+JAfXYPQ4Ld3(kiT-8jV`(`}Wxl#u+0praG1 zIUMilfL~TPqWos5{D9&cqnY4~QEV!J`K&ashThpbq*#?KU@cftM62QRLQnr5AlEJe zEZyDgb0x^o_UUrlMc#X_GmJ!3y+@<imb|Xzj}*ra!Tr+XJCd<cbq~y5dml+bH{H>d z9R(<wJLBgQ?_t71a2+$xMwci4{^6|ZX!m1ZiG~t*CpvN&oU?M>Cc6H~p}Q$co)wTD zsUMSWP*6hVw_2;ss5h_%xG0)C8e$%7T5k!-ce9$Z7^As7nk~lLS!Iz9LX09^e-t)J zp-QSN9qE}V<;~Aq%)dq|Qjp|o0gEDCV}O$xY_ALEe)@$4alP4!@Qe}=)tJS>W~a^& z*l)!wX&3vMnRUFi)j?uLoB(QpjN*K}?l9AtHGNmsR24ejTPd_*&;FzV`tD|@KZv7V z6J`|oosGjg5Sc8tAtnnif%K~xjvCzG>$IDX*P7wdmMrE`h*8YzjgmdvH$g3|@aA0r zTyLjFTYA3zpwkPNcGmzEMYaZbrsg^RK*hszMT<e`Cpw%kYivByV9EW>Ag`zmIEwuU zgPqFFLROh8ZYkR?#Uh#|ge|R7AW<x90DdKd-3_d26BMj{`w}D^()9k?bA?%vbO)Di z-RLzNVRzUFV58XA9O`st2E6M<lNo&4@IdtkkI@4#EJG?l)xoq3eD-`RrVOkuqaOh~ z#rx}g#8C75TWgDr)iAy_0Y>qzHAr?*?jYo*hHS>|Ww1s5eSZ_hd%<H@0V#^6<!hzT zvm#3!jqLEwi<YvI<dDU-9Vs%b1uKegHT<az&8A$g$PWb1;8I2bM3J(*APzK3PON*> zG_8>KYo(-sTi)(`S%*ZUFr#SKABWlly9VU@uY3s?SA&iD?D|e>Ndc4M;NSYmX5-6N zaFO*|=SrAy+-r`*A_<4P=>!bjlJl`xKX0M26>t#YN<dLmYXDaR)U3u&3afh9;ul}h z5*Sg`>cGwJ)D7U)f>yIGT3CJ^Pgpz`n{aI2*lew@NBo;L!A4OZVW_t<G>~<|8H#Yd zuk&;IuA39D-mtx*_2VF|?0CTFY<GY}mSD}S^Rt`E&aPxqmGGj-*B^rwfbO*30gdrK zPBuoPu9V09n8p20XLXg=xdnHlHqht<Y7X>v275nUlFcue4qD!0{iL0bRPB{ES>MH2 z(P@q{e)jk-VVAo2KU>1Crh2Xm@gDc))ona(K&*9xJ5>{CbON;p%F;3e(=A|4Dnro5 zN(Cp&mYOKkS{kme2hpyC7Dc%32wIb7<U@K!ES^W~`sy!1B%>gr$khTn9lLH3y>8fq z&c7Xc5(+#rP8(I%FHXVDoCeKs>gluap**ipZ~-dr8w{sLP06j8rVn8rz!3$|^sl)s zcx0#i614&j2NlE?3)X_GeJbZE*WQl)G>$2Vp7War0ZmD*+a{=!7a-@G`t5)6i>>AZ zy`8);1=ec~(2|Xvll>CLL+*y(h(G)^F0a&EVQH+gTFc&2YKiW7y`Xp4YnU5&CzprY z=xgx!gJHAx_~RCCq#MZ9y>nxX(otd1tKYeu;=;kF2_Vzxc?djNcJG_+d(iepEZ`X6 zw}ke1gD9*!0Hu7;WV$3iq@BPEx7)nOUeHgT{6*4OUvHsoQYb1mBC~ASIg5ACZ$KX= zmD0+LPSB2a${P*ko~?ej({8Qc%3JPwY&ZroI5EFEW_+pB$4#xORmEOBg%>{n1<zuI zR)8%xkgMb3A&2iZzZyRI%Rw_){$NqbAO?(g1+$YiC(61wZ?Wz4j?Aa4hg*D;w%(k6 z_<pmu-D)?syqi_;BM8Ln=k$uqM6#Vp+I0Dv7%tVz0XCHazcAw1C2>^A<s_JvY`Mka zWrM|~Rq$)MQaD*{to547+7NexuQbJW4&imzo1>|jp=(}o;-#M2Z=9KCxiu)oXgYuq zmWTKZ($ygWgitz(z2mU#&CXPUbV=-FClDI}`!SbNhd?A))kmZr0HL|gmDZC@M&jQr zKY1M&)3mT+%}0YL-}G83XAJ|TE;bTSxU(vNs>V#JAaJ;sKp`_?$ZHk_IRp6^`9_NS z*sFFaa8vd6_OPAItfFZ>?h{XzKbG6XL+Bs!go`^4Xm>B-L{CEKz1M`<Wa+`&+pV9n zO&uM*&iQzJ;mJ4MEqIuExI(*`pk1Vjix7PFkJa7cu5lH3Xw#EoXL{^rTL_xBWrKnq zY0Y>D-agb6Kw#K6pS#(Ycw*>T_LddyY@fEgH}tp`swhD*P0QDr4x&E3&CO0P91FdF zD@@rSP9D8-cJON~j6UU-`Rtv}T5FxuyLAEgI;V%C^31;jEr9|<**AecN>Sh`XO1%k zE)kl=-jIRv^AG~x^AKnuVf#_C)&wq3zL8Mi08AF=eY^4G-=M)??706}YC!a|A4*7$ zYj~j2gJzAyxKaqOX%DXs4mA!3B}cM$p^_XIM1>;DCu>%g&!gD3NO8gP3l&?S#6x7H zRk`Aw)}4~a88>(%N!7+m;#hzL<$TF~DUK-V2Pt`sPNCoNQRsFU)UL$fov|exO4=kw zVcO{ed^bC~st=XpUjqeDyV=a__~>)bjNa=Q608u&@8#B?T~dC7Xf`QQ&wrWH5IPL! z{Z$w=aHl%<pqbR!jsFM#v#inE%O+JFIqQvb=Kl5w>O~0m;+WO?!&_ilk71STdhukA z!aBS|13~k+i?ym|8Z(&Y4GdIYav!;Sqn6Yr<o9bpp0V3><nH^mAWzt>aoWJ%yVzFA zVhV{b;$rk+!vup%>)}$5OvVA3a(K<Yi9Q-V@kfUcITewkZX(aW?{WR;gvLeD@|A_X z?+?*%GbXBNlNNZRMS0(n@VD5@(^k)+R8x~p^(S`Ap}cj1{lrqQg9dAm7*D=|(L|ar z(Ri4*&Tax(*`2^tqgJLGa9*F9y4URXP-CSgLWPJvn&XIWohR-Yz7}2NeOR>LdOQ2v z@-Vuw`>;mm$KJ3@`rQ5VZ^YJfJU!+PnSJ+pT%(BWftuqUe(sa9Cm;Jy{<Q4L49rJm zPiA1^N`ctKo*ny@U4Uo*>Q}MHW&&)DdU=5oEU*(#eldbxMrCyiY?Og6DnGPQ^tvn_ z0rI-}v5WY5UH-i>HYfijV{gdcm(#zUt#WRDtGn4~54Te#IhmQim|VY@+?bo2OWwGc zT*gl^US2Tf^WEY0N|S8{7g~+2&W89@PQi|&O|*^w_|sHNxU(~!T6E%ID1-IvpQox` zA8-=rThuyX8v-V+tt6ebnKx&ziV$^F+LHzk)ujzbT*7l5T>RJ+SQJ0}o|l_<@s0Mv z;wNkPrX`9NAtwc;XAYk&;(30{@j6!glXnmrzadT`Y#5#fKgGYC$r|>Myr6~O$$Q#> z#=Yb-1MCzpmk7;@?}Sv~ZLAgj0tvny3e9l_4^tTQc(IuoS4%Bdx|!9VX2#^x4nu@j zle4fkK0%;$e(ZX3CdG+QB*HhD)T-3YPdG2~y9JEYm6af+n*AefvKqFyE<VM)iuW00 z;dOwCtPWd?(UK*u`Ux)z<oBG3k1tjX_$sD86!qyPxFb$Og~XrG-QHaXmOMYSuyjw% z=xTFG70uY3IkV5)xY48;g<#^USTK5iI`{}KG}XOCKy-VZFPej--`s+kL;o=JJJomR zl12CAgVq}U=nNC|x$kv`&;_4-gAY*dGDu)Qc6$7CZm|iY4L4Px1sIe(Hw;>}C2*ZV zX29RD-r5-A@uV?Ky7<|En+b~LDjX8cq(8)ySCR{}pIn*0egPOXk}kTux8MVR057=U zzSbN*n(cPrBIzeHc#}>7n6j@X-R95?11%Hm0&fkI)y+=p(Ohx?@cbt*9wrJjpwXgQ zb$y*p<uE_mp;$TmH8)KTTE+;*{=2c8vdMZY3GI7s%5q9VhLmU+>t%f0R%4=?V`Yw7 zmMxG$@*5su!n}+3$h!E69t8tONk@-1353~x>U!gQKJn2X&I9HO#IC{Jvf6>;?`umH zSV_<Yw{@$L7@|pyV7HCUN2^<UKYHo<ye@e2;N=N>#<F|P^vwd(p9T*%{C?P`Z-j2U zWQP3yV)AA!mj4b88gIZf4U<yO3)V2tgjGxxR@WS+v2%)zQCS+p0sAZwE04@8spUP( zEW?L6b%sHy(-vlAlSRxx4;HVN4PNl%Jo#n=tz%@Bc*0X6u0(1E@`EI$e4Wt`-)Nst zd5%Bm<WjE%-v~5JnSA4sy5vg<VKF!gg96HxmFIpU?sw&K+@u+hv*N{`ck0L7^1PTY zJ4_IcfGg`!Gx;Q$*#vf9)33Qztromj3$dRT5M%BqMPN%rfsfQn0i=GK%z$qWTB~(X zqJCsF1`ZNE{FV$(i2e%Bl{v4KTR$bPZRIMuxIIsMMYswa8LNoOHPty!8~ti|&}(&> zZaL`mJQeFTPqpy{CKVaRim7l&Yd(*HPv4*j5DB#bxk9Tsb^D4MRyE}5OdN!I%1X*$ zox=Y7LbJaLgk=y>o~xi9#tyWBY9R!4yWIy>;ochh1Z#mB7bhi3rtD@NUhIGjTKy4# zlv~_Yv)Lz!v(B%*XZ}HRmBev8v!7nf=`v<-LMW=KQM`zqjc?eYtH46-^iEKV2LFLq z7p{C5iV)k%Afm&KN{3NEqy{$2*ElwVjugBUwBGWYxCO$AP&G=|VFpPk6xh@hi$ZrD z+$kTwm|AEm88h5q^q<l(PQ@tLuINFJeoH}RrCI`Qfu2xR(M6H8Aonh`I&0!skFMpU zoB^}vqHNgL4=yko>w>CLAk%5+QQZ})B&$9{1(}TAZOl;@`T@=KE4D^2sCHXzj3rMK zv*=C{GIpEcj(VHI4qnQ$h@+1;)q3hw8dGtS_{E#+>&?{x0{IvtA?Y)UWkQY71)3~a zk8VLGZW-OZoJvb#QPFW#N#*1?O;siP5M|afwTrj^*09g8dnx6e^EkimFTKzH!O18P z?+T}{y&I!M&!RIPfu~1djKi+J2_??$(cZ<I3l)@FO9DiPd=CRgoPIdjY9aXNJ}Y-a zo^j{Zr-cUd&+`{rV@iZ?6e;F6uxlnu8&p-L<fT+_w~Oz)3u{b+cTqUya;@aGB@nLM zgJa2b@6u*N>nNhHoh=Y4uShT~#2w{hOC$0MT3|&hL(?7%1NG^D$|R(~Jhg^I>G?Vx zrvkeIhkVy>DKt_f<B~4laL+P0Zs|KG;Y?9ml&-EKn>e%#?gy=?O=G?k66Zn(QyJ6Q z3(cg0c1pdtQ5rae!RbGtKI2aDIQ*M*S(NkHiyr-Cj~PV-vwVioIGE<-Z}#N;7o8zR z53(&%PX(9f#enYhF?6QRL-AJbY^*cIvDC{#7f+2*Uy01H4fAJ7^kHg$?u?&$7cmdn zblM21;!X!bjj<+4fLO6a;EEH(k}?_qtm1ON4NWcE;Zo825g+2D9m47aH4!hfa%e>b zHIU_D7i@N0wS)R(a6Pgi<Slfh()sH<jmxy4vmqQ9B2o`vjV(JPQ7?M3=-M5E(7j_| zH*f!-)7iS-kgULptvl&Wk7`3#Y0QE;3?&M=7rsGwEOTyd51QL@Ue4eu40?LG_=S8k z3(w2ByU>6`vpDC)#$%jT&lDOlrz|_+0<^3MO2CY0oRCVBvDZC@bX1I}q>YOe;lX@e z8PhIczY&G~#;##sj>5jYYuIl_VZT`m_9Xm{Twf|GYQQ-&c;5{;H&n<}tn4YIVA`ul zuw%UahrZnnOIZ6B>}@0!u+F6xk@Fl;0cZa+{$v^-DlaYENmwp$7Em@B|4|K^Jp@^; z>X_fpW8!8z8A$%Bh`9<pkHY+05uXh$o;7bD#&7n!Fl}nBKii*B17g^R?i43FY`R<p z9w*bRa<*0quKc_9>Xr&f<6sfLp}}KUcmI3PztX(TikGMGGAGgk>$9Fn3uwY!z*1{_ z=%q+CW(#BgA_bnN=T{(eMpEq_0U5S-CJ$!7kGeio4-4?<VyC?^WI$)T@u;<}7hhCB zJ|*5No)n%LJux}c-^-7vG1pg8!p@WXheGU(Yi7Y81^5lrosUB9^q_cpyo=}ArFedc z(IN^Gx&dmS%^o#0j=AA3m(5ccHDjaJ8JLtL3!ZI4q}+CJjxWLc`JmMw<{W|*+jJ7C z>O)}|>V~F60>KSC->G{~zF9}~q}j$fT?K1GoU4woJ0$)tO&W7Zj^EeRuR3hww0Mnl zswM}Vb|G@AEp`X*GbhERe^pF&5=sJtwd<mFP{?~UuAtT~;1XToZ8i4xXr3f3V&m)} zL?3+(C=B}>=i((yS}k!eT4SNUWE_r{jC-DhxZc`IR-gRWsj)Pf(Q1%(*W41dhBxtO zu-C=x_T8v_jck|a%H||kWX6q8iBpV?nsrHf#RV43-bGUy5Q8yQx+W*mxD{6d5#hDr zs^P;ict@e>W^y|%F4^*q$U;_~nB##HQ?^9RH$tkQMPd&lFy$|Z>&U+F+?L)f6PxdZ zGgR$6`_xP=8>UjDUMgtRXERF%C&Cx7<h4|335ti%;cfx~Q=xzW=kT4(!1r-y;zDQj zORo%SRCDy?%|~5!5+W@bs{uw`t+CD(EUAwANFZCSHf49>m@E^rCg`Xhv{E&)azY~- z6BFcao-I<R5F`K246xTC37ST%r>!c%IOY8Ca9O|(-|o6B!aVp_EcgV=r3wR$P%U^d zMO4nWcJd~5?q2esgC7buX{}1bgFNUGw|4%~1uz?$!xYyPvaS|NG10X9{6f%t4mn6) zacR$);s|8(RxQWto>VZ)kR3cWs8^BUrQCB!o57i%^_8HKGTN}2RCANqT`}ryNERwG zY;6-B&5&Abvgh0i3;!Q9+eo~rvA$<5xtSs81E(@A=}-22;>sRSm^$4mDEN`Y-{`wz zwThn$Mv=}L7`oBFC|7xiViadw@-#d}S;6xfLseQ-bISLk{V3H=FErY#J;|I(({>Z& zW%<=PaMw$%PCpULH9=<^jjZM=V<h!8|8nh|-TaH;G}+=)nRM1PMK=FbAeA-$$SYDq zs_AgdDzF8&*fi&LcNXW=LZ{z{I6!3D1@S2xzKiDAy|pEznLWOa;>+ISG|KN~HZ0+& zb;J^QC|VyaE+))!YgzL_YnyIm_AMh5q{^!aeEg|}yh<2M6$Fd2lzL*ZvjGO!+=3Wk z=2Z_xrg~j$4Yasb9fTv9tI)ylE(`w1{U_gSrA|~6gscJZ*|GB$vuDn8abCRNLf`P~ zTae5P@L#t3aQAv5no%{n37A%fAc%c=-~39yvo)**!Lx=v)965I4;ve+6pf2O!n+s~ zyFxo_9Y5*0A&oH9!vlz&u}DtdYciE%oj!8p`wft(Py^xDqhq}*W3kX7JRaHw+wlg- zB}?s$(wXf6OL}B6ezyCl28RFl*i{jNOmw~`zc)!7D7)ofE7+_xD6jmzi+`0-Y0@pz zeaZ5&*01BWWPVE9F7{{(uJPUsh_QkH7y{vXt1xE5tV?8dpK~ORXim}$#-``NzonM% z@?6aU+e?BkfBJK{<mPJE>7QQR9Bgl0ySmwItX;Zxb)~cR_}bO(wY0RD5&Bge_YN=p z1usoj8ptGdSz{8mf0fCg$STu&hF$(v`X&74>!{l3%w4_Iy>|7Ij&Mmv<qn;8$A)1! z+Lg_|cW!<u+cE&D)Y&3R+}NhfrtSrkt;8oOo4L5>v0(h1n`YELzYu?vC2fY6R5C%N zE}sj@Ba|>J@;p8F1GrnDi8JS7yR-J>m;8kWpIQ3;&eraA@ElsU^nhqO8RxoydGa%6 zcXP&}B#qPa-R>5%Hi1+lS%aaFp!Ru4Ia+7aPKv5vto}6M?Xj%!d2uHy$Eu=$TWJhk z;}se}o(10dG+!P!?tRL<(%I4JmyI({Gm%a;o?9f$#H5C5o*7V+i=3*^I^->+a{=vJ z;97|Ts0skH+e>!G9?|CoB#KLMO|aHvS3y1v<yx7!YGQ839ij&X>Us-_ptZ35RFsIF zoh^!(0hkY!jlk)$Grbl&Bk(?h=~Nw(I+Xd*E~Y^atVE{HM2|t(DO`<BLC#RcDX%ku zKib6vSR=yoz?3qkaF^}HJF$ttAJ=R*P=T=f$vpGl?rJhrrI?N#m<FWa1P%e8ki!q@ z$?1NCiBkuqr%)F{JKv;M5uRYAfF4WZ0r1%gO&=G5(%l!QJW6UNAVPS-BD)y6cUais z*i={(&=IrIX+mS33^ip$rT}vukiN!WtXc@cp)iX<(&I-RoVX~oP##W}eP(eFML7O_ zlthHBR?x@9B81$7Mz6&@7}UoMTdZ5*Z%j8G4qD9om9MT$%qHhsYp8Zfv$h$F7oCD7 z_vDI@P;f6nS<wi6!WTqu<U5`16?#ypMv6a~$U(do-vF2CU<ACQa)FY7!lCK<5LI#B z-JDK(f=H&1L?L{D4UMyz=;@Re5xwSvr*JyQKHJ6Vq?xq}YSY}+vZ?%GjEZ1MZKKuB z)0oL8yO;?Bas%NOWwZEEY!>i&k}k{DyE=@Y*TzwR8ue8R|4h0ynR<frtu7bZcv<bs zITl}97#h_MUXv%^thMO=LHH}xJnP_MbRVi(PNg_-3r()*H>jmhoR0EI2XVh1#9Hu5 zyr5O5mKXIjaoSk+q?M`sX-=a<=iqJJ_k)$X*L+Y5rI}Pk)Xh=$95fiM`tY4>D=%<E zX9LvPm=SV!s}`l0jr+V`k5Ov@7(w)D)-B}$I5uhL)T5QNpcVBRQ3qpABrRck7VPpJ zH&9Uu$<*?7u=G01b`J8@7#4RuiS0=}pUxTWp<t-B2CUiOIpO)Vinzu2;1Voqn0izX z>tK3OEGtTK={t@!m___6lJ{&!IkE(g8B<OnQ(1mmZ>0R1*BR*`YP#C1tu6}eYK>w{ zR6TZjP^f273oAb=-xbF}vO<R&T>rQt2us+fnF_~St+B(|Kl=gK)p1#uQ^+~-%)gUl zI(l%(jemnZW`-Jf+EljQhQ>xej=KL<7u6>itKWtmO3H8^S^ci4r(Q}k3f2Cg?#VGt z-7G0UbGLpi`mWOumEs81_@)%w5@sZDn|Piu^#t(!Ieh+Ux--{>q8S9>_ta1)EG~K6 zlQGt|P!s0~o(2>atecrDd^%lB4GvWx?*7O4sl|QMsDS;!*jr=Ym$$bNiqe*sM&k|A z2_T#w`(tn9Kfx!=rPk|B*+fBMa%Y%xLSHnqH8E3rZvOhC&JdaZo#6x2{gR)w+AX-n zS6c|nr4<1rxqiR1+7j<UpXz4+(gTqH5I$-V`}FeU{b+D<wUN8S(&|BTF1h)L^b2M< zp|I$7L5(6hyG%dmYz-RI3~;~^qi~byH-7Ne_ov~BCDEe;Tq8OE$MW2tum(Kgw^qNk z@?);fp+A>n*jl3>Qza&!{9-5C!#>#?uLVh>El4JvEAW1Lo+YM!Sf3Zm<^0%XyF24} z56b%a%bZ#4<+DimN)tl>hW;*YvSFA`ARRZ|6q$Z5{Tx*^ohc%918y+SL-|gQQTgqp zsEDy61P_dgF1p%@1zQ@Y#piZH=jXo|_Nk3ws|#JE`mJQ8*++U7XIqU`bpxM6^RAzr zNV006|2gEOA2y~f$@5BHbPp49%{O`C$p>j=^LyoM^q{A8t@w`3EGWyFeQv_hTpW!@ z7`V=w)`cSvHCu?r8g}vi$vnC^p#3lFO~sRn<ncA!Iz{mcH41x%E{w1^r9DIYLZgeL z(rESjcn7Bj)?<g|{ETlP%LZ9T5SB1X<sgc!Dd(qpiI{}NJ?G>Xu?YTs@e}jIRZ>?+ zuZrI>us>j=TN=G?H6G(a)fW88@Xv#rtaOkq_9%I{2^TYHC_P09Dt^FCWZ-?Eo{{mG z82b<tqU>>Y#B<jhB4w**aY)N*@xGr4ykD}4wZCvBjA#Fku^(e}(gdZDp(3TecpQe` zI9hQbcy5l9FUD$O?i_I><<jqxeO@(A9$iu(BV~#Oe{!5Wo0-FBDkl}|n{pQDcGH#2 zYYa*<YV!Bxlu<VFUCnx526jvn;rY|kWSUPI*+nTzXFksqpI{`2(Y*h+x$Ak3>p0F} zM1dqk!z2vKl*qE4Xf3#e34koCQYs3TLPCTk84zg_#i+{VaxJh6U}XRc?^}WtUAiZ_ z=a%Fet8&#XM;vp{)raVB&`F1UU-#>odB5L6s+7f|xWK+Q)6>(_zq^OgtY6FT8QUTT z{mD~O<?oj9%|4!dg7rJiT4G81`v@9=Y8^)2WpbBHFD){(0S@b;G~z}4n});&(p)=X zAXZfuQVi%iy$)kLLcT*i-6XajO+9()r6UY!U!UTbIN%eOajlv{R&Sv$r*6_Oq}`J0 zr24MHWfVln>-8zlnB`^Ebd5e`$Bdhu`nQ$c4i$%lZzVY&77wz9($e}>m4chmK<f4n z7^7hz8@@24#KXR4cNa++5vjHqZBVCSYZx|pIpUMraAq{@bkS5MW_aolcW|*$FW6#- zxzX|B^5$^qJ!y16Ujaco;yCI*c;TW$GBYB?l%mVM{r3{5!txS6)6Q|~$ju1)PYec3 z7W_gua2K^vNN<!O$g|N~1?^t(VRMLZ5$c?okicYJJihmIbo@0Fl~X=MLIl~#-rI<* z{TT|>LbtbIPR1{80`5K<_zdY`M1&rz?U@!O6H$8-A(7~B9Uu=qdc-R^z9<;08lsj3 zPRter)jT_%Wcr(?@YN4BMy){oVAQZg&Iuc|JZsH*0#O@DPh3FzUS_lr!4!cFr3d{G z<S2fi)2v2lrUj+7KRftNfH>G*l{8%;P-zC09J^+du-G{*=uab8MS_U+*sCnOS%(w6 zC%GZ@167v@*S>%50=QG!$FdJg>#yK!Y}I8BF-ly@B}#*IbcH-U&qE7*rqJV;!S^(r z&j`+YVyT5e!Y@)$3UW@{x{!l1D6j7?C;!soqnb^btYfI`2zhtNg^Ne<9$y_}12C$z zFM^|ZjBKbaghu6^h2Xd{>JRA%P%M%+zdE0$pd)^g$S4mPBSqdv+@AQ=#0`;Olr{b- z+r<!{)N6L(#h}$)ysETUzX$@Z<bjN!t7=dDA~!#+`;*O2`AvLTh(sZ%a^CtC`;`{2 z%``97|8(SRE?fGU;&Jp`a1<MZ`%U^uN7U-xUcg)3nlYNM&O@~TSS+%r5Rzg}5?d@@ z0ku?hrVl`IG5nL^+!}+_c|%XDUy173+HS+l^!hVP{gKxZj62%_cpNoq)#p_&wf!nz zpEjS|!hChSVw{t0^~oHU?g6GuD5lc9ffYW~<eR`(%!l$^BRzxh(0<7rtiI$~=;BYv zZE2$rdupT54&k?H?yDS`PmvGk|H)U_DAHo`tN7V2bSYkC9)bnT{M4P7ao{j0!daQj zya8%j$Dak*p8BUbETnup|KA@Lo8RCeY;~}ZGHGop6jXW0g^JR)v%AJiGW>b;`&Bn% zQ(9B|IgJ(Nj}{>ztW9Ujo)kSBnn+H~Vf@*aKu6F{OgTLLzYk#+B+;asiG5I#w$SyL z??iW&pCYkxum4`_&(K$qzw`wx7<`hNn<Rl@c?sX^GmHT72}u;P1c%`J5knDt03X;x zB0qv<=I|l<j$v-`+95_{@wBE!1OrOqVestU^)TN%YX9m+;zXt)%8vFivMA7x=t$hz z;u8x-OQQARcpa$us1dXVZtY);HK1iOa728TYYkwnNfjuad<6(V<u|jg`9|`QPr=rZ zyzu~70bW3r-kF1<!Q`2RewU9~3orMabFb&Hs;^15iA>NW`y_x29m9|MFk=^V9HgTZ zf$3~}Snt8h2XG74yqKif1TV=7wnlmK$}KH<@~|`7B~VBS#uZFNN!gP*f}~$n2r`&I z?i}^HY2rtb>ae%dk3r|^3~=v>Y2QICgoITz$U^TaVbeoYKTfy1u)e<VIsPjg>}fpC zU>t_Sb-UTYMkom2NV_=ubjFmfFZ*IS2I0R*aCH1t(OdalGG35-aS42?nWZ~cxlFCe zIl<0EqP7{Uoj^MyR6I8WX3E|ULi1<j{iczd*}#=dr!23u@DZVl)+^L}a1Dbb*8GL; zSTkGm9*3Vk5g*g{a5+d|#bNIBlcY^cJ=$L_YS9oZ{Jc-_Z;DBl?$fDCr9%}tkH;x% z$kBAL`P8;#y~&nwNw2MsAzqPCq{szS$9cag!h>?XK|NO9f&YVgD}Bc7WMJ{~Y}o)~ zTHiuLGC%zLZVP^%>Kl}JK4pWQ-}Zfyc2Fr~an28V=tA5ZO1Sd{RL*Z@cvFhZRjzJ( zHWgD9oAgCzOpL!Yk(z<uCgNa}=N2+C<(6{)_)9oF7sSOIAOF`d;xh2l-T?9M*tKZ# zS!3yCwp+JvMDI^ESZrHz3aF!LYkMxm;vMvmu<S#2+<`W;GJrCot=i$Qg#;9S@n$|w zy9Ob_c;L$JU;wADAom}V_y)@|)t8{NrK2AHVh`PCTC{AK8+suxSguj;IV2U5P`TR1 zP<(>1Se8Len@n&YtcPA3ZaJ%i%tE6@%DFYW!=fkt%7^F^Dr6m80hZ)bwSf?N$dT?t zB~bc0zfq2x$B@2?nV-StGIm9rXxj|NS;SN2@IQ@epMzvlOu$t)8vk|klDZXX26c$j z9|vvOEJ~_*K2ld_r-k0t_09pZuoU!%F3*m!c1s_+4~M{^7?R{lJ_t<*15Ho!T5HI; z_@2-<Xa^w*=}BkuQ<6G*&kqN~Byn;KNaurDmjJ^(K&GYUbbl7ZaK*#Wi_o41xo1m~ zq>%WS8z6}F@bvA`zV>yVllRd&Q2XdK7$Za&g?0|LjzTV=yTD11(=?E9Dceks8z9ky z`emGAy9gdSE<tZLQQDxi<^k8E&bvhH;Drm%CMku-^qTNhCOBD`(Rj0l{+e*-MZB%7 zD9xY<ji*;aNk-|zpZTMkeuFL;VPAO5lGME5`p=K{a5*Qq7<AL)uRcR9Uy`K&!)GX! zYL<=Ex_yl`pmC3iKc%eWJN(JS++u{hslDC{l^=N5Wh${$ka0=rxs!Y!A0kevcPwIB z7|2kOX}-!i!wkl3xXY0U(E4qj_*xVamRHe}#4I}=Ga`=Mbsn+t7#^%0h{1R9=OMm- zj&FGjcK*pjpo}pPzV#XCKK#t$GW});Z!)=uPi+c6*UvmD`^h|aF$2$F=;z>uC`_KK z?|#H%j?gCL99s0#`bOR5{9=5xbK~82lP@>>qy5eye|>nc6U{GvcBudF@t++O>&`E3 zq9eup;`76Oyd_~@j+5{)4k*&00X9Fup(!}=fSb&gIOVMs#Gm;C$%w<Oo_(k^?1GrC z>Av+5uNIN6$+U`$ZP0j!pT!`Jj6yV7qyfCk6aRy~*aifOUE6u@%W4AMjTCecc|!<- z?*rBg$SEa3OCzD;W9QO|TA)rjQ=TJbQ!q@4A=gTucpX(!B*HYQU#{utlF)m^NWC3- zskp&a6%2yAgUCZCnNJO{zUr1|`a`%RQU)vh)0nsXFh&?v&slVGWKKX;^@a=qYQ0=s z!)z^0Szt0(Q|Q_O168d~Gt?~JV5szQ=GirJoCH0gme&9mA14(jUP0$6$!eLpVj}`Z z6SO0OXZCSmmt7+~an#%2<jp~HZ5@l40wydLY6Ix1W5o>yI8mGB2IF1;qe;m&M-1q6 zn`FCE<7_b0EOORzLeC9%_E8Tch0?Buqj}wgRW{}0qH}?cYa+Da_?H9fOxc$X;)~w8 z#E$b^HXQnEByCoT9T9=F-~WchrCauHq1<vp@Q0I-4Y66-O}hbEPQ%<2KNHwN=)gFq zH!CLYiUtF%!QiLNW#;^M;GSwZo6@Rs&-gGkj8Iig^PMo`{Y_|Y%noD1yNC#p1*U?5 zw41Wqv!V@$EjdoNZfjGHSM%oRlYURzd8b}$F_8=2UPe`1rt5I<EQTX>53M33J1%BM zYooDm0b`67u@ZrJQ!F?u6u)VU{&Ik4sH}T^ENB-FHFtmu;2?|I9cZ$DiA9I1TGC>} zX;l#UNw0WgIGmJKvJK|cfS)Rx%@_K5IH#nCH(usV@!DyDc{y&gi+rtU!X`^R#RPZm zlC>~nPUr{8iFhnLn$b`1f~AV29+tkuu6ZWHhC2M&XVj8Hn0-LA@HRS5-@?Bw{54JT z*Z7_>=u8J2u+q>eN0p3yDd`xcc~5wGGWQc-3)wRBfT??M{;)nJ%!>`-ByOokeJ4yk zpY!XTc>j{hi0{B9#ES!&GP$Q6blF6SeRhuUE2ufps}SP5ed|`MMdJ>Ml*w~iJl(q) zsv4oa=QK0b%6MT@yxqb5gj6Nbb(jv>WT-`P3RWDKQ*8a0-PiEk5>IA^(?_eB8`Q4S zSPBX(@Lgz&gyy;Br)fWc#K$MQoF4Ba`x;g%F@KJ$Qk9<8k>B4u?9?zq10UTCoIw27 z)UIOZ5`ILkZCHloguWiCFH43mRc2I2z<$xXcfYksJE#Aj&4qF7`4W5MNt@{eDe07P zuZI5&sn7>-^^qWVEq<=#iTgCg`CCCx$RkM8g`Hs4#q~_m`Bq)(^hN-LoeJU`btJvv z@qb8;W)&1^*~9K<=4c|1qOn%C{HSDRHa`?WM8&0Q>M3jI9heg5l7`+IlBs%oI)y$T z)k$|9s~Vx58o{&B><0L;k&P=IzJ;O<!}XwQl|vC%u9y_qXE-EOROW1YiQ*^4`&(== zsCykTs8p}Y%p;D|5iesw^YNsZO(qTw_iNc!<fsXh$?Di9PS!eD4B6a?W<y~k8lN|w z?QNJV-(WVHu54K*m*n8neStv_)li=JBaRlI3t5<7<pH7;Xlsnp1GF9Q)e46n=rCVH z=tdomfsDgx4)(b2P^FbRE^r8D_E$ki)oE_~sVQ`=QJ^qyOb-ui!&4oqTg|5rI<}Tf zFG^qC>aS*0+G30Kr=i6<#?oF7ghVDt>7?ML?AVRqK0on0JM9y{cVkWdj>q};b&Jlu zyiLkw{mfun>hF-cfKuGRG>JOhF3R(y8jl5f+Joj<zdPFHJIpJHqkbIi@PbeXxDf=M zj3ik=y=Rd;O8cfEh|Aa)Y8lxWwmKcDdo%Er&h=z{HaXxmhmY4*%#jbWwCtYf8hrmm z(OY@zEq-Xduq`qxvDQyd1dV4V8(=2X!>J>;@tKvP61sMfUN3~y_nMB{Xd8rB^muT8 ziCL&+YDkVOP8k}rRL#yN+grmo3gJ-LxiUX8L5(bXH?HZcUgzUJ+{elo`K3ibJzlfR z^;%YHDX`050>b}>z;TFw*b=^-w4-mwHxNI<J=gqj2cEAUejFjpvoCiaA6%!K8BLT% zXy?OfGz6H$DnRuZE=OmImv|K}{9_-@BX-shhzdH&&L_JOV%w^Oxi^d{s0}b8w#Ine zt>#K@HAq^-t<6|Y1z<E(m@3NyXE!*&SahSF(W{9h{iJwl#UuCv_hbaAZ!aEU2D%l= zRLxZ$6hHqfsMbSth3&B_V91Z)=MP4xfPszHw6N6c>@ThMrDtm~)Kg##$<cAxdU=(7 zxp+{E-=XuIY^;mFEHpQ>KZfc?v)<2rkpx6LSFepgAgz4V;vMifEZIX1a0`<w9>L?V zWDkQ8@;l(?4|X8Chm|Av`GXO%dl-zsf<VvAm_jYL0lVFqwyQaqb(`DTV4&JegJ5@q z*WLm%^Z`b5acF^=8cH~29vXd<$-qw$J<M!xFznlPM1uoEqEh~mbS7}qT-A|idBO-t zu7i-PNb)olOgcBQ0{VV}vH>4%Br~_b^A@H%3Y?3xtC|xVM=Ot?Fr2#;ABn^&MpeTr zONw9Kb}ljxTj+oa-6WPrV=4vdL!*kCRR66DvF4mm4u$CeZ$5-7G5)>lNB|i2N63xM zvfBWy&mHL5dIjztuSe2ms`RE%deZln)^zwA?`sQ}s&a(y=tiZg=-p!eK8y#$_D8ug zeG*7h#;q(&>_y@9KI9p4<iLJRajIBS7fVvrtcJG%@Ml;cxgQk|zN1A|G&{I2>RQUD z<%}lYbl@}co26nji8%fWk`D5ksUG-%e6THK_-$>$wH>`#ezb~s_-QuADu3l#ipl&5 z3(~Vk;JF)!e>z~NlUq_H<GzaFv~kwx>eJ#nT0#-ZLT&4r{=s%bINEM#TzM+Z*`uWh zdh2KagR27QX{aCDILj@J(VEzDqnv4NFSPbrTU_q!r;mEu7z^%!O!w*;D6XmZgL8kb zoeUv|y?l%h#Q_Zmh3q_4Man$xI}xV@OB!IXhs4iDEXvT7Ht1&)-tJ((e*4zpa~PUP z|HAF$2VM9E2hnX5mVnP`ti@l*T@Kex%%k12dHoE7=`0`SAta4*M_$OhJX~HnUrPGy z%nf;5XhET4mn3hM&(wA^ZQv7mki|30X1VCP`EU~4>m}Xb%V(fJgE%7I)L+3nzMHP; zmYa?FHMS;dAcwf302&wqw&r(j0L;fgr&<PT8_*lfPkK*+R?MXlPOiph%F(`<0uf~; zsKsX&RJ$?M3R>dm(_wGBW<O?d=6KNqCE7z^ZY7}V>AQMUGvZ?p*H&ssn@ofiX;`fz z&dGa&P26i&eXgctmq=-zvhd;vmqb^;ctNslSt*+2ce{C~;b%p<6folMktwH_IdE=@ zoGnnv0{9JoVuGbw0~TT&y1{4JIpgUFRzBKDETKmaTg_HO`knMAY0|%#N8jI8r18v6 zPz0^gDPcd1jX9MYPcwIu5eX*7lF0egs@SmMQ(CL5l*cEu6LILk&pxr0jNzlK>6&Mb zvM$fu#jI4@$sG9GwdD6&J03a2{ddx=U9Ukxp%Gjox<O<glAn(IX{7})j-GY;h=X>* zccxm~FiOGN5~}AGOLbK=)moJ=wB48edaAXTdtSUtQ?0Gs7m2rSs<nP6N^V1uoO6u5 zhF>uS-4(!9@Ao`*DBXV{0%=jzQYNR}UDG6g^@AQ-T<(pcg=iJwHgIuDBDkRXJG+vP zUQWSZ!g>v_Ew!vwp9)Eh^@XJ6D^;tcp$4J>D|3sOvq|};Z$ir_$&wz+M$@^mP;(pO zJv7lpx+%CN(n}8!!h(Bjvp0Iy!&cLOru)=6=*my=9&{Bl_n2|a?H)=2wrbeMz1*Vn z3tR)fRmAwE_$Bxt#bpPqg0&DSK$3%1j`w$v7)GoRTii_Y4PyFU^4WAb!?Qb(?nq4E z*LyfXuZM}gRX!a#EYBIx?*=$?Ki(qls_F4<apsHgc5IDxF$!+swVJ^k?$+9J(4t~$ zkSWNZJ;0H5XTe7M`#K?MlM6d*#MKlqKpu&kaUBj$ul2TTP6*qUIZevFIJu6%wqAx@ zzO;wvf#G|JDaI^yQ!@fJ130ui?f95dl~Q%w^j988mnUS)cD9+w3jz>5s$Rvp21=m9 zXkD|25guLsE>U{iEVB=WI~{oONMcZtwc4hdTxOsNq=kw<D!5fP?z0l-0Je0^`M4uS z+cyx;Ov(05$LjSnKi^xtELK9`()usaF=aJQAFBc5of0tE^NSdZK~p@uStZc}ajh7L z{sFU_p$4FzRW(LeOF&SqdX%_}Ur1s#LE+J4x=C7V^#J|67$7zYM2<NcYt=$@8F~)Y z3bih%gDcVcIgtK{q^PghR8hoW%@WUJFuVK6pUsya)r+rx7lobNNv(ad(5yhSct;u~ zG@h6@$9L&4wH%T~d}gN44`65oT`8YDM%?&Ga$9cnV0$~p&q!+%3AQ4#3ldvpSG<Vi zn?{D2_!P?7&#G(JXwDEy97-5EO1OAReho^HYW6_JWKw3aC3dA_2Uj0UV>J`N;0kov zB(D2vBKG$XYBZ&c<4m(~SMTs+JfM2ev!HQ`Xs`Rfv@tlWdnd`ebgP=wjLYiR*q=JB zCS~1X>1t7b6fTJ>mf8B6^YCeoi83mrQM+P^>+^}6oQIl~4hn>b`iVfLnu>KbsK$V1 zvXe|`fAYMgy=vag$*dOYs(-{Yc~?{j#iIADc6g_lNE+AfkEsAdN*{Bf5x^fq5b?g< z4?3d`I*;mYyEDRogcM|Es8nuy&oT`72V|^PyuBfC(iY4*yyXtXXayNIk|F-apCCz? zZ8ZFYLf6^5b4R|tE0w4c3YbTt%?6Z)HSEBB;DOfFXyP0EB|a!`U9PEvat1~NxI^^e z#`+or`KUkoobX0P^L>b$+IURZ=}#u))zO>yLnb;WVkt!OnYk6}(h`Sh7mfD_`h$%( z7zQD?NsRVj;x`V+m*yV)hER<+ia+|*2~Ov@9<k}hpJN8zF4LHk&2&(o<N6{l@Fe5v zaifeQ>4&$nPl6i`)zTObAv59-BV8yHhRAlnPO=-WRwLY~->Z$mVDDZ>i(jwew9f$v zT1Hw%XFp2lY)*>Dh>$U-Vfn5q(dEQ^0h4HtN7fIb#rX;5Ax$$?)(eUhO@E9A+5K%f zBV#V$RbVKw0&rx$!)c@@zT<WP_YrN6BI${J0<bU3Ayi#DE*$?A(P~aS!CO$@>H1@| zlOpGHFqLxJpLyIzwG0pyr4GTED7y?&rM9pw%97XmJlURm{B$!$?B-C;*x1AKN;u+- zx>(WhuOQ0@+VV*!I19+B^LTiFM0Ow+)6P)aSC0wvc}O<~V(2|Pa<p^N4co^pQ@l6v z1SIsj2s0J5M24M!kp4wYLMJAa*Y<a`9CFMB%sK}s+qY3bp+MFzL_7M!NeLxyL|mO< zA?HOm=g`m@+|W}ih%_KjmQ<Wy8uk#3+UniyBHMqf*A2u^QE17h2UNT`iKgCzAj|dT z-=f{Gs9Y5<oyAKu^S$Oa`P-+1`uFaMf0kyKQZMP4Tc%Zf)RY)+WF<nPPQy)nUnqwp zNh8jyuU8-82IAh3f0taH8$xlwjBauT{4?26gO$AE2dhIvxnq1ri5oq*P$Gcl_(`ja z3XtA$G?u;2b_eKST0Aut+9t~DnbRS@bVn?2=$xn)M_>|BDz^2a?`H>efBYA9zf=Hl q9;D4vO3eFxeVOG5b$DRDbC6NvAUb#a&w;^HGWS10uKwMrQ~w9=w0DXC From 519f2245f613d14dc2a4e128f496982ef1b41a5c Mon Sep 17 00:00:00 2001 From: Laurent Trinques <scorpio@qelectrotech.org> Date: Sat, 26 Sep 2026 07:51:31 +0200 Subject: [PATCH 13/13] macOS: fix arm64 bundle rejection (-10825) on macOS Sequoia The Info.plist template shipped LSMinimumSystemVersion=12.3.0, but the CMake build embedded the host SDK's deployment target (minos 26.0 on recent build machines) into the binary's LC_BUILD_VERSION. Launch Services relies on the binary's minos, not the plist, so it refused to launch the app on macOS < 26 even though it ran fine when invoked directly. - Set CMAKE_OSX_DEPLOYMENT_TARGET=14.0 explicitly in the cmake configure step, matching the real minimum imposed by the Homebrew Qt6 toolchain used for this build. - Sync misc/Info.plist's LSMinimumSystemVersion to 14.0.0, and have MacQetDeploy_arm64_cmake.sh set it via PlistBuddy at bundle install time so it can't drift from the build target again. Reported-by: guillaume.ruivo (forum) --- misc/Info.plist | 2 +- misc/MacQetDeploy_arm64_cmake.sh | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/misc/Info.plist b/misc/Info.plist index 16da6501c..3d138a781 100644 --- a/misc/Info.plist +++ b/misc/Info.plist @@ -62,6 +62,6 @@ <key>NSPrincipalClass</key> <string>NSApplication</string> <key>LSMinimumSystemVersion</key> - <string>12.3.0</string> + <string>14.0.0</string> </dict> </plist> diff --git a/misc/MacQetDeploy_arm64_cmake.sh b/misc/MacQetDeploy_arm64_cmake.sh index e548f24a5..1d247cee7 100644 --- a/misc/MacQetDeploy_arm64_cmake.sh +++ b/misc/MacQetDeploy_arm64_cmake.sh @@ -99,6 +99,7 @@ fi cmake -S . -B "$BUILD_DIR" -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \ -DQT_VERSION_MAJOR=$QT_MAJOR \ -DBUILD_WITH_KF=$BUILD_WITH_KF \ -DBUILD_KF=OFF \ @@ -258,6 +259,7 @@ echo "Install Info.plist and app icon:" cp -R ${current_dir}/misc/Info.plist $BUNDLE/Contents/ cp -R ${current_dir}/ico/mac_icon/*.icns $BUNDLE/Contents/Resources/ /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION r$HEAD" "$BUNDLE/Contents/Info.plist" +/usr/libexec/PlistBuddy -c "Set :LSMinimumSystemVersion 14.0.0" "$BUNDLE/Contents/Info.plist" ### add missing files ############################################### echo