From 8e71d33841ebd233d8e2c14475ca6a88e0f06dd0 Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Sun, 27 Jun 2021 21:19:20 -0500 Subject: [PATCH] Update changelog --- CHANGELOG | 9 + README.md | 22 +- easymacro.py | 639 +++++++++++++++++++++++++++------ files/ZAZFavorites_v0.7.0.oxt | Bin 77498 -> 79181 bytes source/pythonpath/easymacro.py | 639 +++++++++++++++++++++++++++------ 5 files changed, 1069 insertions(+), 240 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 85092b8..5c8a32d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,12 @@ +v 0.7.0 [27-jun-2021] + - Update easymacro.py + + +v 0.6.0 [20-dec-2020] + - Update easymacro.py + - Separate main + + v 0.5.0 [22-nov-2019] - Update easymacro.py diff --git a/README.md b/README.md index fbfcd2a..04c20f7 100644 --- a/README.md +++ b/README.md @@ -5,20 +5,26 @@ Extension for set your favorite files in LibreOffice, with Python, of course. Thanks! -https://gitlab.com/mauriciobaeza/zaz - -### Software libre, no gratis +* https://git.cuates.net/elmau/zaz -This extension have a cost of maintenance of 1 euro every year. +## Free Software, not gratis software + +### If you don't have money, no problem, send me a postcard from your city :) + +#### but, don't make the mistake of many of *thinking only in gratis software* that so much damage has done to **Free Software**. + + +This extension have a cost of maintenance of 1 euros every year. BCH: `qztd3l00xle5tffdqvh2snvadkuau2ml0uqm4n875d` +MONERO: `48ygK6NuuNAfwWfeAbeK8YP2ryPqxMAsUZBnfAhaHVkoHZ48JRYiQKKFd5GFMmaytyUpfxnyA95pWavjRgPUuKv1TUTvhkd` + BTC: `3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV` -PayPal :( donate ATT elmau DOT net +ETH: `0x61a4f614a30ff686445751ed8328b82b77ecfc69` +LTC: `MBcgQ3LQJA4W2wsXknTdm2fxRSysLaBJHS` - -* [Look the wiki](https://gitlab.com/mauriciobaeza/zaz-favorite/wikis/home) -* [Mira la wiki](https://gitlab.com/mauriciobaeza/zaz-favorite/wikis/home_es) +You have others cryptos, welcome too! diff --git a/easymacro.py b/easymacro.py index 5c786e4..42bb52f 100644 --- a/easymacro.py +++ b/easymacro.py @@ -21,6 +21,7 @@ import base64 import csv +import ctypes import datetime import getpass import gettext @@ -49,6 +50,7 @@ from enum import IntEnum from functools import wraps from pathlib import Path from pprint import pprint +from socket import timeout from string import Template from typing import Any, Union from urllib.request import Request, urlopen @@ -82,8 +84,9 @@ from com.sun.star.util import Time, Date, DateTime from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK from com.sun.star.text.TextContentAnchorType import AS_CHARACTER -from com.sun.star.awt import XActionListener +from com.sun.star.lang import Locale from com.sun.star.lang import XEventListener +from com.sun.star.awt import XActionListener from com.sun.star.awt import XMenuListener from com.sun.star.awt import XMouseListener from com.sun.star.awt import XMouseMotionListener @@ -203,6 +206,12 @@ class ConditionOperator(): CO = ConditionOperator +class DataPilotFieldOrientation(): + from com.sun.star.sheet.DataPilotFieldOrientation \ + import HIDDEN, COLUMN, ROW, PAGE, DATA +DPFO = DataPilotFieldOrientation + + OS = platform.system() IS_WIN = OS == 'Windows' IS_MAC = OS == 'Darwin' @@ -290,7 +299,7 @@ def create_instance(name: str, with_context: bool=False, args: Any=None) -> Any: return instance -def get_app_config(node_name, key=''): +def get_app_config(node_name: str, key: str=''): name = 'com.sun.star.configuration.ConfigurationProvider' service = 'com.sun.star.configuration.ConfigurationAccess' cp = create_instance(name, True) @@ -308,6 +317,11 @@ def get_app_config(node_name, key=''): LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale') LANG = LANGUAGE.split('-')[0] +try: + COUNTRY = LANGUAGE.split('-')[1] +except: + COUNTRY = '' +LOCALE = Locale(LANG, COUNTRY, '') NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName') VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion') @@ -337,7 +351,7 @@ def info(*args): return -def save_log(path, data): +def save_log(path: str, data): with open(path, 'a') as f: f.write(f'{str(now())[:19]} -{LOG_NAME}- ') pprint(data, stream=f) @@ -365,13 +379,15 @@ def inspect(obj: Any) -> None: return -def mri(obj): +def mri(obj: Any) -> None: m = create_instance('mytools.Mri') if m is None: msg = 'Extension MRI not found' error(msg) return + if hasattr(obj, 'obj'): + obj = obj.obj m.inspect(obj) return @@ -384,7 +400,7 @@ def run_in_thread(fn): return run -def now(only_time=False): +def now(only_time: bool=False): now = datetime.datetime.now() if only_time: now = now.time() @@ -476,10 +492,10 @@ def json_loads(data): def data_to_dict(data): - if isinstance(data, tuple) and isinstance(data[0], tuple): + if isinstance(data, (tuple, list)) and isinstance(data[0], (tuple, list)): return _array_to_dict(data) - if isinstance(data, tuple) and isinstance(data[0], (PropertyValue, NamedValue)): + if isinstance(data, (tuple, list)) and isinstance(data[0], (PropertyValue, NamedValue)): return _property_to_dict(data) return {} @@ -492,6 +508,8 @@ def _get_dispatch() -> Any: # ~ Used only if not exists in API def call_dispatch(frame: Any, url: str, args: dict={}) -> None: dispatch = _get_dispatch() + if hasattr(frame, 'frame'): + frame = frame.frame opt = dict_to_property(args) dispatch.executeDispatch(frame, url, '', 0, opt) return @@ -538,12 +556,12 @@ def _struct_to_date(value): return d -def _get_url_script(args): +def _get_url_script(args: dict): library = args['library'] - module = '.' name = args['name'] language = args.get('language', 'Python') location = args.get('location', 'user') + module = args.get('module', '.') if language == 'Python': module = '.py$' @@ -557,7 +575,7 @@ def _get_url_script(args): return url -def _call_macro(args): +def _call_macro(args: dict): #~ https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification url = _get_url_script(args) @@ -581,16 +599,19 @@ def call_macro(args, in_thread=False): return result -def run(command, capture=False, split=True): - if not split: - return subprocess.check_output(command, shell=True).decode() - - cmd = shlex.split(command) - result = subprocess.run(cmd, capture_output=capture, text=True, shell=IS_WIN) - if capture: - result = result.stdout +def run(command, capture=False, split=False): + if split: + cmd = shlex.split(command) + result = subprocess.run(cmd, capture_output=capture, text=True, shell=IS_WIN) + if capture: + result = result.stdout + else: + result = result.returncode else: - result = result.returncode + if capture: + result = subprocess.check_output(command, shell=True).decode() + else: + result = subprocess.Popen(command) return result @@ -641,7 +662,7 @@ def stop_timer(name): return -def install_locales(path, domain='base', dir_locales=DIR['locales']): +def install_locales(path: str, domain: str='base', dir_locales=DIR['locales']): path_locales = _P.join(_P(path).path, dir_locales) try: lang = gettext.translation(domain, path_locales, languages=[LANG]) @@ -667,12 +688,13 @@ def sha256(data): result = hashlib.sha256(data.encode()).hexdigest() return result + def sha512(data): result = hashlib.sha512(data.encode()).hexdigest() return result -def get_config(key='', default={}, prefix='conf'): +def get_config(key='', prefix='conf', default={}): name_file = FILE_NAME_CONFIG.format(prefix) values = None path = _P.join(_P.config('UserConfig'), name_file) @@ -697,13 +719,15 @@ def set_config(key, value, prefix='conf'): def start(): global _start + _start = now() info(_start) return -def end(get_seconds=False): +def end(get_seconds: bool=False): global _start + e = now() td = e - _start result = str(td) @@ -723,16 +747,20 @@ def render(template, data): def get_size_screen(): + res = '' if IS_WIN: user32 = ctypes.windll.user32 res = f'{user32.GetSystemMetrics(0)}x{user32.GetSystemMetrics(1)}' else: - args = 'xrandr | grep "*" | cut -d " " -f4' - res = run(args, split=False) + try: + args = 'xrandr | grep "*" | cut -d " " -f4' + res = run(args, split=False) + except Exception as e: + error(e) return res.strip() -def url_open(url, data=None, headers={}, verify=True, get_json=False): +def url_open(url, data=None, headers={}, verify=True, get_json=False, timeout=TIMEOUT): err = '' req = Request(url) for k, v in headers.items(): @@ -742,19 +770,22 @@ def url_open(url, data=None, headers={}, verify=True, get_json=False): if verify: if not data is None and isinstance(data, str): data = data.encode() - response = urlopen(req, data=data) + response = urlopen(req, data=data, timeout=timeout) else: context = ssl._create_unverified_context() - response = urlopen(req, context=context) + response = urlopen(req, data=data, timeout=timeout, context=context) except HTTPError as e: error(e) err = str(e) except URLError as e: error(e.reason) err = str(e.reason) + except timeout: + err = 'timeout' + error(err) else: headers = dict(response.info()) - result = response.read() + result = response.read().decode() if get_json: result = json.loads(result) @@ -1166,6 +1197,9 @@ class LODocument(object): return def to_pdf(self, path: str='', args: dict={}): + """ + https://wiki.documentfoundation.org/Macros/Python_Guide/PDF_export_filter_data + """ path_pdf = path filter_name = '{}_pdf_Export'.format(self.type) filter_data = dict_to_property(args, True) @@ -1520,6 +1554,142 @@ class LOSheetCharts(object): return LOChart(name, self.obj[name], self._sheet.draw_page) +class LOSheetTableField(object): + + def __init__(self, obj): + self._obj = obj + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + @property + def obj(self): + return self._obj + + @property + def name(self): + return self.obj.Name + + @property + def orientation(self): + return self.obj.Orientation + @orientation.setter + def orientation(self, value): + self.obj.Orientation = value + + +# ~ com.sun.star.sheet.DataPilotFieldOrientation.ROW +class LOSheetTable(object): + + def __init__(self, obj): + self._obj = obj + self._source = None + + def __getitem__(self, index): + field = self.obj.DataPilotFields[index] + return LOSheetTableField(field) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + @property + def obj(self): + return self._obj + + @property + def filter(self): + return self.obj.ShowFilterButton + @filter.setter + def filter(self, value): + self.obj.ShowFilterButton = value + + @property + def source(self): + return self._source + @source.setter + def source(self, value): + self._source = value + self.obj.SourceRange = value.range_address + + @property + def rows(self): + return self.obj.RowFields + @rows.setter + def rows(self, values): + if not isinstance(values, tuple): + values = (values,) + for v in values: + with self[v] as f: + f.orientation = DPFO.ROW + @property + def columns(self): + return self.obj.ColumnFields + @columns.setter + def columns(self, values): + if not isinstance(values, tuple): + values = (values,) + for v in values: + with self[v] as f: + f.orientation = DPFO.COLUMN + + @property + def data(self): + return self.obj.DataFields + @data.setter + def data(self, values): + if not isinstance(values, tuple): + values = (values,) + for v in values: + with self[v] as f: + f.orientation = DPFO.DATA + + +class LOSheetTables(object): + + def __init__(self, obj, sheet): + self._obj = obj + self._sheet = sheet + + def __getitem__(self, index): + return LOSheetTable(self.obj[index]) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + def __contains__(self, item): + return item in self.obj + + @property + def obj(self): + return self._obj + + @property + def count(self): + return self.obj.Count + + @property + def names(self): + return self.obj.ElementNames + + def new(self, name, target): + table = self.obj.createDataPilotDescriptor() + self.obj.insertNewByName(name, target.address, table) + return LOSheetTable(self.obj[name]) + + def remove(self, name): + self.obj.removeByName(name) + return + + class LOFormControl(LOBaseObject): EVENTS = { 'action': 'actionPerformed', @@ -2045,6 +2215,10 @@ class LOCalcSheet(object): def charts(self): return LOSheetCharts(self.obj.Charts, self) + @property + def tables(self): + return LOSheetTables(self.obj.DataPilotTables, self) + @property def rows(self): return LOSheetRows(self, self.obj.Rows) @@ -2558,6 +2732,7 @@ class LOCalcRange(object): cell = None if isinstance(value, dict): for k, v in value.items(): + # ~ print(1, 'RENDER', k, v) cell = self._render_value(k, v, key) return cell elif isinstance(value, (list, tuple)): @@ -2569,7 +2744,11 @@ class LOCalcRange(object): search = f'{{{parent}.{key}}}' ranges = self.find_all(search) - for cell in ranges or range(0): + if ranges is None: + return + + # ~ for cell in ranges or range(0): + for cell in ranges: self._set_new_value(cell, search, value) return LOCalcRange(cell) @@ -2718,6 +2897,72 @@ class LOCalcRange(object): self.obj.fillAuto(0, source) return + def _cast(self, t, v): + if not t: + return v + + if t == datetime.date: + nv = datetime.date.fromordinal(int(v) + DATE_OFFSET) + else: + nv = t(v) + return nv + + def get_data(self, types): + values = [ + [self._cast(types[i], v) for i, v in enumerate(row)] + for row in self.data + ] + return values + + +class LOWriterStyles(object): + + def __init__(self, styles): + self._styles = styles + + @property + def names(self): + return {s.DisplayName: s.Name for s in self._styles} + + def __str__(self): + return '\n'.join(tuple(self.names.values())) + + +class LOWriterStylesFamilies(object): + + def __init__(self, styles): + self._styles = styles + + def __getitem__(self, index): + styles = { + 'Character': 'CharacterStyles', + 'Paragraph': 'ParagraphStyles', + 'Page': 'PageStyles', + 'Frame': 'FrameStyles', + 'Numbering': 'NumberingStyles', + 'Table': 'TableStyles', + 'Cell': 'CellStyles', + } + name = styles.get(index, index) + return LOWriterStyles(self._styles[name]) + + def __iter__(self): + self._index = 0 + return self + + def __next__(self): + obj = LOWriterStyles(self._styles[self._index]) + self._index += 1 + return obj + # ~ raise StopIteration + + @property + def names(self): + return self._styles.ElementNames + + def __str__(self): + return '\n'.join(self.names) + class LOWriterPageStyle(LOBaseObject): @@ -2755,18 +3000,23 @@ class LOWriterTextRange(object): self._doc = doc self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph' self._is_table = self.obj.ImplementationName == 'SwXTextTable' + self._is_text = self.obj.ImplementationName == 'SwXTextPortion' + self._parts = [] + if self._is_paragraph: + self._parts = [LOWriterTextRange(p, doc) for p in obj] def __iter__(self): self._index = 0 return self def __next__(self): - for i, p in enumerate(self.obj): - if i == self._index: - obj = LOWriterTextRange(p, self._doc) - self._index += 1 - return obj - raise StopIteration + try: + obj = self._parts[self._index] + except IndexError: + raise StopIteration + + self._index += 1 + return obj @property def obj(self): @@ -2785,11 +3035,37 @@ class LOWriterTextRange(object): @property def value(self): return self.string + @value.setter + def value(self, value): + self.string = value + + @property + def style(self): + s = '' + if self.is_paragraph: + s = self.obj.ParaStyleName + elif self.is_text: + s = self.obj.CharStyleName + return s + @style.setter + def style(self, value): + if self.is_paragraph: + self.obj.ParaStyleName = value + elif self.is_text: + self.obj.CharStyleName = value + + @property + def is_paragraph(self): + return self._is_paragraph @property def is_table(self): return self._is_table + @property + def is_text(self): + return self._is_text + @property def text(self): return self.obj.Text @@ -2802,6 +3078,13 @@ class LOWriterTextRange(object): def dp(self): return self._doc.dp + def delete(self): + cursor = self.cursor + cursor.gotoStartOfParagraph(False) + cursor.gotoNextParagraph(True) + cursor.String = '' + return + def offset(self): cursor = self.cursor.getEnd() return LOWriterTextRange(cursor, self._doc) @@ -2846,25 +3129,26 @@ class LOWriterTextRanges(object): def __init__(self, obj, doc): self._obj = obj self._doc = doc + self._paragraphs = [LOWriterTextRange(p, doc) for p in obj] + + def __len__(self): + return len(self._paragraphs) def __getitem__(self, index): - for i, p in enumerate(self.obj): - if i == index: - obj = LOWriterTextRange(p, self._doc) - break - return obj + return self._paragraphs[index] def __iter__(self): self._index = 0 return self def __next__(self): - for i, p in enumerate(self.obj): - if i == self._index: - obj = LOWriterTextRange(p, self._doc) - self._index += 1 - return obj - raise StopIteration + try: + obj = self._paragraphs[self._index] + except IndexError: + raise StopIteration + + self._index += 1 + return obj @property def obj(self): @@ -2887,10 +3171,17 @@ class LOWriterTextTable(object): @property def data(self): - return self._obj.DataArray + return self.obj.DataArray @data.setter def data(self, values): - self._obj.DataArray = values + self.obj.DataArray = values + + @property + def style(self): + return self.obj.TableTemplateName + @style.setter + def style(self, value): + self.obj.autoFormat(value) class LOWriterTextTables(object): @@ -2920,7 +3211,7 @@ class LOWriter(LODocument): @property def text(self): - return LOWriterTextRange(self.obj.Text, self) + return self.paragraphs @property def paragraphs(self): @@ -2973,6 +3264,10 @@ class LOWriter(LODocument): ps = self.obj.StyleFamilies['PageStyles'] return LOWriterPageStyles(ps) + @property + def styles(self): + return LOWriterStylesFamilies(self.obj.StyleFamilies) + @property def search_descriptor(self): return self.obj.createSearchDescriptor() @@ -3055,6 +3350,13 @@ class LOShape(LOBaseObject): def shape_type(self): return self.obj.ShapeType + @property + def properties(self): + return {} + @properties.setter + def properties(self, values): + _set_properties(self.obj, values) + @property def is_image(self): return self.shape_type == self.IMAGE @@ -3232,19 +3534,21 @@ class LODrawPage(LOBaseObject): def create_instance(self, name): return self.doc.createInstance(name) - def add(self, type_shape, args={}): + def add(self, type_shape, options={}): + args = options.copy() """Insert a shape in page, type shapes: Line Rectangle Ellipse Text + Connector """ index = self.count - w = args.get('Width', 3000) - h = args.get('Height', 3000) - x = args.get('X', 1000) - y = args.get('Y', 1000) - name = args.get('Name', f'{type_shape.lower()}{index}') + w = args.pop('Width', 3000) + h = args.pop('Height', 3000) + x = args.pop('X', 1000) + y = args.pop('Y', 1000) + name = args.pop('Name', f'{type_shape.lower()}{index}') service = f'com.sun.star.drawing.{type_shape}Shape' shape = self.create_instance(service) @@ -3252,6 +3556,10 @@ class LODrawPage(LOBaseObject): shape.Position = Point(x, y) shape.Name = name self.obj.add(shape) + + if args: + _set_properties(shape, args) + return LOShape(self.obj[index], index) def remove(self, shape): @@ -3403,15 +3711,19 @@ class BaseRow: class BaseQuery(object): PY_TYPES = { - 'SQL_LONG': 'getLong', - 'SQL_VARYING': 'getString', - 'SQL_FLOAT': 'getFloat', - 'SQL_BOOLEAN': 'getBoolean', - 'SQL_TYPE_DATE': 'getDate', - 'SQL_TYPE_TIME': 'getTime', - 'SQL_TIMESTAMP': 'getTimestamp', + 'VARCHAR': 'getString', + 'INTEGER': 'getLong', + 'DATE': 'getDate', + # ~ 'SQL_LONG': 'getLong', + # ~ 'SQL_VARYING': 'getString', + # ~ 'SQL_FLOAT': 'getFloat', + # ~ 'SQL_BOOLEAN': 'getBoolean', + # ~ 'SQL_TYPE_DATE': 'getDate', + # ~ 'SQL_TYPE_TIME': 'getTime', + # ~ 'SQL_TIMESTAMP': 'getTimestamp', } - TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP') + # ~ TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP') + TYPES_DATE = ('DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP') def __init__(self, query): self._query = query @@ -3437,6 +3749,7 @@ class BaseQuery(object): def _to_python(self, index): type_field = self._meta.getColumnTypeName(index) + # ~ print('TF', type_field) value = getattr(self._query, self.PY_TYPES[type_field])(index) if type_field in self.TYPES_DATE: value = _struct_to_date(value) @@ -3562,10 +3875,11 @@ class LOBase(object): self._con.getTables().refresh() return - def initialize(self, database_proxy, tables): + def initialize(self, database_proxy, tables=[]): db = FirebirdDatabase(self) database_proxy.initialize(db) - db.create_tables(tables) + if tables: + db.create_tables(tables) return def _validate_sql(self, sql, params): @@ -3676,6 +3990,7 @@ class LODocs(object): return doc def __len__(self): + # ~ len(self._desktop.Components) for i, _ in enumerate(self._desktop.Components): pass return i + 1 @@ -3717,7 +4032,8 @@ class LODocs(object): return _get_class_doc(doc) def connect(self, path): - return LOBase(None, {'path': path}) + db = LOBase(None, {'path': path}) + return db def _add_listeners(events, control, name=''): @@ -4445,6 +4761,13 @@ class UnoText(UnoBaseObject): def value(self, value): self.model.Text = value + @property + def echochar(self): + return chr(self.model.EchoChar) + @echochar.setter + def echochar(self, value): + self.model.EchoChar = ord(value[0]) + def validate(self): return @@ -5285,6 +5608,11 @@ class LODialog(object): self.obj.dispose() return value + def set_values(self, data): + for k, v in data.items(): + self._controls[k].value = v + return + class LOSheets(object): @@ -5771,6 +6099,70 @@ class LOWindow(object): return +class LODBServer(object): + DRIVERS = { + 'mysql': 'mysqlc', + 'mariadb': 'mysqlc', + 'postgres': 'postgresql:postgresql', + } + PORTS = { + 'mysql': 3306, + 'mariadb': 3306, + 'postgres': 5432, + } + + def __init__(self): + self._conn = None + self._error = 'Not connected' + self._type = '' + + def __str__(self): + return f'DB type {self._type}' + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.disconnet() + + @property + def is_connected(self): + return not self._conn is None + + @property + def error(self): + return self._error + + def disconnet(self): + if not self._conn is None: + if not self._conn.isClosed(): + self._conn.close() + self._conn.dispose() + + def connect(self, args): + self._error = '' + self._type = args.get('type', 'postgres') + driver = self.DRIVERS[self._type] + server = args.get('server', 'localhost') + port = args.get('port', self.PORTS[self._type]) + dbname = args.get('dbname', '') + user = args['user'] + password = args['password'] + + data = {'user': user, 'password': password} + url = f'sdbc:{driver}://{server}:{port}/{dbname}' + args = dict_to_property(data) + manager = create_instance('com.sun.star.sdbc.DriverManager') + + try: + self._conn = manager.getConnectionWithInfo(url, args) + except Exception as e: + error(e) + self._error = str(e) + + return self + + def create_window(args): return LOWindow(args) @@ -5832,6 +6224,7 @@ _CB = ClipBoard class Paths(object): FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker' + FOLDER_PICKER = 'com.sun.star.ui.dialogs.FolderPicker' def __init__(self, path=''): if path.startswith('file://'): @@ -5909,15 +6302,17 @@ class Paths(object): @classmethod def config(cls, name='Work'): """ - Return de path name in config + Return path from config http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1util_1_1XPathSettings.html """ path = create_instance('com.sun.star.util.PathSettings') - return cls.to_system(getattr(path, name)) + path = cls.to_system(getattr(path, name)) + return path @classmethod def get(cls, init_dir='', filters: str=''): """ + Get path for save Options: http://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1ui_1_1dialogs_1_1TemplateDescription.html filters: 'xml' or 'txt,xml' """ @@ -5941,7 +6336,7 @@ class Paths(object): @classmethod def get_dir(cls, init_dir=''): - folder_picker = create_instance(cls.FILE_PICKER) + folder_picker = create_instance(cls.FOLDER_PICKER) if not init_dir: init_dir = cls.documents init_dir = cls.to_url(init_dir) @@ -5950,15 +6345,17 @@ class Paths(object): path = '' if folder_picker.execute(): - path = cls.to_system(folder_picker.getDisplayDirectory()) + path = cls.to_system(folder_picker.getDirectory()) return path @classmethod def get_file(cls, init_dir: str='', filters: str='', multiple: bool=False): """ + Get path file + init_folder: folder default open - multiple: True for multiple selected filters: 'xml' or 'xml,txt' + multiple: True for multiple selected """ if not init_dir: init_dir = cls.documents @@ -6056,14 +6453,13 @@ class Paths(object): @classmethod def kill(cls, path): - result = True p = Path(path) - try: if p.is_file(): p.unlink() elif p.is_dir(): shutil.rmtree(path) + result = True except OSError as e: log.error(e) result = False @@ -6094,7 +6490,12 @@ class Paths(object): return paths @classmethod - def walk_dir(cls, path, tree=False): + def walk_dirs(cls, path, tree=False): + """ + Get directories recursively + path: path source + tree: get info in a tuple (ID_FOLDER, ID_PARENT, NAME) + """ folders = [] if tree: i = 0 @@ -6219,6 +6620,50 @@ class Paths(object): _P = Paths +class Dates(object): + + @classmethod + def date(cls, year, month, day): + d = datetime.date(year, month, day) + return d + + +class SpellChecker(object): + + def __init__(self): + service = 'com.sun.star.linguistic2.SpellChecker' + self._spellchecker = create_instance(service, True) + self._locale = LOCALE + + @property + def locale(self): + slocal = f'{self._locale.Language}-{self._locale.Country}' + return slocale + @locale.setter + def locale(self, value): + lang = value.split('-') + self._locale = Locale(lang[0], lang[1], '') + + def is_valid(self, word): + result = self._spellchecker.isValid(word, self._locale, ()) + return result + + def spell(self, word): + result = self._spellchecker.spell(word, self._locale, ()) + if result: + result = result.getAlternatives() + if not isinstance(result, tuple): + result = () + return result + + +def spell(word, locale=''): + sc = SpellChecker() + if locale: + sc.locale = locale + return sc.spell(word) + + def __getattr__(name): if name == 'active': return LODocs().active @@ -6234,6 +6679,8 @@ def __getattr__(name): return Paths if name == 'docs': return LODocs() + if name == 'db': + return LODBServer() if name == 'sheets': return LOSheets() if name == 'cells': @@ -6244,6 +6691,8 @@ def __getattr__(name): return LOShortCuts() if name == 'clipboard': return ClipBoard + if name == 'dates': + return Dates raise AttributeError(f"module '{__name__}' has no attribute '{name}'") @@ -6330,48 +6779,6 @@ def get_fonts(): return device.FontDescriptors -# ~ From request -# ~ https://github.com/psf/requests/blob/master/requests/structures.py#L15 -class CaseInsensitiveDict(MutableMapping): - - def __init__(self, data=None, **kwargs): - self._store = OrderedDict() - if data is None: - data = {} - self.update(data, **kwargs) - - def __setitem__(self, key, value): - # Use the lowercased key for lookups, but store the actual - # key alongside the value. - self._store[key.lower()] = (key, value) - - def __getitem__(self, key): - return self._store[key.lower()][1] - - def __delitem__(self, key): - del self._store[key.lower()] - - def __iter__(self): - return (casedkey for casedkey, mappedvalue in self._store.values()) - - def __len__(self): - return len(self._store) - - def lower_items(self): - """Like iteritems(), but with all lowercase keys.""" - values = ( - (lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items() - ) - return values - - # Copy is required - def copy(self): - return CaseInsensitiveDict(self._store.values()) - - def __repr__(self): - return str(dict(self.items())) - - # ~ https://en.wikipedia.org/wiki/Web_colors def get_color(value): COLORS = { diff --git a/files/ZAZFavorites_v0.7.0.oxt b/files/ZAZFavorites_v0.7.0.oxt index 518ccebbec36422d8c1f94e90357630cb5175262..5525383418f95d3e84d2d67c66f80b1e08c80095 100644 GIT binary patch delta 40222 zcmV(+K;6H(-2~0*1PxG20|XQR000O8K&soZ4T%8*K&sobnE?y~13;?Vv#11@2m?T> z+p|Iq=WYSZvnqVh1r9)}+fq#rBb!^A004{MlL&$zfBSyhMv^f4zn%h{{pOHL7}#d?yEV6O5lisG&d=VWc zqarV(e{3EdWLHIcJeg#p6u=Pp|BlXXvND=v(=>vA7fDe?`6T+E{{O`M`KGEC<>s?z z*I5;hmPwVC@jR`brPEomeD-VdD?rUE z71UBi$$b1QFQQpK&L;O%9$qfz4D@e_~c575MP#=sbFr&eI~9MkmXwX*PmZ zjM90TMhVc1Z_1l=99=OYEV74G36qpLJpmg!_U?NL#H ze~y0GKYM+AeirqQ-b6q2PfzjoS&W?4|d}y8l*^AN*Ee? zcS0is9XL*_B%79^#cyCtOCWDLj&73Me-y@clxDX;ToR4)#eMs*5td|{&#$SW#A;Er zKZ)jf)r(3X?ms2Z-QC^A*YjnZ7uV0GT)KSrHy{K$BnL*lO3L)xujSLIyj4G|`$byH zCm8*-%4Vs2zD}z}QkKSJmA{dfsj9Xt^@ruvqR2<7Cb7I%KdW@Mz}c#vZ;CV-8&sJst%_un zUL~Wq^2M(i7hanb`3weZI!#B&;bkNMjtiKD>3Am_RUS;7T#Y2$;j&7urs-j_SYX`* zI!;H~48~i4?C>LhOXtg({IEZ-e|F)KKTMYMQI+RYMZsN>EK2^iNGco(`Q-#2#fL?a z%`5qypZE)RYGm{U%p~y%rYJC-_;d#Sh%=hM0lygE`t$o$9^H`l)yrx@cjrTRE%fktyZ}e~D&r2!-E` z(gh1MeC#h_vdyb(L;{X6bAQiZ&c-une>_`GtBeG@9J~F)-9!1(1II~aLcWA&4+tlW z33P@N$N)kNb&UXV6gu`yHFDT+g#1xQ{YPY&mk_GSz6G;F02uu zsz&)7q&CQ3S^6j+EJruH({u&}6c+_b!Z;-$H|FI;7yj`~yudl%e~WeiWN(_>A{+Y% zuF^!ylam6bMp4~=pG=of@+g_5WBMH^2x@TC`UN(g_cP~q);{ZHKpm;l-PPd`8 z(5y3%`m+4);mO&XUi5wc;2e7QZ1=~r9xjT9uownVA-}4cfx)Sb;=lMDYA4Qt7;7%_ z>Gn+mqPEgK1}ks>f7NOK2Ck;b;WVs2;%$m(M?{MP3RAXu)Lr4x6gJ@Lj+6{ zEwT>sQ8Ep6stNQXamxWHE4VT@bK8%768b9wAA)>e6*LDe=rOQ|`6CF~%SX#{MOc_V zD?;wWs=Fd6@a>9_KV}&u!v6k)9iYV5>g3+ljmLAS@! z|9!rD3es%*`0%iQw6nHW75AHK5&W?_l%{v7DuN@9i@26vBtZF5{50PFM0oITI85cb zFhng31ov>b#_ytiLQWb6uBRziFYAi7GQ1o?@|Jj>@jAa=cBtS^|7@3vji3E#_Uun@qCdUf{L|s)p9Y;Zq3*}Yczl3JaPjKO zm%FE@f5)f2sPohFufDq2_>ZqQX7olpKA!<)jpcWCU!K3h^6xgTF24F|M$apk-apzq zR)t^8@G(>th9(=q`ZCF`xgWNi>RC10(mmKCYiTm$ci1_E4SGnH1as*Cex^ltIK*xp z4si^mX^7@NKtv#gE7V|@(mc+Qn5r+X3#&talh(}{`$?=fBE*We;t3Fe*M*p@nrns>g#Wz_r}TO z>gxHoCJHa_-Jqc6@K_N`Sr{94>4MS ze^CBlcMl6cU)$b2f<+netex(^dW|n%tgUVL54N!o2$E4}?T6EShUwfD8K?%GwVl)c z5BNMTlDp2@{^7|fn(FWZ+EV~qcGh0@2Sg9fsm>aV$7_6oA-bV&``hAUHo~v_NBlJd z+Romb><)L15#T*dE+l3XXz?_xc(6c|f02Igz;cP=uG6D3OtM=_X(|phHphjlBM*H6b0QwV&k7Xv4Ke_4;O ze(um~S`zg8Q&8Aa`{Tg*TGD44arM0`Yv@I)obhw8&NK{O_fHsKaM%X7?*=!?BHdP2 ze@7SdO2NYdx+WfssE{I>6kq1m!QGF@Ij>+jxyeSyB>Ou|3hLwo1BRQ{QQzE89U*3F z42PJFg<}}aq|&yxumg^chvL`ne}A9%5Aem=kbbU>rb$^wcImG0QLOVaM@4DkD%0XNYtewt=ee*tcE=eqSvn;>=--oXz8-%ynY{SR^YLH) z`r^gLU&eplNWcB|&y&Awj8c?~qNy))bn-Y&ghstQKHVXK#m!WY+{gh;f8K*#7IYs~ zvE$L>79`&!$+zRHbd;o5-=rIVNxuH`w^z@TZ~pS)&wm|#^XEjg04&IieY&VCb=M7D zD8Lvtw4v}wJL?G8;)mDAsA%o%Ztou=f8f#wdJ-%cY&{MSc8_||!Ttc2$nEn1>Ve-Q zi`vLPVb`Ri$v1!5`1-GZfBx$EHK;wWi z-H!M&9KZiN7A z|D0#@E*3*)HY~y?Z_ZvHlitQ#cAYgaaJbbxJT5?-zQd(&e@HV8JMI0$+7O4WB1yeA z*adBMX8^i7E=b=#k3Q%By!d);Xa7{GgP>z3xV&zvU#!D)rsO%I5Ar8zEPvm9qYJ~p zfdac3ZNTC}Uk{IW_V@O8PX`*NyvZgNz!)ydc<_3E?@UxQs*0)e8L(`KuV5(nA72{j(2v4hr37TFZ-lel%y9v12u7Zl@#({(4qm@ zXat%R*cI_|o^PIHqqpb+kzGam6zc04K4G=;Gdic$*Vpi1e!LTmEWc}Sj)X{ILaWcT zv>V0I!Js~V4-e)?u$w{Ns?YoMXacaArvUco(F7nbe@N*7kN~$@NPk-W9K^Jw?TA12&i*=pHv$4U zY-e|`e|~T_#J!FoD&E9g^K0NAJ*anLS%FWqn|E_{1 zWpIeg@!5~~dBE!XVKPsyX%Sjm8>f?K1on274#~X*!_-A3XA}1$d*sO)ju_cybOj=1 ze`_z9qVp~(uFFl_irhMa8rP#Q|Ar5|M!=F`71Zmqr~*hD9L8MlzIgWol#pa21wEvC zor zvx826gZ|O0^FH}Z9Pa3VJrUzxyf7~YP-^k)VB`7GGgRpEoVUq9u|phCUZRRi5DK6L ze%V>Scz&tf>)XfYM`x#RY9Kc*g?HQq?x1gZyHDmaSJ}n#Jqg0frEor;?Vla2+!pB0 z@p4pgYq0+T&-b8)?UTy*I23?^f8Ko03N8B5U40ixe28w}iz*(X_p%>Y{nhXfpRKJ4 z#_l|G>g9;DcsrSnp5cF%7{FKYCj(y!sl`A=bat+ zjHdkXcyDj8iw3)l2EvW*w0qx+X1!><9)oUIjI((%RZ^RIFq=yf^8bV8y z7^hdu>+a_$2}Kdqh@j33kWk%ZonoqRDI-~XsgQEH&QFyv7qHZN06$jy1oTv_9ebJF zrbB@5q5u-&m0-Cp+H=7{rSH(UNoO5r?L^PoNlc#Z?xgb`DVpbZ-Szd0&5gfaK15%> zm;UyLFQbm0*c`k=MD?)Fe>9nGO#;-7l4^9LH>kQ3LDqK^FVq!95E3JbxR-j-=byj5 zGy2ODp@wLgcxALSY8F-`(|OgI#Bx)_`s$c?=HINmzRKTqRiswTx;nPBYe;LG|9C|K zkRgukmR?$9Tc8UR&y)+$xw`q)&!kO|B7qtOlk#iwYhcCd%+o5Se-O_Y0Ahhdj2bis zq<>Pu2m?|SL{~p|j1GoJ-sX$pf3lL;pd&E4vm&dba2BF(c2Blgd{|_fsu_l2>Vl$o zQ6TNUtI|1zd>)?e(|R|-sL+nH-T<__;;cQf$+MOQ7t1*`XUNfe-N{@|X#Ujw{4MjL z$+u903igZ7xFDz|e<1j_CUe#ox1bm^?-rERMM;N2W!2&N%48a-R}hC27x!L=C?`#= zRH|5@b31~Re$a%M9i|beTDctjH^%o}i)G=hsJ+U^$-Q(|iLX{&v49ZpLmD@w81u@$ zg+7bUrrThER3nOPK)@g{r43eJKs-yp3oLng0iQ1=3-d%4f7{EwsLHBox& z5^c)}LyN_~!{fjAF#a$d0*0*)PH4a*x$CpfK8v=A`y+ul!ss|PvZCB(B+B(LNO%q$ zLcfWv>DMpIw792Vh{i;LuGv*Qvl+U8CT-yvKk6{Ly@X6j_REU4uo4UW^fs$P^V*9| zIb&Ec$rnk1f3X=`5(O%lJ8Aj0lF>1Or=WcX5Z9s!>oOYM>uP+&sL?{C0tGBK1 z8!f9;F(8G3;+hm1d&S2XQwT%_*`ybR7~{?EV0eVv{BrO*7AX?t7DXsBDPr)ODUpmF zqC+#H=A(|K5!EsIBhgD-3OOop^clF$UJGC_gy$Oce;bf+w>V?ves>HC$E@rcf)Zs9 zNaAw2Kwot!Z1V1H*h+b8QcdOs$rPl9{OLY9$_l6NX{r1+_{Y2Mp!|cHtNj#mU;W_t z2MPtyUw9Aw;28JI^;@-1esH|cp#l0EZ-O5jWB7}H%RAi%$A_q!nXvoY0yrBribe6w>EU?qS@&LQ& zB47s3rS*HuI_+GHIir^&eyNrkS&>#MOX0GCvFdg%F8%n_*s2!HsYPkEdr?YGz%v*3 z*h*}aXrWxKap-TsVBCyu!5Ac34MHER6-?rjf1TBYGCm>?$8Aj1t%MgNREFc_40K^b zX%|5FG1eb@fNKmAaO-Q3bTCJTV3wCci!`uJ^JH9$&G;y}0e-7S8Kq!=vQmk7uD?rz z-;1VMS*@>=Q^A3OUUk8|#n~AfLClBNSsSt(qQDzXCc*%D|6t0LaaJzSlIhx_M9#Lx zfAx?%zrnXHl z(Ac8>p#Rdhe1QwBCzP};C+m_c_>R>Ke`*1GW_r={9wG~ElLW?703|&O|8aZ61C6#CTu*j$e{;hf z)kaZZ7`!3)WZmU1G0aFLlCW1yhC;${GS+j~ncottl?=y?=?Pi{@$ylSy57`tJN6I) z41I|HO%A24t&LrSQ;>n9rKrG>ln*fct@S%il{7F5{4ILkLIU-M=g?`Vt5;KIJG+t|3P$cD4AGj!UrXk^-j#e}1~?i02Nw2!-p4KjDLTk0(c#XmIj34wH~C(E)wJ z0SrtN#tx8g%z_p#5gIrB1ni6gBQ408h?R^waYwJ=nuIM?o#EV(XgcxY{(p7!Xj{cd z^$nGpd=|gwhlltxlL>TFwglNWBN$EXBn#S2{(AU7WWDfC{Cen^`~V0gN6;!g!*kz0H~hP!EEtY@R1)yr zGZ|4!wV>YcYMG7GXMD^9tU~>3xQ9#IU0%E$o}cay2a9x+O+=5F9TH+v<_7#_@dEw= zPC)l30o3iuiJ;tt*uaYqf0GhyE2d2D>Io+V_tS(Q0*(h!1rsEWwrojw;XtqvcRQVR z+VbV*K+ELZ6o$T_E}P%xZ&ThKCCSVGrEMnPnpe(lYxq!K7p_9fj8b)35?z9><~lT3 zMfeb{om?tzxex8VT}6V+asgL`c71k7tabLFr3-*a<)$}nu32q_e-_b8W7~6vl9&!w zi_JKJZQZ9zAEl0|+L^9$m@livvf2`ly$CnP$p`{6Zqn&=i(U54jwu1Vo&-@F|A5{a z8=)>@4=j&9P?ThTDx$J`oHIpc9U;z+m^s520s(8iC|&!M4R zSYV9S+HXO8AAVe%YU?Vswq-znWZ}uvC*7NrF3>)ZU0>QaX;~7)f8f)xOu@MPR#+#JX{@4NjYc_ZA#mu<7Y5lYk_jCyv5nKI{mrjK91k3d zFjZ@xI>%E`A`*xWPxUZnO@eOi?4Mq!@YYM|g@p1F0#~pT-X9;H5a#um_qh!;ffyV* zUcDuAh{SYoe#+t2OjFOQrl)k%a*MZ+)-6=AXrm#Ze}{mcKFK^KE65)T@fPqhW?Mc2 z_+*Vx&*@EC)I>?Gt8wA+K&J>t zhO>2YetOWkw6w+sZ;z}CnT$_`Nv&3UxfRTWi1alVAcB2hT@k;{+}{T(Q~IqdPoVPwj%e4q!e(BgR5mHwW*cr0TmN0mH|rVpm=jIT?f{CRg>}s zqO5j?!1KWhg4gWIp%l)7Av&wY*a@6gsGEWpe|rmPfV{;-8v^UPrKB^E94D(Qg`w_r z=M%f|i5;dIV~nyMPDPqOSQpTMOW6rF%keB!y(pU5px%om!d?LAC3mGdyI@2M-~!6; z14~OfA9t}qVp$4oCk1LrtqLkqOrkF(h}A;e>#fF$JO|(WJs%t1jtzv$y0=nv;`__r})OrNAjtOkvQiMA9NFFbfAeRB{<*nxLru)8gK}< z*d=fS%2isFG)r&OBAeU`OB9C&C!aKsMMkSFagtq(6x6Oqsz`r<2a%mhJ0{G{e{)ft zzjqF0G2y_F0lEkuPh;g*mI(G;c z`J8f4h)i5vXol!s#w>eH{M%&xijaDg3*|H(3N2+hrB3_)f}zqROvP&%KXt zl3!s3j~7LTCroZrmHi6!wX|HdRQz^4i5FM!-xn&4)XTr`?7esmb`etzf8U@@`fWFv zUgt$t-ORSQu6Xdek9sF42h((ZUEOSb^`b{3$A0SfeH#J*K^489rq{UpP0o$V|Zag-fpS%9p zsP(%=tkjB=Du0{KDTLP~f7szU88?ZrD(IV`>D?3C*NgV&w|IK`j1e1z3ZcG2+bt0- zO5moH#!0$A`m+q4QrGt;9Z8n+T*m$uIIxU)-%pWqDSli0(c+G zjeb6SM`cBVgB`+vDGoZ0V#uDa!K_+fd{;_wxhZXNDF2b;?qYq|f8Ydi$_z^?Zdxn) z8z*s8V_+7dWVL}WS&0k898bAziC5G7Izy)@Rd13R3!j)|+Dl3XHsQ1c!nSce>jM+Eo4KLZ<_vLn|tt& z)obfO0{)4~gtmceotP~Pq=gOGEHH4LZ@&75_?H#Py6%&LaM*1+#p@55AeU^HK-FIx zRnx?9X4wklv>gCmk)}W&Hd%W%8HVz`N+lm3vGr05*Qg4@aKUmCp+v`uO_doq7;D7E^Z>oX=7rOqdVxEmUB99enZ zxYt>az6b$rZ#My1!*wND-GFaUT5J^o<{Vb&tb3{rJ=xT9$cfh7(~I&b9?f{n@E6Ci z?Tf2f^W51Y&c}B;b;}hUWEDlaL{(2uU@CpNfAXsOTM286W})LV<<6$ZjL$ZSH0d!u z3dcOVsvJ>+-$7v+z3ny(G!Ko5^3d!(XB-g*riedK^kp(#mN!Oa6FgHrbt^>3<=mmm zJaI`;P-M0^=0r1>{<6$m&z#h}5LqM)7z~JCf&0wE{qm1)j&La!VYe_RhN+k&NRDDV zf4ON&XQ&OMmBHv3HUG52engwJ-Q~zwyr2Ubr-gFRrckrjX`81lOY4pGYmQCPjf~6> zY6q;Y!J@sAF1>;Vyfo^Jm=UAs6jm_8)6o>qriqgAY~El9Ea7Md_AKnrlHbL%@Gt+t z$MYX}qJqxJ2#ek@HEJCUf>$jELaT)-e=hWh_YeCgUz3&V;_o>wizk?|Rwa+DAYjYd z-j8-`*3k?w3zWAXQoE#Dw2O;U{y|MF^u$i`DXNxwVojIhbj#9+1xQ4>`!q)0c>s%I zoE3&`!{d^bW|yL@C##mBoh6AfXq3{W+gVnVFaOfT#CQ6mquX<*9~G|t({ zY)oW7!)SLqNB}CkLp-thj($-pz;$X*v}W-5!#R#`=V;{}Jtwq|{R zb~UaJG)!vf&1kPwX%>6?2WMv5e@gu8jC0H_**P3UKY+B0{`zM##~gfoXMTP0{P~}w z9}f>ymbjGt`XEo?n#?*ua?4W8{4zH4C z<(rvnK*0O+F}mvVqQ2{If5FDP^5^lL6m)zhdRtyp#tB^9n(ttgzZZzaL>GA7scu&1 zPxcjSy+f?BzGiXoYo5>Ay6b-c=6e-W`5hK<$yR7;1eAqFg=p4E8E8x+O$fkc@s~@B zDqcs6SaNijDE=*H=F)WzAR_;%spL=*Tl4S~O-2?^QxHywW;+;Ze-%;)@y}8UeLV*d z)5`cd8;{eujowg*)1(-NdeK~Vj3$EOL}hBcSb?b~?}!RiV0NQe{s$6V!J(EbC%8^h zvz!yfp2`pJYL_$2z&uQrAOm^JqVz0*WD;J-HzA`-bEK-7VMTugn+Tnq^13=$d4> z%QlqpdP}3^%-$SxIIpCUNp39_pT9~qoDy7YX5fyEo#4=|c7Z2pJq{hUa)WtyButEK zag`^@m0pNQdpZ#BKc z$A>7@?WRdhe=h{K!x`v}$~BmFy|gBZVb%=!LC9VJwI@BxK~wCq4!JC*yz6MBjlsXi z#*GKYqSIM(7|S^igK)+Q#-r^r8ya*~JKHH|gtNSIJha-*m50!L_Mk2j7WM^zUH*$5 zJ`y|Fdj)le(lAr;;)MBck=)0;`oO#Z^z02kuuzQFR} zwn8m&f8S{!*V1tsp-#2w#tbRE#0Fzp(A@Rch$nen*t$kQh3JcFF15&mnUoTl?y z7vD6UD{3wGEp#g$_)(;gOW7}PvZKUvL9mw=y3#?X4?zazfqlZzz%ov!E*5`9GIoop z7XPFWpIdS5aRa-f4-%y7lG#!I6Udrv$jbYHlOC{onbOL zcVXb4VLBl%#Vz(6U5Bg~pkwb;crlr(Z)Mg2lYe#XCQAi$<;Zs2WA4+w zA1x4sXSVCQ*|(FcE-#yPQ`aItK)@M=>+K ze>9f`?qQp$ol57L(?5YDg#v7*@&0VVB#}V+Up3m5!9KuRhTy_{E?FgpNIgm_=J*NuV3KrBb88tiF8#S-ggbt{TQE8 zf_E*|X&3&~00WwCXG-a1t;QnG=CwInf4B4LayCEB?_M)JW0OZ+9RN ztK_PcPHOBK05T3N;%!?=G!3LFG;K7E8YvoqU>@@IZ*}E0gp0^=%aMTJOJ>;=G^UG= zR*Q_78ehpMIkyO*uHAXL8WwatuuFmA=3)LqlMhwsQw>hE+3!P4t>LZ|+?vhWe@P|H zDiVQyPvBcq!WfDRee0RCz)@ig6tTICx(O@=B3}nGS9-Bv&_C{>C-PfW#>{K>Ux9|f z=sZa)Yg@%dY+O3-dxwpFW(Qx`3oI8AE0o;s9Fa50>l;~=0qnqKcdq zHay+Y;F(*xr6*0Pbfd@+ASOYgpXeF`YQIYqzjY8ArJ9N2(m|pO91_eqsgw0o{8%~% z3#!0Xi^_OGV+IrPd35Fp>@_2Xj7R2+DD%VqF4VWnShBpN@FKhPeAla+N2PXS7bzYv zNw?g?QJO6<5g_BEce;r9e|O#MpcQ+Egx9=hHr;phcYZ# zLNNY?Ra7&55~~fX)ZT(gYpST4E9Hvlzm{+624mb?-BLW#?3@BCVz{tR_3>C4Le2S7 z=e$ZyorIhiv#WGGPRH!w3>)Vi*1Fx$c+^9~(e!lpud0T!8R46*e{P9W00q#NSvWos zhr6C+@*6>>gmauF*F`d;+lgRozerk^RC#9SLKP)nj z%Hl82+LFcVtS!NpcG!!`SkFnu-6Y`_BYclzKT4+V#)>9Xy`qbDMmKyma^hShD zT9nc`pMZl2e>JU>Y?@cZ0!GpJ^!SGWr+g@r*zeg!l?I>`4HqX-XB@lfFi$Z-FQC5e?CE8WE@z;ZGu7*h@|lM@EN4X zH$XaOx5{BGp={gTxCYTKM@Q?)C2@P{TuZLX$GIg?c24$=NjQYNW<*wKYwxhJYIcw) z=qbYnzJIuG+CDxwKRl{62MJ=IA@vjWhM&5n0I?!gTUx@UJdR3T@!O7vkT+{>z7*iAa`m3QSK>hc2$xQF%V{RKU-0Db7x zf2y_6+D2JK15vlg=A$-2!ZANF&XZC+JlSzO(~*?l(Ke>DRx1Q`Ix8b+kC?e`A>%B$ z=CT0l2g+Qx&;X^|NT5+`B!VEgH2rkR&=~3nku#=|kaUg$wecJ^v}l*17>6k05@cek z?;C-sm8@HJ_N;~~WLte1;;x2|jSXmuf1(+WhlI`&5$?@nLe=A|vM9e50@$ilQ!=y9VK5BgI83XXTp9Ab6d4y;X=sV= z>|XC#(eiTPVRMTz$=e{1BmY88=Tb7Wgs7@B5Z91es&IO%lqeo(&(WOT+D+UFf3zDj zm;B_Z%23j7?pB}^g29f0r-~GB&oqY0;41$b-Eb%Od~$m=qwAj!l%odwI8;j4P#hal~>a9IEgJ@?< zIy~OlJ#Y*kNsqlZO+s-bkI%<@*}HU%M3_d9AhfX{mLWHhSx_~hvFJ8me;ms#Tg{}Z zk9Da%jfQka(A5RLX|z6>dG+tt5R3y zY~UFoe~DN)$z4`Noa)M8e^{%@Sl0I{TVR41>Kny={+SZ{2#at}P?Z>Z=%qfBNg>eh zBaqsfnw}uOAiY4EE@e4hKZ2!WX`^Mf`@lGiDh-w(5zge3?g{ZCs0sc)`@K~BDJH$d z@Zq~+azlXktu$3n-5~SvwfY@eV#e6BOAE@`2StxLh+0qUFzAY;e=!nK#@}$#sM?8Z zBW!i|lj(ROIa)5#QI<^I~-SJIHLE^>~`!S-B(cETA83(A@(qxY-{^J3!VC=vYRv$?_Gf2xd|S%9i{fh6(Us^4ao zAHL;ih~D6NdB0E2N#T|tEbjimctHvMy;bc|3$v;h-kIAuAs$$5mDYh^e!r--T6t!< zIV-Hyk6NeIYiDnlTen?#Ug8K$PTo@sGXL`&$P_e!!ae zlnrL*Ak;_Qe_L)kWhwRqSCiAO*^k?K4YJ7CX=V>jm|^i-kV~yCWtZvgGgLz0Wpnpv zo+3(aJsSeDF;li%jv7;Q{*j^-_e+i?OUFI&e3;Ca$rR7%zeLBfd_BO6D2^vbDIMRp zCCw>@R<#NmaVR(xvS`PO*x!ONuWiC*#eT+^FiK0Hf16Wjs$xm>a;>Zn{jH zukWC~NvG47uqbRJury!bXCPWGZw=S9khN~}mP1Mvxgd$$M(2JhkzW^>Xz@%JW&Ace zZ%5d#f2^S$4VAUE>V|amw$`vF&nUQrpAbXgX&{vG_~%;kMFp0WcT`A~JLd1IxOECD zob=QbK0RJ2LzshFE<@K=;IASL6$Dm^+6ta7<+nv}=pSFu!@uHWa-+Q8HlkfWmdJnJ z3k&@wi65jx3w`nVUvl4Lm(}I|9Xb)(`i49We~f_OU8*#a2Ju5ko-BQ2>3>$?W9Cm& zd0jrzIjBdaKU0aZ{!n4X%^N{!Qr=StO>A^vXlLlRJwE;6PJ4x-U40uj-b|sfVFZ#U zN|p0fI1^zLc@kk8iGOfG2udHkt6<8t1o4sVC{Gk@!}TS60b5-(L#MHUR_O+@Du}i& zf4so*%enj#Mo^y7r?Tf3!cerZ^o}Z}fS!qNw-TiOi#3W2|`U`cw&g zXub}$d9Yq9jP%@+`>x_+M2(2gG>m4qaSwz{GD)EYj+ zp-=L~sG*i!$1GhI(?GQJt-rk+e+5$9Q)g1$xShHsBdB{KdVC8oI@g?|sh@)0zLW+U+(IYr5+!?mt)n_HLk;(hsv=xrjJ{xx%f;B7h4It% zhml6n=#NL|QZ!K3=TofYJ!_Or@l&KwwAv~HM^v*+Ol{c;Ba!ee$ns{^K-K!(NgcQz znsd(C7@lKJ3PDe-*r%Nhe=V6i6SGNC+CAHcNlB)Hnf7e0TMMjhSNHb)lg&k6-m~V7 zReLPMMa?WlIJ@_K*hKWjRlk&Ee9)UQj=Ypuwz@OvR6h)upV8Y<_K0_(`Y| z6&qEqJ033X;1Be0+3(A76wEJ(H`jBbGI9shrgq=nJvjJ;PO~iNe=}nekrSUg??%?U z8sFMHeOLKNJw3$-&#`DRp+d zS9Lr!`&~q8wMD(#C6NBTP60wP4Q08WB;OHZsOk=uurtP|MP2$%`cF;Gt3=A1ezHe< z%w2s;ng-p@|3ZVmv#wvnl#- z0b0$*=IBMUv-1%yu-MtmZgzwLVh^v^mwsbEs3S*aM~23U`;xzWlI~pPbOjx&s3{*j zhI#91XL5O~f5h4H@B0VmyY|9mIgvnEl9S0&>|G>hyFZ>a;~0=W+K2=LoX-#X&3I6f zEvJcpjl?bYO6%cLCl{w3t|3y9dl}@>LA59_3_b|VSTCMC=O40(e2@ON&X#i|1OHUh zO5HS~(1X+@bOvA#3gC_n=qn*^C1M=xI^0zH+_If?e}oYLb&;T@WQ@r)Pb$XPhLYo8 zs6dZy(RAZseC(@G3jYPG0hSE;!@-Is3Z+h~^1K*l^JMDWkB;^=;flWWk;QnCgDf{* zUkBPi{T!FkvuLopeSEYt81D4nv^4`T@AS`hhsS$+gWWR_Al0K<_1G4*Qm}IEHT_9o z@lC!gf1=N$ufBc$9GXP0X4xE60C@SWdc_^K{BZ16m zB`cz3x&%Z}l~WexE_ww;`Cg+242Unt0N%&=WS-&k)@ITvxs%dnBenx318b+nz6#3E`jlPK+_!ZnZv8Xj23 zR~qF6frcwmOc(`r#%C3GN%nC!gtM5q+d_7P>by$SdcP%;uBnQ*;Um?$1)<^Et_>7% zt>lmoS^_rup@Y>MmPRuf0+am_y>!!Le^I7qxi~m@%BWgnRfM_m=!g~aWrmzQk2Ig? zjAGb)0zpIH9&d`~cNn=jZEnFTmsrrLGV8jUfWrm_ehUsfGuuE%2!*_;+gcLDA>vKp zN`hh>r|U#Oh{MDt7{7Ahev}~UijE&0h&LX@n^1ZSa|Ng~GsE$Ojm%9xV_dofe|!G2 zOpALFAc$hZO4lV}FY34=z}?2GM#a4~jn^6eSj$PXw76a=)~s#r9ugu7G;_E3mge-3#OqSm#1397D<|FJ$^)`0Xh4F^dBVF>B1Lr|L9E+8m~{- zpD&ixA*`nf-9^9wyAsehD8O!+W@Y6;;vdeQw=0BriMG6@lp&P&g7Q(`f09q|EI!yD zocRUp%Drp3ESy4_++e(-R1HeY|8U!jx-`eZ;({Wsi^%+=0J;C@#6RcRynE64?ES-M zDw}D>k|d*!xbz)rGVg&HhaUA>;25?ZMizN?o|ckA8Ea#EjL*$cSiEg7_upwBxa?6V z!7!Ol-AD!{SoP)|Ba*>lf3~dmg4_Zn$T>)G!bK>Exaja(Gr5aVia%~AWjaXbs9D@1 z1BG@R&joZb&v@Q2RypQRQcDgazQiVi1!+; zDQfEZHIvT|0R4Eg4@!wRQMZ_Q{jXX3N1e42o(?9OlS}YR-Sku`c9!NcWW~6MK(pFi zF8bOtr<2pc!nmhRlitse+k$O~eGDWjQ@RhLD{y%Y$6cc?Iu-$(7-3_aYX@piqP+`_o%DM+zdf3UJHcruV|N(2F=B%~r=8 zf49)3?2ZY{g>kEG-POe%^S<7?*AXKdpvRo<9_{R&c3d-ewN9Wm1rH>vyR7lgjU*7w z=%N`fubc}7e8>tBuB&@5RNq;BLp;P@X^S3>F!A zLzz5ywg2kq_;h!>KiIX|N3{#j1u>4eTwckFs09OYXu>RKd=RH>+V0NsdN`K#f7&Ho z>1oXZLz0m4W-|sVpkfEVUOd3pdf~95v}-@r5{j!R$Km<#0dn6g-YEOqS3Bo~j5*L@ zCx^fAi33u>b;O@wc9%K}h#_45dHdFur=|z0PN@(@%ziTNBF00#J-T;vc#|f;!lkQX zOeU!P@J-KHknek5H@?Sv;udLFAIiQANiV>< zUmoFw0of?*zMlwT^SzK67Rm;x<6!oD^YC4K4P({~w_JV9Jlux{^VsP#CS%IEj0bXF z({KO=b8t*RV>l>HKzB0f8F8byMCzav+$&`R09qD=wMf6Q|2M(MB* z9C;<9*Lm+ji!<@gX8+zaxi0Zyi8D9F!C`)z;>v=mlY-B}7haxhw}ZeKqLl7IduHVhkxlOms6;yEZ9Zt(#@8F+ z7Hv#XnG#tdw!>=d zg$UxXbK3Jez^T8lJH-b+b?mGV#WWyRvAE(Kamn$R;T1e~lImq%@0Fe)#{N zjFz5y*bClJU>f>R&U}J?+8DUY?(pi~I%`LIO<+5clx6m-a;PbS$Ye~t6v`WXnQ@>w>XJ}c76Gs+sXNJc4`DZ`E7M!B5RKUGrDzc_&S z1Lqtq5%EnmbFK}hH5h4PH8tUmj%hw>2NbYu)1(8Ft>%7}3C3A1z^tNboS5)H*fLV`u^ZLSEpIP^}~v9914ZO-Jd(>Z&v6i?RREZog`fR z+mL$&!<|qh1kUMM^PA)6mG3>|`?)ACIeeD}W+WBcNB9?gi5)vXqpMqGg>5aW)mQAyd-7BkQ-cUsy>jo3@C7|#ZxUi@Prq{K1 z@W$ZlB3WSQvwo<9y-peIIt@eYp(%hM^dk%dM(8xA7L0={-~ic z!mh%Y3NTr#e&^~my85jSxx-aie`prm@3fdN zD4Of)=gZ$n$aHQXi0psFd3Rb|<0- zf6&^iMP=LOK4&;hHev_4M+=j{HTs7p6detR6Vx_eb3*mD>&{C}-xDu8FIOTYc%;Pd zTf*2dQ_QYKp+GX%x}{j>>JXE<0Rt+4J_dJ;9(k^1g;oSx;O)7#wItYzwsA12YMdx0 zU;{GZ|29Mf)Pw{Y*NOvRYLgkXl&5Soe+}isCvi;-ScBMKLPT{3aBJ{4C+EU-Qsw3% z@N}B`X(Lt%sKngy;ua#cWOkk4VFUCCS26`>?~@5IC1yHqD!5=MYYV+-T9Fc9|tuiPtULbQsjT$SCc2tMhb_FtX$PhJmSp6>Sl?ggBC?8=Ty zwP+iIq6LDNzsSK11IBI@0|DQ zrn;NPu_xe$c`#nYU`|!_X4MMD=|{7x)O!6?Gh(Hyc8zM*pI|Y&IE0P-e+RKWm2-6aXdC9laD7-iIpB>{dgKGj@Ow8Z`apvJ^f&P z;QV?Wo2+uxd4NUgBoVWY$Q7@b@J0_CMs3&n*W9%dGiXDB%dmd9!gY?~S~BNgnsGHC z>u|Ve@oBX{Ds=rZtVbH(f473VlMfhMT9mEaNcGVf!>&$>`+-hgdki_%W%R@8KCY@y zw7j%Pt<6NEAZqXgmQ>5A`>@-Uym`=wObuONak3l>eDr?cjWk>I4abTxJL$kX03{aR zb%fdo21q-4rS2%vJ!ZBw{Hx8r*@nno^3+hTt=`1J>;B2^6Wa*?e|1}8(rsQ?ChzmY zwValW%MT}=Y^42d&&pD<5{p1>epipvt0g)30#z9yR4$26ziq9i^ryH0?luFfw%wsJ z9F5}d0d%`9M_CIVDFr;|Ow*l<*QwZ8aWO9(-z~t%UF-{UZ`TV82y99%>J$EiD-Uk3 zs!jATRsUpnMWIt_e@M4K2ep5Lx3sIv^>10;ZQo5nRitz8#?4>_=&O1h`p4x)3FKk; zfb=J9u8SlLlw6xM z>4L)%KpuM6_ShYXi!FGl=U3k4%!Af4YX~c(vjfCMYa}!m|Vp>xY_o$tM;^c5Jwk@!piaX3{$Gf~Qt8}LQJ$h3-J}$EBY!1IX z20-F!sGDW8G_>l@s>e_`vw~v{nhpUytsvH{hSM>n}Oqct{h-RPz^N-4G;GZ zcZX+hPIm1{3)})dGtLT*kFa~E_Cjd@+he00_3a(hh_#;HX zf1ta{Bs2yLUtbq-S!sP?!G%PAck#W;GvfIn7 znk9>PXaA*rNZve)X-p1KH_~Jl<6R;zfA7(N?XLF-Z?H6lPkp&@8QU?bl&7m^j1;py z#EbcL$3_d#*v{dVDsk0uKs?J!?LK^(gDhH_+ zDmt;4+b0&4{0QuYnP=;%Dt}8%N&q@ouT2AbexDin!;I$6g^oiM`_%?pi~of-fBIS4 z@b3z^?X9<(Vv*k{-bbIlU_9!6>7|=(t?}AwqrbzUL1rbP@E+0T547%TZ3O?OUAMS( zt8NXNV4_GD5!qOE7;ebmYD2+hS*;C$W7CGB@rK)}JSrVVaG_Zs`Z6-pt+)YULOF)Z@M^GuL~#qE&~>34He1XPi_A%wFclY))I5 zjG5m#jyuqW?6vn41Sr@gQ~T}ibeb)k+)flOZ@$>h=W{4+m|j4Uo@Zj3>aJCvRKV#X zU+93-ufhSR1fv2@ZJ>7+(2rg~>b>>-jrUzhL=A#dszXbc9vi8WJiHe^e-ksMNm|@y zBg8QY`}_<%55ncA%9D~nrUK>jd zQ`3mJ6T$2}k=R8xCwa~==3`Fc;!cgWl`y1F_n6$UT`Fn|*`=yqsj;SA>WU0mnbBNL zgUV`WMoQmgU^UjQ7am^Oe^@i-+|~FW5vRS%jIu(wYi5)k!d)|?RLY;48Kv_4)Xyja zQ8S8K7??s<(0Fsac!MMT1LDT(=M;Z$nNtkZI;X;6bo!o z(+mz$LERECU{clI!haaE>4dYK{Fn-9NU>?fa%5izN0afsy2UskWZ}z?AQ0MS7JLV?4%j1+D1H9|F?^=_l6WT%j+Ie~%9^n-2cF+dskxJIsT1 z29ufc@W8)=v;N^p=b@If$D)Q_^!ev+?;N+G$LIlQhwsN%!c~W0My(?@)*3fr$5)== zYsAWfK+MM}-pBI!=YEKiiu@>(NlNJ;ZPz^`(x)D-#KA@dz{oMqYew#`8CtXArEs>+ zpd(Pj8V;pRe}*uO=hEvmy9GY&x~=KEbhHG}@)wn(?UyNCevr&cac~$E(OFix(VCbh z7)F$jfdSUx9q644^j+DyjeTqvTQBPD8a4T;wv9+=>BShz)lDwI^1v?LK}5Xio=f2+ zj&>0b`h&CK{!T|0^QwGqm_hknIZP%K%7$xIR?k1Ne^uzI`)Y`Yo#KW>InD1F8q}Q9 z`tsk{a(!9}VNTxAVmgS-bYGqC`=@v)6sIPrQM}o1q`&IyAD!*K+LhlAa{DXJZ1D-@ znVW)g@ZSf+gX5!D;nE5OXn3=)pgbBB+}^=)|4cybP4lD*0ZF;TU@!9=uPX@wVrL9j zXaK=UfAIxyD71rcO0sD8pfjQ5YuyO?YZcgK^-J3m#q`JG*>*w zGQEWg=wIg>=wylf6d%IFj(NgcXy<&?To({G>1VFCsI^1^#gw=ApT3?Q}PH^?I;H!Uj+y>VV11 ze{>#V-k7IUjBDp z29|$da#*a&z@iINlfUfG&1H6i%PxO#e^+3<#*x4Hi!QFM{LNWqagpQ?&ax`aBmFVF zmcmDUNL{>mnaz{po_F%C_tX5!dcLnx_qjA*7^zQPT-y$=qouetOFXk9)_)U*!#w@_ z^GR-gIT2j*y$UT5A5POrlT)D9Ayk{HK==h-_6NJ3<%B2Kn?2AaXr|I8q!d5zf6SC6 zjK@-et>sdLNoeOdzTjh74h|Ji;drdI@}MLJ0@xun90`=Z%SxDdfk+@TVO>@Zi}V^G z(;^KVa3L58;0mQH!=4!#PFi|5w}KJ_VU2caXUo*BDQ1sa2l{`sna-}#@fgUR2y?yT zLdzkNZgLpByh!^cVCfpYMwf7Of7ji$A>3q>t;ScL>Nls?ygHGkjc(?S7+iycN8+X# zt)+p=<|}FVRtdw($dvHg=GK@ugcvkgaY}<>_N~ESF<*;8IErtQ@>D@94~@ZWbqiqd zxWDp8TvW7qqdW?@4pn*`g7LyZ6{!H${Uxb!Y23bDCKkf15uv>LY{4M%3n)bUy2W9bq<#Yr)C<%d`$rxtL~Emms~I7=h{ry9c}5 zXSAiwKcl_<)4^Hvp2@|1vWLKa+Al`Dv5~`|u6r;_4Qa#U>?L{`e^te9w8Jm@;#0fx zLykrKb9|A=s|#pdQlta0ipT+hg@b85Opl}>6U9(yqyp85gaWFTm8y6&x#8O$n8coE zXVQ5e@m6ca$sFgt46uy#_qF16zM;=)yFBiBc*ID-<*$dmv_`;5!jrgLvbW{=P z46qVkn&5~jaK*3Ve>PUG<_3Nf`A0%L6G}O0Lq48s)&8Z(tRP5aPp)(DCd6Dd<ngQK|MfPdzuv2nyURNW1@41$UOjFnkQQklRGk6>{#_kHDJX~r@BpY9zD6F zkFC*tf4zF5pRq~WfpCbL?5E9{ zb=W_9ZM!V8(I>7FOx*o#bE6+moLO!X%pUNz%JD1*-R2!8!B_57De{EzlQB44l?i8+ zdyLC^Ecz#M?i&{}9+S=a5%RL4csrjhpwzr_k7CpYGtt@itRdjtAjk;+!DwqMC#(Fk zquue(y<}Wee~#xnsB(-SKFg|UQ`G$j5g}cM0>@))Q_k&&pDyr=XA7Yyq9G}LernoR z0Hj~~@$oBdDo6~Ld*7f_e78=q8zip2mk?SAWJj802Gb0pGfQVn4X~%n*uy8WHSLT# zS2z3Yx}1D^IL0O8hl|6n^9 z<~mU@I0w*E7wmZ9_~q?+C+t}G&nBHkk=>#{c9LMA`u(%=y~J&tcgYu36i5hSFC)xU z&;;EH(>xig=I<5x4E;+SJJtc9Ndjv;tk};fy5C!nLQ}WC|A3}BcVJy0+-IMC799hW z77v*?e_LjD-g&u9rqlayS`YktosGxooG%o_148~K&-m9bWm?iU$kQ|#AJ3=vZEz>h z=DWNYZ}J*9EK@KSDi7>185Q|1sU1K+UdXr^eGLQCM^*-Mq8S2|KKdfXR9-F>7Tl^g zW5P<27L(eWF)6+hfBdMJ;~>YIr0okbA5)_^e-03?PmVYKK1|11qBE)4HJZmW^pU+_ zX!LJ9B^sr&;bYLx_0xw>4C!bmo-wZ5#F8HG*%QA>kPqHWMSt(w8p-!$JRVNbkv30@ zvYXzb6viz?%A(KCu&s_%ycM7wh5|VH+Mbd)d2m{2JDn z0#UeV3z#0WWbq`-r(D)Wi6PJBlMo)le_YHkid>;2oT!4lg>e>}>9B|>K8{iCE4%h$ z?G3J-wpl>Q(Lo&-0Ei}^yFIZjTjhdwjcI`6r=}vgmwg==@nrL58X${?`V)|aX$L-l zEXgVkW%lH4BFu#B>ParxXl2U69w~FIyNW+30k?};3IV|Z-lU(hfMg2&v2?+)e`y1G zGDEe`z~z@fEn!O29G&F+1X$#YdL-)nImv$Kz#B!B_KdVqg6T02-H((yO@Gpj*6%Jl z@?;U;v~Fak62}?W6}~r*!uKYK?~T9*V}$+9u@nXnzL%S!>WWdEKB+?%UBz`&X! zEII49=cvO@L3k$hJ;veHR*BuY-l1Quz`Lwk0UmX`5a-y)4)fc`)V)(A*Viotd@iTO z+IaqC%xlj>y5?b&Pss=WfBaG1PNEk|F|Q8jvUpzUn(API%{P?c8~Fd{HcI0oJ9w#R zw{r!u+}qcD%($;Wuup*71h0N;DA|4rODx;u`t-snq54kJ0!6`U^2y4WGh_sv-&1Z_ zolBNvxNj}fQxLFyd~|kte1I{S`haA}3=!7H?l`N68${S+ef0iEe;S|(68$R4=Cy;P zvpe`a8?dufIV0ekdL~M7Cga|no7I7m(QqYlpIP>sJ&YW8)-ZJh5a>>$x7P*c&6QJV z`}pAaba;F;+&kVrAJk4@>W+iFtUhvQ{1#30b`KoZ{d;;JW?aL^A)0FX$e0#@!PwZq zTcFN=ySJQ=oVU=7e{7P0RiSG5#HdE?pzRk$P`DRYnkKdXl?<@i3b$5pvMXt(>unZf$fI3v!ahEOz@v6;7`V?eUC1sYgTe67U# zJfckt)JoL3f3$wZX@a=SkD}`MjgyXpd`P0;X@0j_Db^}S=y|oyfr&+qs6lmz7B;E^ zpMndb5f2qQ`61dKk5h)}Pp3d->BQEBmt3=aTWO07^teecmVEa?&Wu0a2xb#KE;LG5 z|KEaxbUmJl3IYyn5863j358=IYCCWTxPd=jQpDt`f0A$*QA!~rE%Wj$xe6~v#)jZ; zV`Jl{za0K-+$8uE^zS9`vT>WVOXtfPe=B@>RKKp;qt@{xRC!)!*Edtl4Y%U5MQW0m zt2G707+4AtO}5z#W`LM5*uwp>H4uC)g%Q^Z7Ut5`%4^m)W0c#DqS+X*j$u2R-%%gI z9`8GxfA4mAsLW34&X>AU7E}H}dj&PKJzwx=L-({_G%@ScyF(eRDh?@W;9fAisw_)YWYNo!A#Ey*&vj~pdVOUm~8oB|QKKg2~*{J_a^d(mM3e|8Pc!Cff| zf2QS+y;Q8eeai5IoBVG62zZVcZr*OiVSSkw4MMu z|Cdli&gZ$l?m?ensZ%T{F$9Kk>QGD?{In@CgxsD~_LhlWB#cotn8{)cRf1A301k7+ z-Hl%%Gz6@a7sORyymdQBAf^pqg1qCNe->ki5Ts!08ee2-O-eV%Drz*CcC7q^3^ivn zpfS4l(|02}g2cbX1yWU!jMA%Q^ft&%A2q1~bxLF5nKGaQrB^6fQ}p+{gHZ56%PoX$ zAxSf}7SyMFz!M)$IQS+8@_pCmV`#ijPs9Ku;yOKmb~{NTsJY-vA&CBP_l`j+e}T=) zVd|5X&hemqW5x(><}L#=8d1t6&P3MOX98JUzrnh^Xr~M}IT!)L`}ZLV9E}8tjgm%c zK=Hk9ya$m{^%0CwPzmosJcXu_B0|&3SS!->J|B6SwRHYz7DO^0`_ z*RwEYT&aKHOIiqfXtb|ga&PL%y?F$=uU98`HHnKzRmjA5 zs$h^%g|U@Pp;EOIxtx#bu)>Ozo=b3pT!kV?vt2UC7u3hRlCDHE%TD(WpR zHqz!b#t2kvq!bmORVj6%TNtB8;L_`$Zlu=_oN1(bhUY_ut8oUMB~h0Pe|@Kmy7W3o z8|hU@+bG4jaS9S_Clrkfb(7I|s-R1zjj@qRiLsRl$N*Y_0SHcvJN@>?Tx0SnBU@{E z&G{5lOhgi71wzqAa_jY9tPqPEzz7EwaS7IV8het^w2$>_OMof>@8qowdm^64#Z?KvuTg+C**sA*g$`aGAtVAS2Y8vq=M54miMq$ZW zU7GLC_M9NA3&TYzkox`+=@(geTZc~;S_(Nb3PnM?l$-cD3clXyx+sT}BA*E|OY*Y2 zsJJKC0l#oFb{L1)f5{0aFx})u_ABORnbI8;Fhs)E+oCN4v!7)*v$w_xLByDqg|T4c zA79vPESUI*lT_7d&nx84yXaZ;BKneRqV*kL_|p$z-zkhFQ?Ji}u6F_1fy6To`1ytWf61-=!e~~F=rN0%Row?* z?=|ebu1fU67e;ey>N3k)TV>qhKncNKwIM0z^ZX#WN~c}R``+w!Z;Cq6H_ipbS>QH$ zAq+ZGB%;&cYgw*fpHNE}1(gVRSZePMa?xnf=kydEB9jllLq|dN9g`?=9O`!-zbm5R zk3N8>$vDe@fA6j;kcdBePi^0%qqi^fcfWUMjgXG3{N0E47sdF0cz+R^Hm!(c*`tP# zO1LCxG>;j=nl3If(EJkr=E#5(t;medQUyI-(!$uRObUz!pP~N((;}50oEIs%qm)R2 zBZiz7NpUoKZ+>rXrmF-#kdw7v>q8iM6<=05y2(d3e@UG;Yjk5;cJVGi;}JSxC(6R! zK9z~Id80}oB%No>duepbve{Nj3K}NR6leQ%bLQ_n`gDEg(}#aqe2~D0;%x(t8N!ECN0F z_K%ROe?wl1bAiy8t9UwA3hj8TI$2g9w7d#4e;@*>=^SJ&C3K&84K|fJv-zT-z?Dp) z)gCYZktZ)16Y*vo;RX}IW}2;pIy*^{IaZE2>ke_rI})^nTjjhwgel{4N3Sl=OlKMvr(@D_9)uRopcbKeYVwxI2Cvyr=yDJeLi^fE!P`dcm+6+stNFSx^_o7G6(2CA%`ueN9zxCqs zL+35jK;glNFt|_lo6X%)9wZMepypQ3K*9y4H(lrSy%O>9PF60aiMR)_R&5GJf1&c* zV7>7PeY2M!f^JAS90m5Jctgb?S-$b8*6{%ZAqCSMIM|^1R$N!w#rGDL-n!o~0(w$Y zLes+B$`v&7zw6N#En9m=libGW3y|H$+e6~@t&qqyRTg>f4Y)d@gmbQ`^_@<*=@lK3 z&Yj^S0Rh;)q74Yf6rRvbMtB4OVrDyPG4+CE>&U#b5=-MfoY;5-a|9lXWK}y?7nF%1@D*3H zHaiLFdb*h;Br~YScggfE2+yJ`bWZN1Cz_iy)E{79$`ykQN&!;CaNQ7>e+8zCI+%vv zLsP{xG-&2R{o>F9{^7!pLP)LsJ{~2k1OmF}6w6#}T=txK=Uhv6lNmQ_yG)B1UR-)c zs48f2FF`vuxd}AOWT9}{tPty1d8qg>iJKg&h! zQyK!eJgBZCbEwLCk##ttv?D(VK^aBdx)Pn}crZ1l*pE$~y)oq*8Aj-uR25{sQz zUCsf_9tQYD@*m_+e=`A)1xlv{=;~ui4LZ2!ygKb;&UnmC6#XfBLE zDWIGZ3_(?w7DnPD-dTkzonr>N*FyU3B8E|2s>nSwc zyvJ{+IpqCKCV5ii`I(*?h-llC1DLk`7ja3~X?>#l0y8%>e{8;JMwHytEaq3Fh-db1 zfGR8bhR7OZs1tW>?os??GFh!1AheFg-V-p4K|J_Jr8J&ep`-OD(_U`g$)K@Q8yQX- zHg6w;YZ%(AF73M+ZKKR*N`RV-F9@_*T)0;!wtH2829^*&Hu2wznlCb(7qX@9M#$s;eQXmy{!SZ%J2!@GtKzeSu0i zozIC$Wdo}RfSu{%q|~#AGiYTzGNqm*g=eS1f1-A`yVDqX%j#rQk2D)!s0HkC z9ivT2ycBAsG#maFOHFnSPS_Rs7tQ`tCz^0_iJ+=vqv6}lKrnjC6X|qTgw0uUh2yfn z^AWQ%{4;D_56eY5%95#@6$5x7Tjb(uP^%^Qp6=74h-sCBr9)eCbkh=+vD=4lE(8QF zK>U1ue|pfl4D|zkUJKSK!l7;Kc*m0raH=6d6QKYvl_<7{&;?r$w1m#F9M9>F8`U84 z*4dweF1OZ3ip$G7p+4kuCQhB=rBHtP*u%QlMRYN8YyaQ|zeZ1YUva@lHUfR@!4{}p zj5ClvPDAW(m_q94)xqu~YbI|>u;!cmPOL0xf8o|_eG8fLt@YAfg29UEz>rfRzY{}7 zhhjpE_K4wjr@SUqDsdtcmYCnp%;sj8qmDzc9#8W-`+jck=s)Q+T(v;RK z4K<)w0M|9lbnSG~fUKrSNChgcvlkQAmsy6iQe~tc$#97{@doEd$HT+po!x`M1tKu! ze|pV*b#?_Jn;8!kri|z~nu8sSfDpnBN*}zt_M9VrBJkSDo$B18YHA41U8*7c*y8Pj z{$Q{xnk@6#uKP?)o?;ou=tjE8>jA~eL}XCJUA;6AdA0K@j7e~o+K<9Ny71ke*)s1l za!DAGW-IZl1|3gWb}Af2E;OKk(C(M*k$w^EDuu0mOU!p#ZQ zKySyPR`GnwmP08;Ku6&H{r4I;1ZLBn(3v`xELvfNUy2Z$%(G$CHB{8j_XKBLlTL3} zn&8NmI8%isK?Uuv#=w~4tapQn(qBP3=tLf=B%;XMYJU1FJm0QPp*+=N0%EodXDwcRZkmLS3p;h%mwKZ*0B zs=B_qC5FAdwLRE33td%NSy@?`Syh=?g+9=tt6UcvVyMDBgtlb=!oNGYv@#&M2S;jw z_&wiJw2#*Celu8LX6qvNfqRTSQS|>AxBQVWM4ll{WGOm+} z8oa|-4*R06WmmnNfr^-?ka5PjT*C+P;rNq%EF%T&*hfdMg0CU?lKV?Qe=-?$At+fX z57;Zs@F~d$mXrPHsE|j%P1VJ14XZDz&J(N@q8T^ zdQ}rf99`pkRquxJDiB#s1H$v~l&0(q21GOt)n6*tvi*WvK9if<2 zG}>R>#L?ANuxc2xf124goUO%`s-A2uceTeS2lSd>c29yU?)>m{?`-el=;R~ln+|=l z)X&RQ(96}(OH|QI)zM2;(wC~G7ptb1si&8zs4rJjFH%)ssIFeBvRWSqlhw|ZtJ^Qg%IFhl?<^eQV7`$Nmue_EDJqj(U_IWJi$_c3R# zO?xlR%_+NM^L;1c$j%LSTtSE&vdL$l-I-y52wLYZ#48Bxz=tr%PRLIw^4&Oa_lAXz z7ali8fr0OWV?4#A@8gBoR|)}b-5h%FM4+W{>{~vLMy%faw@pRo=J*cChE3hT>26Vng7bL4iqHCa52cDppShP@^K}g_xA@ z=HqOllTjQl(w#>!!l&9JJy-vYgt+@Ce|styVm1br#wWu)*cHz^l4cjZc6rMj)QkgR z{P90Y`CM+oAG8&gw663H;fuefk6e>KyapgVVl>w7WVp#1*J=wEajrfWgG;JOZswQjY50(dS)SX8WwDp4liVX$tu zv6PWJ4Pb2vjH@Klof9KPbrtQ0XVTUsr4`^M1P3R0hjj-FyjI@4Y-ZvEVI+pRh(Bc@ zv9buYe+>~^l2xZJnm}4LGMe04Y@%uPgkhM~e6j~k=<(HtHh5E+c>Jj3{arZs-5)rf zyEBzLkOB{#X!e>neLbU!RbfVJ3!Y54FfBG@6+6)5-%mB>H3iVbzzVgS&F#ZME z*nj_I?0=Api$D4sHUIdVC+^$bdCY@Rs<~nmq-WAMA}eHvUX|gQ-#j5+Ht@Vf?rez2 zd6}NSaPG?8;jO8cq*5|flFw_!aawUz&Hvq;L0=s&zdBwT9ej1X{OWl5|Hko>O8zf+ ze_nodye$21cf2$=ZOZRZI%3LdwtpsmBl}B#XhN}pcr-yz?`;jg_}~5(R~B|eXE$qf1C*7(a*@B-ljZKqp2}ye44`TmY?Q$1OLt1 z-k5KNP`?kJe)VTP%(h0yvdE;S{963n2S{1@GA3QJ_=5=L{R{n9A25CJTGUFK2A_k` zGSyT2^RYM?wqiV2VrV`zuPPwWe{q;B z5W|&0oS@~{OVl4&t7nd&@LF%q2upU|eyYh)-Z>OhSMO{RctaFdIY^7K9G@ISBS1zR z>0eScBRSvi7n!Jrg`u>+<*4kzY4nTYbbqP6rA}!ag7o{~;gB>CM%&J2px^TEQx^+2 z1=<47Lf~KPdos#Ni%1X!6X{z^fBm~P0m5)HuMC!9?b~T|HJt8^Mz9fxhiMdp2{Z|> zm$7xTCH0XH25j4x)8L0Aqv?m?9JGCWzQlVn{a!P>3%&UH^l)%+vVW<_kQs9`Ztl7D zkiXblhGj_P5)ILs^J640ubgNIYK~B9a-v0x{IdvJfkVJ3V=>@2jqIaYf0mt#4_$~o zDpbwp!>b5S>1ShoO0m&x@W97Y%Ge+vS~pf$01TzJH=QcBG=vM)C9icVvrI4zUxY$7 zG4=NDL4vDLLub27O?M@7uG+tXdAzlUOrW&krjaw+1SbPji8fqS1#neZZR*8rJ#s^N zWAsMbFd-pG#A4mcowtooeg#6PatR_Tm<|g%m3T%?>Pj%#jx>I-4RQ%~1xF~T znlAl33Kl6yuk+>T=8!L(4(S^#May9!xLRIUCgqP&iI41dN{ zg3Y=3%K&RG{VUevmvNeoCH7UsS;e^j-T2N)JaP44EzIAE=T;I=tk3sxG}E)=B$U#`x{@f@RU8TxIq#RJf1ndis`MfoLW`d|7|c~PXo>*$Ae>nX3!#U%ilqy*g zGmjPFj06AUt!3I9XsJ*6QS_|&3LI6NH~Rb}%PXFu49;a4f1gM=2zbSk4UJYIo_Tu% zrnr@*LocZf#Y3vFV+y9SMz}z)4d~-BnC>=Q zbT!k_|FnZOe@cz~1_7dd;Xm{r7+V*MI-# zf0QbZ;nOClnc3KKnG~ZoI?W@a?W2Z2GUu}Z<4uyjV(!E*g4n(^R`zralGJl-f-HtJ z^S61K@1ZZV&WQbHo7Te;EJj@Jz}gP~g2biz27h?0e;Dz$wsx%i`!Pt_nVeM{O^I%} z-WHUD{uODAP+q<{u&?CDBU_ip!D2cbxhI5~RmV40+R!qAH5G4~7xPeZzZC!v0%^ICn zWakt!CukkN8Hc(CEtxQ!wT?x$PN96c>?Ea7;^0m=4CKiIIYys6pt2P*!LEN-Ag!1W zUs=_a<4WB|>P~ZV0zLWG6BePjZ>%8=?o5919^c-1_t3aT2+CB-Pz4&dYgJ3+H#yt&}Zg9*uaZ3SClI&TRVV4ZJ4APtH!ku>Nx(tUCJQ zS=H^M%tghPg1fwMw2P`N?L3QpG=Zd-XhjEPZfY>4ID=eGFRJDcOzXPvtv?r{@qpSY zfG?Yfm6Ko`Uh)#l>^PwN%OLT8WeZH(z^x;9S78vt1Y2&l}H9r&=jfiE-cY;EB!f4=r6 zL$hA5Z*lVtQJWWYVFRwRL8yo0-Hl+jNFVsmX)uAdb^arb7V3BMf>3|4Z-V-hZtC%g zrQMAb*qT4$vbMk7hv^Mvp}88yyBiZ+JR4j83S_5g_!VHpdag-)xtVIuTe+3 zCU@$qYAR1;v#PCAQ<3A#ZqAP7U~U{;=w9ABr3RB2on{w~o)*Pw4)d#k&FZhEJv$_7 z;>~<&)pATQ12HjU>qOU6gWAO~x!p$yk#-uMjyy-)IZ@4wF#&@{>B#bFfBq4)*j{{1 zYCNf!41@m1V|rk%QhtvB$YmLJ{1uy=fq^odUr&R| zYZ$!M#4*W)$*`*2k zh>8vz?1X4Uo>+V^uYvHxf0fDXG`3&KM;UKEgO_XxD)&YO5^inwdRC7tw6kqoPPBPW zXY3wty){(Q1HvlJW~W+`|2T}L2ACTvZr9TS!wnv*8Z1`Wk5~oB`PI_t$@%%wzd6z? zGoe2QmpxN8B2?!8w!>QK(m5q%)d3Df(q_@OB z?mT8~WS#+^AkGk@$Iv)nqbwSis}hWJf~n{ue#R z_*cp$O7QGL6G-J8&e0VqA32-{iy?WSR;+_F|1q7`63?yhy%;_lmm^H@Se%V7`zTJe zPn0towl~gVp(DU$G|eCC=orh#0D{fBVe`$t5CM#l2&;oB{;X z6mZvX|3>3ah^6@|BXlySfsbLSU>w*4&$H5-pmcOliYD|MUz9?nQW}-60&$5JjB7fS zA#Td?cM}RThz+Rb^v~BErBWSuP-X(EmiE6p-2Z;>-SHuw?t+!HcW`t<-{9|NwY2xc zh5EDYfCSNGe<8Dol8|!k+}{LoV2$k_gq?qM#>Qv$Vn-rlBEc_T>Y5LWxdyVezs^Ds zB0;rTb6IP>uUJ9ZErVhAXJQlj7Io~vU$YY>AF&&CDDJg-$ueOIYd$&!df!D|RZtwh z*JZKAp%gFf?u!>GR@|*Xai>UuWs$PDTZ_9}aW5?H?haeriWDslAOGLWmzR6yOmdRE zWHOoDd$9j%0gPdV=W9Z5YhO4ZlJ944S#uE717ri#2i=$dQX%HLzv1`=&Hh10TKK5z zz&}j|o!36R=?-G3-H3`kTugm*q&Km+=p5LA#th$FJ%AWZ7VgLrOuP-0JJ#x+kdQ7l zbgBq5C%I&x*i$dCj_Ba^=f%PZUIRWs**VP1naVMz;$;W~gYF`8SJE)6cO3O5D;d@m zBA5dF=QVZE)nqzr_VE-N7*kW*qCUZl;)%if3iAnI;x14X^ zw=mvp4bm%BKA(z(|MgD{747X_o;Jaqtcbc=mcGC=E}Z3}d%|}Wi0<9I9Wg;;E>5MO zQri97sq9&2GVekA?Bo3v{C(E7T<5R1Xd^}gj_8SQ{cYV$!mT4z{KkYC)m0g|z8eQw z=@*_1to@dmQ-^ES(l(=ISaV(IdlviSTQVgdnws3@I^Botd(_zcfTFt@CS_FnV_~%K zY`${JwcF!_10NU64WdDHZ>&FliYX-Sm~E^-;VGZ*v7{m%T~bXm{TiaLaq5+$%V79p z+1|#U@Nao5OdoF!Z(e7DM&=J zuOZ`=(U+exa~q@^r%8*Dn#6!9)4bJ04GrUzqe`;m$#-X=3v>k)ve9T6E9Vn@CS{Xx zQM_t5H7_dw4=(fUk#ym-w=FD%iA3U!la8o9l5NJ~Js)vN^1eW#5L5^g49FN69K6oF z8w6Y#a{`6RkxwTgP^Q_;y(xLwent*ljkKJ~SAJxnzt@{_8|13hNGcJWUJ|#VBVby* z`a`-{lljaK4U-^E5lCkgAThq6ZortE*1ZIg2B6aR3*FlF^}=&Pqdcd%DOa5{GM}z( zU#40(WS$YH->We~!|SJ_p}q~$+?O?8Bz?39yPab_a;IJU z>fn56QN&!Tx+VSxKX5|F#j|DlTxLY`1qFjR7l|Wts&4f#(~~J|LmXXj=`Q6E%A?y+ zCE5bw?7=eJqU`-ppa3E~SP3s)anbk{vvUZzKJJV8Gw&eGXZ3qBnu(V$!6KX_bAoTf z>O!YQ11-@&A-)jpHD%Q1NZI%O610R%jG+d4_WpYxf$rb9SX^L<{KGm`wlJat>B3U8 zP}yd|Yh~X9T@isc31M*|F~brwehOf%V|oex*_36okwA>p68( z{p=2Z-CjU`MY-8L)z+bG-%L`+WjSLi0bTlU6vDx2*{H}6g z%}8F0+Tr`$r0m<=P|U9(=E4q^?kz7R3MBpXpBXIq;|6ZTkf~7HS0fCi z<+3V09wb0ghHfLlcnNObsw!kERi?G@8RZdw^HKn4hJ`O2NyR^oRH*L4zKsbDh}I%P zC(7P#Kv3$79|P)}6*pLg@r97w6|f$w|I>q<|IKGPaG7Qv~K7jdRpFPO9N00{@tspkM-m6S- zf)~4FCpKv21FBA%lduRl&@KwvT#Qy<+&epojEq1J;s5wiN!Rj}H+lBeQH{YJ@V&Yy zLh+trp`TNP1W~X1Ab}z=jB$UN{)I@uMA^Bf&1EZQ=IzQgVx~t~ti?y7J8j%^6SMM- z>Y*zwUwK7j*$>Wp^c!(xDx^6DtbqL8E4NRe-^DY745}6Mvg~Y{zJv+TJom2hOpF<= z55DutI&-C%ybWKKZN?Wa1*C&=INRBfyqHwnG=7g&`r$E3a;f+eZt3)DQVXzdC~C!> zV=+bk6xZza=VW`ECX0Jp_SpJQ==&m?n$<*v6u8xvMhiiAG$Y3`{2t-<{qL*yjX%Q& zQm)m`UiMC>PrE>e9z)0DP|iF=?ykGK^I?xK(@kQVeF%9ohu-r^jbE=r6F=H0GPNi%P1l7Q(c~+NDw%jeKsqZ8K(bfk)e;^_~S1=378t$0Z zMu-rLLZ3#&Bd1d|BXn2(H^Bz1WbJm?>wsubWwk|CrCul}qSl2=XNU|2M`no0${&6R zuF}KGkmi%LE|Hn(o|nozs*<5_>$A-G5s;RqIr%ngEnW%=eH-h<`t#IU3b=E*QJ_3A z@Lut@EoLr67&6(BM(duiJ5L*HTAgJoiRtcX@GREh7uA{E0$o+hXq2@zDI}n#U`*TG zRA$zYE@&?`l0h#0QP$~!pm{#Vla?B70!##LnM zjc{oUG=CY4Quoe!|J?4M_r)}74Csqi`kSVZ!FHX*Z0N|&(93DNN^=?HWxb62ESv35e zXm`#d&7O`?7d!)oiG;_du87Sxxcyi2-I~qQSnMqpgN? z0M`&9`c(Is6dJ*TsM0Ov_Px1UMzi4y`%9`&t9+U?ZOsp~QoWL$eI?Ugn@+B{Czl@a?kWRSHU;{Yq4Bf&C00C_o59mG~ig~(9 zfGgv=s~gl?(%TcJ>UI<%gtYFB!2r$-%FC={9Pk#&)D{6pcU6zrj8I$SWB zfY_G%tKWOBvq3k;+atT9@3?e9s04OeD2=2?xk0Hdf@({)DKDDM{m%vj6sqhXElS9LHSIuBsG6DjctlrZL z`1OPk@`bi}xN=^~Y>Ewm3zuT{^bEKG{ zLX(iLZkV8m!qsZ!l>0Na%)lECV<{FvLF3q$jdCR#t8x+bKaFeS=Kxyg!5=Yan`sk8 zwAo@C3^#9ORd7*u40@h~UPzJI*ZQFj$B7On;Bg%$RHJ@)`=I%o{$JFVDsNY+4{(Wa z->MCyx~wP85K6rMw!dcZ5b%l zFj7QLTP_!DrIB{^`==)Pu*R~{4>l$J(p7lof0=se5n3?UyW`o_fB%xbLZ|Nh_4RR~ zg4pH^2>QM`Ag5?ex%RGE8d7~L1og(sjyClX;Vp0-p&425`^(J?0SP7D=#H@5n}!e8 zS{K{BY~mO1(fojlBlnV6EblwgiystwM^Fl&&$tlHm4;|7FH_L9pB$tLjT@!Pwpp|3y06z2yDB% zG;Y(F;$S^rEj)HmaqLsaHI~bGZT1lU^3+(yxLr_pL1Km$Ptj~hwJRFl2VCTKX% zRPj;1;kqdGZL@-!+h)8=e z7(8t&gnvTImKPvOb*mrg7K#tj^5>?Y_`1wx9Te!9T>WNV7oxMf6h6ocK6An+sENL2 zR!3sg5$^x=v88l8{G*q+EbxGflR?^ihGhP)bzhPXon-yl@8B84nRC*~M4q$Vu{f^A zh58$-N#~BVPz0xIHfJl+fWHD8+N2$FTL$3fVKgX}z)j-@@gy8I@v3WaBM723BOAG% zH{7ixK5;0eg2F6kIegS`}SS<0X2k(Y?%BPcLlssrA?maC++mCe@>GGXWG#&neUfvl~n<6Zi_Nam0g z%mVciSduHqKnvnD$i=gKgO+ZED*VAE`E-CvZE6?+IBqqld7SPcOOp}**R@DwxRRTq58z$gB zV8^I?ZeCC>D*ETNRCueZFRT%zb*Q zzZMjpqzH5CL#(8&JfN^e#xQr*4=y`wDQ(!fy4x(mY2aM4Hb?d@F-jFnn#TZ@FBn?JJo7HA>qZD*`WzjVy(iZD8O6&YpGVLVt- z8+?73XZa-C>SJ~lhg4gHPrXBDa|X>ZjYS{qu4qq31!`CJXq6NwuRHt&q#b|bSaaJ# ziD)B7-)nq06EH%~tvvuEzpUKz{Mza}jv#xxZ?|~E{=hWI1P-NI;)xDqBfu2$X!omc zgwHU#2&wg&BzHflq-w@E!Qf8US1gpzb>trunrH2nb9fAK6<{X||G*`y3(zR2@j%@u zxEBF}lG*nSMD}E@XH!?seHX%W^3VI)+As_PqKG|P&ThT?g7c7g?t&qDSZljj(HwIM zIUbLFI_HcowiQabzg8_VaQ@Tp>K@0|rm^nSl)-@%V*wyiNZ6>S?pjy{){4Smp)w>WOu=9nm<` zjw#2(>D9ZZlTaN7^pfU4MT!Gsu9#kf51N&L8bfU9>Nv_!H(boPxBEtcOI1VQcYiH6$r7?F=e7bmBd|i@aE3aEHq&^lIyI(K zzzoI2GfIX|pXA!tzpSRpYb~`8{T9vgt6p!G>LMRU@wr)fzrj}G>n_cO0f<<=_AanX z8tm40UoUH}tP8%))YU2PfIBVKB$zUP50YI3;?%HFyG5`#+7%6>f~f8HgC zM{N0Di13UGz$#Cg#19j84;azI%==Lq7T8UO<9@yD)*ldyu@kUS2-{KkyL9Up;Z2pSCd8(r%2t|4=X|d- zZk*GkI&L}0+agklh9;j-75oV)`3bLn{!b?p;F9I0$ZEQ7mdfPm3!H5jq{DlUQ7$4} z)%o2}F|kTm4b{8tK~}RiiBz`V=22@Xt=m|j&(e}J63aVD)sNvc(Im3#7wMKqFtwTeZb5} zS*`v6CRF6>foHcLucJ;??zm(5`f4a>M|XN|4g3wZ$Y*UbXVAr5#Zc%3GpnGlDqyP< z7>dw^hxCppkK}s877s{;!nRvFY|TF0hfd^#ToQP`;cE)di21TTW=6z#C{50grr{VE zCs$yGKcQo%WioZS2|rt>QxWuNhJ}g+U^Jj%L+J>S5#)R{Fu4OnDC*;5e<}bPunuJz zwjtreqCVIEz?167tp>=f>*@kVj33dwf3EXly+qrraNyYwTo_=L1mul~z*VcwDo}pX z7L$%8F@|fy^mAqx}00%kB-Zjat)aS?aBxYz5eGMZCv zKwqNwq}nVg7T~D$DqI?0YgS9&Ie5I@ry;mAj-G~cHq%e~r2O2JHAvWpmB}Pk7uk6< zbM#$X{6om>x4B?hm6|`Ip{}IzxY8`Uk}F`90xr_n!C6TG;4_ePk#8i4A9#(6(aoF@ zSDy{LCX!qfmLvvV;}G18_3WSqm!}dya}y>;6-dVR>CyAdnr+bVmssGn`M{t`yFXk? zZX^#9##inS?cVK2iHb=xh^m4l@F_;8!&iGR)%6V*r9_Vv4-5KqM0-y&nAMoW$bckf zf1v?hJRxA`^vFWZS(5tArN3^7j*}zptgV1Domu(ypMim{_@Z%~aAAsy75pwJVyH@g z(`PXBEtXbtY)rDk7x?ihC?_sJPTtK#Yq?UyX|TZ_9te3aeQBar>C?y zKSPK*Z$@B%-Tu`%aI!9rf=vkeDUZfpO${WZ#+g7wpsP&z{(} z((ZD->eB9wo$c3m-Dg~gOj6csVzP$R^Vnsc#K_60`4fCt*s5)ecV)(AOfM>@S*qtU zrM=#HID|Svu373+|4&%l(tTMZi>W77?eJ`lB*F8c7{$Prfz!1ubrA+MQ33Uz1bMC} zLs$N%dxbx%rhd(Cs^Z5!Q6aucW+{}l;6G3C$UHh}s>5%;>B)3_DXQ;ZI3M0fw6M0r z^ImPPL6r1oOl`$@PM?j%f8Lbny`!*UUR+V$cyI~s(1yiHMlhx6d3yYGOp;%^adN(2 zHi;km+EKvt6XDR3pNTyj>ZASH_k-GtQ(m~4SuYDJ{!-3_1PM+DE3tbj*4C~s&Ra`S zM$5&|eM|iOSUhbD*|7vhrn#p#KU*Su&prHcJ)ZH@CWQ!i7AQ1tF|&nBavb)tWD8OM ziP5u(>V6iO8Y!kKV5cd+9puF_-#=H7wa~EI05H|lsH7wI+o8KRKpQlWy02URJluti z*;p21>t0S=?~)PonNL<_5RvB1-d9>VH$?^y5mJ&=*>c!`&~jBPova|&d$*K8y-|n6 z_j;~fQB=l;DAtXi#$Wp4xMp~jW_*d1lNGp&AMB}Mhfa}?zY{ye*Z93Bw@khHak3bP z(yJPLJ-e3wfN8JFpybHL^R}`av#t%wp4UY3C1D4xn7Y=EP{Cn29Oq$vG$Q|ajXHbC ztwphPqlwYSv$Rd}{NVua_M~Z}{F@~1$eIR(_npiN)1P;&tEH=oq_7MH-FIhy410TF zob!{8c!~C$SB`#`mg@WrwtC6@Iuy(EseNg}xOb|7@DsId1HN(wlJvqaOMUDm?`(OI zlE@jo<|9G?0S=Pn&(&r`dO#=Qf2fZUU;y|ZN}*;3eEJW3V+J_>2acHmp#K0p3&8U~ zkj(<{`wvjD0@?wiDR5SR1kUSVO%+_a48wE;gsAltRyKeRqCa^`02@FIF^@8(lMSGV zxK8!INSVUI4q!*ZqXncqPyi@W;A{Z=lrVMx8Imjge-u>;8#@3mg`5LGhKRtF@|PVT zkJ!ijzetjz&H;Es{lB^LtSxWR00;=-hzJOT2>;&-1HxHT0yqFt61{8y1T|}GI}0l= zMQ3w2PKbqvx)K190EytWHyXnKL^R9rx|m)?P+vue|6c>4FhG$b1;7bl_-~smoPc*o n#hic?Zsyk&m~aBH{-d4#MIAyo1PxG20|XQR000O8tgw4oxk|_9JPl4k( zeMs3f>f%dxYeq9>=~BgQ-9}W|u2Jjb2a%wJE|Opapj2|L_FeW7_8HELZCvu634oHS zZ1>1qGy?A^ZtG>j#Dh2djd*?c+605!CyNEX!{ zkWDBK_fB`-K$-rl!NK6{9Z(Teg|V(0(rAZbbp=Pq%gMQG`j)fl4zVS@7jlruq3m5 zaYYR!R*Ry+G+N|UFDik!f0I0SdwUySEmm<}Ts@m{>GIjX10m2MIWX#FQl{U3E1$;Y zjrO(q6aW=pFg z8K;-Y_`Q7bOU8varbRx7A)3w7G4ga734r4Q=3P43&Bm1n6DOBr33s@vlFM0om@JoA zH-S#laW;n$79hL)$lub%YA!zv7S$d+@_&cvYB8?ze5NS4Es|x)-NUZ`Iw>_|{+C^`f^6Xc&K86*H(SF4DiR(o*3*<;Na= zhB<7*rbPkMLO{MfJ=nwNUi9Yd?1X+Q)`Wgo8a!3bD|%##`9Y!?9zx*{<8;X~3V$E_ zE0{xzDjSpBV$9sBbC`&ki;BfCyzVyIxu9%Ro;MoJhSz!X5;VdzL zkeSu6A^RuQM0GZS$dBn_oC9AeCdO}<`3KcMt3_`7yiRA!w2 z%#P$LeU*QBwW=y)V37ZZ!`Gu%Z-39uj*o`n(y=afnwHQziu`wbHAOTdjH_gEHG^eg znEe9(J;@c*dDWccB?2kNJsu7R|Fs7t;lIt*{3Qjhg#R4kYM7-3J?w$#4^=hJ7a)v5 ztjf|y`EWJ9-kYU!D4@6~P!h%|0pYMHr@HXZXW|7;>|V4BAp5iA2HDt0aDSO5T4keU!3!p-NRW$>HQyay9@j28^oC7h|T;#Kz>jdO! zrF#q()c)(!{>hustJA&yUw`U~qyfB;4AC6$vKJD+E?VW}QFnHtVKFQ$& zP%m&T4FJy)E#H17u4w=^F&~0_UKcb6z2zaWhj|OtW{LfLyeij(g_*G?(T z*M$5jTTJrXbQQx0#tQb=rugxG<;~8VJepFhJxj|$d-z}A%8s)$Lyy33Fp13 z@`Di(&(LDX$zmWiY?6=5XW3--tVpNN7BKD0B`6$F&*;VI1yn`TQT!$f$C z%KZ!kSA1Q~XU#ol!H3#W-GO}g5yTIykF)+PyIP>|Q}g`zqz8-F?(P8yh*!t3HXMd# z*-e(-#;V)Q`8gaMy?@5CAXCl;y$F=@*Lxuh<>V6N#C#6cj9DDCaV-6xZ}(0?Q0*Ka z9`=uRH#Vx`ZfhfgKUQbb^fpyRaKv$a)`E#-BR`6t#@oLV9{d}PQYrFBs6~NH9*s8m zT{Ix%q&(nKnR4~Au4r3hhu;dlcyB)Emw$s^qSB;ybvtMTEPqlmcAzW3w&C`G{j`|f zMcI@rKQekI!UiQ(A9aq-=Elax!SU-6O6~p`pzr*lo0MZzVmHg^>*x>N8J0ob63=s9 z!Z*tf72NHg?NPDGvp>wA{o!5ohc{b)INbWfu(Ki5^*EVK4iE{hOI`VL@AUNev=?>$ z`uv-3&R_iNw|_6@^hP{Bp95u$<#+d9y?u@4KfJg+|K^)HJ+EDQaI}A{3csA=W2h_) zO*V$5W13xYKWsbIv(~k(d$32=&UDW2uyY6-^pGqG=FS29OpESlgxxwC;TT9`4h?jG zh(HQgsGKIVioT)#HZEgUC_#*MI2;AX^x+Jv82gJrDMYa47WT z8!(Bb&WNVSuz!H#e%TrS`MYob^!=azJoz^L_M4ZJ>Ez|*x8FnWO_J&5<@4_+osEq% z&_dBd-i}^8r_n#^AJXW9+1T0G9~|t_o6*kk(f;5ye)uK%U!Iv*LHg@_4J6H$=$+)xe)9HX=I=4jztA1x=_q6{LK2M6|wzDxf zJUK<<8eTwq3Si65#;g92=)pPF*?{qQgHJF-*Ys_$BR*zh{5m+|uNlyG_U>eFw0n#I zA8B$SF2E_N{A-Ag|P7e zMCM6+Vmvs-v3I;Cf!vf}D2;~ssu-uD0Cu2T09k%DOX7Y0SLmKuTIxy$e#g<07Qe!t zAMEZa^n)W0eF1YK9>UKGbnw*-Nx9$HIDYkijdu194sgJRV^l|vFaOq|*R&+)_otwP zrGNIvq4Tw*&otuddso)bi&Qz|=Wvs07{2MBFuvfh4R1aSuajlEqpbFhF6Nbjhb44P zJRDOYMKtNO%&WuOpOJH3!*X(+jgLw8cbF7Zw}%D{H?5<-xt}^h%+%NfG1~#hFq%oF z&1#|IA03axuf6|#+dse;XCwN#F`gx58GqTOyTZq?$;%uSrHPME5*JN>`iyu;1n_5p z8Qy&JKpm(|i<_)P1A4p2g+Z}5$&ks?8R65>Z=@`G)@ztQLm0qcS&GzGu0zEatM?6V2=geCspit^tc7dcYjIp z{p2zoC+X#P>5D%l-~RFY%jd~=e|q`HKaaorVW5Y^lDJ4l!DyJ<+e z@K62IBT#935vw4F{hia}jUW3%t1C2`&(R_H17-j)KU5`W>`S%<4-O##1yOl3O~1TB1k;nN>>lj0UtiMKL(PLe(@3LjKwy{{eNE_J82Wc%T|0Sq z_U4#WA>Oy@Y=F(ct>#g80pj!nt|lX5UhK4w_ZuVRhKhvW#&8c5z}+FJzbNCse;$3w z|9ScC#_r%$X;`4PCAea3sb8!XbY?kdfc!!JBqiW4d+&5%&{sew+<%H*fV`%!hsV2v z{lVVpP{Wkh*|Y)}!=V=s-wgK8L`CDOm^q&T%M0-pbZ`ITOQYyK8T$a=5HYkNlrC1~ z#?kTa-so`e=k?UT4J;NugR)2m*SFZZ{1|H0hw}O%7ckLjN5Gl+N^_f;nqd3~^>f?{_V15Ks z6hxT%JfKGtfGsBluuqRB067*)2Y_Uv)k2a#3TlW?=4W)Ys;{WunjguxsXLE0R2&kW z`tiRe$P(CAj}1K7q=8arkOoiIXOQ;BXMD0t=ePFPA-oX~z<*)8d;9&j2WKPP85p51 zOU$*n0{$`H2p+=sa+*EE2T{r2md5+PEz>K;eFze#&w8<(Z8#Dil`QTY{{_qS(X|0A z+tVL*lEpa1NhN;SU)jY&8%qd6k7JNrNf8w*7%3lgk`?ezUfj9x@b+&a!cWbf#ql zav;aDS772tsVv4d+~eqM?411!BLjSa>%+l=g?@($hM+O5GmXH$qfBrNpV$f;l|ze z5!ARDef{tFz-t678CF5P`im-nq~T%A^$x_lpP+;!8!6}^)tgi_odHIwaBWQe;)=}J zQsC-h@qgZ?#8;;4p`y}UsDP!rSSV=GchIXN7*lL2I)-o^A90QE)4Oe0qq!b@6)^d* z42&$<>O1BWSkgBz%V7b)(!!E?2!j52OimCiK3+n}&>(|0UaUm(ka7UCwvW2#C)@7e zCz_?bh+c22R&r70K&8qOtZdmhB%(bqDu_vrihtl7K#(jZVcShLwE|}ct?7gQ(d)N;ay~db(E-Ig z#{Fucrw^gj^4Ybu=G4n!Q1MPO8$ZMUtT1fg*)awPJwp$8XXDN%o;WG$yn6?9&1*j&9>V8I?dRQH z_>9)-=y-pBxQ8~W3|PT!+O&Jui{`y(vVR$au2oF3MKV)Tl({2YOmo3`v-~PHUK&C~ zl$fNKtE=vpD49eN)KH+#bCA8=WRn7YaA_ggccGASxz1lJp}u3O%>aI^_7Ui*SUdJI zxk*O=-$l_tuI@xsLpusMp5jv{>1^Uun(C=EjmeMOopwGVF^l}RySaJ3_2SPL_kYpX zAEh_>{_CitXB&r>5IsFyozi5!Jq-{xPO9;>-hSy$1zA5(G)q?$K}d{u;STCWUw--i z*61ovt{L-v>Xp$VqFI6%OTjdjE`RH*V{Ms#^YZF4|Ik%&L@}$)*wU^cLT%P#F%KXk z9M)|u?`2z{3lzJQOHhBh`Q_heVSlGJ9T#^d<(K4_z%tTVfW=QChcN)e0*4qiXbgzt zq=FF!q$q9a%#0VUcM<<`@mATO&FY z#n0Y{DqT?2;o<3k)}1K^CUzXT574gU-(VVAC@xkDAa2CLVcqFMPDcLJ{eSX3Gm^=8 zK$eOni_f?qEchU_wxal-kQ)*Zhm(Lo%t=e8zJGvtmVoD2^5PsmUr6rbIVko$dr_5Dvvix50!)UIsy#a9h{4RN6v*WzW5^AAuf&t<_IIQ)R>BLTahT&!+6sL@CN-R z_M~5bU!}zz{X#S*3iKJS<1)<9kuq(I8~9m=ZtW*zkg>y1w1t&In16!rvnn({y`YIR zh82@_nG_f_uq{!b!nT{1?<*O$A$SVfX8>_6ny@aT(Y>z5M~oV+A!-NPVpG73ZmsdE zN)-cA=pimAp|MwdjB#v0RFF-2QHU|#?F~mqxc@8%uVaxSQEpRI9FrmjznK!r*daPJ zBWgbCSb9tylRpr>#DArbquNEEf$Qvr1_nd8l|d^3*>;07R&K<`pexMFt|1~(_Q1MP zu9oOeE`?>=y$Ngm?@g*nT_>4>)R2?gCr8<`^c^hmZNuZi+rbCNsGMqRUvBsw9REan z)cOl=?j9WDMy`IVHgFG)2fSykzwz$u!7;{V=(oHDdvJV+YJZgpJJ=Dx*;x7pl;D7- z34Pb>c#FwI8_y-c1w#leH5)_Ge6$ocQ}+gqCb0eSLk~R^pk{B>xN-yJAuB8L zKK4%r!c>~gbSsFYEe^(C6*J)iWJe!%$M(m2$0m?PfuEfYq0jje7eh~gXp>38%hh(* zB88~Hjeo9Q^t^}20?IYj%F2PGO|I4bT(Tn_VPb4i|3r$R{VO?lgM5C&T;(ar25*^R zdxlm%iQlD30pAEkdT+#W`Tc?p0|)dz2W&y+Ue@mlv%q=-SI}L1hQ+yp>AEnuY}fDQs6|um**Yv z+<#&B+nl1@&?ynK`$0I17#1G{ARaDQp`FOzI7UFeL~rj2@7`|;uO1&)vZ2LGgvK4O zj$UOo_HBj9aGPi%mv{fOqsP=LM#^ZY)bxw^BR|~7UzkI!soWM6*~4wLqLVCXmyCnz z2nxCzKin)PZlqzy_&)7?gdg`?A4R|4OMg;6V&~rfhit<3NBQgif602`o%nU%F-IK` z%5kUlbdHC5%`yKMXF)ey-MEnByJs@&lJMi&{(6;7(r0`Y04y~9YqXC`*KJaxX6{yydXK9a2bU)nd3Kgw6ta#d;U<#jrnF}iq?jybA{?dUm*YdV4} z_O(PIcNBFMME6|NENa^pkD&agADDJoF}u!{$tVB=oyR|*nJ#=TmEGf+Q!?WGvw`ZEK(0|0lqdRB< zAdG0gEoSfNYzdtRk|P)wc$9Z3`SF3fq>Qke;*P`ucpfyRsvsz-aF??*U3N>cqKdA= zMcw{jYyTXbh#Es7Czvzi028ZND4Id^WYuT{$Y#?X9pI-k?S#1((KIqW@D8fjDzDpy zPtcrvxlED039a){X^G;O{ePJ%Mvo!>tI0*yr<%+#1>BaS_C_Qg(n%c0V3BsjMo?EH zl)8c;Q*N&@kpxX`gXZ`)$wWcB`{kc0Wibs-~yZ!g8DUQ#LJBv1plLn2i8EeUjNA){r_Bj4a?~kg26u|A3t5ZL?nt##yL=VQl!)|I2OxqSMO_gR%shUby!`Ha+fOK# zNRgx?HbCUrw9U=Hf)k$(vC;E1dq3fKeywm;qj zs}|`r`>@?X5Hnb7M0t0%BljGelxkd#t7V6+sTJz+6!R;VAvSM8@#R3R4lMGjCZ)2V zfObZ})4~M(8+PST3Mat`9k*iW1WqfAO2G?1I~oA*G0}m*x@jrN3?zBL>Ple@DF`p!e}>kh>(k z4^vQ>$7T2V=KY7-k1sawrT4_NJ%pU^e85w^Mf871S4FyvzWDMB_&Hux(btpc3;4gU zr{8uQLVr+eWb>8HI_4Z_++wNAbC;lpfXoo`wPR;(v(bDFI!{`ZG>>l5BAea`Qwuv0 zr-#Luu&g4@(lPRPco6A&w54wD>njhZdyTWe=d(_*1h6z$U! zHy)eL&s~3P)Ed_^!)s@DmA_9H6s2hrZ1}W{#u2Ov>1Ako_sI73qQT+@kAI#qVuMg2 zU)N~6B`rm194&)9Ly@+cC6kmGLBkCV%-@ z^oYFy4ew*I^DB-zQCV?9dzUca8SRdvHL)vbIIor%2b5B@X*#YN{6DNK8k|60icv|$ zO-){Z;{5nj1(ln^uR2nWPCv%6a)ztGI7!21r=n{QkVd zBPDjj@Q)^t{*I5vS0EQwSF?OMGd?>5DS>DcN<&@e7(THbbvsv>G_Qkt43PzV(aBfU zEYIJomxedr4I?MHMD(B%LRfvJ!(m8~nJ~s2gu*$7P3)1M6y3oh9m{4TqJKEOp5@&Z z7_uCyS=j~`z$LbJv271((P%h4__VF^^{gj#>P8)wSTn6;pq^$zd4TZ3CQbyN?+DpY z&%D}M%7`V=N-+V{>%ZguJ_enuG>NcI3 z^oLB4OIAam>TivzX<|6DY<~@M+KyYUNmHN?n+|l?WEe{GI+c8S#MVnKTrcyjRRr%N^FHGMzt?1L87xlk)APdXRqEGG~_(tmlU$_+s-V0OkP z3~z;x$0D_Y13O%Cx*ZE?DPOwKbV?0Dbtcv>`NQdyg+7FXe|R>MEPMn8%?jv&ahBMf{;!hEE{1Fq>F4hlyiIz$wl0>Kdn& zML3SB2qUm*o-W9(CV%!A6i-+%OZJh;{I^{z!UInZjjOc!nooT>^B9Yw$9uF)?$EYF z?;%=-qsvSEBnG>ot>_7b1&<0fPb6Yj7X)fL$G>u6HRG zA)hcOMyZ%2NRDDVxt~bKWDTR0!RVwc|Fi-jMVqwU<;YmP695{gg>ulQP_x%*o2M;H z>y7nm4%X0(jLZ*ecc`wx@~ozyORt~-FO51&guXzN(|>hg1tUBiO|e#*C>d+z4TiuH z-ri@=!eE~KCZ2_V`VT&x|G*O!bk0Ip^oFTX>tGPPYB>;EElhFQKs-3?pL|PJu8Y6t zxGWxF##)s;u!4XsYkNQ1tyxDiz??hYUPbMaYSAt(arg%{vCtDc&1a}u>WMX5P10>k zBNiYLWq(T37+A#@5_*R7y-H#|NmwT)9mxswjhP zxbP~Qv^D5-wLo9d+re%f651$hBw;+pexc(cjrtmzo2>+a+&U1)UmB6kIsIiTzN|cy zkWJ{wk%Na=+wq+O=rKap;zQH829Fhbseh2ZJw2#J1}kqZF2kkGmr;QQ|}&Zq2ta z%0CK3VxkMY?o>Cc^C$b7wca9DSzog__$ANhZQb=>0P~}YH~ayMxMV9dH3G^)qkqB| z>!b`crjaHD;IjD3r9~C5qeUz^I)oDcR&#UddJ7;T+oY-FP!U`6@Dxo(7SB=;PKahF z7zGtl2=UKS3Vl5X5Yx)|CYwysg^k`&h|{DPg?iCkc8n&1;zVU?yjX#$CNH@ORA6?a zSpJ6+T*0B1D<`;4X0lok#h%I!?|*8SGt758N>(5PdCQ{oEP-Si2w@Lhi9xw@`+$nm zZ=> z4z<1d@g9Ljd;-NjeTBN{rhi*b#=eD)lbDHN@lS*#Ya1;To>>S)c zIAb~CgE#KTqjgoa^MLXUIBOjT4y(OYd05J459%Ue?w$kK#Xs5M6MwOT?YOTyL?yWZ zZLKwCKc?Bigj#`v8I~7ytq#iA@>xUSvU{#yw)fncy;s|VR?{5!t?!<)$n$et%2O$_ zvx6>8tvAqDo3ovbpMzt(CyMWVG2Msj`wf*tO#pFXHT?7-^Gy+b)L^+S)%9C07X8Ik zoMdjSVOk9q(_B7hsee|Tg;e;s6v@i2OxGfL7WoUOa9fIlR$%zbwLHFfqIT>p?R9QC&a4OjHBrveMXkSWmM#>vmM;~$ z6%WEFQpmsSmp9o_;yEYS3kzN8pwp-I0`tH=3TI%Mq%#+bzkebbTenn;e}aY&5x{?$ zcNJ%)Gn)jnYH^uzsXGJ+@%sbc(msg5^BKI4bca&gqzv0Ki}cp8U!I8$x;EuHL|_vnDDZzo#{^$gBGdeFa?4zx2E%j%*v9R z5Yw$L<>Mv~P=8OwyC&YJO(2P+ZW1+#0}}xlo2y0j)HxuKJ&2j<6>wa5r?@s*5{b6^na z+HH`_QGY>~jk**VJ{RUMH2F}4KGonvoBck-)Ee$m!EM;AomA4SA`$5K1im#TjG?&D zx1Ko*92Leu5u3}Xo5@fh@^v6{r56hZ{o|fMA}3O1%)Dl25@;BV&XcsVwsriq#udiC ztJdge_O^vxvT_lz;=1k55gC2FzL7;4z>acR$bZ8hWk9)+J-JY40d#+O?WkS-7v{=8 z&u>hhGad&jx4(X2s=cTzpeHUb&33|L^lxr{N(n2~{>{dosb@do!oh!HtAi~C0%;ew zA2CAKgKC+lNS)T&%Kay&kLxoiT*G%RhXDtcg6h#z;*ZIvq4v`Zt<`31h&3j%AvL4Z zz<;KqpvkR>eS~L zjUq#Um;{M_qTKV;ewQeI>mW2rH50|9gG3oPB$#t-ChMtSu5b-0Vc#2LvjwK9V|?^Z z7ZLw%dL6W8?~w3X^vtIF5{`1oh{?gn|FKOX!3plwF3i-If=LL*zb%MrrcYwEVU^lj zFlkK{Rdc0W5&hTlOpso23^x;t=)xluGyXi04|Ha+@4j%YwcK`({|6A^RmAfU*|e8e*-7VvyzSEN=4)c z3GHnRm{{tlX7N!^v=k-*SDhA4V!;RqTZ+6Vkp_#D0`NRWqAt8Av#g|tNq;SZz6b=#wagH^5O43hoBYnO%7nb;u0s8wDz3#C zFcG%y?x12Ndq3_SojLLM34eKmG02{O!92oXmULpq;g4t8_&vhR^HrIi;O$uofcG8I zQ5?jq@j>yQ`}7Vkx=$CWbw9a<89@*6g#+0b@DEZdOK*FW1>k|ZAy^QF6#V0SL1ZGc zfb(T83dEQrY36*CM%>pg9)5U5Y%qyKC|I*TdxAga#-Ws;B}2C5`!_ z)Da?QOd}!b0wWC@Pk%c=i}o0bafl)=K_;g9z7d#O$+}SyqBT?@+v@8y_B4EKc&5m` zKADUNoh2gNg!#g`!WrJ_6gmRfv)W1mFG3dGMDfB+M(#l^Aa3|VP=nUpl&|~9&1h?a zi~Ey_6w)xClDQqA#V~~9Fs-ihi8MEPDKhe}YiNn?>`oiAw12#ud)VBfO!5xjbnafs z;^fjdONgpELve+TrGln6N*CdQ_B7D+#%|(vpxt=B@UNaO3MK94ZU;J{CUT5;sz~wv z6=SFjuJSKh3U_kPC%0EKx_&qrYt#135tLnJ`obEIHm;y41h^(_T(8(of#D&Q=peaF zQ7w>&3-uypG5Vc$ zA|5JvQXihlnBK>C;TcB>H}v2ux*7TR+J}5^^KZ_Hq8l02#>W2f=^80{SN zhuYW>Q)eqM*;xWITWtAkEIx}CZ-qvww{h83R>2aczXH?|w2JPb5c6 zyjC=sx#ui;BrdFLvG6aO3Nf;+7k+D^VK5-3`5oZRT6m`wiY_|x%6DHWU^CgP zxPP6C4kWo?_T=WTWR4v#cF13hi1f9m)+d>6)j}b93yZitNbgjCVG2a+{cem%9FV zXMKEUe{@tBeL`VSbKX~6g(k%Q5cjV-9)CKzn=Jb!?b3h1EHKlv8ZdIFu6vSWLMt%O z?+ie^Mxco@de53LFDBmMMZr%#n;Q(S%D6|4sCpMj62GJRZEpGDTVlp2i3x>RzPcNb zb5gh^2#dQvFj-RCO>b3u(88?hg?DCPUWf4+BtyZ2{Zq6EO^@G-F^?%yg zJ0%x;`_^f_ebHz~u<@b3vP1t-+o=0;$04wNI$8d6$Mk6`*V=1h{c68j)aABxA|yZQ zak8fHYq2M|o}6~ge%#J$kVVF}F?(>r42$1_Tx!J`yG(BfR|!0MU)I8HUwm2 zK0CJ@HKryonsNpXNSPI}_`Fn?LBk{KS}d4-N;`Fe=yVvnasDV^)FCCzDmyM~|< zrv*aEB6cK|D>G4(?BTW@dMuSWd)X$7elDZ9rJfp+zO8jrzSFm zPmdSM5aytk%h0tI_^U`m1%H86qPBv^OL>lk{znk>@UJ+s&?xU^gFdCmf8GlV{U(VY zq(cjR@%f)}-(#2c<^C-?5!(8OJPnM1;9aUTk_PcZNFFVHWa z%8Q^*%-1Fr`7LbC=8d2x}=jP-XK13gM*DNkc{8FCgBkV2zC5fa`|NA!$JgXLHSatP;+YERhdpk zpw}lZmE%=W=IX8nLVrhZ49`8kh_CW0-&;(Mr*8pQA5qnX+FO$NTomtLmZ0)fG~F&5 z{bI`fSkt3+A`-C&C*IT}T{ex6_J`IKr*kZgKCf03^*%e1lE`a}6;EA%hKf(q)S)&{ z+-QZ7o?DV)6w+r=i&l9xw1zFb8TAuIDaG}~8bCc$$rT!N4S((_dBz(t?<T|*UxADi8+4YSfsdzXn99vNc!rUInInD!SFC1u z3!@ocYo$5jkZ0p7K4NglVk=Ua6fvtJ-AWII&0UhsO(#EvMH~g-+VEa3yi`~J1ON5{ z!gUu0vfwRmFn>Jw{K9hWUZ%;SRC)aN+|Yb#4WF>UHgR<^>W^jDF&bCJED+0l z<8Qu3fy|WDnN&A!c5ch~=AMY{-Uf`$Re@-Tr}Ao2(Vy?#y*Hw3k%M-R!N)LKzy($j zyqA*OhhY81U3YmSkkp^CEYqamtIK7qd5guwe)l02vwtGg>*NHJ_~05&xtw1G?M0jU zaNJc8cLyv0d#}#R#DRy_T|}JsP@>cLg)d``RCWz{XRx$R8Db8)QtRc(##*WkYweRJ zzQE>g`u!Qmz+%w4ej1k0SOv4EDD3N{P-#w{^7;D1$bMq<$AeR#7%1!0pj7g%0!o7N zIWnJEZGRPE9jaL-rnV#_GEYO0<;`Rts`a^(@nbVI=bV!(Jja~OAD&pT&-xlVEO#az z0;g;lwuh0CjKDzVN2o<_Fo3uWw|z$ zMc~rGK1x6Lhrz7VOhtEz)rBv}H7WcoREdg>Dt|W}{}Xrc6a7#2`*IRa3xc;la()3a z)@w5|?(7{Ld`6d67W8N_iO7l1op)pFU5)2!k$$Lrq@LYvj@`MaQtqFRjZ0BLhI75>Ez&T^kX{v(d)W}n!O?-Bf_%YDH6!qSf>CXnTE1lPm=E@ zF;sO2OW0N7)1od;B>ktR=5^xOO)u7i{eRi6z9mhAZs&iBOYGH)n355gZ?+i3rK~Cc zQM0$jb*wb+A~G(|d-y`OCz(tz$%H_r0bXK+e*+quPyt>PtUH7~ZtFPmMF4{(9S&Q^1?BYzAK zdw9LR^c(x6jvSjE85$?wj!J2PW`OHLcW5BMLo8O+se~_Mian*nkapiHl0a zIM{W#88EqJyXhGB=j-A$OUW41S)Npku?;0hsZfC)U4G+6tN7U0p%ng`;#I1#{NZ3l z69pmTD$k2awn%2q9fN3J6RzlMA6bm~S7o`$<|fbv>gS}4o<+mGo#Uh3;eTki|E{eW zfO)rnwl_N7-yiOsfdHu<)T)QJsFi}XYp>}~0*kNnRS|s|ee?bE=g=g2HP05H0>I1f z)hq6>&4+bZy$%#`e2Qd%QMND?svqr5PAtdWrn}V|TSoF#xR->O!9ukHJoB|0$t#8w z0Q~~+;oWh zNSp+qO{v;6KSB~fpvVXQBDwOv?j%b zQDA3$R&kePA9q8riGPW^EucoI&g;aK_l1^Sr|6ricpE-aty>TpuI<_|4%bQ!`Jg3W zqaQk0ybAr$g{J%4LS5J!BsgewV(aTKi+ z0U?h1nqd6Of%{p4sLZ-QI}q7!LSA zP|kc=`Ik~##DBBYb2b8<^Slop%ss64_coMmvw2YRKrs#~;x3{ZPs8HLK+VqNQeElT zvSiY=OpJu@19a1FC`2tsun1A>TCVSdZ;56#AU#dPLDE22qArbZ=`Z-2O_Fuw`i}~d zQR$KaKahztpvQ@|PICT@jT-;N?mw6GwzuifnMf$2>3_l(asTLD5PEo>-wqbbRdopK zX>x@n+b+okyJeP@{&l+ehqLGX8X;byE$=Cz2W6$8Y>_wQ6FiF#2E#MIfL*zlP2a*P zl*t#2SCpzjY55;+dQq3=I9Oaz#B~vwe-t41ubudBdA8`DcfR;||Aopmnz1Cws3R_X zhnmbvAS%Y8N4*v}B&~;$MV_5SrPP`^GeD4EUNlOMnu ze>m^(TQl{FQHnqABxO2G7pPg>AOnlCoP)*s=qF+Eko}Yw5#-V4f)#Zy<&*o+`(v?|ZK~BriSHet}@)j5{91^sH;2z{_3$gZzg~@VeHz_+`V_ zSZA$bc6)i(fq&D=5P?qjbs-(W8L zL)u9qT;93Fl@C8GWEu2F(h~MO*iuX!iKj2PZ+UTIv|ghFD=(jR(EMa$GZ#D?r={GX zM~c?Fux-^Dj?sT1czpRcCj`kIfZ$mB;ZVy2-D)Ub3fk&lX5^7%^5E6r_0jR^-cEnG zXOFjP7oN>w9C5k2loe46hT`CYSR_L{{T?h2dD0&GG*7l;?thydurwOod=`QorDQX~inH48o zqzfbfKtR90j5bfFF};dp@?^eY;=%+tUgCKdGI|(BzA(USsl{M?F!~}Sy#VW=Ji?Uv z**NS%p9*2~qmUVY7Rn|^nT^@=kHdHIHH=v|+;X=u^Kc&;%ws2*m`*4wF&>I}L&E_W z%)v1Mjp3l9`rYZYXT)w|sHqMN!3`UN52};QN5mG>2F;Ld9CFNirjBd7NvC<>*eMyF z&U+79oJ)5$-1le6Rf$(GoVjTR4)dE7FJ^#`--h0W@OtR@6D56N@R)n3ahc_B9Ow) z`p)kFr~bZw=@b)@6?QrCk_$=*x8%=Gp`Qi(&pzlo2lSl)eP@DF-u(Ghe41kGeu62x z!;6?T*#N>`RVK^W>P6jun`WUnk#{)D>1xp!qkUHR(M3?w8!hwZWSv3%|B%trQ_sBa zUJV5%Y7b?V=WC)LH3sgoJG#8H&byIb6W9_YWtshdTjwvfdRrIqjgfT=|C|5|Uwa+X z$KZbPIMxU6qW>Xk)33r?wPSL1^rA2{b| ziHNU%tGRQrF0H{xla%{iq^d!dQ=Zto^n^JQt{0-du@LbWc43K|KLF&p12BA_Ep?y` z08l?VK>hL{TfDFN7+&ihw#cvpmBxq$#`^W7(4*J7==DfF=}q_qx<* z=M`$VUH@cXptDCt$ajnH)c48Oxf{&_t}j%7eB*E=46y#vIRmpsM`_sA|Y^A&YIsG!>;__A!p5bals)>Z9Ym6M9M}Y|Gl-ZV(No4R2#d`)&78oQl%yM zslX%pcuJMxmE0S|wPoIzq9AzPwo$e@%OutwQT6MkmRvtSWNkaw$tg^5zT1>uBU93U zk4NQBa68?^Y-dq;#Qg>WPt6?%&12E|>q12Hs9`8KyaLOp4^HNS4>8aaQMXyZ!k@f_HpWRl*D58fdVwWJGtYMmFTNkST2*na4t0K(}1$ z>N&K%Rf-9&+1CNMul>fVxIMZKdr?6bk2>Gz?xc(K9t>sO zP%4{m^7@(TE$$G45x0T`7Y%tfK#P|L`k8KnK8Y94pBvZZU5EV-HV{?z(9wL2dO|j4 zwYTFSlV9JS9su6a2}UpA-H6x}7qm~V1`%`CAC7k301NM&?VUPsGA7}F)_Je)0=aG+ zdjf8l2a{zC8e3Jbxvio9K0$SRfKL1fW!S?ghA&CDCVR z*5By@np0LD5gA16<}FZd&+)$}%=u^1v&nKz%AKZ|Qpoe%5@}zUu~wNHbhn# zJ<&GSZ{qMx|77oxZG`{2EivgfuWpbx8(`*864n<_C!K7W!H#DQDWCW$ zZihfs##Wh2;^Xg~s44w9uEM}8jz{f|gwc2${|KNvZTTQt@JK1(IVGBIpSenfkJZJz zbUaD`v!BefSq8R$Q%C!rJKmYff4KS|Gig3v(K4b->VkT-G4OPo3uUtCHW>T? zTc4^(7v9A{!3xmf^Dy)eJ0u!7koJUgpltJs(`b}z^LKi(tkbW6@XJ*Nd|rD>3(t8) zfx9czDJ=tub9Ok?RT{dBnE!dwEqFdvo&2)5|3A&KRe=eAS7AOI>My~n{&QdD6L;zO z$3kV{M<0uI2n?KzwP*{Fh9xX5kqdB$CY5{2Db;_TPyMG9`3I09wX<%$^RiSdn6`m! zXWL+wEvv{r>p(SbpW+vEXQS%oJ9ow^^8?|ow~U7rQ|H7yAmre%|9THM6fIvdYP`4) zXt|3CN2l3;Gv#_cZOXb8-2JEp8Iq8qXqejyXhoB(#`;Wr;4&x)vGCk_H zQH8(ls!Y1jw#n>aR;e3>K>9P=BC#Suh3M?kUc`2PDKel%yafTz{KK2dwVBDn+wvX* z=zaEIVOw2_q&4yw?P^d)W|Z|Ds}9-*It{dK#J1h_z;Ud#sif$uTb@0viW=UZG9^KM z^h-D;h}>PU?z3^S88_qfvz6EFSdi=_w`Br4 zrPtDb9UDCTCs!+Rj4rfXS*PFp1xt@iYnVv;UB8qx>C;^FYoKZ)3^zlYs9F`Xnv%Gc z>J$_QB&=Ybh80U(mq;74m_c6*go^JE$C4qn-3fy|I|V{(AH zktXvP(-yzFLld#P*(1Ec(iG+M^^1#t*goz|mq^r%kz%&{c)7Uh*k}P7+c~;aB`!M- zh-cd<=lkag>23?`uup~3R|N86!NhqUX^Y8z7h%xeb&MfD5Cu@=YXwl4RqCqz9U&PEA-wu(kMKXrmvFfq%is6e{v7#ir;?{ftLlWw&yFvp_W7 zkZ1JwxqE;)?KZQPx-ohl+dmoW`?c8_lkdG)4zYPY@U+WjsQ%LB|wjyKT2LUZST0v#FG0_%o| z`9N%jV1WSe=4C0Q-1fN2u#qTOIAkQMz9E9GI6G(l%F38zhX$2N!;G%I&cKAL6W$(P z*;q49*;T(E5Zn8YJu9e%foWg`8aKxnH~5X85NljNFZg@QykMZ#c@YjZZk-pF8akNM zM#iU$K>PH1=+YQWGf+i;p2usl@9K&oBZ=GD>n>tfO8T-XD5iX5+?W~bq-}&~M3)cX z_>5Ky%IX*jfoKS-q5DW45cz`}GEk==kKS(@gSZ5Z!@tnNPkkZMUU1@!6D;IkIm)xq zAkofzv93Z5wIVY1_iJRzH4R!}3S4 zp!F|ny|B-`yH={$XK!={gqT+Dv|ECuYsr_-5!SkU+W*O@)R1JKx8A|w$?4v3sH#R2 zewWe^VG<|x%dC2GX=SZ*J-Tx8<8^Q&3dJf`WBVEinv8eVb-q{&6JtPJbSI$1WKett zJi!#JU%zvTv1c`Z)z;JRnDYIsNH4Quf}#AE(2B17Auvsmeqt@oPxR{e_yBWY;J5QzCC#XQVke(6W#s6dA@nWmJ2#`dFsGa?bDF8-}VNG-L zMa|Ln6fcG6a}FJW8rEne?J9&}JQrT4*)8yC*KJKdq~jHUmVZ}yA^tw2q^HTe6o*Yg z5uIn18=Q!#$zVj&595@uj&4EkT%se%)@|&gp4fU(XV<97Pw!_$rNUm;j0hWh6 zDfc+>rh9aMf|oej(mUu6&qjmYjx6R?`P?vr^4oHhOsABA%c`uNe`2f9V>h`F5qqc& ziE^6XGBl_;rS;`MvE}+e4Z@tfqs4R>nF-W7!~Z-O9ULFM#<>Z4)Iko*de8p+WB>Hs zKtb^4xC^s?aNIu=5c_xuunQo?0fW5CbIcy>0wH~WBa{{b3}s{xMoJTaK^f}7C?TU^ zKue!51t8~3qu!wEpi8O@b6v;9ri&(zH*x)4Ops=ezNY&iDgTvs62-m=xB&fw zqGU(TMZbmOA!>2WU4MMMu%>>*TU))Z_~F$ln+ti(UL|*51y)I5a#%>pz~YxJD*iHm zSeQ%R6qi8$;I4*v%L#w+7eQR__?xrx;R41VoaIhh5&EOQ&T-P$N+0MIFJ5Jfq`2eV zXY2hezqFq3s?>ch%@-=WhL3BV7JOcyIAU8XIYD-Yyr0GQ2Q$Cp4AQ+FODOyXR*xJ`VWPHJg zbsQWj2*7ddYQ;cF3F}MZ?k3|w_t$~3$<||PJ;J4%CL_N~ESF<*<_G>)&6@>D@9M~1;{bqiqdgtju<&nw#FP=+_ILzP~K zV7zcp#p&%$e@SW_8{gEdYhl2DzT_=C!H7=THRrJIJqaN@?jRrQn^t31e(b4HzqMDS zH~IUT{d==Ug!1aM1%v1VN^7a`tH`}zymWAGyA!oYr$t&`H)QP{&jJ}>^_cVLras^b zY7rPrvj#Oreka>~hNqT3fDOQWW~xvqKs~=6kz=V@8i|=iYI12nT{d2ZO`GS)?U3PO~LPVPF}DZU0W&R)3$#(?i|Pf8bv07oCsG`_30V zuoldjz_s9%{rjvAQMsIDRhJ;WWCelhhI0`ysmpNehO*Bqs%3Ly4+O7?$-a`^;JQ3=ZCy(_~$t0kRzASx}->lVEd2@0SgE7 zEtu{(K_&{D&`1TU5r@fDEo)WrU~)xN-;EvB$0YVVYm&}_VU+fbO^s-omiN+f@KvD{ z{R&+=?#7~bwZsjo&ZY;+F3B!XSJ6dI7UJ{j!cjP`^hL)ybD#--j+g@XTsb~e<#%o1 zH<1`3#519seKzF7xmIoFiBt80M0RUBM?yl(Ra5@$lDrfFwawGL#ipPKNGnW}dRkMp zKV?jG?hv_$e@pXJBVuw#MvEP*9=X`B+38fbNzQ{Om-KQrkDI7Td#c%GYNT68D|UO- zxm5oy?x#>rP84Z>o96chsn>9^h3IE&l6DguqQ3fha~vJ^&)(RMiER9ts{})Kuw(9e z<5?)n8GYmV@4)Q+&5hFdHPU zzZ(!*2xLdLriByiI(ihd(&nF2X@-9B+T)yb+Ofu_bQs2_K}T9CYE-z@4^(KLR@eDN zy9v_U?ilxfm}zeT5N_}E4|al)oKppZoQ+<#V0Q|qE$=`ZAyV8E6<-&*EV3K)rB0!# zd2#ow{3vl7=PUAM6$Mf}*oyjxK1bgWheve)Xqv#v4eRi8O48vi zGocAt-+w^Uf;+G-*6WKezKD(iN>BPsoMkdQ?`^q%N@laWaH0nMdy`Ej>4NX+zym4% z-D&vOFVDn z2Bwd!4CF*}1SoyyzVujlU1mNtWo`Sayx(DFS^&EExU!D^H0=S!;L>^mG06;S(x4poeEnD1g+EA0OF| zzD2P2sPd7JP9_t&Cp2B8McGYnQ0U@rALSBfzm>lCR{`3A6@a5puG|Ch9ctMlOs`f| zl`nc0=wZGpQxB5f+JO5o>ZJ!rZ*4%l?#+XL!L>Rkg7|>U!@tx?1Rahezto+r&&ttNkxdL7HTP@aG?`>K@mZeF-e;JHJDZ4X@EwT> z4?I5{)7wS9pM6LtZ(vC&5QU4jfY~rlmXE@G%4J=Y7{psX3gID4y$s``6-vTMSJ|q6 z%bRh{P<-rPYa1F|J6EoNlB0u)DgY2oK6iUkTDHms?Hbbn$4^Z~@&x;eEaJ%)&efbu z77g`hAPY~mKY=XCDh_4#UcBBe!QhyEPR=ak%YBGy%9{0 ziNt=U+*kUOZnS=P-jQcz_`X8@C0>G23^+CwzIPA8_b!O#u6fY+EtsB{?9905Z3(Z;T+-V|r!~GLVBgP$Vi%LGhE+_}I;C*&F0})MuX4);U zhIR3fAhF@PYKFjpI|QThRZ@`Fv*`>EiLtIfR4_J{)RWJLxj82vFk($!Di2m;onxgZ zco;&3+`9cn&vG<7AMZgy%*OA3J278N+|@&2sh(6S-a$}`p+w>P((XqO@g!ee&eHYp zt86c+quN+%3D~gaopD+*eAekf>*yalx#nRC6;Y+eSYDTP<h6w9pZ<1BS4I)CZ zK8XGk4bT*cew}2C+QHF(IR|{64cJ+#9A(@o@bGhodL~M7CgTR2n`?k_op2>`vsm_< zJ&YV8)-ZJh5a>?h_g4ibK9y5w=lJ0GbaZ?)+CScTJFK0+)Ex(TS$*Qp_%)j7Z2>r} z`5}N|7jpwqM z4~_0H_n8*@=U&dVR`c4BC?&a~Yd4ese9@8x`pa(QnLAShEKv zSu)G7T*)QkxE%?9#<20QN|&ktRy&x`rd%VzH!5#DHo0bKd*-`<@i3Z$5pxCX}9~vnZf$fI3v!a zhEPbBv3IwoV?eUC1sYgTe67U#Jf=+x)JoJ5vVO&hZ@A2V&!X!1os(dKd`P0;X@0w2 zDb^~-=y|n{Y>7pVs6lmz7B;E^pMndb5!4hqq#@cKPf~{I&t^bn=>*7ymt3=aTWO07 z^teecmVEalXU6Yu1hc6g7aAq3|KEdybTyfa3IYyn5862j358=IYA0|LvVlKdQP|_D zl5iLnN)aM|E%Wj$xePBx#)japV`JkUza0K-(j@p4^lv5bfV>uImo8Q{{#N+%pnhGq zN3D}YsPeqYuC8a8?QG3ui_|1BS8EE0F|ZUQnr!nq%m6WAu!Vz(H4uF3ff1Yv7Us&; z%4^m)W0c!YjoBEmj!`?B-%uaH9`8Gx?{;~p%x>y`&X>AU7E}I2dj&PKJzw%?L-({_ zG%@SUzZ!N-nGE2+4crTcm)s%5-@N5RK_|SeVK6kmz#ypg^`o4ie=kO@JCNL>w&54Z zo26gCk8`wsGtDa2Zm3mgy{5KvZJ@D}^dGgkhrs3Y?3Xo#FPAyO2F@N>XlK^s3{Xj! z8Q3|0pW}2m!;Hp^QG2X?Q5zU4S*mrIeyee6bSvpi*LglkW~9;ScbBt#{64IFSkrQ>td)9lpO(Zm?Q3P{0gBVV5Phut^(t&+d%^Hgg+DHo!PV)Lxdm&v&{H^ zB1>yhx;a)+qrtRe)p$w01^vP3{q)0_&Jpo1aX(R2B;)il8NUy5( z6S-PU=&-_?l)jbV2Du7FkY>ArR>D;UZPe?iur<~b8B-=!6;;$*Tx_JxYm5=7)<`KT zKI>BIM7JWWhzrkG76$O?p_ zjpWwbrC1>r7fcZjD&i8X@ig`%p=lrM^_Bor{D&p~xR!kW_U1xA<7g3NuYp* zPQ;crv9@{ccjw(hyYt?q`L4A)tK@RjekHmz zGA}7Tv`{K!N#9^KQMQ<^jImYs0hA@?PFagcgw!7m>BBXM9GVD7$*YX)pnb4C0)71osQqX%0K+poi#=}F7pph?JtV)e|mornl`P7WZ8p;kV?2DX*3TR!kR8F zGSK`I|1QLU6RpUM&Qb+EUDCqXtV{}w2A`q-0<$2MPfmlB+)@Ulz!5{vf}}Vay*Ix# zH&fRCCvviX_G>+bk$qp5+=7_Ya)~J)26VaNZ`_@9!{g)ob5%S^f3m7wfnV){2#QsD4&fPg<{p-8>YL$#k%Pu$B_K^124wOa$!2&6n&1t|JO9 zpLp?&Jj%$Z=xQN{T@|)KP(v*`7%A+vZkf|DDp9bO;?}G3RQAIk=t2V5yO1<{sU@d6 zqH(n-bq?mR+W5?tcDU?LLwKl_aD$)n(`n~9ZGqj>ZkiPyZ?U>dtpP^6#0p0P5WzJt*^qhI;T-J4+88=3|Op6#^UU){RDrj*p zK|A-G2}#Wt2=8E#E*0DiK$YhL1FoI~Z>G8G~GA&~!?N)c1<-tA+5XB3xApyH zmI|iWkz$ZRX_$63!^t8 zkqvfDX8pC6XNT9=;YD6W-JokuR-+S?bIzL=J@RY|{FKEeAat>#C>fE&Vkat>a{$wE z0e+E92l>;?sAGXr_&r_wOSv|O=bhK5eN4iR$$p|gL@!AkM)Ko-Pj3cid+=3VPLEYx zSQv?qc&iesbmI1Pv$^7R#Z7R3K`Q-{$tf=p5GM4%Ur}dfN3rvO3u=%1HQF2qWm|v43p4qiHR&pUI0IJXU%&d_I&*`QoC8%Q8x3C<27=LBo=B&&B5cl*OB|QM?k7xl@ZVwU zdQ>jcahA;7G!wuJ*)kVbYg#SA_jExOg&?b>CLP+6qpORsjNLwbb1ooo0pjPkrw5&j zP(R@3jbNQ3zSzc&mnO*ory2q@5eo1^iDG*QU9io6KuhRg$nkN6Y4`gxZ%_(UJB)x&k<~TT}0OfxAqTi@N4vRnG_d%U?b4S9&CZy#W(}$<21zn zhB=vzULWi|ux9e61Z%#|Z^g=z7H-Yfw~#5{S}$GB7p$00;5ZfXJ27N*$|S^S4;XHD z%4?>4SH9opWYRL^3;n$w-}RNlgvGxtuhFA6vY0&>s%>M3ZHL z*iE0Q$x|!?8Qn-1dEcH`nTQOExT}{2B2jf-g)s@vQu|T(N7ta+Gg~H7MlJ~>(rhJu z)u7`E%Pt0D&oDa0&HN(>qck+?2Y%Wxc%gDqgsGA8R%-FyRVd5PxH+L3=WhQ2g@RkhrSa5E^2rMjOJI zvOn-|FFBP)QtLQU6C@n@R-t~hM)aG1#R7A8E%G-Q1P8d02?|wAiWxeH@n3%`&Fz&( zaVDD6_ozPDoYfK(cM}R*u{zt}!XNmz7aDhCg!7m;u)002_}c)gb#?#hsoiu6SI0AB z1p?Ek)bNsYmNASLHMobb0`>*0qgOqhftr}7k#Q!qT*Hp|Y;xhcWu%~;g!++xLGXHk zP_}%DNM?6#L?wahkZl->Pb6<>7srja)S=#6O^ zycEWZQa5@V_uOZ!9{XJuR%zAqP33t=ta5T-nu^hg z17p!AszksPuH@>#uu%T^C z%WUy#9igZJt@3BrMSgjInYJ}Ug4t!W`C445;AClO)gB!0()DVIMlN*7DmdFGl%- z6MaRsw<9w&*Y$SaohP+=4J1K16}`ke|@W zcgx`(JQg}x2ErHx1)&X&$qcioPnN>26aw1WISlTJKuOE(+d0U`yu5{Xo0|OQ_=iEJ zNpWXwdK~aOZ1@m=nled>iQ^NQiAwEak`gEfHuo$OkN(Dnpj~5uL0Xl#K3X77O%_rM zkn=)JJ2#7o9_VshWXo#nqiErM{E_Z|{|||A`=k7I-)W?50xXSpa0jSs9(U}TZH(Gw zlR1qohcNzy?|6JDH{l=Z3M-mdW`*!33>oUM3QBH0`v_%!?w>J7md{l0J>%YsKg?&H zHCP!cXlGw8+8+IDsNRI#+cR80irGaKj$g+3qW4*~7RED%^>D1Us|7uPelen=>ugks zZ}MUTXLlRFGI1v<%q>B2k3_oXF;cy*PWz!x+S#OZ4tNQ{!5PzG-oXTqJDcY(wfI0B zrKK+7UkAE>SZRcYLByJ5&x1u3$N(dy$%kSU&43e%p@zJ78%^Z#)`rn|doc;bQOW(g zY!TW&@FK~@Uap9Ia(h#LiR6%!9ZxD(_apY>{kr`n2cRG97b!d0oqb$8T8fh@~h*e*1=cD%dd`?|8E>GspMb5^YW|XrT5S7c&Q)Sq~D=% z#1z#`|4jTw`j`50gJc8#3W1u&Q3k@@Sr0OQDDp&`M#b+?LZ)b7gD38!SCDdr_SAdc z)@qT)hRnrb**g)yc?KhwuO1j6wfgGA5O?asn)Ey2&`C`X1akJ~JB4|?F^5c`l;P&FHQEd(0|dGB-xRt6One zdT(RZ1e}gA@7jTUc<~2J`$T;~S4~(G*wkVG3Bh0h!8N4>;T3eZ0hLOBY({nJ3NXdF zFuga`VgYswM@Xp3j`m>|Bsoa0i_Pr%gkAfb&^K6$hTA|e-7M>i+MC#8hO>R|qrmP{ z&7#uG6tQqfGDzcEBc^goc0q#&=fwhv~hsFn=SS+e$pX zK3}HsTHOU~NPkmG^4?s8v^1(ORNtgx#%d@Xybhwx_RJWMQOY)A0Q|GU~7tOceDBCc(q$u6`!qo7i&jAV-L~fIVRAnzd1WTnIMJxhv99oI%wPIDypOVfdylf3i&kx8tEgMNFZ`MXz^VBn7);qGK<TRg;w&_wO`zDW%yaAqBO1vBW1qRO9}FFeWEy7#Aeer8n!4U3e^p_OZWtr%Y0T;wN8otZNN!^qmb{u z@S&R3*&-71u#TVwKUMhG*rpCMn1LV8%PiBVm;kF-prZWUJ}*e9Pmf)mvC?FUGMTb*B==G$B685-A!n3!8w zA`d6w7pxl1HY4tv%^m!&wTFC>RJU^}Z=$#vMz`^ekS#Sf8vb4sI)*Sgv+JTa@ER9C zB_{<<`!9j8&Gf})Rn?CQM-fvB9xnC#yXOz-^Ni&v+A zN8Zl!y}dIyWu6r;80;Ni9((NXV;)rH0qDKGlQ%ow&YUiYoAZ3W1CSMffJ&6@!-s<% zd>>(dZx8R%m6s7ZtyXJ~HQ(X2*f!ugCs-%>J^OPNETCkVh<@nIi!A=fr%|7C?Hox6}h50q*f|>g1!Oj8~&(7X|0NH68zQ$pHjl=#L zhy4#4hg}&vU25!}DaQ?W&^4WLTpkaP3Y9L65--N6#Y`)Eo3eS+vq#!)sl2B`M~|Oi ze{AhGD(n3GfI7lKxZm1VQ~CqzRn0v$=b5(5=FGht)Q!_i)z@03)MSyO>uO?u?bEzi z&S7~K&{^HJl*fN~O}v@UjarrprXj{>>>)Ak)S!9kXE#R(Ay%y6`OIPBE{QE>7!xpP zl+O&$;vZobJ4~0fjc0Y8VbBYBPS2dxYcCN1ISzxCb>e6Dul-pXg91`B=3H%b9%mQf zuh`@*C@6lkTm|)~FnFVhrIK-fmEk}|Ubq?4yl}mf%8XAjL_QO{J za(=@*KfAa%{evaF3OpJabgH}7cFQFYXX2bX!dqZ0s@4aaHX_= zVq&9CUJLd?+PCmmn?>qbJE&*hGytt~CT0%YrHC!+$GLJ_Hu!51y*L zlEld-F|JTlUg5gX_WTLw2Sm&HxZ-aZxW0{`HziX_jqh9H|oH99@wzlfy-j_~e0FHwwj;_SF8zqi8J|%$L-Xa`^{^? zB|K)tzGF6=0yxuDaMxe|rNo~QOZ{y`=p>?n&ta)xG}Z#`S^0I~ogRDff_`HcrBKPs zV{aPpOSE9#RH68Pcqqr;btsHMOh8Sme|F8`c`e{Uk&mb09esat^uytcS0`xQ1ug0D z`1Fjv!QY*Rclhp7{@JrYf@m_3N#ZP|j5l}JK^hoiy8~h89-VgZ*}mA3$e7OW^Ow5f z!=kT&V(mXSHw$Frk7`1!Zu8S`Stmr?yd1ttpkc1)N3?jZn5mvO@CNjXwLDsT0G zCh8Nc%2xVAaBoN~_@ZL^H8Q>!$=AsEuaWUzBjX+YevOP5b-qT%dtVkAFOF<~$MAUE zDjyUg&)#W&{u(C#H+`Q7zx~rBYtmV>G*QzRW{2CFV@%QU&&#o=MFF_q~!q zz=jtIgMAq^GT2reIyA{$aS+xH7t$G};!Z(Ep<6(TGlbg+RURE)0ZJT4bo-fB%Z}n! z?V79?HzrRA4K{WLtgdWp(gET}rAT@}(0|3e?H3Avv3>=(4)W`GZk~k*zr~W?hha4g z#|*_OL&OfuR+$M#We9{;hdRp4FKMA_h*aa?fGdX!3Tg5p_S3nU1^(@SogST77F~38 z%u_$g7HG$Ywo`1|yts#Dy*?6uGvn^jtJCurXNPZ(Coj+5zCOI1T%P=Ni4gJLeGeEr zjD9zNyY^GyhJ#JMc-|iH_pTUbsBvEMuFy}SzKP=NUlYy zCQ@NS{z5qNvz;D~?IEkIX-&M586tDtRANKUv}#RejfryF%TNg_zwr1^ZRHozOti*D zSYS)sqg~6>r0Q4i4@NXshKmZqOlWx2vlZK;R&SQflx{iIA z;@1h3UWt>W3SD4vOT8h!o*cbU7oHSYn0YOuSJuSm zRnFn~jh9blavinPgIY~DZQw_OmS^aoRj(}o(*E9_`F5gEb3uzkEKy)JvFf{Ybr~}e zN#9u#cZ@!cSGPgkx>4kCin^bZ#5PZV6?0INIpLN9LM$g+brXVwwLV+B;gk&4rK;

P5ALbpN0DhnGgiZd`^4;)?LS5`Kv>oBwf`f>@2ydu98708&Ueh6aT|<~b7y2A=c00!ze@bO2aky0m3C`w}s7 z{E^t90I##fe}MX&#ZBu(6;Dp>LpTgj_qZQwS(K!20q%lWO)- z%_Q;}rE!3o52YbulqKaf4Dr8Q`@mn3kyrQ>29GF#-gJ`UkHoizFKT$8yVdd!c|&_% zL&coCCx|f{>K*^eIa=b8 zEv*7eBPrbtyVBCll7a$C2+I-@0^;M(bDr~`SD*Vj*UWw9-OM>N_g%I3rsEk`sa(ch zO9JJNdu)!>I{gB7f1$R!{+eKIIFqB2@M9jsE!3bMM8dP`JcR*5CB$K9SsDwnMA5O~ z-t&Hrb~)QtS+-U{nJ7Kvok7HmykDq5f0TSsg>9`(v?E+;m@oO!6&d$uDb?Q*zpbuT z#jy?s2KcbB^XgYI=n&=a0+d2x6j1g;Ut;KD(dwHfim%@`v7`8ZK3~8)Yp_f}u-jBi z8duY{wddgPJ2iavYGE<>X;C9j_q_U~eWfaLpnakYukw{d^5}w@5VO>>rxbaX*0+0M z3NeGNs@?qrOqhbtA+UtcW8b#GN7pbbG2#O{)~;y3x9dsO zar_KB`smA}uXo9uLbQL*IfPbUzHK`Vr?td6i2VFY?|VJvl`d zZnHQ0ep?m-#);wt z^GXe1bh{mWl|eqN8P`}^>70-{m=&_AX5ZTE8vE|kg#BhHW}4UMyvPMY%$RzN-9+K! z-(H+j^mFK~Z87(;-n@(BQt9h2mT}DoT{Y%qCiAE_iBQhrBPqK@=qlCEK3Od!^+>wM z2k(WrG@sb;o|$z+^g!q@CZM*_^9x2IZ3Y31S18F$5YY_e=oH7QgjjVZ5a^UGZ?k~k zxEd>S6mWWLH|iRBwmc~0X$y#-9X%XgExcFbbF?>7C7=wiR(W!`cuZ?+;QLbcVIs7& zTP&KHz@yn8`}Nh35mVc#Q2ubajeYTzcl3u#X*E^Xv#TQ;xoycr%!=wCY*EOTdP2^q4{1(^JJE5w z5dDaJ9~>L{Y2*fL{0DqHw@pyt75c3nP%QK@8c7G}gj6x(bgKBp%;$)daVeKQu|a(2 zD_9IZvy4iD|4_lI)~xW9$0BZnfWf?F>c=g-jowN+G(4YwRWoKlEx1wIBOHI^1!rFr zIf{O%DR+(zUk!B?N>@QkKtDGQ7!Kr$Nv(rO4tJtcl}V9`<#(^=Bc{xheQE0fs=VZu zi($v#mp816=(~_wLgu>P7Chg(v&2e+uh(;%+qs{{(ZvQjJ^boqF<-W>|J9AR+rk}! z=S^~~uj5bKO+FfWo~4y%cG4D%YNdR>%euT1yjUjRZL*RDo}K`uFTdD3O|`P;Oh&nd z&8>i*#IX32ZavHTEjTZJkua`l; zR*Mz?RG)g4H^^289}+%sgiVCFc+--8mbPZqmXv5_h~q73CvY1V#w*fjI(@2=E$!&Z z(y8+8P09HCV+(a<)MxD0w#*oMt^8r#w(^kQy)T76S%?RpeSW`wHU3r17O1A1x`h_| z8dGTs2q;VA#86L9tR-^y9WWt>J^RE46&+rdeTx1*X?QrTUXZqEuTXerU8as1*V99> z?B@EvLnW4a>xR!fLP6I`y%)zEZAKPD2FAD2H=rYA7UAyK8EGA!t14-x0oBFo!pTt` zhHT#ue=dX~m10L{tG^x^0U4fBU6Y$Ez*-17Y!-J&^6Hs}!Z9V8tL>q^8pq?wzT-Q! zZP|3`pGJB}n9hsdh+SUk^%WvnvC0B`yU?Vu3m*SNYdS=Ar%ow5&dL&&{6$=3K?z?y zj`N~rJ3!O%hv9Tvx|s`4v&|6Ja#K_XMd?X`g zw~ERR9Ehgn_98SRc2qH}POD3fsPzeWe_t=Jr0i{=}W>471MNvx`1gy}@a44E|UXZZzAg~KoWY{b1@2A)JR;l-K} zRDRlwI2iL$w*)gvpkgx1lo$)EXpiicynHupJ1w)GOjtX`{|+wR|E)}<6@rRiXXNX^ z{vK$C|F@yGY0=X1*)RU>kjVw!F_!*cR7a0@(-+I^UfO5`)~PW=iP@r-cQvc@BWAd& z%#seQcE zG>KX6Axlp0#m;k>yLF%{y+nL?o41!2lG|wT$ZJGAj&uEkF#cFF^E`V-s6MTmerAT1 z(r8#Eg{`M@js}(w-Nz_4)5hTKd$XLd&s$?Ydr+SZV4M6%H3y*cfa-deTOz(@tPk(~ zt^blnd-T+io1vV(*cly=8yU%+=KGR!a9fJU8~hu_MfItk#7O~*XwG(ep7$aA$mvjH zRg=fj&FugR$?mxQOr~tq3Y%D#|IR@QPmNkwFn5KG;-x1Dm^u?{Y$YMo{G$}lb?oO? zTN~Jc?$~7NT+U`F3(pw7bz16Um<+@5@O?CwXz0caDiRsuELk|iZ5*|9>u{fu7oOaO zBYdKoiYKGA7;LfZi8LYIpbZzUTDO75O-j2Q%?o!%+9#Cv-U(-n3VIA!s=&yEhqy(({rrpXNT99OQPSo3@=hFcu<^TJU1nf|s3}At!L8V+VFEz; z$pn-5nNR~m{fq>+df&Ba3hp|~UqE0q@j?Dgz_j$6kJsniw}rRAn@=P=Ll8vlgWy2F zvc1Q7TLr|w>7!k$ly@{1M^9hsH-Uy5&d6^cYPTN0b9niE;(+0DS^6m8#Sj&3PNCnl2mA=&5Jrb33@}#s474iWr}Fxy$=uZ>g2+jq+q6 z58-CPpEjAE;iLp%RihVnDbtcG;{4n63f6Ux2?v&ol?UAHSXzWRhDcib4GE=FOg5d~ z4Kn!dzO-|!pxJix`?@_;$b0ozkgg>Sp;0Xhs{#M5hJ(d} zCa_fX_8786A08rzyui=9;7vr`?h2!GU+ayA2Iq6TG*LDgMSIzmxd#j1VigC7GiIuu zVz+AqOzQeFCCt}LYbwZ49JGIf;QKegz=W?~vob(Df z?)CA-5Z8?u$p;gGd-E{_cdeIpA`UCoqP$+FJ|_OWEcr;85Vvo;m&OpX@`|RfZBVAb zu9CW@&MRG(NR#evJimrdg-ZwiaX&7$|1_Nx+0S4CC#T&M9ded|3R#A8eEHTZ<2R{@ zaVv9dsTj+YbChSQEVe&(UhIl6$$X#p@{gYeujexq2in1A*X_;$%oD#+GATO<%W~9w zmz^Ev=VWTT4Wi$!UDEUXCg13(pw_nRg2HO8Zu!!_tF!wY>bE76z8CT?XlB0+6^gl& z8wt*gnzEk3B((te*tcTZQJP$@7tw(&Tl8EgC(&8vluyVanN`!gYkr9lt9sGHy~neW zM#+2Kik_)YJxVla>pZ10u4lTwW>snt9 zX$2j1Qw|k8+doAW#0Mk5>X28M%i)2OWgL(%^~(#Ei`ZUcqhE(P1%K;|T$5~@{QwZ?G1%5^AkjO){|_o)};h-)vT;DEGgUqWZ&6f@*qkKiI3rMD4J zbgZzW*M)&xDGn}7;3xTJgh^1;Nk{#37)4?6V0Mc<{Q-fBOMtI1o`~nAA>R8qx0EYu zl7oO5$??c{O+g>i5Aev=*4rd1iI+t_xTrOiC#S6*kuGe})Qzcx_m45SrI9f*I48ez zkc~R3DA&5S744oJ>*7^yw@c#_hi~thKSX=hEB*+4_2dM)lQ)NU74&)tO_*HLk!(=AH_Ms=b9bE` z>mdc$Jni<{yP3mq6ZF289_9=j1&AA&{|bBySs?f}A5_sa#|J}^&e=3tCo%;SUKpa+ zX{A_+-V#IUR86J@;N7Z#6wHRa#)m6wt@k;k?~`MreUj~z5;wj7&muidp%NSReLwLB z(}^)045>;wvI*5@bZHx`=XkWFMCt@Iux&ubC`N@kU==y#>|XSOfRe}EKZG{6iiats ztB}Ujq^hZ*MuP>1U)n(=%VsGD8ne)wf_`gdGkI|~RpAf{e?|tcpW3*3=P_7br#O@T z+BVVmHKWd+EgSz2t|)j{%2Hvf=VHzxKC#a-+OI}KFa4sn*!J?kZWbZcOBS7_798I%sasP&1G&t&x$(!NbS0ZuM&dokV+SNe zA4HiUZ9*zGnWotNXZxd*TIB)eC(>q8i_h7QTAt>}`!PHI3S)4J(W{9{b@JXJVmDpY zrStptic zxH5KE(e}aXJtS(9(kLz}UmEM*5*O_ID_6LTbDtPTv}K&*|F$tVCpL)D7OmiCrl@pm zl$maLB5U_mz9d0n5_v?>HeP4Md4dTm^kc&T+$v5TD6g6i?3+!FgJFN>a{&DPShP*l zy$TQ4`1Gi#fM@2_qpr=4PH(ilW>7MTm>s>Mh!Yq~g}PVgpmzp&E3=9gSU@ZJd2i(9 zslfuM_G3M7rb{S>m=}L8ppZW-Tk(B8c$Vpk)&8>%f94!h8?a2#(&TLQQ_k5R)HMdG zl5##T3aX%UT!L8qD#gk-0Ia6^Aqi@fDg%8wR2<%VT@H-$Jnqb4f1m+m=-cvyg1(?- zSJE22#xlQ%dGRMp0aV>$@61(!zrWZYj9nw)5|j?uKS;lJluf!#rAG)Qs3Rc|LGXyY z(Qv_wC?&R?2um8H&Vbhw+pX`1EsPo4TB0Jjp2>z$`0|+qbHH#(fVhOWW&wfBSJG)I z=sGPALo`c(ShX~b!@<=D5pm~Y?KNL~JI!f3hnN|d_#(q;=M@KfCjp=8z74~~yg}p5 z#Ff56&282B#?6KK9y#*=bST%kQniba`;x~=S<{(15iX>Cr(#*zF-VNN5l$gV54PBaHm^+g7axw)lrvhpt(?V`JkVMr_v>h_N zlLL6u*&hJ!Fngh6%4RMGgv2(FQC3Sr9~pUU^D=t+mqBOqLvEAhbj;M*8REI6xjd1C zP(w~;CSCGFPz7u7t6kO{I+8Ir zMX-mQKf;Pz241hD%%2uc;s7#zLbYg3@%O?%dJJ$?k;qv){3=mTD>Ql2lK_XhLORTh z!+U}R6`kB18WJAW<)d^+h+Il*CwU8XiZ?fTPp10@Z{2 zl#{Ucxc+@3p?mRs9wr#x1+mT&&(*x_2Af%M2I|YblR}cx<_ct`2`4A68%(QSjKp*) z90KV+saw{sD)BJtYPofR`P1_wD376TeQAQO*u@01owJ}c)(SzbY3&(vx|WHB+qyJC z@)O(+LkbSq8>1$VpsSMIOR;%5r>iy_!r4Kk{J^3Lq1h5LdiXA9!!&mR1=_ISobQ_> zOR2Ztz_>oAY*ku0g?4^XO*Cq8&G#`;03X8IZsUN}hqkOF*+@`Av`@r&jHs4E?C+U6 zp3BW0>W=S@AcWlN2Jfe}hckhw$*^mhxY{%LKt14pWGo0W1^q{v%|alve?TD&a{mW_ zFi89#v<#9B5^Ls1D2O7n{y)hB z0?ORv0nugVh=PQ%AF}<6m@@Z7K_rm>QWiPdUlD+?uwH|)uxPOUH%cSU*)yrdK+0ed z&P-!55c5B`UL{2@_g^>OUpL+V%vhxn?Od7ZVj#|c+d_ze7{OFLnJfP Any: return instance -def get_app_config(node_name, key=''): +def get_app_config(node_name: str, key: str=''): name = 'com.sun.star.configuration.ConfigurationProvider' service = 'com.sun.star.configuration.ConfigurationAccess' cp = create_instance(name, True) @@ -308,6 +317,11 @@ def get_app_config(node_name, key=''): LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale') LANG = LANGUAGE.split('-')[0] +try: + COUNTRY = LANGUAGE.split('-')[1] +except: + COUNTRY = '' +LOCALE = Locale(LANG, COUNTRY, '') NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName') VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion') @@ -337,7 +351,7 @@ def info(*args): return -def save_log(path, data): +def save_log(path: str, data): with open(path, 'a') as f: f.write(f'{str(now())[:19]} -{LOG_NAME}- ') pprint(data, stream=f) @@ -365,13 +379,15 @@ def inspect(obj: Any) -> None: return -def mri(obj): +def mri(obj: Any) -> None: m = create_instance('mytools.Mri') if m is None: msg = 'Extension MRI not found' error(msg) return + if hasattr(obj, 'obj'): + obj = obj.obj m.inspect(obj) return @@ -384,7 +400,7 @@ def run_in_thread(fn): return run -def now(only_time=False): +def now(only_time: bool=False): now = datetime.datetime.now() if only_time: now = now.time() @@ -476,10 +492,10 @@ def json_loads(data): def data_to_dict(data): - if isinstance(data, tuple) and isinstance(data[0], tuple): + if isinstance(data, (tuple, list)) and isinstance(data[0], (tuple, list)): return _array_to_dict(data) - if isinstance(data, tuple) and isinstance(data[0], (PropertyValue, NamedValue)): + if isinstance(data, (tuple, list)) and isinstance(data[0], (PropertyValue, NamedValue)): return _property_to_dict(data) return {} @@ -492,6 +508,8 @@ def _get_dispatch() -> Any: # ~ Used only if not exists in API def call_dispatch(frame: Any, url: str, args: dict={}) -> None: dispatch = _get_dispatch() + if hasattr(frame, 'frame'): + frame = frame.frame opt = dict_to_property(args) dispatch.executeDispatch(frame, url, '', 0, opt) return @@ -538,12 +556,12 @@ def _struct_to_date(value): return d -def _get_url_script(args): +def _get_url_script(args: dict): library = args['library'] - module = '.' name = args['name'] language = args.get('language', 'Python') location = args.get('location', 'user') + module = args.get('module', '.') if language == 'Python': module = '.py$' @@ -557,7 +575,7 @@ def _get_url_script(args): return url -def _call_macro(args): +def _call_macro(args: dict): #~ https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification url = _get_url_script(args) @@ -581,16 +599,19 @@ def call_macro(args, in_thread=False): return result -def run(command, capture=False, split=True): - if not split: - return subprocess.check_output(command, shell=True).decode() - - cmd = shlex.split(command) - result = subprocess.run(cmd, capture_output=capture, text=True, shell=IS_WIN) - if capture: - result = result.stdout +def run(command, capture=False, split=False): + if split: + cmd = shlex.split(command) + result = subprocess.run(cmd, capture_output=capture, text=True, shell=IS_WIN) + if capture: + result = result.stdout + else: + result = result.returncode else: - result = result.returncode + if capture: + result = subprocess.check_output(command, shell=True).decode() + else: + result = subprocess.Popen(command) return result @@ -641,7 +662,7 @@ def stop_timer(name): return -def install_locales(path, domain='base', dir_locales=DIR['locales']): +def install_locales(path: str, domain: str='base', dir_locales=DIR['locales']): path_locales = _P.join(_P(path).path, dir_locales) try: lang = gettext.translation(domain, path_locales, languages=[LANG]) @@ -667,12 +688,13 @@ def sha256(data): result = hashlib.sha256(data.encode()).hexdigest() return result + def sha512(data): result = hashlib.sha512(data.encode()).hexdigest() return result -def get_config(key='', default={}, prefix='conf'): +def get_config(key='', prefix='conf', default={}): name_file = FILE_NAME_CONFIG.format(prefix) values = None path = _P.join(_P.config('UserConfig'), name_file) @@ -697,13 +719,15 @@ def set_config(key, value, prefix='conf'): def start(): global _start + _start = now() info(_start) return -def end(get_seconds=False): +def end(get_seconds: bool=False): global _start + e = now() td = e - _start result = str(td) @@ -723,16 +747,20 @@ def render(template, data): def get_size_screen(): + res = '' if IS_WIN: user32 = ctypes.windll.user32 res = f'{user32.GetSystemMetrics(0)}x{user32.GetSystemMetrics(1)}' else: - args = 'xrandr | grep "*" | cut -d " " -f4' - res = run(args, split=False) + try: + args = 'xrandr | grep "*" | cut -d " " -f4' + res = run(args, split=False) + except Exception as e: + error(e) return res.strip() -def url_open(url, data=None, headers={}, verify=True, get_json=False): +def url_open(url, data=None, headers={}, verify=True, get_json=False, timeout=TIMEOUT): err = '' req = Request(url) for k, v in headers.items(): @@ -742,19 +770,22 @@ def url_open(url, data=None, headers={}, verify=True, get_json=False): if verify: if not data is None and isinstance(data, str): data = data.encode() - response = urlopen(req, data=data) + response = urlopen(req, data=data, timeout=timeout) else: context = ssl._create_unverified_context() - response = urlopen(req, context=context) + response = urlopen(req, data=data, timeout=timeout, context=context) except HTTPError as e: error(e) err = str(e) except URLError as e: error(e.reason) err = str(e.reason) + except timeout: + err = 'timeout' + error(err) else: headers = dict(response.info()) - result = response.read() + result = response.read().decode() if get_json: result = json.loads(result) @@ -1166,6 +1197,9 @@ class LODocument(object): return def to_pdf(self, path: str='', args: dict={}): + """ + https://wiki.documentfoundation.org/Macros/Python_Guide/PDF_export_filter_data + """ path_pdf = path filter_name = '{}_pdf_Export'.format(self.type) filter_data = dict_to_property(args, True) @@ -1520,6 +1554,142 @@ class LOSheetCharts(object): return LOChart(name, self.obj[name], self._sheet.draw_page) +class LOSheetTableField(object): + + def __init__(self, obj): + self._obj = obj + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + @property + def obj(self): + return self._obj + + @property + def name(self): + return self.obj.Name + + @property + def orientation(self): + return self.obj.Orientation + @orientation.setter + def orientation(self, value): + self.obj.Orientation = value + + +# ~ com.sun.star.sheet.DataPilotFieldOrientation.ROW +class LOSheetTable(object): + + def __init__(self, obj): + self._obj = obj + self._source = None + + def __getitem__(self, index): + field = self.obj.DataPilotFields[index] + return LOSheetTableField(field) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + @property + def obj(self): + return self._obj + + @property + def filter(self): + return self.obj.ShowFilterButton + @filter.setter + def filter(self, value): + self.obj.ShowFilterButton = value + + @property + def source(self): + return self._source + @source.setter + def source(self, value): + self._source = value + self.obj.SourceRange = value.range_address + + @property + def rows(self): + return self.obj.RowFields + @rows.setter + def rows(self, values): + if not isinstance(values, tuple): + values = (values,) + for v in values: + with self[v] as f: + f.orientation = DPFO.ROW + @property + def columns(self): + return self.obj.ColumnFields + @columns.setter + def columns(self, values): + if not isinstance(values, tuple): + values = (values,) + for v in values: + with self[v] as f: + f.orientation = DPFO.COLUMN + + @property + def data(self): + return self.obj.DataFields + @data.setter + def data(self, values): + if not isinstance(values, tuple): + values = (values,) + for v in values: + with self[v] as f: + f.orientation = DPFO.DATA + + +class LOSheetTables(object): + + def __init__(self, obj, sheet): + self._obj = obj + self._sheet = sheet + + def __getitem__(self, index): + return LOSheetTable(self.obj[index]) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + def __contains__(self, item): + return item in self.obj + + @property + def obj(self): + return self._obj + + @property + def count(self): + return self.obj.Count + + @property + def names(self): + return self.obj.ElementNames + + def new(self, name, target): + table = self.obj.createDataPilotDescriptor() + self.obj.insertNewByName(name, target.address, table) + return LOSheetTable(self.obj[name]) + + def remove(self, name): + self.obj.removeByName(name) + return + + class LOFormControl(LOBaseObject): EVENTS = { 'action': 'actionPerformed', @@ -2045,6 +2215,10 @@ class LOCalcSheet(object): def charts(self): return LOSheetCharts(self.obj.Charts, self) + @property + def tables(self): + return LOSheetTables(self.obj.DataPilotTables, self) + @property def rows(self): return LOSheetRows(self, self.obj.Rows) @@ -2558,6 +2732,7 @@ class LOCalcRange(object): cell = None if isinstance(value, dict): for k, v in value.items(): + # ~ print(1, 'RENDER', k, v) cell = self._render_value(k, v, key) return cell elif isinstance(value, (list, tuple)): @@ -2569,7 +2744,11 @@ class LOCalcRange(object): search = f'{{{parent}.{key}}}' ranges = self.find_all(search) - for cell in ranges or range(0): + if ranges is None: + return + + # ~ for cell in ranges or range(0): + for cell in ranges: self._set_new_value(cell, search, value) return LOCalcRange(cell) @@ -2718,6 +2897,72 @@ class LOCalcRange(object): self.obj.fillAuto(0, source) return + def _cast(self, t, v): + if not t: + return v + + if t == datetime.date: + nv = datetime.date.fromordinal(int(v) + DATE_OFFSET) + else: + nv = t(v) + return nv + + def get_data(self, types): + values = [ + [self._cast(types[i], v) for i, v in enumerate(row)] + for row in self.data + ] + return values + + +class LOWriterStyles(object): + + def __init__(self, styles): + self._styles = styles + + @property + def names(self): + return {s.DisplayName: s.Name for s in self._styles} + + def __str__(self): + return '\n'.join(tuple(self.names.values())) + + +class LOWriterStylesFamilies(object): + + def __init__(self, styles): + self._styles = styles + + def __getitem__(self, index): + styles = { + 'Character': 'CharacterStyles', + 'Paragraph': 'ParagraphStyles', + 'Page': 'PageStyles', + 'Frame': 'FrameStyles', + 'Numbering': 'NumberingStyles', + 'Table': 'TableStyles', + 'Cell': 'CellStyles', + } + name = styles.get(index, index) + return LOWriterStyles(self._styles[name]) + + def __iter__(self): + self._index = 0 + return self + + def __next__(self): + obj = LOWriterStyles(self._styles[self._index]) + self._index += 1 + return obj + # ~ raise StopIteration + + @property + def names(self): + return self._styles.ElementNames + + def __str__(self): + return '\n'.join(self.names) + class LOWriterPageStyle(LOBaseObject): @@ -2755,18 +3000,23 @@ class LOWriterTextRange(object): self._doc = doc self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph' self._is_table = self.obj.ImplementationName == 'SwXTextTable' + self._is_text = self.obj.ImplementationName == 'SwXTextPortion' + self._parts = [] + if self._is_paragraph: + self._parts = [LOWriterTextRange(p, doc) for p in obj] def __iter__(self): self._index = 0 return self def __next__(self): - for i, p in enumerate(self.obj): - if i == self._index: - obj = LOWriterTextRange(p, self._doc) - self._index += 1 - return obj - raise StopIteration + try: + obj = self._parts[self._index] + except IndexError: + raise StopIteration + + self._index += 1 + return obj @property def obj(self): @@ -2785,11 +3035,37 @@ class LOWriterTextRange(object): @property def value(self): return self.string + @value.setter + def value(self, value): + self.string = value + + @property + def style(self): + s = '' + if self.is_paragraph: + s = self.obj.ParaStyleName + elif self.is_text: + s = self.obj.CharStyleName + return s + @style.setter + def style(self, value): + if self.is_paragraph: + self.obj.ParaStyleName = value + elif self.is_text: + self.obj.CharStyleName = value + + @property + def is_paragraph(self): + return self._is_paragraph @property def is_table(self): return self._is_table + @property + def is_text(self): + return self._is_text + @property def text(self): return self.obj.Text @@ -2802,6 +3078,13 @@ class LOWriterTextRange(object): def dp(self): return self._doc.dp + def delete(self): + cursor = self.cursor + cursor.gotoStartOfParagraph(False) + cursor.gotoNextParagraph(True) + cursor.String = '' + return + def offset(self): cursor = self.cursor.getEnd() return LOWriterTextRange(cursor, self._doc) @@ -2846,25 +3129,26 @@ class LOWriterTextRanges(object): def __init__(self, obj, doc): self._obj = obj self._doc = doc + self._paragraphs = [LOWriterTextRange(p, doc) for p in obj] + + def __len__(self): + return len(self._paragraphs) def __getitem__(self, index): - for i, p in enumerate(self.obj): - if i == index: - obj = LOWriterTextRange(p, self._doc) - break - return obj + return self._paragraphs[index] def __iter__(self): self._index = 0 return self def __next__(self): - for i, p in enumerate(self.obj): - if i == self._index: - obj = LOWriterTextRange(p, self._doc) - self._index += 1 - return obj - raise StopIteration + try: + obj = self._paragraphs[self._index] + except IndexError: + raise StopIteration + + self._index += 1 + return obj @property def obj(self): @@ -2887,10 +3171,17 @@ class LOWriterTextTable(object): @property def data(self): - return self._obj.DataArray + return self.obj.DataArray @data.setter def data(self, values): - self._obj.DataArray = values + self.obj.DataArray = values + + @property + def style(self): + return self.obj.TableTemplateName + @style.setter + def style(self, value): + self.obj.autoFormat(value) class LOWriterTextTables(object): @@ -2920,7 +3211,7 @@ class LOWriter(LODocument): @property def text(self): - return LOWriterTextRange(self.obj.Text, self) + return self.paragraphs @property def paragraphs(self): @@ -2973,6 +3264,10 @@ class LOWriter(LODocument): ps = self.obj.StyleFamilies['PageStyles'] return LOWriterPageStyles(ps) + @property + def styles(self): + return LOWriterStylesFamilies(self.obj.StyleFamilies) + @property def search_descriptor(self): return self.obj.createSearchDescriptor() @@ -3055,6 +3350,13 @@ class LOShape(LOBaseObject): def shape_type(self): return self.obj.ShapeType + @property + def properties(self): + return {} + @properties.setter + def properties(self, values): + _set_properties(self.obj, values) + @property def is_image(self): return self.shape_type == self.IMAGE @@ -3232,19 +3534,21 @@ class LODrawPage(LOBaseObject): def create_instance(self, name): return self.doc.createInstance(name) - def add(self, type_shape, args={}): + def add(self, type_shape, options={}): + args = options.copy() """Insert a shape in page, type shapes: Line Rectangle Ellipse Text + Connector """ index = self.count - w = args.get('Width', 3000) - h = args.get('Height', 3000) - x = args.get('X', 1000) - y = args.get('Y', 1000) - name = args.get('Name', f'{type_shape.lower()}{index}') + w = args.pop('Width', 3000) + h = args.pop('Height', 3000) + x = args.pop('X', 1000) + y = args.pop('Y', 1000) + name = args.pop('Name', f'{type_shape.lower()}{index}') service = f'com.sun.star.drawing.{type_shape}Shape' shape = self.create_instance(service) @@ -3252,6 +3556,10 @@ class LODrawPage(LOBaseObject): shape.Position = Point(x, y) shape.Name = name self.obj.add(shape) + + if args: + _set_properties(shape, args) + return LOShape(self.obj[index], index) def remove(self, shape): @@ -3403,15 +3711,19 @@ class BaseRow: class BaseQuery(object): PY_TYPES = { - 'SQL_LONG': 'getLong', - 'SQL_VARYING': 'getString', - 'SQL_FLOAT': 'getFloat', - 'SQL_BOOLEAN': 'getBoolean', - 'SQL_TYPE_DATE': 'getDate', - 'SQL_TYPE_TIME': 'getTime', - 'SQL_TIMESTAMP': 'getTimestamp', + 'VARCHAR': 'getString', + 'INTEGER': 'getLong', + 'DATE': 'getDate', + # ~ 'SQL_LONG': 'getLong', + # ~ 'SQL_VARYING': 'getString', + # ~ 'SQL_FLOAT': 'getFloat', + # ~ 'SQL_BOOLEAN': 'getBoolean', + # ~ 'SQL_TYPE_DATE': 'getDate', + # ~ 'SQL_TYPE_TIME': 'getTime', + # ~ 'SQL_TIMESTAMP': 'getTimestamp', } - TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP') + # ~ TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP') + TYPES_DATE = ('DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP') def __init__(self, query): self._query = query @@ -3437,6 +3749,7 @@ class BaseQuery(object): def _to_python(self, index): type_field = self._meta.getColumnTypeName(index) + # ~ print('TF', type_field) value = getattr(self._query, self.PY_TYPES[type_field])(index) if type_field in self.TYPES_DATE: value = _struct_to_date(value) @@ -3562,10 +3875,11 @@ class LOBase(object): self._con.getTables().refresh() return - def initialize(self, database_proxy, tables): + def initialize(self, database_proxy, tables=[]): db = FirebirdDatabase(self) database_proxy.initialize(db) - db.create_tables(tables) + if tables: + db.create_tables(tables) return def _validate_sql(self, sql, params): @@ -3676,6 +3990,7 @@ class LODocs(object): return doc def __len__(self): + # ~ len(self._desktop.Components) for i, _ in enumerate(self._desktop.Components): pass return i + 1 @@ -3717,7 +4032,8 @@ class LODocs(object): return _get_class_doc(doc) def connect(self, path): - return LOBase(None, {'path': path}) + db = LOBase(None, {'path': path}) + return db def _add_listeners(events, control, name=''): @@ -4445,6 +4761,13 @@ class UnoText(UnoBaseObject): def value(self, value): self.model.Text = value + @property + def echochar(self): + return chr(self.model.EchoChar) + @echochar.setter + def echochar(self, value): + self.model.EchoChar = ord(value[0]) + def validate(self): return @@ -5285,6 +5608,11 @@ class LODialog(object): self.obj.dispose() return value + def set_values(self, data): + for k, v in data.items(): + self._controls[k].value = v + return + class LOSheets(object): @@ -5771,6 +6099,70 @@ class LOWindow(object): return +class LODBServer(object): + DRIVERS = { + 'mysql': 'mysqlc', + 'mariadb': 'mysqlc', + 'postgres': 'postgresql:postgresql', + } + PORTS = { + 'mysql': 3306, + 'mariadb': 3306, + 'postgres': 5432, + } + + def __init__(self): + self._conn = None + self._error = 'Not connected' + self._type = '' + + def __str__(self): + return f'DB type {self._type}' + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.disconnet() + + @property + def is_connected(self): + return not self._conn is None + + @property + def error(self): + return self._error + + def disconnet(self): + if not self._conn is None: + if not self._conn.isClosed(): + self._conn.close() + self._conn.dispose() + + def connect(self, args): + self._error = '' + self._type = args.get('type', 'postgres') + driver = self.DRIVERS[self._type] + server = args.get('server', 'localhost') + port = args.get('port', self.PORTS[self._type]) + dbname = args.get('dbname', '') + user = args['user'] + password = args['password'] + + data = {'user': user, 'password': password} + url = f'sdbc:{driver}://{server}:{port}/{dbname}' + args = dict_to_property(data) + manager = create_instance('com.sun.star.sdbc.DriverManager') + + try: + self._conn = manager.getConnectionWithInfo(url, args) + except Exception as e: + error(e) + self._error = str(e) + + return self + + def create_window(args): return LOWindow(args) @@ -5832,6 +6224,7 @@ _CB = ClipBoard class Paths(object): FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker' + FOLDER_PICKER = 'com.sun.star.ui.dialogs.FolderPicker' def __init__(self, path=''): if path.startswith('file://'): @@ -5909,15 +6302,17 @@ class Paths(object): @classmethod def config(cls, name='Work'): """ - Return de path name in config + Return path from config http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1util_1_1XPathSettings.html """ path = create_instance('com.sun.star.util.PathSettings') - return cls.to_system(getattr(path, name)) + path = cls.to_system(getattr(path, name)) + return path @classmethod def get(cls, init_dir='', filters: str=''): """ + Get path for save Options: http://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1ui_1_1dialogs_1_1TemplateDescription.html filters: 'xml' or 'txt,xml' """ @@ -5941,7 +6336,7 @@ class Paths(object): @classmethod def get_dir(cls, init_dir=''): - folder_picker = create_instance(cls.FILE_PICKER) + folder_picker = create_instance(cls.FOLDER_PICKER) if not init_dir: init_dir = cls.documents init_dir = cls.to_url(init_dir) @@ -5950,15 +6345,17 @@ class Paths(object): path = '' if folder_picker.execute(): - path = cls.to_system(folder_picker.getDisplayDirectory()) + path = cls.to_system(folder_picker.getDirectory()) return path @classmethod def get_file(cls, init_dir: str='', filters: str='', multiple: bool=False): """ + Get path file + init_folder: folder default open - multiple: True for multiple selected filters: 'xml' or 'xml,txt' + multiple: True for multiple selected """ if not init_dir: init_dir = cls.documents @@ -6056,14 +6453,13 @@ class Paths(object): @classmethod def kill(cls, path): - result = True p = Path(path) - try: if p.is_file(): p.unlink() elif p.is_dir(): shutil.rmtree(path) + result = True except OSError as e: log.error(e) result = False @@ -6094,7 +6490,12 @@ class Paths(object): return paths @classmethod - def walk_dir(cls, path, tree=False): + def walk_dirs(cls, path, tree=False): + """ + Get directories recursively + path: path source + tree: get info in a tuple (ID_FOLDER, ID_PARENT, NAME) + """ folders = [] if tree: i = 0 @@ -6219,6 +6620,50 @@ class Paths(object): _P = Paths +class Dates(object): + + @classmethod + def date(cls, year, month, day): + d = datetime.date(year, month, day) + return d + + +class SpellChecker(object): + + def __init__(self): + service = 'com.sun.star.linguistic2.SpellChecker' + self._spellchecker = create_instance(service, True) + self._locale = LOCALE + + @property + def locale(self): + slocal = f'{self._locale.Language}-{self._locale.Country}' + return slocale + @locale.setter + def locale(self, value): + lang = value.split('-') + self._locale = Locale(lang[0], lang[1], '') + + def is_valid(self, word): + result = self._spellchecker.isValid(word, self._locale, ()) + return result + + def spell(self, word): + result = self._spellchecker.spell(word, self._locale, ()) + if result: + result = result.getAlternatives() + if not isinstance(result, tuple): + result = () + return result + + +def spell(word, locale=''): + sc = SpellChecker() + if locale: + sc.locale = locale + return sc.spell(word) + + def __getattr__(name): if name == 'active': return LODocs().active @@ -6234,6 +6679,8 @@ def __getattr__(name): return Paths if name == 'docs': return LODocs() + if name == 'db': + return LODBServer() if name == 'sheets': return LOSheets() if name == 'cells': @@ -6244,6 +6691,8 @@ def __getattr__(name): return LOShortCuts() if name == 'clipboard': return ClipBoard + if name == 'dates': + return Dates raise AttributeError(f"module '{__name__}' has no attribute '{name}'") @@ -6330,48 +6779,6 @@ def get_fonts(): return device.FontDescriptors -# ~ From request -# ~ https://github.com/psf/requests/blob/master/requests/structures.py#L15 -class CaseInsensitiveDict(MutableMapping): - - def __init__(self, data=None, **kwargs): - self._store = OrderedDict() - if data is None: - data = {} - self.update(data, **kwargs) - - def __setitem__(self, key, value): - # Use the lowercased key for lookups, but store the actual - # key alongside the value. - self._store[key.lower()] = (key, value) - - def __getitem__(self, key): - return self._store[key.lower()][1] - - def __delitem__(self, key): - del self._store[key.lower()] - - def __iter__(self): - return (casedkey for casedkey, mappedvalue in self._store.values()) - - def __len__(self): - return len(self._store) - - def lower_items(self): - """Like iteritems(), but with all lowercase keys.""" - values = ( - (lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items() - ) - return values - - # Copy is required - def copy(self): - return CaseInsensitiveDict(self._store.values()) - - def __repr__(self): - return str(dict(self.items())) - - # ~ https://en.wikipedia.org/wiki/Web_colors def get_color(value): COLORS = {