From a759a2945bcec4b32e07b90b14a93c96219d225c Mon Sep 17 00:00:00 2001 From: Dave Kuhlman <dkuhlman@davekuhlman.org> Date: Wed, 14 Sep 2016 11:27:07 -0700 Subject: [PATCH] Updated version number --- build_dist | 15 + generateDS.html | 6 +- generateDS.py | 2 +- generateDS.txt | 2 +- generateds_gui_notes.html | 6 +- generateds_gui_notes.txt | 2 +- gui/generateds_gui.py | 2 +- librarytemplate_howto.html | 6 +- librarytemplate_howto.txt | 2 +- process_includes.py | 2 +- setup.py | 2 +- tests/catalogtest2_sub.py | 167 ---- tests/catalogtest2_sup.py | 778 ------------------- tests/ipo2_out.xml | 26 - tests/nested_def2_out.xml | 9 - tests/nested_def2_sub.py | 200 ----- tests/nested_def2_sup.py | 1180 ----------------------------- tutorial/generateds_tutorial.html | 6 +- tutorial/generateds_tutorial.txt | 2 +- tutorial/generateds_tutorial.zip | Bin 48764 -> 48767 bytes 20 files changed, 35 insertions(+), 2380 deletions(-) create mode 100755 build_dist delete mode 100644 tests/catalogtest2_sub.py delete mode 100644 tests/catalogtest2_sup.py delete mode 100644 tests/ipo2_out.xml delete mode 100644 tests/nested_def2_out.xml delete mode 100644 tests/nested_def2_sub.py delete mode 100644 tests/nested_def2_sup.py diff --git a/build_dist b/build_dist new file mode 100755 index 0000000..a78242e --- /dev/null +++ b/build_dist @@ -0,0 +1,15 @@ +#!/bin/sh -v +#cp ../Xslt/xsltvsgenerateds/xsltvsgenerateds.css . +#cp ../Xslt/xsltvsgenerateds/xsltvsgenerateds.html . +#rst2html.py --source-url=generateDS.txt --generator \ +# --stylesheet-path=/home/dkuhlman/bin/dave_docutils.css \ +# generateDS.txt generateDS.html +generate generateDS.txt +generate librarytemplate_howto.txt +generate generateds_gui_notes.txt +cd tutorial +generate generateds_tutorial.txt +zip -f generateds_tutorial.zip +cd .. +#python setup.py sdist --formats=gztar,zip +python setup.py sdist --formats=gztar diff --git a/generateDS.html b/generateDS.html index 0632a41..dde039c 100644 --- a/generateDS.html +++ b/generateDS.html @@ -220,7 +220,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.22b</td> +<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.23a</td> </tr> </tbody> </table> @@ -229,7 +229,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">date:</th><td class="field-body">June 01, 2016</td> +<tr class="field"><th class="field-name">date:</th><td class="field-body">September 14, 2016</td> </tr> </tbody> </table> @@ -3180,7 +3180,7 @@ following among others:</p> <div class="footer"> <hr class="footer" /> <a class="reference external" href="generateDS.txt">View document source</a>. -Generated on: 2016-06-01 20:25 UTC. +Generated on: 2016-09-14 18:26 UTC. Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. </div> diff --git a/generateDS.py b/generateDS.py index 26fa828..d4091bb 100755 --- a/generateDS.py +++ b/generateDS.py @@ -204,7 +204,7 @@ logging.disable(logging.INFO) # Do not modify the following VERSION comments. # Used by updateversion.py. ##VERSION## -VERSION = '2.22b' +VERSION = '2.23a' ##VERSION## if sys.version_info.major == 2: diff --git a/generateDS.txt b/generateDS.txt index b439517..3230e02 100644 --- a/generateDS.txt +++ b/generateDS.txt @@ -12,7 +12,7 @@ generateDS -- Generate Data Structures from XML Schema .. version -:revision: 2.22b +:revision: 2.23a .. version diff --git a/generateds_gui_notes.html b/generateds_gui_notes.html index 2b70089..8196a0d 100644 --- a/generateds_gui_notes.html +++ b/generateds_gui_notes.html @@ -220,7 +220,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.22b</td> +<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.23a</td> </tr> </tbody> </table> @@ -229,7 +229,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">date:</th><td class="field-body">April 20, 2016</td> +<tr class="field"><th class="field-name">date:</th><td class="field-body">September 14, 2016</td> </tr> </tbody> </table> @@ -401,7 +401,7 @@ $ mv generateds_gui.mo locale/ru/LC_MESSAGES/ <div class="footer"> <hr class="footer" /> <a class="reference external" href="generateds_gui_notes.txt">View document source</a>. -Generated on: 2016-04-21 00:07 UTC. +Generated on: 2016-09-14 18:26 UTC. Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. </div> diff --git a/generateds_gui_notes.txt b/generateds_gui_notes.txt index 656a1db..bfcd944 100644 --- a/generateds_gui_notes.txt +++ b/generateds_gui_notes.txt @@ -12,7 +12,7 @@ GenerateDS GUI Notes .. version -:revision: 2.22b +:revision: 2.23a .. version diff --git a/gui/generateds_gui.py b/gui/generateds_gui.py index da981e9..21f2b10 100755 --- a/gui/generateds_gui.py +++ b/gui/generateds_gui.py @@ -41,7 +41,7 @@ from libgenerateDS.gui import generateds_gui_session # Do not modify the following VERSION comments. # Used by updateversion.py. ##VERSION## -VERSION = '2.22b' +VERSION = '2.23a' ##VERSION## diff --git a/librarytemplate_howto.html b/librarytemplate_howto.html index 303c083..8d2313f 100644 --- a/librarytemplate_howto.html +++ b/librarytemplate_howto.html @@ -217,7 +217,7 @@ dkuhlman (at) davekuhlman (dot) org <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.22b</td> +<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.23a</td> </tr> </tbody> </table> @@ -226,7 +226,7 @@ dkuhlman (at) davekuhlman (dot) org <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">date:</th><td class="field-body">April 20, 2016</td> +<tr class="field"><th class="field-name">date:</th><td class="field-body">September 14, 2016</td> </tr> </tbody> </table> @@ -380,7 +380,7 @@ this command for your needs. For example, you may need to use <div class="footer"> <hr class="footer" /> <a class="reference external" href="librarytemplate_howto.txt">View document source</a>. -Generated on: 2016-04-21 00:07 UTC. +Generated on: 2016-09-14 18:26 UTC. Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. </div> diff --git a/librarytemplate_howto.txt b/librarytemplate_howto.txt index f508d04..7c62ef2 100644 --- a/librarytemplate_howto.txt +++ b/librarytemplate_howto.txt @@ -8,7 +8,7 @@ How to package a generateDS.py generated library .. version -:revision: 2.22b +:revision: 2.23a .. version diff --git a/process_includes.py b/process_includes.py index e9516b6..1745adc 100755 --- a/process_includes.py +++ b/process_includes.py @@ -40,7 +40,7 @@ except ImportError: # Do not modify the following VERSION comments. # Used by updateversion.py. ##VERSION## -VERSION = '2.22b' +VERSION = '2.23a' ##VERSION## CatalogDict = {} diff --git a/setup.py b/setup.py index 4468b67..9ade052 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup(name="generateDS", # Do not modify the following VERSION comments. # Used by updateversion.py. ##VERSION## - version="2.22b", + version="2.23a", ##VERSION## author="Dave Kuhlman", author_email="dkuhlman@davekuhlman.org", diff --git a/tests/catalogtest2_sub.py b/tests/catalogtest2_sub.py deleted file mode 100644 index eae693c..0000000 --- a/tests/catalogtest2_sub.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env python - -# -# Generated by generateDS.py. -# -# Command line options: -# ('--no-dates', '') -# ('--no-versions', '') -# ('--silence', '') -# ('--member-specs', 'list') -# ('-f', '') -# ('-o', 'tests/catalogtest2_sup.py') -# ('-s', 'tests/catalogtest2_sub.py') -# ('--super', 'catalogtest2_sup') -# ('-c', 'tests/catalog.xml') -# -# Command line arguments: -# tests/catalogtest.xsd -# -# Command line: -# generateDS.py --no-dates --no-versions --silence --member-specs="list" -f -o "tests/catalogtest2_sup.py" -s "tests/catalogtest2_sub.py" --super="catalogtest2_sup" -c "tests/catalog.xml" tests/catalogtest.xsd -# -# Current working directory (os.getcwd()): -# generateds -# - -import sys -from lxml import etree as etree_ - -import catalogtest2_sup as supermod - -def parsexml_(infile, parser=None, **kwargs): - if parser is None: - # Use the lxml ElementTree compatible parser so that, e.g., - # we ignore comments. - parser = etree_.ETCompatXMLParser() - doc = etree_.parse(infile, parser=parser, **kwargs) - return doc - -# -# Globals -# - -ExternalEncoding = 'ascii' - -# -# Data representation classes -# - - -def get_root_tag(node): - tag = supermod.Tag_pattern_.match(node.tag).groups()[-1] - rootClass = None - rootClass = supermod.GDSClassesMapping.get(tag) - if rootClass is None and hasattr(supermod, tag): - rootClass = getattr(supermod, tag) - return tag, rootClass - - -def parse(inFilename, silence=False): - parser = None - doc = parsexml_(inFilename, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = '' - rootClass = supermod. - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None -## if not silence: -## sys.stdout.write('<?xml version="1.0" ?>\n') -## rootObj.export( -## sys.stdout, 0, name_=rootTag, -## namespacedef_='', -## pretty_print=True) - return rootObj - - -def parseEtree(inFilename, silence=False): - parser = None - doc = parsexml_(inFilename, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = '' - rootClass = supermod. - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - mapping = {} - rootElement = rootObj.to_etree(None, name_=rootTag, mapping_=mapping) - reverse_mapping = rootObj.gds_reverse_node_mapping(mapping) -## if not silence: -## content = etree_.tostring( -## rootElement, pretty_print=True, -## xml_declaration=True, encoding="utf-8") -## sys.stdout.write(content) -## sys.stdout.write('\n') - return rootObj, rootElement, mapping, reverse_mapping - - -def parseString(inString, silence=False): - from StringIO import StringIO - parser = None - doc = parsexml_(StringIO(inString), parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = '' - rootClass = supermod. - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None -## if not silence: -## sys.stdout.write('<?xml version="1.0" ?>\n') -## rootObj.export( -## sys.stdout, 0, name_=rootTag, -## namespacedef_='') - return rootObj - - -def parseLiteral(inFilename, silence=False): - parser = None - doc = parsexml_(inFilename, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = '' - rootClass = supermod. - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None -## if not silence: -## sys.stdout.write('#from catalogtest2_sup import *\n\n') -## sys.stdout.write('import catalogtest2_sup as model_\n\n') -## sys.stdout.write('rootObj = model_.rootClass(\n') -## rootObj.exportLiteral(sys.stdout, 0, name_=rootTag) -## sys.stdout.write(')\n') - return rootObj - - -USAGE_TEXT = """ -Usage: python ???.py <infilename> -""" - - -def usage(): - print(USAGE_TEXT) - sys.exit(1) - - -def main(): - args = sys.argv[1:] - if len(args) != 1: - usage() - infilename = args[0] - parse(infilename) - - -if __name__ == '__main__': - #import pdb; pdb.set_trace() - main() diff --git a/tests/catalogtest2_sup.py b/tests/catalogtest2_sup.py deleted file mode 100644 index 370be94..0000000 --- a/tests/catalogtest2_sup.py +++ /dev/null @@ -1,778 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Generated by generateDS.py. -# -# Command line options: -# ('--no-dates', '') -# ('--no-versions', '') -# ('--silence', '') -# ('--member-specs', 'list') -# ('-f', '') -# ('-o', 'tests/catalogtest2_sup.py') -# ('-s', 'tests/catalogtest2_sub.py') -# ('--super', 'catalogtest2_sup') -# ('-c', 'tests/catalog.xml') -# -# Command line arguments: -# tests/catalogtest.xsd -# -# Command line: -# generateDS.py --no-dates --no-versions --silence --member-specs="list" -f -o "tests/catalogtest2_sup.py" -s "tests/catalogtest2_sub.py" --super="catalogtest2_sup" -c "tests/catalog.xml" tests/catalogtest.xsd -# -# Current working directory (os.getcwd()): -# generateds -# - -import sys -import re as re_ -import base64 -import datetime as datetime_ -import warnings as warnings_ -try: - from lxml import etree as etree_ -except ImportError: - from xml.etree import ElementTree as etree_ - - -Validate_simpletypes_ = True -if sys.version_info.major == 2: - BaseStrType_ = basestring -else: - BaseStrType_ = str - - -def parsexml_(infile, parser=None, **kwargs): - if parser is None: - # Use the lxml ElementTree compatible parser so that, e.g., - # we ignore comments. - try: - parser = etree_.ETCompatXMLParser() - except AttributeError: - # fallback to xml.etree - parser = etree_.XMLParser() - doc = etree_.parse(infile, parser=parser, **kwargs) - return doc - -# -# User methods -# -# Calls to the methods in these classes are generated by generateDS.py. -# You can replace these methods by re-implementing the following class -# in a module named generatedssuper.py. - -try: - from generatedssuper import GeneratedsSuper -except ImportError as exp: - - class GeneratedsSuper(object): - tzoff_pattern = re_.compile(r'(\+|-)((0\d|1[0-3]):[0-5]\d|14:00)$') - class _FixedOffsetTZ(datetime_.tzinfo): - def __init__(self, offset, name): - self.__offset = datetime_.timedelta(minutes=offset) - self.__name = name - def utcoffset(self, dt): - return self.__offset - def tzname(self, dt): - return self.__name - def dst(self, dt): - return None - def gds_format_string(self, input_data, input_name=''): - return input_data - def gds_validate_string(self, input_data, node=None, input_name=''): - if not input_data: - return '' - else: - return input_data - def gds_format_base64(self, input_data, input_name=''): - return base64.b64encode(input_data) - def gds_validate_base64(self, input_data, node=None, input_name=''): - return input_data - def gds_format_integer(self, input_data, input_name=''): - return '%d' % input_data - def gds_validate_integer(self, input_data, node=None, input_name=''): - return input_data - def gds_format_integer_list(self, input_data, input_name=''): - return '%s' % ' '.join(input_data) - def gds_validate_integer_list( - self, input_data, node=None, input_name=''): - values = input_data.split() - for value in values: - try: - int(value) - except (TypeError, ValueError): - raise_parse_error(node, 'Requires sequence of integers') - return values - def gds_format_float(self, input_data, input_name=''): - return ('%.15f' % input_data).rstrip('0') - def gds_validate_float(self, input_data, node=None, input_name=''): - return input_data - def gds_format_float_list(self, input_data, input_name=''): - return '%s' % ' '.join(input_data) - def gds_validate_float_list( - self, input_data, node=None, input_name=''): - values = input_data.split() - for value in values: - try: - float(value) - except (TypeError, ValueError): - raise_parse_error(node, 'Requires sequence of floats') - return values - def gds_format_double(self, input_data, input_name=''): - return '%e' % input_data - def gds_validate_double(self, input_data, node=None, input_name=''): - return input_data - def gds_format_double_list(self, input_data, input_name=''): - return '%s' % ' '.join(input_data) - def gds_validate_double_list( - self, input_data, node=None, input_name=''): - values = input_data.split() - for value in values: - try: - float(value) - except (TypeError, ValueError): - raise_parse_error(node, 'Requires sequence of doubles') - return values - def gds_format_boolean(self, input_data, input_name=''): - return ('%s' % input_data).lower() - def gds_validate_boolean(self, input_data, node=None, input_name=''): - return input_data - def gds_format_boolean_list(self, input_data, input_name=''): - return '%s' % ' '.join(input_data) - def gds_validate_boolean_list( - self, input_data, node=None, input_name=''): - values = input_data.split() - for value in values: - if value not in ('true', '1', 'false', '0', ): - raise_parse_error( - node, - 'Requires sequence of booleans ' - '("true", "1", "false", "0")') - return values - def gds_validate_datetime(self, input_data, node=None, input_name=''): - return input_data - def gds_format_datetime(self, input_data, input_name=''): - if input_data.microsecond == 0: - _svalue = '%04d-%02d-%02dT%02d:%02d:%02d' % ( - input_data.year, - input_data.month, - input_data.day, - input_data.hour, - input_data.minute, - input_data.second, - ) - else: - _svalue = '%04d-%02d-%02dT%02d:%02d:%02d.%s' % ( - input_data.year, - input_data.month, - input_data.day, - input_data.hour, - input_data.minute, - input_data.second, - ('%f' % (float(input_data.microsecond) / 1000000))[2:], - ) - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) - return _svalue - @classmethod - def gds_parse_datetime(cls, input_data): - tz = None - if input_data[-1] == 'Z': - tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') - input_data = input_data[:-1] - else: - results = GeneratedsSuper.tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = GeneratedsSuper._FixedOffsetTZ( - tzoff, results.group(0)) - input_data = input_data[:-6] - time_parts = input_data.split('.') - if len(time_parts) > 1: - micro_seconds = int(float('0.' + time_parts[1]) * 1000000) - input_data = '%s.%s' % (time_parts[0], micro_seconds, ) - dt = datetime_.datetime.strptime( - input_data, '%Y-%m-%dT%H:%M:%S.%f') - else: - dt = datetime_.datetime.strptime( - input_data, '%Y-%m-%dT%H:%M:%S') - dt = dt.replace(tzinfo=tz) - return dt - def gds_validate_date(self, input_data, node=None, input_name=''): - return input_data - def gds_format_date(self, input_data, input_name=''): - _svalue = '%04d-%02d-%02d' % ( - input_data.year, - input_data.month, - input_data.day, - ) - try: - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format( - hours, minutes) - except AttributeError: - pass - return _svalue - @classmethod - def gds_parse_date(cls, input_data): - tz = None - if input_data[-1] == 'Z': - tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') - input_data = input_data[:-1] - else: - results = GeneratedsSuper.tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = GeneratedsSuper._FixedOffsetTZ( - tzoff, results.group(0)) - input_data = input_data[:-6] - dt = datetime_.datetime.strptime(input_data, '%Y-%m-%d') - dt = dt.replace(tzinfo=tz) - return dt.date() - def gds_validate_time(self, input_data, node=None, input_name=''): - return input_data - def gds_format_time(self, input_data, input_name=''): - if input_data.microsecond == 0: - _svalue = '%02d:%02d:%02d' % ( - input_data.hour, - input_data.minute, - input_data.second, - ) - else: - _svalue = '%02d:%02d:%02d.%s' % ( - input_data.hour, - input_data.minute, - input_data.second, - ('%f' % (float(input_data.microsecond) / 1000000))[2:], - ) - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) - return _svalue - def gds_validate_simple_patterns(self, patterns, target): - # pat is a list of lists of strings/patterns. We should: - # - AND the outer elements - # - OR the inner elements - found1 = True - for patterns1 in patterns: - found2 = False - for patterns2 in patterns1: - if re_.search(patterns2, target) is not None: - found2 = True - break - if not found2: - found1 = False - break - return found1 - @classmethod - def gds_parse_time(cls, input_data): - tz = None - if input_data[-1] == 'Z': - tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') - input_data = input_data[:-1] - else: - results = GeneratedsSuper.tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = GeneratedsSuper._FixedOffsetTZ( - tzoff, results.group(0)) - input_data = input_data[:-6] - if len(input_data.split('.')) > 1: - dt = datetime_.datetime.strptime(input_data, '%H:%M:%S.%f') - else: - dt = datetime_.datetime.strptime(input_data, '%H:%M:%S') - dt = dt.replace(tzinfo=tz) - return dt.time() - def gds_str_lower(self, instring): - return instring.lower() - def get_path_(self, node): - path_list = [] - self.get_path_list_(node, path_list) - path_list.reverse() - path = '/'.join(path_list) - return path - Tag_strip_pattern_ = re_.compile(r'\{.*\}') - def get_path_list_(self, node, path_list): - if node is None: - return - tag = GeneratedsSuper.Tag_strip_pattern_.sub('', node.tag) - if tag: - path_list.append(tag) - self.get_path_list_(node.getparent(), path_list) - def get_class_obj_(self, node, default_class=None): - class_obj1 = default_class - if 'xsi' in node.nsmap: - classname = node.get('{%s}type' % node.nsmap['xsi']) - if classname is not None: - names = classname.split(':') - if len(names) == 2: - classname = names[1] - class_obj2 = globals().get(classname) - if class_obj2 is not None: - class_obj1 = class_obj2 - return class_obj1 - def gds_build_any(self, node, type_name=None): - return None - @classmethod - def gds_reverse_node_mapping(cls, mapping): - return dict(((v, k) for k, v in mapping.iteritems())) - @staticmethod - def gds_encode(instring): - if sys.version_info.major == 2: - return instring.encode(ExternalEncoding) - else: - return instring - - def getSubclassFromModule_(module, class_): - '''Get the subclass of a class from a specific module.''' - name = class_.__name__ + 'Sub' - if hasattr(module, name): - return getattr(module, name) - else: - return None - - -# -# If you have installed IPython you can uncomment and use the following. -# IPython is available from http://ipython.scipy.org/. -# - -## from IPython.Shell import IPShellEmbed -## args = '' -## ipshell = IPShellEmbed(args, -## banner = 'Dropping into IPython', -## exit_msg = 'Leaving Interpreter, back to program.') - -# Then use the following line where and when you want to drop into the -# IPython shell: -# ipshell('<some message> -- Entering ipshell.\nHit Ctrl-D to exit') - -# -# Globals -# - -ExternalEncoding = 'ascii' -Tag_pattern_ = re_.compile(r'({.*})?(.*)') -String_cleanup_pat_ = re_.compile(r"[\n\r\s]+") -Namespace_extract_pat_ = re_.compile(r'{(.*)}(.*)') -CDATA_pattern_ = re_.compile(r"<!\[CDATA\[.*?\]\]>", re_.DOTALL) - -# Change this to redirect the generated superclass module to use a -# specific subclass module. -CurrentSubclassModule_ = None - -# -# Support/utility functions. -# - - -def showIndent(outfile, level, pretty_print=True): - if pretty_print: - for idx in range(level): - outfile.write(' ') - - -def quote_xml(inStr): - "Escape markup chars, but do not modify CDATA sections." - if not inStr: - return '' - s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) - s2 = '' - pos = 0 - matchobjects = CDATA_pattern_.finditer(s1) - for mo in matchobjects: - s3 = s1[pos:mo.start()] - s2 += quote_xml_aux(s3) - s2 += s1[mo.start():mo.end()] - pos = mo.end() - s3 = s1[pos:] - s2 += quote_xml_aux(s3) - return s2 - - -def quote_xml_aux(inStr): - s1 = inStr.replace('&', '&') - s1 = s1.replace('<', '<') - s1 = s1.replace('>', '>') - return s1 - - -def quote_attrib(inStr): - s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) - s1 = s1.replace('&', '&') - s1 = s1.replace('<', '<') - s1 = s1.replace('>', '>') - if '"' in s1: - if "'" in s1: - s1 = '"%s"' % s1.replace('"', """) - else: - s1 = "'%s'" % s1 - else: - s1 = '"%s"' % s1 - return s1 - - -def quote_python(inStr): - s1 = inStr - if s1.find("'") == -1: - if s1.find('\n') == -1: - return "'%s'" % s1 - else: - return "'''%s'''" % s1 - else: - if s1.find('"') != -1: - s1 = s1.replace('"', '\\"') - if s1.find('\n') == -1: - return '"%s"' % s1 - else: - return '"""%s"""' % s1 - - -def get_all_text_(node): - if node.text is not None: - text = node.text - else: - text = '' - for child in node: - if child.tail is not None: - text += child.tail - return text - - -def find_attr_value_(attr_name, node): - attrs = node.attrib - attr_parts = attr_name.split(':') - value = None - if len(attr_parts) == 1: - value = attrs.get(attr_name) - elif len(attr_parts) == 2: - prefix, name = attr_parts - namespace = node.nsmap.get(prefix) - if namespace is not None: - value = attrs.get('{%s}%s' % (namespace, name, )) - return value - - -class GDSParseError(Exception): - pass - - -def raise_parse_error(node, msg): - msg = '%s (element %s/line %d)' % (msg, node.tag, node.sourceline, ) - raise GDSParseError(msg) - - -class MixedContainer: - # Constants for category: - CategoryNone = 0 - CategoryText = 1 - CategorySimple = 2 - CategoryComplex = 3 - # Constants for content_type: - TypeNone = 0 - TypeText = 1 - TypeString = 2 - TypeInteger = 3 - TypeFloat = 4 - TypeDecimal = 5 - TypeDouble = 6 - TypeBoolean = 7 - TypeBase64 = 8 - def __init__(self, category, content_type, name, value): - self.category = category - self.content_type = content_type - self.name = name - self.value = value - def getCategory(self): - return self.category - def getContenttype(self, content_type): - return self.content_type - def getValue(self): - return self.value - def getName(self): - return self.name - def export(self, outfile, level, name, namespace, pretty_print=True): - if self.category == MixedContainer.CategoryText: - # Prevent exporting empty content as empty lines. - if self.value.strip(): - outfile.write(self.value) - elif self.category == MixedContainer.CategorySimple: - self.exportSimple(outfile, level, name) - else: # category == MixedContainer.CategoryComplex - self.value.export(outfile, level, namespace, name, pretty_print) - def exportSimple(self, outfile, level, name): - if self.content_type == MixedContainer.TypeString: - outfile.write('<%s>%s</%s>' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeInteger or \ - self.content_type == MixedContainer.TypeBoolean: - outfile.write('<%s>%d</%s>' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeFloat or \ - self.content_type == MixedContainer.TypeDecimal: - outfile.write('<%s>%f</%s>' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeDouble: - outfile.write('<%s>%g</%s>' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeBase64: - outfile.write('<%s>%s</%s>' % ( - self.name, base64.b64encode(self.value), self.name)) - def to_etree(self, element): - if self.category == MixedContainer.CategoryText: - # Prevent exporting empty content as empty lines. - if self.value.strip(): - if len(element) > 0: - if element[-1].tail is None: - element[-1].tail = self.value - else: - element[-1].tail += self.value - else: - if element.text is None: - element.text = self.value - else: - element.text += self.value - elif self.category == MixedContainer.CategorySimple: - subelement = etree_.SubElement(element, '%s' % self.name) - subelement.text = self.to_etree_simple() - else: # category == MixedContainer.CategoryComplex - self.value.to_etree(element) - def to_etree_simple(self): - if self.content_type == MixedContainer.TypeString: - text = self.value - elif (self.content_type == MixedContainer.TypeInteger or - self.content_type == MixedContainer.TypeBoolean): - text = '%d' % self.value - elif (self.content_type == MixedContainer.TypeFloat or - self.content_type == MixedContainer.TypeDecimal): - text = '%f' % self.value - elif self.content_type == MixedContainer.TypeDouble: - text = '%g' % self.value - elif self.content_type == MixedContainer.TypeBase64: - text = '%s' % base64.b64encode(self.value) - return text - def exportLiteral(self, outfile, level, name): - if self.category == MixedContainer.CategoryText: - showIndent(outfile, level) - outfile.write( - 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( - self.category, self.content_type, self.name, self.value)) - elif self.category == MixedContainer.CategorySimple: - showIndent(outfile, level) - outfile.write( - 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( - self.category, self.content_type, self.name, self.value)) - else: # category == MixedContainer.CategoryComplex - showIndent(outfile, level) - outfile.write( - 'model_.MixedContainer(%d, %d, "%s",\n' % ( - self.category, self.content_type, self.name,)) - self.value.exportLiteral(outfile, level + 1) - showIndent(outfile, level) - outfile.write(')\n') - - -class MemberSpec_(object): - def __init__(self, name='', data_type='', container=0): - self.name = name - self.data_type = data_type - self.container = container - def set_name(self, name): self.name = name - def get_name(self): return self.name - def set_data_type(self, data_type): self.data_type = data_type - def get_data_type_chain(self): return self.data_type - def get_data_type(self): - if isinstance(self.data_type, list): - if len(self.data_type) > 0: - return self.data_type[-1] - else: - return 'xs:string' - else: - return self.data_type - def set_container(self, container): self.container = container - def get_container(self): return self.container - - -def _cast(typ, value): - if typ is None or value is None: - return value - return typ(value) - -# -# Data representation classes. -# - - -GDSClassesMapping = { -} - - -USAGE_TEXT = """ -Usage: python <Parser>.py [ -s ] <in_xml_file> -""" - - -def usage(): - print(USAGE_TEXT) - sys.exit(1) - - -def get_root_tag(node): - tag = Tag_pattern_.match(node.tag).groups()[-1] - rootClass = GDSClassesMapping.get(tag) - if rootClass is None: - rootClass = globals().get(tag) - return tag, rootClass - - -def parse(inFileName, silence=False): - parser = None - doc = parsexml_(inFileName, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = '' - rootClass = - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None -## if not silence: -## sys.stdout.write('<?xml version="1.0" ?>\n') -## rootObj.export( -## sys.stdout, 0, name_=rootTag, -## namespacedef_='', -## pretty_print=True) - return rootObj - - -def parseEtree(inFileName, silence=False): - parser = None - doc = parsexml_(inFileName, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = '' - rootClass = - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - mapping = {} - rootElement = rootObj.to_etree(None, name_=rootTag, mapping_=mapping) - reverse_mapping = rootObj.gds_reverse_node_mapping(mapping) -## if not silence: -## content = etree_.tostring( -## rootElement, pretty_print=True, -## xml_declaration=True, encoding="utf-8") -## sys.stdout.write(content) -## sys.stdout.write('\n') - return rootObj, rootElement, mapping, reverse_mapping - - -def parseString(inString, silence=False): - from StringIO import StringIO - parser = None - doc = parsexml_(StringIO(inString), parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = '' - rootClass = - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None -## if not silence: -## sys.stdout.write('<?xml version="1.0" ?>\n') -## rootObj.export( -## sys.stdout, 0, name_=rootTag, -## namespacedef_='') - return rootObj - - -def parseLiteral(inFileName, silence=False): - parser = None - doc = parsexml_(inFileName, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = '' - rootClass = - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None -## if not silence: -## sys.stdout.write('#from catalogtest2_sup import *\n\n') -## sys.stdout.write('import catalogtest2_sup as model_\n\n') -## sys.stdout.write('rootObj = model_.rootClass(\n') -## rootObj.exportLiteral(sys.stdout, 0, name_=rootTag) -## sys.stdout.write(')\n') - return rootObj - - -def main(): - args = sys.argv[1:] - if len(args) == 1: - parse(args[0]) - else: - usage() - - -if __name__ == '__main__': - #import pdb; pdb.set_trace() - main() - - -__all__ = [ - -] diff --git a/tests/ipo2_out.xml b/tests/ipo2_out.xml deleted file mode 100644 index c6da399..0000000 --- a/tests/ipo2_out.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" ?> -<ipo:purchaseOrder xmlns:ipo="http://www.example.com/IPO" orderDate="1999-12-01"> - <ipo:shipTo xmlns:ipo="http://www.example.com/IPO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ipo:UKAddress" category="1-a" exportCode="1"> - <ipo:name>Helen Zoe</ipo:name> - <ipo:street>47 Eden Street</ipo:street> - <ipo:city>Cambridge</ipo:city> - <ipo:postcode>CB1 1JR</ipo:postcode> - <ipo:category>oneA</ipo:category> - </ipo:shipTo> - <ipo:billTo xmlns:ipo="http://www.example.com/IPO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ipo:USAddress"> - <ipo:name>Robert Smith</ipo:name> - <ipo:street>8 Oak Avenue</ipo:street> - <ipo:city>Old Town</ipo:city> - <ipo:state>PA</ipo:state> - <ipo:zip>95819</ipo:zip> - </ipo:billTo> - <ipo:items xmlns:ipo="http://www.example.com/IPO"> - <ipo:item xmlns:ipo="http://www.example.com/IPO" partNum="833-AA"> - <ipo:productName>Lapis necklace</ipo:productName> - <ipo:quantity>1</ipo:quantity> - <ipo:USPrice>99.950000000000003</ipo:USPrice> - <ipo:comment>Want this for the holidays</ipo:comment> - <ipo:shipDate>1999-12-05</ipo:shipDate> - </ipo:item> - </ipo:items> -</ipo:purchaseOrder> diff --git a/tests/nested_def2_out.xml b/tests/nested_def2_out.xml deleted file mode 100644 index 692c598..0000000 --- a/tests/nested_def2_out.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" ?> -<container> - <item1> - <inner attrA1="attrA1value" attrA2="attrA2value"/> - </item1> - <item2> - <inner attrB1="attrB1value" attrB2="attrB2value"/> - </item2> -</container> diff --git a/tests/nested_def2_sub.py b/tests/nested_def2_sub.py deleted file mode 100644 index 2abcd14..0000000 --- a/tests/nested_def2_sub.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env python - -# -# Generated by generateDS.py. -# -# Command line options: -# ('--no-dates', '') -# ('--no-versions', '') -# ('--member-specs', 'list') -# ('-f', '') -# ('-o', 'tests/nested_def2_sup.py') -# ('-s', 'tests/nested_def2_sub.py') -# ('--super', 'nested_def2_sup') -# -# Command line arguments: -# tests/nested_def.xsd -# -# Command line: -# generateDS.py --no-dates --no-versions --member-specs="list" -f -o "tests/nested_def2_sup.py" -s "tests/nested_def2_sub.py" --super="nested_def2_sup" tests/nested_def.xsd -# -# Current working directory (os.getcwd()): -# generateds -# - -import sys -from lxml import etree as etree_ - -import nested_def2_sup as supermod - -def parsexml_(infile, parser=None, **kwargs): - if parser is None: - # Use the lxml ElementTree compatible parser so that, e.g., - # we ignore comments. - parser = etree_.ETCompatXMLParser() - doc = etree_.parse(infile, parser=parser, **kwargs) - return doc - -# -# Globals -# - -ExternalEncoding = 'ascii' - -# -# Data representation classes -# - - -class containerTypeSub(supermod.containerType): - def __init__(self, item1=None, item2=None): - super(containerTypeSub, self).__init__(item1, item2, ) -supermod.containerType.subclass = containerTypeSub -# end class containerTypeSub - - -class classATypeSub(supermod.classAType): - def __init__(self, inner=None): - super(classATypeSub, self).__init__(inner, ) -supermod.classAType.subclass = classATypeSub -# end class classATypeSub - - -class classBTypeSub(supermod.classBType): - def __init__(self, inner=None): - super(classBTypeSub, self).__init__(inner, ) -supermod.classBType.subclass = classBTypeSub -# end class classBTypeSub - - -class innerTypeSub(supermod.innerType): - def __init__(self, attrA1=None, attrA2=None): - super(innerTypeSub, self).__init__(attrA1, attrA2, ) -supermod.innerType.subclass = innerTypeSub -# end class innerTypeSub - - -class innerType1Sub(supermod.innerType1): - def __init__(self, attrB1=None, attrB2=None): - super(innerType1Sub, self).__init__(attrB1, attrB2, ) -supermod.innerType1.subclass = innerType1Sub -# end class innerType1Sub - - -def get_root_tag(node): - tag = supermod.Tag_pattern_.match(node.tag).groups()[-1] - rootClass = None - rootClass = supermod.GDSClassesMapping.get(tag) - if rootClass is None and hasattr(supermod, tag): - rootClass = getattr(supermod, tag) - return tag, rootClass - - -def parse(inFilename, silence=False): - parser = None - doc = parsexml_(inFilename, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'containerType' - rootClass = supermod.containerType - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - if not silence: - sys.stdout.write('<?xml version="1.0" ?>\n') - rootObj.export( - sys.stdout, 0, name_=rootTag, - namespacedef_='', - pretty_print=True) - return rootObj - - -def parseEtree(inFilename, silence=False): - parser = None - doc = parsexml_(inFilename, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'containerType' - rootClass = supermod.containerType - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - mapping = {} - rootElement = rootObj.to_etree(None, name_=rootTag, mapping_=mapping) - reverse_mapping = rootObj.gds_reverse_node_mapping(mapping) - if not silence: - content = etree_.tostring( - rootElement, pretty_print=True, - xml_declaration=True, encoding="utf-8") - sys.stdout.write(content) - sys.stdout.write('\n') - return rootObj, rootElement, mapping, reverse_mapping - - -def parseString(inString, silence=False): - from StringIO import StringIO - parser = None - doc = parsexml_(StringIO(inString), parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'containerType' - rootClass = supermod.containerType - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - if not silence: - sys.stdout.write('<?xml version="1.0" ?>\n') - rootObj.export( - sys.stdout, 0, name_=rootTag, - namespacedef_='') - return rootObj - - -def parseLiteral(inFilename, silence=False): - parser = None - doc = parsexml_(inFilename, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'containerType' - rootClass = supermod.containerType - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - if not silence: - sys.stdout.write('#from nested_def2_sup import *\n\n') - sys.stdout.write('import nested_def2_sup as model_\n\n') - sys.stdout.write('rootObj = model_.rootClass(\n') - rootObj.exportLiteral(sys.stdout, 0, name_=rootTag) - sys.stdout.write(')\n') - return rootObj - - -USAGE_TEXT = """ -Usage: python ???.py <infilename> -""" - - -def usage(): - print(USAGE_TEXT) - sys.exit(1) - - -def main(): - args = sys.argv[1:] - if len(args) != 1: - usage() - infilename = args[0] - parse(infilename) - - -if __name__ == '__main__': - #import pdb; pdb.set_trace() - main() diff --git a/tests/nested_def2_sup.py b/tests/nested_def2_sup.py deleted file mode 100644 index 0240702..0000000 --- a/tests/nested_def2_sup.py +++ /dev/null @@ -1,1180 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Generated by generateDS.py. -# -# Command line options: -# ('--no-dates', '') -# ('--no-versions', '') -# ('--member-specs', 'list') -# ('-f', '') -# ('-o', 'tests/nested_def2_sup.py') -# ('-s', 'tests/nested_def2_sub.py') -# ('--super', 'nested_def2_sup') -# -# Command line arguments: -# tests/nested_def.xsd -# -# Command line: -# generateDS.py --no-dates --no-versions --member-specs="list" -f -o "tests/nested_def2_sup.py" -s "tests/nested_def2_sub.py" --super="nested_def2_sup" tests/nested_def.xsd -# -# Current working directory (os.getcwd()): -# generateds -# - -import sys -import re as re_ -import base64 -import datetime as datetime_ -import warnings as warnings_ -try: - from lxml import etree as etree_ -except ImportError: - from xml.etree import ElementTree as etree_ - - -Validate_simpletypes_ = True -if sys.version_info.major == 2: - BaseStrType_ = basestring -else: - BaseStrType_ = str - - -def parsexml_(infile, parser=None, **kwargs): - if parser is None: - # Use the lxml ElementTree compatible parser so that, e.g., - # we ignore comments. - try: - parser = etree_.ETCompatXMLParser() - except AttributeError: - # fallback to xml.etree - parser = etree_.XMLParser() - doc = etree_.parse(infile, parser=parser, **kwargs) - return doc - -# -# User methods -# -# Calls to the methods in these classes are generated by generateDS.py. -# You can replace these methods by re-implementing the following class -# in a module named generatedssuper.py. - -try: - from generatedssuper import GeneratedsSuper -except ImportError as exp: - - class GeneratedsSuper(object): - tzoff_pattern = re_.compile(r'(\+|-)((0\d|1[0-3]):[0-5]\d|14:00)$') - class _FixedOffsetTZ(datetime_.tzinfo): - def __init__(self, offset, name): - self.__offset = datetime_.timedelta(minutes=offset) - self.__name = name - def utcoffset(self, dt): - return self.__offset - def tzname(self, dt): - return self.__name - def dst(self, dt): - return None - def gds_format_string(self, input_data, input_name=''): - return input_data - def gds_validate_string(self, input_data, node=None, input_name=''): - if not input_data: - return '' - else: - return input_data - def gds_format_base64(self, input_data, input_name=''): - return base64.b64encode(input_data) - def gds_validate_base64(self, input_data, node=None, input_name=''): - return input_data - def gds_format_integer(self, input_data, input_name=''): - return '%d' % input_data - def gds_validate_integer(self, input_data, node=None, input_name=''): - return input_data - def gds_format_integer_list(self, input_data, input_name=''): - return '%s' % ' '.join(input_data) - def gds_validate_integer_list( - self, input_data, node=None, input_name=''): - values = input_data.split() - for value in values: - try: - int(value) - except (TypeError, ValueError): - raise_parse_error(node, 'Requires sequence of integers') - return values - def gds_format_float(self, input_data, input_name=''): - return ('%.15f' % input_data).rstrip('0') - def gds_validate_float(self, input_data, node=None, input_name=''): - return input_data - def gds_format_float_list(self, input_data, input_name=''): - return '%s' % ' '.join(input_data) - def gds_validate_float_list( - self, input_data, node=None, input_name=''): - values = input_data.split() - for value in values: - try: - float(value) - except (TypeError, ValueError): - raise_parse_error(node, 'Requires sequence of floats') - return values - def gds_format_double(self, input_data, input_name=''): - return '%e' % input_data - def gds_validate_double(self, input_data, node=None, input_name=''): - return input_data - def gds_format_double_list(self, input_data, input_name=''): - return '%s' % ' '.join(input_data) - def gds_validate_double_list( - self, input_data, node=None, input_name=''): - values = input_data.split() - for value in values: - try: - float(value) - except (TypeError, ValueError): - raise_parse_error(node, 'Requires sequence of doubles') - return values - def gds_format_boolean(self, input_data, input_name=''): - return ('%s' % input_data).lower() - def gds_validate_boolean(self, input_data, node=None, input_name=''): - return input_data - def gds_format_boolean_list(self, input_data, input_name=''): - return '%s' % ' '.join(input_data) - def gds_validate_boolean_list( - self, input_data, node=None, input_name=''): - values = input_data.split() - for value in values: - if value not in ('true', '1', 'false', '0', ): - raise_parse_error( - node, - 'Requires sequence of booleans ' - '("true", "1", "false", "0")') - return values - def gds_validate_datetime(self, input_data, node=None, input_name=''): - return input_data - def gds_format_datetime(self, input_data, input_name=''): - if input_data.microsecond == 0: - _svalue = '%04d-%02d-%02dT%02d:%02d:%02d' % ( - input_data.year, - input_data.month, - input_data.day, - input_data.hour, - input_data.minute, - input_data.second, - ) - else: - _svalue = '%04d-%02d-%02dT%02d:%02d:%02d.%s' % ( - input_data.year, - input_data.month, - input_data.day, - input_data.hour, - input_data.minute, - input_data.second, - ('%f' % (float(input_data.microsecond) / 1000000))[2:], - ) - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) - return _svalue - @classmethod - def gds_parse_datetime(cls, input_data): - tz = None - if input_data[-1] == 'Z': - tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') - input_data = input_data[:-1] - else: - results = GeneratedsSuper.tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = GeneratedsSuper._FixedOffsetTZ( - tzoff, results.group(0)) - input_data = input_data[:-6] - time_parts = input_data.split('.') - if len(time_parts) > 1: - micro_seconds = int(float('0.' + time_parts[1]) * 1000000) - input_data = '%s.%s' % (time_parts[0], micro_seconds, ) - dt = datetime_.datetime.strptime( - input_data, '%Y-%m-%dT%H:%M:%S.%f') - else: - dt = datetime_.datetime.strptime( - input_data, '%Y-%m-%dT%H:%M:%S') - dt = dt.replace(tzinfo=tz) - return dt - def gds_validate_date(self, input_data, node=None, input_name=''): - return input_data - def gds_format_date(self, input_data, input_name=''): - _svalue = '%04d-%02d-%02d' % ( - input_data.year, - input_data.month, - input_data.day, - ) - try: - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format( - hours, minutes) - except AttributeError: - pass - return _svalue - @classmethod - def gds_parse_date(cls, input_data): - tz = None - if input_data[-1] == 'Z': - tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') - input_data = input_data[:-1] - else: - results = GeneratedsSuper.tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = GeneratedsSuper._FixedOffsetTZ( - tzoff, results.group(0)) - input_data = input_data[:-6] - dt = datetime_.datetime.strptime(input_data, '%Y-%m-%d') - dt = dt.replace(tzinfo=tz) - return dt.date() - def gds_validate_time(self, input_data, node=None, input_name=''): - return input_data - def gds_format_time(self, input_data, input_name=''): - if input_data.microsecond == 0: - _svalue = '%02d:%02d:%02d' % ( - input_data.hour, - input_data.minute, - input_data.second, - ) - else: - _svalue = '%02d:%02d:%02d.%s' % ( - input_data.hour, - input_data.minute, - input_data.second, - ('%f' % (float(input_data.microsecond) / 1000000))[2:], - ) - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) - return _svalue - def gds_validate_simple_patterns(self, patterns, target): - # pat is a list of lists of strings/patterns. We should: - # - AND the outer elements - # - OR the inner elements - found1 = True - for patterns1 in patterns: - found2 = False - for patterns2 in patterns1: - if re_.search(patterns2, target) is not None: - found2 = True - break - if not found2: - found1 = False - break - return found1 - @classmethod - def gds_parse_time(cls, input_data): - tz = None - if input_data[-1] == 'Z': - tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') - input_data = input_data[:-1] - else: - results = GeneratedsSuper.tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = GeneratedsSuper._FixedOffsetTZ( - tzoff, results.group(0)) - input_data = input_data[:-6] - if len(input_data.split('.')) > 1: - dt = datetime_.datetime.strptime(input_data, '%H:%M:%S.%f') - else: - dt = datetime_.datetime.strptime(input_data, '%H:%M:%S') - dt = dt.replace(tzinfo=tz) - return dt.time() - def gds_str_lower(self, instring): - return instring.lower() - def get_path_(self, node): - path_list = [] - self.get_path_list_(node, path_list) - path_list.reverse() - path = '/'.join(path_list) - return path - Tag_strip_pattern_ = re_.compile(r'\{.*\}') - def get_path_list_(self, node, path_list): - if node is None: - return - tag = GeneratedsSuper.Tag_strip_pattern_.sub('', node.tag) - if tag: - path_list.append(tag) - self.get_path_list_(node.getparent(), path_list) - def get_class_obj_(self, node, default_class=None): - class_obj1 = default_class - if 'xsi' in node.nsmap: - classname = node.get('{%s}type' % node.nsmap['xsi']) - if classname is not None: - names = classname.split(':') - if len(names) == 2: - classname = names[1] - class_obj2 = globals().get(classname) - if class_obj2 is not None: - class_obj1 = class_obj2 - return class_obj1 - def gds_build_any(self, node, type_name=None): - return None - @classmethod - def gds_reverse_node_mapping(cls, mapping): - return dict(((v, k) for k, v in mapping.iteritems())) - @staticmethod - def gds_encode(instring): - if sys.version_info.major == 2: - return instring.encode(ExternalEncoding) - else: - return instring - - def getSubclassFromModule_(module, class_): - '''Get the subclass of a class from a specific module.''' - name = class_.__name__ + 'Sub' - if hasattr(module, name): - return getattr(module, name) - else: - return None - - -# -# If you have installed IPython you can uncomment and use the following. -# IPython is available from http://ipython.scipy.org/. -# - -## from IPython.Shell import IPShellEmbed -## args = '' -## ipshell = IPShellEmbed(args, -## banner = 'Dropping into IPython', -## exit_msg = 'Leaving Interpreter, back to program.') - -# Then use the following line where and when you want to drop into the -# IPython shell: -# ipshell('<some message> -- Entering ipshell.\nHit Ctrl-D to exit') - -# -# Globals -# - -ExternalEncoding = 'ascii' -Tag_pattern_ = re_.compile(r'({.*})?(.*)') -String_cleanup_pat_ = re_.compile(r"[\n\r\s]+") -Namespace_extract_pat_ = re_.compile(r'{(.*)}(.*)') -CDATA_pattern_ = re_.compile(r"<!\[CDATA\[.*?\]\]>", re_.DOTALL) - -# Change this to redirect the generated superclass module to use a -# specific subclass module. -CurrentSubclassModule_ = None - -# -# Support/utility functions. -# - - -def showIndent(outfile, level, pretty_print=True): - if pretty_print: - for idx in range(level): - outfile.write(' ') - - -def quote_xml(inStr): - "Escape markup chars, but do not modify CDATA sections." - if not inStr: - return '' - s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) - s2 = '' - pos = 0 - matchobjects = CDATA_pattern_.finditer(s1) - for mo in matchobjects: - s3 = s1[pos:mo.start()] - s2 += quote_xml_aux(s3) - s2 += s1[mo.start():mo.end()] - pos = mo.end() - s3 = s1[pos:] - s2 += quote_xml_aux(s3) - return s2 - - -def quote_xml_aux(inStr): - s1 = inStr.replace('&', '&') - s1 = s1.replace('<', '<') - s1 = s1.replace('>', '>') - return s1 - - -def quote_attrib(inStr): - s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) - s1 = s1.replace('&', '&') - s1 = s1.replace('<', '<') - s1 = s1.replace('>', '>') - if '"' in s1: - if "'" in s1: - s1 = '"%s"' % s1.replace('"', """) - else: - s1 = "'%s'" % s1 - else: - s1 = '"%s"' % s1 - return s1 - - -def quote_python(inStr): - s1 = inStr - if s1.find("'") == -1: - if s1.find('\n') == -1: - return "'%s'" % s1 - else: - return "'''%s'''" % s1 - else: - if s1.find('"') != -1: - s1 = s1.replace('"', '\\"') - if s1.find('\n') == -1: - return '"%s"' % s1 - else: - return '"""%s"""' % s1 - - -def get_all_text_(node): - if node.text is not None: - text = node.text - else: - text = '' - for child in node: - if child.tail is not None: - text += child.tail - return text - - -def find_attr_value_(attr_name, node): - attrs = node.attrib - attr_parts = attr_name.split(':') - value = None - if len(attr_parts) == 1: - value = attrs.get(attr_name) - elif len(attr_parts) == 2: - prefix, name = attr_parts - namespace = node.nsmap.get(prefix) - if namespace is not None: - value = attrs.get('{%s}%s' % (namespace, name, )) - return value - - -class GDSParseError(Exception): - pass - - -def raise_parse_error(node, msg): - msg = '%s (element %s/line %d)' % (msg, node.tag, node.sourceline, ) - raise GDSParseError(msg) - - -class MixedContainer: - # Constants for category: - CategoryNone = 0 - CategoryText = 1 - CategorySimple = 2 - CategoryComplex = 3 - # Constants for content_type: - TypeNone = 0 - TypeText = 1 - TypeString = 2 - TypeInteger = 3 - TypeFloat = 4 - TypeDecimal = 5 - TypeDouble = 6 - TypeBoolean = 7 - TypeBase64 = 8 - def __init__(self, category, content_type, name, value): - self.category = category - self.content_type = content_type - self.name = name - self.value = value - def getCategory(self): - return self.category - def getContenttype(self, content_type): - return self.content_type - def getValue(self): - return self.value - def getName(self): - return self.name - def export(self, outfile, level, name, namespace, pretty_print=True): - if self.category == MixedContainer.CategoryText: - # Prevent exporting empty content as empty lines. - if self.value.strip(): - outfile.write(self.value) - elif self.category == MixedContainer.CategorySimple: - self.exportSimple(outfile, level, name) - else: # category == MixedContainer.CategoryComplex - self.value.export(outfile, level, namespace, name, pretty_print) - def exportSimple(self, outfile, level, name): - if self.content_type == MixedContainer.TypeString: - outfile.write('<%s>%s</%s>' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeInteger or \ - self.content_type == MixedContainer.TypeBoolean: - outfile.write('<%s>%d</%s>' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeFloat or \ - self.content_type == MixedContainer.TypeDecimal: - outfile.write('<%s>%f</%s>' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeDouble: - outfile.write('<%s>%g</%s>' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeBase64: - outfile.write('<%s>%s</%s>' % ( - self.name, base64.b64encode(self.value), self.name)) - def to_etree(self, element): - if self.category == MixedContainer.CategoryText: - # Prevent exporting empty content as empty lines. - if self.value.strip(): - if len(element) > 0: - if element[-1].tail is None: - element[-1].tail = self.value - else: - element[-1].tail += self.value - else: - if element.text is None: - element.text = self.value - else: - element.text += self.value - elif self.category == MixedContainer.CategorySimple: - subelement = etree_.SubElement(element, '%s' % self.name) - subelement.text = self.to_etree_simple() - else: # category == MixedContainer.CategoryComplex - self.value.to_etree(element) - def to_etree_simple(self): - if self.content_type == MixedContainer.TypeString: - text = self.value - elif (self.content_type == MixedContainer.TypeInteger or - self.content_type == MixedContainer.TypeBoolean): - text = '%d' % self.value - elif (self.content_type == MixedContainer.TypeFloat or - self.content_type == MixedContainer.TypeDecimal): - text = '%f' % self.value - elif self.content_type == MixedContainer.TypeDouble: - text = '%g' % self.value - elif self.content_type == MixedContainer.TypeBase64: - text = '%s' % base64.b64encode(self.value) - return text - def exportLiteral(self, outfile, level, name): - if self.category == MixedContainer.CategoryText: - showIndent(outfile, level) - outfile.write( - 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( - self.category, self.content_type, self.name, self.value)) - elif self.category == MixedContainer.CategorySimple: - showIndent(outfile, level) - outfile.write( - 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( - self.category, self.content_type, self.name, self.value)) - else: # category == MixedContainer.CategoryComplex - showIndent(outfile, level) - outfile.write( - 'model_.MixedContainer(%d, %d, "%s",\n' % ( - self.category, self.content_type, self.name,)) - self.value.exportLiteral(outfile, level + 1) - showIndent(outfile, level) - outfile.write(')\n') - - -class MemberSpec_(object): - def __init__(self, name='', data_type='', container=0): - self.name = name - self.data_type = data_type - self.container = container - def set_name(self, name): self.name = name - def get_name(self): return self.name - def set_data_type(self, data_type): self.data_type = data_type - def get_data_type_chain(self): return self.data_type - def get_data_type(self): - if isinstance(self.data_type, list): - if len(self.data_type) > 0: - return self.data_type[-1] - else: - return 'xs:string' - else: - return self.data_type - def set_container(self, container): self.container = container - def get_container(self): return self.container - - -def _cast(typ, value): - if typ is None or value is None: - return value - return typ(value) - -# -# Data representation classes. -# - - -class containerType(GeneratedsSuper): - member_data_items_ = [ - MemberSpec_('item1', 'classAType', 0), - MemberSpec_('item2', 'classBType', 0), - ] - subclass = None - superclass = None - def __init__(self, item1=None, item2=None): - self.original_tagname_ = None - self.item1 = item1 - self.item2 = item2 - def factory(*args_, **kwargs_): - if CurrentSubclassModule_ is not None: - subclass = getSubclassFromModule_( - CurrentSubclassModule_, containerType) - if subclass is not None: - return subclass(*args_, **kwargs_) - if containerType.subclass: - return containerType.subclass(*args_, **kwargs_) - else: - return containerType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_item1(self): return self.item1 - def set_item1(self, item1): self.item1 = item1 - def get_item2(self): return self.item2 - def set_item2(self, item2): self.item2 = item2 - def hasContent_(self): - if ( - self.item1 is not None or - self.item2 is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='containerType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='containerType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='containerType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('</%s%s>%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='containerType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='containerType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.item1 is not None: - self.item1.export(outfile, level, namespace_, name_='item1', pretty_print=pretty_print) - if self.item2 is not None: - self.item2.export(outfile, level, namespace_, name_='item2', pretty_print=pretty_print) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'item1': - obj_ = classAType.factory() - obj_.build(child_) - self.item1 = obj_ - obj_.original_tagname_ = 'item1' - elif nodeName_ == 'item2': - obj_ = classBType.factory() - obj_.build(child_) - self.item2 = obj_ - obj_.original_tagname_ = 'item2' -# end class containerType - - -class classAType(GeneratedsSuper): - member_data_items_ = [ - MemberSpec_('inner', 'innerType', 0), - ] - subclass = None - superclass = None - def __init__(self, inner=None): - self.original_tagname_ = None - self.inner = inner - def factory(*args_, **kwargs_): - if CurrentSubclassModule_ is not None: - subclass = getSubclassFromModule_( - CurrentSubclassModule_, classAType) - if subclass is not None: - return subclass(*args_, **kwargs_) - if classAType.subclass: - return classAType.subclass(*args_, **kwargs_) - else: - return classAType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_inner(self): return self.inner - def set_inner(self, inner): self.inner = inner - def hasContent_(self): - if ( - self.inner is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='classAType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='classAType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='classAType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('</%s%s>%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='classAType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='classAType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.inner is not None: - self.inner.export(outfile, level, namespace_, name_='inner', pretty_print=pretty_print) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'inner': - obj_ = innerType.factory() - obj_.build(child_) - self.inner = obj_ - obj_.original_tagname_ = 'inner' -# end class classAType - - -class classBType(GeneratedsSuper): - member_data_items_ = [ - MemberSpec_('inner', 'innerType1', 0), - ] - subclass = None - superclass = None - def __init__(self, inner=None): - self.original_tagname_ = None - self.inner = inner - def factory(*args_, **kwargs_): - if CurrentSubclassModule_ is not None: - subclass = getSubclassFromModule_( - CurrentSubclassModule_, classBType) - if subclass is not None: - return subclass(*args_, **kwargs_) - if classBType.subclass: - return classBType.subclass(*args_, **kwargs_) - else: - return classBType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_inner(self): return self.inner - def set_inner(self, inner): self.inner = inner - def hasContent_(self): - if ( - self.inner is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='classBType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='classBType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='classBType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('</%s%s>%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='classBType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='classBType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.inner is not None: - self.inner.export(outfile, level, namespace_, name_='inner', pretty_print=pretty_print) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'inner': - obj_ = innerType1.factory() - obj_.build(child_) - self.inner = obj_ - obj_.original_tagname_ = 'inner' -# end class classBType - - -class innerType(GeneratedsSuper): - member_data_items_ = [ - MemberSpec_('attrA1', 'xs:string', 0), - MemberSpec_('attrA2', 'xs:string', 0), - ] - subclass = None - superclass = None - def __init__(self, attrA1=None, attrA2=None): - self.original_tagname_ = None - self.attrA1 = _cast(None, attrA1) - self.attrA2 = _cast(None, attrA2) - def factory(*args_, **kwargs_): - if CurrentSubclassModule_ is not None: - subclass = getSubclassFromModule_( - CurrentSubclassModule_, innerType) - if subclass is not None: - return subclass(*args_, **kwargs_) - if innerType.subclass: - return innerType.subclass(*args_, **kwargs_) - else: - return innerType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_attrA1(self): return self.attrA1 - def set_attrA1(self, attrA1): self.attrA1 = attrA1 - def get_attrA2(self): return self.attrA2 - def set_attrA2(self, attrA2): self.attrA2 = attrA2 - def hasContent_(self): - if ( - - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='innerType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='innerType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='innerType', pretty_print=pretty_print) - outfile.write('</%s%s>%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='innerType'): - if self.attrA1 is not None and 'attrA1' not in already_processed: - already_processed.add('attrA1') - outfile.write(' attrA1=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.attrA1), input_name='attrA1')), )) - if self.attrA2 is not None and 'attrA2' not in already_processed: - already_processed.add('attrA2') - outfile.write(' attrA2=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.attrA2), input_name='attrA2')), )) - def exportChildren(self, outfile, level, namespace_='', name_='innerType', fromsubclass_=False, pretty_print=True): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('attrA1', node) - if value is not None and 'attrA1' not in already_processed: - already_processed.add('attrA1') - self.attrA1 = value - value = find_attr_value_('attrA2', node) - if value is not None and 'attrA2' not in already_processed: - already_processed.add('attrA2') - self.attrA2 = value - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class innerType - - -class innerType1(GeneratedsSuper): - member_data_items_ = [ - MemberSpec_('attrB1', 'xs:string', 0), - MemberSpec_('attrB2', 'xs:string', 0), - ] - subclass = None - superclass = None - def __init__(self, attrB1=None, attrB2=None): - self.original_tagname_ = None - self.attrB1 = _cast(None, attrB1) - self.attrB2 = _cast(None, attrB2) - def factory(*args_, **kwargs_): - if CurrentSubclassModule_ is not None: - subclass = getSubclassFromModule_( - CurrentSubclassModule_, innerType1) - if subclass is not None: - return subclass(*args_, **kwargs_) - if innerType1.subclass: - return innerType1.subclass(*args_, **kwargs_) - else: - return innerType1(*args_, **kwargs_) - factory = staticmethod(factory) - def get_attrB1(self): return self.attrB1 - def set_attrB1(self, attrB1): self.attrB1 = attrB1 - def get_attrB2(self): return self.attrB2 - def set_attrB2(self, attrB2): self.attrB2 = attrB2 - def hasContent_(self): - if ( - - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='innerType1', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='innerType1') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='innerType1', pretty_print=pretty_print) - outfile.write('</%s%s>%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='innerType1'): - if self.attrB1 is not None and 'attrB1' not in already_processed: - already_processed.add('attrB1') - outfile.write(' attrB1=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.attrB1), input_name='attrB1')), )) - if self.attrB2 is not None and 'attrB2' not in already_processed: - already_processed.add('attrB2') - outfile.write(' attrB2=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.attrB2), input_name='attrB2')), )) - def exportChildren(self, outfile, level, namespace_='', name_='innerType1', fromsubclass_=False, pretty_print=True): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('attrB1', node) - if value is not None and 'attrB1' not in already_processed: - already_processed.add('attrB1') - self.attrB1 = value - value = find_attr_value_('attrB2', node) - if value is not None and 'attrB2' not in already_processed: - already_processed.add('attrB2') - self.attrB2 = value - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class innerType1 - - -GDSClassesMapping = { - 'classA': classAType, - 'classB': classBType, - 'container': containerType, - 'inner': innerType1, - 'item1': classAType, - 'item2': classBType, -} - - -USAGE_TEXT = """ -Usage: python <Parser>.py [ -s ] <in_xml_file> -""" - - -def usage(): - print(USAGE_TEXT) - sys.exit(1) - - -def get_root_tag(node): - tag = Tag_pattern_.match(node.tag).groups()[-1] - rootClass = GDSClassesMapping.get(tag) - if rootClass is None: - rootClass = globals().get(tag) - return tag, rootClass - - -def parse(inFileName, silence=False): - parser = None - doc = parsexml_(inFileName, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'containerType' - rootClass = containerType - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - if not silence: - sys.stdout.write('<?xml version="1.0" ?>\n') - rootObj.export( - sys.stdout, 0, name_=rootTag, - namespacedef_='', - pretty_print=True) - return rootObj - - -def parseEtree(inFileName, silence=False): - parser = None - doc = parsexml_(inFileName, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'containerType' - rootClass = containerType - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - mapping = {} - rootElement = rootObj.to_etree(None, name_=rootTag, mapping_=mapping) - reverse_mapping = rootObj.gds_reverse_node_mapping(mapping) - if not silence: - content = etree_.tostring( - rootElement, pretty_print=True, - xml_declaration=True, encoding="utf-8") - sys.stdout.write(content) - sys.stdout.write('\n') - return rootObj, rootElement, mapping, reverse_mapping - - -def parseString(inString, silence=False): - from StringIO import StringIO - parser = None - doc = parsexml_(StringIO(inString), parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'containerType' - rootClass = containerType - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - if not silence: - sys.stdout.write('<?xml version="1.0" ?>\n') - rootObj.export( - sys.stdout, 0, name_=rootTag, - namespacedef_='') - return rootObj - - -def parseLiteral(inFileName, silence=False): - parser = None - doc = parsexml_(inFileName, parser) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'containerType' - rootClass = containerType - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - if not silence: - sys.stdout.write('#from nested_def2_sup import *\n\n') - sys.stdout.write('import nested_def2_sup as model_\n\n') - sys.stdout.write('rootObj = model_.rootClass(\n') - rootObj.exportLiteral(sys.stdout, 0, name_=rootTag) - sys.stdout.write(')\n') - return rootObj - - -def main(): - args = sys.argv[1:] - if len(args) == 1: - parse(args[0]) - else: - usage() - - -if __name__ == '__main__': - #import pdb; pdb.set_trace() - main() - - -__all__ = [ - "classAType", - "classBType", - "containerType", - "innerType", - "innerType1" -] diff --git a/tutorial/generateds_tutorial.html b/tutorial/generateds_tutorial.html index f0388da..95260f7 100644 --- a/tutorial/generateds_tutorial.html +++ b/tutorial/generateds_tutorial.html @@ -219,7 +219,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.22b</td> +<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.23a</td> </tr> </tbody> </table> @@ -228,7 +228,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">date:</th><td class="field-body">April 20, 2016</td> +<tr class="field"><th class="field-name">date:</th><td class="field-body">September 14, 2016</td> </tr> </tbody> </table> @@ -1210,7 +1210,7 @@ named <tt class="docutils literal">garden_api.py</tt>, you can create an instanc <div class="footer"> <hr class="footer" /> <a class="reference external" href="generateds_tutorial.txt">View document source</a>. -Generated on: 2016-04-21 00:07 UTC. +Generated on: 2016-09-14 18:26 UTC. Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. </div> diff --git a/tutorial/generateds_tutorial.txt b/tutorial/generateds_tutorial.txt index 284cd93..b8c51a1 100644 --- a/tutorial/generateds_tutorial.txt +++ b/tutorial/generateds_tutorial.txt @@ -11,7 +11,7 @@ generateDS -- Introduction and Tutorial .. version -:revision: 2.22b +:revision: 2.23a .. version diff --git a/tutorial/generateds_tutorial.zip b/tutorial/generateds_tutorial.zip index c4d2106650554582769f23f527c2ac60244d8ce8..f04f23a34a619a12fb46d87854fc0a8f89142bff 100644 GIT binary patch delta 13656 zcmZX5Wl$a4*6jv1?(Xiead&rj*WfN85D0AC-7UDgySuwf@ZjzVkax~K@7;U9?{!u8 zk1^JqbFA5`s;k!O@%9G!=M54=RRIc!1polx08P5gasm%r{s|a#u%8pwb-pL8Cx{V& z(V*Cf+cJO_w%tG_f5_=MWiF*0Pyv<-SvfD{-GPsc-s{{PxuGQSHOWr5PgnQ*R7ETv z>sfSXZk_R<(OANTX+t4^U)PI>U8>agk^W(`qT(^$Ad>6i0dwFv|M5EtQ8Tx>Jl9&U z1{|}8alld0sy}tCs-SjX<#c;3Pu3#%wCD#lJzq_7AhB2;60zQDbi6@uXjf?xqKwx- zdJ(CFQ5ZQbwSOE_Y#!x6{M>+9aDFRjkWc5akfH4ud_}pRl;ntP(EMJ2TdHm_81>C~ zV!kN^qjqnf(Qu8i?ZwEoCf_gmYV9XM&$K}sC*zv2$<DVqIX0!VzC`@s_SAYX7MBI* zf<*yMZV_Tyzd8FnF)KtGp1G68r!9KHEun#K4m^w%1-|lQR^<7-vi4gI{f*DewX-7f zKfPr6>;{WOToNa}be(Lozj32jFevK%bYtVH+v&}S4f%1sx5U3VK%{i@$zm3Wt^&0) zQ3urt%}f{x4b1ge_345<@GxfvueI$So;3y1sMALK32jNRGky7$Qpxa11XC|i=Hiu- z7~beXw`(9~+LU8L(-)_c4g~GIO5Zk_=Ud>3{K!x9gkXJE{v)YH!4zF>s32J3OZ2#4 z6_b*&5{`c`(&Wt?Z=9ejH{4`jsLEhI9A#p$AdxP14#uN;RX3@^yW&g*cpoiC1z0%A zG)LZ8XPdJvAeb6dFl>wTZA*szEmk3ul`iu(8n;?0jy`|f?Br}buz6Uxm1|3LSzlW& zgY6^jAn-OQ#rknW;uptnrOLPL$}`gcEIDNZW;s}$pE6P`06@wJ0DuP|0$5u*S-P2h zwzP0J`Rwu8Iq9_>5eyH2(nwv`$^C0pdUzoMAb=-O0KmT<OM>t2o6=u;4{F!gyQ4l! z#1~iyw1DOhHf#&Zle`GpJu{R?8>vz$7ywbG5Ne7(e|&aEnd<;zkrvq*Io4DOLsy%v z*T18ByzkR#_QkMiR@NU)+4%|KQl>qytUXtQDhz{JV8Q#-oNd2KpGCSm-;WMj&GiOC z<8nWa2B!ts;6@L6jk^frc6NGj!M{JA!cZZ}!Z*dOXqX`i6h{u6!9?Nx4WRqUTd!vQ z7;RiiqpcX{KfZ6_bu?}3JxB`9$8-#Z5ZQ{bkf|B%R}dUuAJ4F_Np=e+B`Nk92*ZD2 z52&&Sih#=*ibe7Ae>F#v*1%qW)~={Ra$apG2<PkVBuPH2C!(BMHSb9dQ9Ej;9$ph0 zx2ULr^<>Zp0eS2>`qdt5;nPZI$I#%W4HOWqtH?;}3>z{5Jh>(``K;0{4QcG``pch1 zqFAwb^z=^3GAa3jrzl(v`sL~sYeu@dLL#dsEWw1RuX#hgT9Z^M_@w3&9tD!{p3OSh zgiuTHBVhC!`8P`<AO~^v@E@Q!2ryOb<?%#&`xs_NBBTBdwku+3RpOSkBHV%|Y+pe1 z8RFwEFyAX`40-sO;j5~pV3-P09S3JcIBqS(PsN$*YXl?9`QjHlu|GEl?aH5B>8;=e zN5IeJpsW20_3TQlouBODwoTW6NPu@DX(9S=xcRovevcRX!<Ej)O{nmf5*QVRIHK4; zL>L|ghdcnGd1Pz@veR5>q~X5w?BD72JG0^bv@szP3gX<aA6__^2qLlac2=Ge*Jyrg z1vbon#+Xm!Jt~c*Lej%cU^qbrjc+1K&w{lWW`=;^gMF$Q&9){N+7~R(Bk`vl*f}le ztNKc2Qu8?(?AM{0N(z-FV^2vq3?LrWJd|pgP3`ubTX{d{rIi{pQG#Gc6P>gJQRETd zn_=H9$IDj~5f*)n&tJZfn@m0RO`gKsyecrrL=9{I98^C}EmbD4*JHbNMu_)veFB$S zdGan=mM?lo70SK8Qh~9gX<e6O&vt^2USXE3N5xarF~*{h<8eF1u2P4N8j-y)Lsu(# zCXWdxXTLCk=Z!wxM$hu(fi5bvKBuZ^DVvXkIgSBpgn8jwwJI?@;e7SxiF7VhUCvSC z)sA+Q2D=FhHPr!eL3H?!LU*QZpTOJlJ_lMvDU%9juRXF&z$MIPx>h-XF88M>@Twbm z(hCX>u9t61l%8=)PVTRPj<rYGEF80DU}bn*pD=mw&|dn8S~BbTp@TM3NOn++NvQ;z zdfZovgQ-@20p%0#D3h={{n=}9_2-BcEa5;_C1fe%GU)*v_LwBDynGJiPVn)WhYYIp zN~Lr?gu_Z2Qq%No<J<f*M~-)ImlxmHuk&#?I`Ykid-%V_ns)o%mW%!2q*}dH3~P#M z{qV-&Zc1*P=}vqj@)h5|prD=c^sNhM-Pmhkb>LxyTV|)cnPva%pey#tf>?ji!asg9 zr;Y;6Y>?oLQNB%<GDKEto`5TY=~O=-89R_MyIm{Ex)P9vhCd1+>9;v;$DTNEqwt)4 zU2*mtI<KkXY%nnyo%dzrPsKK1Grw}!Rz}+FSiiNLOv$7xXrCnK0Zk@EjR<fz;2ed2 z=-G>i_e1Llwx+K6vzt*7n^R4f5cC_zoN9zOj&g7JnG$^Tr3?usz<}>?1$m$sP$Y?# z*MlMz@qFt2;C?cK9II5;Cx<R+DUhCKF;g+8m=2NXR!z~Y5rxpA0vAGIiDjVFG$R7T zys!n)#^&@$%@h0eBxfbE+}AWi-NIoT!u;!J(9QJ}YbPvO=1vVJ44KI*_4X%h&a9bl zY&k<rhBZVB%2Y?ZRKYcKtQ*aVxsWvTLW9_}4T9L{*_vQ9+ZW(n!>)XX?@cFA%z%z{ z(4D#uw;WP^F`zFwFD2GHo|T1Iu~np#KmiLw6!j11Dq)(o>Btb9Vn;ydHJ7X|Jd98z zuDu#FcK8>_CoJrtpO<;)^zteA(5(v1IJ=yZmZCyd_G(AyaNtNI-icMpcs#`Q%M#QM z@qx4Ya4n1wx;r04B<E9XT)*J7EqeOuBdFXXk_+2>R;~cu2woJVYd%YFVgBBD$pcf` zgg^Ci0YpFKLUXl@D?Y=(e1#mJeO*5s#^ihrqwF_4wnsqqT-f_=K&||<R5Yy7dZ3ky z(zP=>#zi_){1yyAX0ZD{ALSO3iJeBFZe={gVF?7~ehMC(fZ3q+Yiq|Q-EW_W?sx!= z8%s+b*TtMkXl}~mMdO#c;&1RU4K|E=b8;8rv_4apXXA&99e2`iP~fRUA=z#{%FLui zsAJOib3=QR*G#xc3}L`kB0hM>L_rlo<0WfEw;wC)k$~}TU6K7Lp$LuTA<6~<u<^dS zLdwbJkyvJaY7&D54C1hjqW{E_)F}-=-tl`OoBCF+uD4@K6(8nrjBAtMXGqvZX)H<| zdBJ434B>_bNlQqD*4D;nMdd`crx5+bobc&uJ!_qMD#W3z8ZKEP=6FfWnKAZm|0`OI zx+YN{B{X;!0J34IVDYjX<C#-Sx04PQy-RP%guwRK;XjtQZ$LRywU87?B7&q(01}Iv z@(QuX`jCLyghR$51Sb%MU~v@`90UQhppI31A+xWkQaUti{9a<3$ixnkg2$>8zM<Td zwT0B*oS;Uf4E@(LHv(%Ro)H-<H}ICpb0XB7(7=iqD!-R-*XGrCYQMQ!TkPAgrz?MC zPb+?G{JDg+D@)VKtA{1B_$uj<UyQ)^+x_@^Q01oJb*FdGk$h1sZwvd?kiP7R1DTHO zg2F8WRcm~I-{cLO(!iH&LK)nk(_tFF+-QmFP(|5-B6N!e5~OxU85zT&6Rh&ol5iGm zO<gdAV%v&VdVvX?PJGbb@D)e5+n5NUVy+{_9}ZDW9D)?<Dt>&3IiMIO95PGLT&!ri zjq%twIcOMG1OKcEim=uD{)bl@<FcMd8Z~GBeJ_Kc<gX|_!P#auZd`G=d72!}$*62k zgm`IxiHTA&{DA?ShZW<63tlUsASntcYXH+>g<o~C7b_2r$n#<KLSV`G>YrZXbZs`e zn#h`2kWfNtU^NfWmJeQ0o39oQ`tsjdS3z|9{k{z~sgscC6E2Q3<Fy+_lElA-_F+C& z2>Zb(St}E=gU~9~#`L5AfT4dU%$6PjF1#~hQog~vphug8mexAxlt+kQTtKQZ=>jZs z)b{c_IC?DZ3Yh38yGjXNuM^xYasJ}3#N}uD(R+&7e2q7v`Z*vRW(-$!Ihg^Kw)r7} z4l+&^myjR_GuBu418H*@$cTsnIi4Hj5`82UJR`wM_r5aZX_<s5T_uAHSMM%~G?-{y z=~fg+31k`2g4naBlYpC=U}Z3ey8sUsgV;gDybn2S-a;LsCq`u6KpEKpmk}fxUEWcO zXAr0&npbY@Q8#|veWYquhumrwjRPP)B}ryb6;j(IL(kfwSM`OP6YBcLEef_c#6<Mx z@g#4=uAXeZux_1}A@iW7@Y!n@1Ja8cbf6&snp`qtDLp{LYrPce8pLbX4~7TQ0=86u z%DOIiE!O64K#kwGM<*OpWJ9hkCHeabL(MWwzg#U<2LdUg+@o(2hVq*i5RtANeqv^# z!BUb5025c1MWT)whZ<!>SlPu?xf$#7dbkT<jxfSLoxuOh!Jss%8w3m;K$bIB79o*Z zsB;wwib!DjU>$vjm0Ft;0W$}OP~c5C83jmM_HvHUiCEqw!7;pguRe`nXQo?U69w7z zy*@;SA=jze!8!m_RicswVs*Pqj+r?cnrf5ivqZN+bUo9UyJV6rj7D2f2?$2pOnWR; zDa`AnZbYEfcy9>u19gyAB1;7@X;|{yhnz2iJGp$bkF>#*{1{CGe8?V^VjC2E@rG*z zou0;@&X(0k2Xk?N|4dc($9w$w#;&iW2~B+v(dHsAHcRIk5az0pSq)vM0PGWA(j7An zMBrQ0`sxz%3I5Je&AG#Os&`Oc?tA9_nm|-&@t392PJ6v*v|?A-QUeQ}N<(RCvMQIM zb-{89R%sz30zI1?@J8P|O3{+B2ie}4Xn(#383Pph)NVR^{LQ4OSS!-!I^7F80(cMs z^e9e@qy{Gf3KKy@PJvn-cwW|lo&dUAs&ES-I~P`OB<ZNmD{IopvQ%sCYo{7278P}T z3$N3P@e+d5U~8YmXhvwO>7IFw+Xk<*nx)|@)lV`$s}{l_a8X|!Vjj$8pbR1zM_Oy` zJ{3g%c{zd`+mio61~j3(I9FYuV#BokO+-k0V#y@uZwuwy=zKfRntKLvz96_3)e3Zy zhb_?q^}yTwePc!zWFnFD`5(o8bpwE83Uv-lf0CA#AX6ekyHWFA;@pE6W!>a2=SWZ# zmVB0@+o(js;8Z6aRr^MTdLO2UIyj&Y*-gL>J4s<|$Zu`$BYOj-+M|~3bszP}EZ$+e zOy1Wwe5qge$BX&M+U*DTWc|(47})WBlT;tbAQ@C=8&vI&X^oZgx3{*B>5bwG_#Qm4 zN3~tF{;p~xG_tNWB0&dUWO{L>J7SZlUwUU2y$;L(815O*ODKH>{f&!M%aX(4tulN^ z91AE=5`0zHVm2CY)kesX%RIQP+MnsIkXyt%mdHS`yX&Cr2L$`lI~;~i<5FD&1S8f% zVxCbU?4{y868>7G!RwnoL2EFmtCJe=mrEadR>?*o{PQI|xP7=#V<+}%i>s2%dLOgu z;~~QyYz^ODX{iL4B}Ay|f<(^#S&Rt!+oaPW4l?c7Z`kZw8OF2C7YFB0D+94*6U`y1 zY64;u;|@&hE-a>D{p+F48N!xXGBZZAAB2f05XJys_}CTV=oIHY6me$L!y%F}Jq`zz z&=V-OZPwCD-9Bi%>J{9VG9=bMN|nx7k+N!ZaK`TqTo*irN|`bazlVXoeqg>o5){U> z+hBxKhpb5AK-kILBSqfhiH|q;VMU#RvZH~%r41nFJkR_M%M^0=*Wxt3MeSN%!XM-D z!yo$Em2nb#u%lbwwpRMw#n66qZxTNYF8F701*;;gyG836MY)YgQ(=Gk0>lw0m#AFC z0<X;*W~@-CW5+MB%qUb@<?#Tj3cSShRE_vUcBQPD^EEF`;VV&$k=E_>Hovtitqnqb zZsSbM$O9q`TMfgMI+O7=Ew!k1>Yb(Z<u>H!k<MXoUAh<HI&Op$+?VXvRX5D7a&6W2 zxtMCyYgm(&YUp6gIyscg7W6^MBkU9BfORJ5r~&(zRK5aQ)*CXe`K%cFtDp}HO>6bY zvMK8DQbwphAblbnv+&<%9iqbBuLKUn4$$c4BSZ|$Y{${aXQpLsK}nNtd<cD479EEe z2(t1iqTcypK3>U)t=0%3#skW2`V7~$%u+Mu5&rWejD?Vfb9PI~ug2IGeMOb1;3uly zSkYbd0&*=X7uX5&#q}zwm31P)Sq`z80>Pn#X;Gu!0HVO8`&LqC<#9B%fIPWrzDGzv z^cp%6)M_=S;dSHGr(b<-r~sKa|D6~TrNjD^D?<15L;Y6WsFBE-Y<6R!M|eWoRV69< z5SRmfy;lLw5&f4v&Cd2NSt>a;a6ICtco<a9r+6mlg)N?lLGmX3H)b~oc?CVw*A7*o zo&_6iG|=*VG)I=+?zi~BbtwTbs9yXIPk>JPL;l;O)iWYof=qBsbBSISEhaZX@Qw#m zVQ!?z9#SU`2eNQyc{rrpesacU7QP?8B`=<yIiDS9o#BRq-=1qfwy!1xJoQRGwia9> zc|hA<gcP8uXlViZk;3R$NQNr0%5E*?(JpU_g_>0tFMfv#r~XZJeIkIUPV`6D*PwZj z5zVqtItw|{(7LfQ&j$c|SD*L=IR)C&vG*NlcBbg0JX4w@EL~{02ous*X3?+V4#s*) zXz}&$LomLaGQ`grnA?a3zvYZ)p2nWyb9#_nN4>-{m<e7;_^s?B(fcc|mlHnp>*_U` zfm9n}ci*giuvoptVfz9*x9znDdeEs%$9lOX;zxmkIJ5R3-5e$9r)t`P*r%F;b>h9u z>iShhkHhp426FZO8CF&dVex7NloorwFywb_J|)462a@+(C9f4Q-jn#-x!blZMRWHL zxByZLbnObKD$g-8wxx!C2yWor9kQ=w5VHRcjJ>mDZrudgL=q9PnL0E+Wdf2E?3YhS z6Ub%TnPJdpNg4(L=UAmlz+3lR^?;udZivMlI9tNrD(3=W2K-KLz4$0;A=$&<ZKvYk zChC?xt?8%Xd7s^ZbI($cjmS?#FY_1T7#*Lnnu3%gTC~PLEI?;I$?`<=izUC5EOrFb z`N>U-AVEI4H&+@p^ShxP-1V;1hzw<7%TgGQ_A_zrDQSldYQH5F52Otbcq6Xaja0Q# zdS+yIa0Q7Qf;li45a`5qu`Eh5ZzS3A$?!X)>L1tbR^e{JjV)Rsoi71=<aHwyF(V8x z-WZNPBQ_!r1wL#ny&eH2O5FDBS4<@_yRTz&&$qj#WA=eGwPt%{7OH<*X7Jb$Qc^<m zm@H_wyfz&)+XH8eBYt0Jc5br_{wW-BbEMyu0hy3}=Uw}{2GEsBOePnP&%apnzXw4a zA~UIo!!!?raj{w$W}ENp9`)D}y{m^X10_blfh#+|4BR$7a$}%Ot`7EFs~ZSRXppT1 z2(7)bf)ujjTLu|5Uo-@27u{mRVBZC@4~h;Z-vrZSA7NqhBn~%}`V2F~uK1hkHAA6I zN^BVIs}^%g=<u>#n)4#cGf$e%7@s9KCW}*LFzT_v=uP7<!A~TD4n4Uee&c$dD~o&A z*oa%nLh|rIP3>_SU!b3ii>m9^6Gif0c_Qnf?A8ZX+KLQ=jF5da7Iy<Jdwx|$bP3G_ zUIot@!2JvZta5+YeV4`_#P~51trUM|K6$yFMur+wf14$6{>GZ|wZJ00EuUJ0-EF1$ zV`A<PIBY(L?o=I)nw_DPfU0{aZT>+3Ote<H>P{V2(4XFeAroWpD?Z3yJE@cTlmk^v zu`9#>ic?y&*e90OZWOTbZFWB-Wy(=?p2b~#vqEHr$x0`@fWwzm+f(S~qR%7C`kdyj z>4}sMlPzINn_`-u>Q}M0ti$#qA_&3)L7Yh)jH~;p5o${RYhnPSZ;_S(WujSK`8h8Q z+9xC8Ej6+7-o~oD)So0ahTLZG#SOe2i|;f6h+d-X?~IK{o~tw~o6+A5=B98J>A5@g zmHBNH;fWrvV!v!ONo4H@5zpER#3s@7<sD{b5bKxZayLmawjqi*Jy-@rlguUX42<@a zfZG{oGE_e~VG<I3ZYs|E*le|%M0P^=JrFp_Uc#!B)jipz`)OMco6eRN5wpfu>_O%@ zW^!$R7@eszQ=T-feoRt`SgpYGY+p*Vg~f_7i>%BmwuYDb)+AT2KJVr4%-YUjgTDuJ z4(W_D$&hQWt;;xAN*SqLd#Rn3xgXSr4F0mtw9BrEUP5pei`izIUIv?zy>ejUx+2dU zG{WGO>i=Gl^|Nz4SRd4<u(1VSJDO0ChR14eh`99Ks?%pBoV??avSPzbRjzuL-*3p1 zOPN`!qB}`4l60#JBnIjBOT4(P(hzk`2Bz`>+gB}_5v^~n=WBaS09L`^o9Qr<J6Lap zV|i_If%>uKY((KZnI8I~uK&gN_L1w{Kh9XQlhQv8A$NJ41hdwu9KQ4n`lW?2ONP#z zC1o8uJf>auyW)*a5RbaV_qg(ywuq4!#y!gyFM1y@<Nfe}?QsEMViN}u%^7ETRP>?9 zxQiSGAZ*l=(+21aM<{^uT=(K+V8Carbh~PwoEswV>D#~?B<=3Z8<kZsl4*KEQ{%p0 zJX;=AM9K%<u9N+h#~tK$jjL78DFt{&2fNj~F9?H&&S_0Uw_Z3?P@L&nAvyG@8}OXg zw<VYuM!3zOQN~^rEx=*Lp9})-L&d9!_ooGxPw!DB5#O%x>65||omGe>qrp55pt<nY z_Z?b-uYUGdsIhwA^{9zOb2|PkLK--iz|Yvp87vR#*DS-AvaeI4X!)xs7`Ri2mgZ?; zv+`nU<3UuA&<+LcTI}eqi26qgaQ~4|{FUri7#-JH>gwh5@Fm(yB@ANL{-)cA?>kc? zC81UXodHCO%M^jk_+t6a%1`isG5!zqowMeMt!n$_M%5@o2`?$B0={6kXBQI!oId%- zoPnc?E}mV<%LjCiErQGhiRN{jP->YYgFmZ3nuS|kiC(XN>o^p+0qDHqlMmOr3bZ(- z#w!YolHv4}$C;NBb=A-PJG+ehsqV<ZJ|!mi8?>VGX`Kj_4hg^0Pfx+8-%m$teINrS zBv<g*tlZJRN459jAC=eu%K{GLIQr3<2X{vk^4={@JET=nbwL|j`y{iWBf&!+6J9iA zy~AwUJP|WfQR_ztL;@`w$AOrotgO&RH@q=36SwqHux;E8U#9Ab89#UqRRTN}WLeRo zjM%P$D<;URwpNo0%LHJhdi^gthoLk(TSQsd%4mMTBkfHPqpL(Dj))t5b=^zMD4za6 zqU~nCdn(!rFy=cMqMELpxGHwd5K4FL5lNtZiK37A+C@;ZJ&N#5%%~z*G{BguqdiN& z^0%kKz?B}7DCPK77J4uNbR@gP{$ex|*%er}9(=Gk5>m2JPYnL$2dLivNZt;73d=PB z2*A8J<F+kLptxt0qt`Sh=QR{97zPNN7gyMy$C@B;j*#LYF({Z49?_u?{I=0_{#2We zTE<?Zo)x)fs01NtTB`-T(r^&tit9_q;!wd_PqS~@2IW~CuD@sBlK+UxBX>#~C(;zK zn{!z;NjevyqXaj!40IY+V}ETfV}Q%-<IU_As>ahg4Q{0@rNOv%*6$?u^ryO**NxyN zX+_?0AZ2GuB=8?NE3Ito@i!g${I!lW_)NxEBfqHn!EBuPO#KV2b0bz{7K0;5;V4c} zV=}8FcM;kF%5Mx>;Ql(SSB576oYEOe8dv6uOfMdy)CaEHDkX>Y>#BkE?!r~`?)eE| zdo1L1+O3kpGr=!J-n{-E`HZr21YN;17dO}<Pc_gJ8%`uEm9OAiX>^EfOuT6U2N5uf z_O3<Lwumn%E-F4O3G4lopBA|uHu=~H#$+5YJ3oZ)8q*n11dlF^y>;rBp5RW6JrzNm z@7=rSNrFd0I9*Yq<Wg&2XHPH;_4Qk7l6!U)aEe{`QMSm0#^yWnZ|J-Lq5?^m2uP}q zaNJGo8KDFDN=w~`XVj6H3MkG#h3M)Hq<$I?1I|PU&8GcO@BOTwfiPcp;i9P_a{AUh z`9~JH87meYlYWVFd3ycv{_f@<c)qV&&l{~ofd}s3UNK1ewYsi$bwDpKn@XvueLK%$ zN|~H16yT4zy)@fd13@>cl$|huGes+HA+GE!x?B}@qN^@Ibof&g4LIP5f<uFFDtFL$ z08l5(DMy^a3EU!!hWTqVtTRr)v+{FzSfbex6ie=jR@Fh_kFEPsh@LDC7sh_&E>MK5 z=^U88SQWCvgrdwNAKlQYXrRTtf!|Rgi-#0lddL!snRBgL+DaLete0%k@MSDw{R@q4 z@A~5KIU((OWGVA56?T%bo%Q6pxJ7~(Ws#zI1_-Z0x9I7yXSZ~2d@YsN%hOW^#yV|C z?5mf}TdW{KY|>vFKOrJS4~+5zhOiIW7(U=r%$?$=^%ly_{9X2*8*;1m4a6D_b*Ce} z(uql-MU%yfrd5L*N@&}cQib97?M!^CJS>%Izg3ILR85_4suSz!!K*)S$a+4v6`f(2 zO4wMKqq|cuWQ&NSYxN4l=JoQb%D3Qn*Ki0tr&s8jQ+C))2McceK)A!{L*M_rH)aBc zhEc;HZR5q~wJ~x>-T$nX>2gJ1``Oes63nuE&U|{E&Z=#!%AoZcOV0%vY=V1N2|Wsn zw&H;y>V;ya?>lv2DHW8XK>#q1Z*p6s)q*bi5H#rL_TS+EBGySK6l~eT_$9X6l{`-y z+ESR2?jZajx(eLivuo_&Py^K!LurG{f5MJ$`9WzJj8#}cXQZe{z0{wmotqnij^$ND z_h!i8T&i-t=fxw28+ed>tZy512U%1HY!ZgLcVJTKpZ%yAMEP64fXBGJ$eLE~5FEO8 zRS+{Q-)vl|J|nk7f$~mwiop*OcVsYb%TfgRh8bhj+iSu4_E)C0#ZVS&LK|T4!h-Ou zgb(T)k01Vxrwmt9g`_!;rTYOwWR>*Fp$0#7_-DKFq3R|Y^Zr&@4*Ieg1z3(BO3j8w zxiV7G6<`Po9Wbt$drcexZcRAmkXv);kKKBr!>Fk5L;Y67MHQqAGW@kRSL`K8?j2rC zyLVr55Si`PPo~?_a0{=|geAcSj;4wW4UB{NWz&s&No0(yF8w(ehrv=C+_CVb-H8g2 zFfYYh7}JYBq^m;`ZB+6#a3|c|(bjLURzD;hAk8-$`N``;O)wHsNTQg!vBWD>EOq$A z$LWXecVEeqhx*oFsGTMCw7KtP4G%Im)zu=oJdC@Y%<?O>hAQ62h&sURGM>7X`TDa* zI@}=qy=90&6a}KRf_#@8jrVd%gW~1#K|6CuQ6hc?TzlHsf~ars1#>k|QZ%(#M2JBB zuUR22MyuvL?NN~BFQH|tBv^G&?p`%Y+nIF=Ddh<4kf90^x3G$np}YC&AA4JLQ*qYz zRz7Y_^WOk&U=wTwR!^`Kr#NP>!<39V?iy&RO}O44q7)`q502^Am$)@*-g)it$icGh z)`w|N_eo*;Qy7a9LzXe+{CyBd<_CWeG!}vk)XRc2;uo81xlID*uU&>miS444B|{<< z(ef<B!P6sAld%l3^O)(~3%}7-d2an`hg~*2K#a~lt(k<61Eb)*M&jQX=7b%e(dKk{ zj61S=Nz)+w*fTVL+sgHVYI$G`<Re4^iMJf^>kLaSJ}ISsghfOM6C9^R@p%_>f7>*2 ziu`7SMWbI4kKG%<c9sPPB28sG)-NN}D>q_V=C^NXX=I36zOEXv+it66IA6Z5TnVf` zpKi5~A^Zb;`0fkNh~O7|y?uFqU{qR)8(m!N^(~Iz|8;uvK7M|1Nju@r*F>Gnl^r#Q zoZ5I)4-Xu*1+gr<fy8-W$KO?y(9+-`$me(B4apCU<7?8HWl376OxvolURWogddc!K zr3F{HJ7e9g&|c!$7|>W&^Y|l5@osj|``DLzgR5XvEyTc<vy(rp5gUvc?8uKQB-L~( z8>1F}o}u2iVTlr~d%eOmlOW)+TEAH&#Z0R2Mj$P>xmFgjz6?XK#JXVF-|#;}_p2<$ zYVjA^8K%RE^1#hx@iL`<Y`c{e!J%t*vl?kOTmcC336CK4M_}V*Ttc(CX3???Dmua% zDZ;BF%EiH1?(O*6LxVQ;fGSLFqmmB8WGgZ|&ptcP@^D=0K~DR%ll(&0X%|C(-m?np z!GcF3J6(2WeeI81l=nMBAC2osUm6*q9Gu^t7#0l+=+3#OIQu_lX08s?cxX#sx|&yD zn&c}=faP(&SY=YhVrSAQIc~?OpP9FSToI({UejQ4%U7vyuqv9ImpvDtE!K_~u(rQ- zE6y)(bEa#V3~d`E>&^Uy9|8n?ssdj2yG$WY)y%F26$B)U=yEpGC6aP7O;dMQ5=q8Y z@M|`9BsTi29^(@R_GG>b<zi!P-eXTg%_}qOR~%b(>KA>L7pURw(eAk))l@VYt)6>w zmPTNW3I3@&3q2(c63$*VcdrwU)D<s)>q=LC@$|~Q9am?`L8hpu_d<=p_B|)<GW5QD z^!>szsA>UW^C$C(T~IH>Qw(rMlrS;5vd<vI2k}|NH%VdemF0dq(a(SNz1o?BC14tp z@mXoEt$+=;;N2#btq@Xx&-CCIK{5KeDl&Mo)JCJ6puF<R>KN8p<GQen=@A|8JA3Ga zCIIgKe#{8yzL5B2L=QdF_8rrcptq)_ag^WB67@4DKG;$D>vE*w6H_}!6PYa`kPHSc za9>tzO0LWu5G-*SOubUc{k3Udbc71VkZc~3)1PM4gh;-P-^HFsmPD|k!69@d!U=rZ z1P`U*pch2)Zq~qX7omSk<LW*5qk_x}OR&P&c8R#_Ren^yq>}er)^_mT^WIhCyS2)5 z?gzB;{EvDNyYUW{kBf5`ZcIM;qzY4S8V(CB3UQDtD<Z0R_%5`_=&PRg5QjH5b8j@x zgyCtWkP`izE(TLtCp`?LLK?0-DJ{6l^%RE@I7cnas!D8HR`bUKEtyb$#*OtPy~VPJ zCU?FNt%FR3ug`psrC(&&;vDN?vMLj4(S`c<C6WDF&<Zb2pd;$HA)>#%RQ}1}=BJAc zMo}Oewxmyt64CM35kD3oJc7A)qY+ZrVLmCJ18XpMjUPebmBmHZPZaOPfZt$^#gQOs zVcyT>YPvz_BYnR;rs&zi)0ZM-Qoh+)ElSi?Aa)Yyt;BqCG^{)%a%F+Go*Vd1FvHCx zG>zndUK@63r1QabH&?QHtdBdh>^8e+iVLH!*d)CrhC-TInsw8h(8^SGIbr-VURV@< zIoj5nrq+-*fj8B$0E@aQ0{98m;6=MJ#0=b%QLNO=eXIJzJHZlV_VRMO<Gja%BFDh| zaNe%ph)qVMdvZ13PACK-ODxJ?6pRSZ2Krxb93G$tDbS^`lzO_9-<jdXv5ZPo#-Kfr zSEb<F$FJ({lq!qBGxgF3kg*Yvs>Ib{3Zcb%GFZ+CN`^4_qO6k}J@SIjDWfhF9Y6B4 zh}@+@4m3|K$S`2dSQuuKie%#aR3{49<NK>G4}Y$v{PgFB4=!9nOV}yM{r*0)6%5z5 zgsG-8S~VyN9glCw0zy}2zEKN4*@aRF{xgvM)Fia+E`>gL2CMqS)Nys*3cq`R@TAnV zrlkU@Dd%e@N&$TY`>_Dd#oBki92Ah?oP{}J0fce)N`x=w5N?D$GyFhf7cO5l?b(wO zBX2*?QeU2^#T7nXd#vea+tWm2bg>{Bh;z<RxS8dRyG=TOmPQ-MeI&}*vxZ6x#r1&Q z8lqFQaQ9+Xg(W@Su7n-0H>ks@A3@eCT%5p4CbQe>fn`3xHR1&0H=Xp437(F0qG+S{ z^P^}cWIfeKzU1ZH@e8l-Hs0+L0riI+oz2f^ioc2vX_dV8j@{v}xeDu}6BlwImcqp< z{l2EzGT+u*Q7Tlm#FS)}kO-9$<Jxt}8m}=o9tLqu#b*$o;7bC}ET&WEElE)zK0z+! zR&Z@^a&}}JNu+?Q1;5AC7971=fAgv$A&h3ZcknQJfX$We1oj2M#HEvQHhGEtCc<uW zl5LbY86l{D&jH0<H9leFe~@JAK-$k<(b6wn)}@kc)K7&v3FXoIA<hIqd0`0?wJq@Q zlqy?G=9*=93CAa7(k4Ob?V`9vZe6b5<{4Ato(U@|t#*PNcg$83bVhK|b4EU?)#TuP z3QdqHZtyF+ASHxJmu%7%6*KsJB+BGy1jefA@_M#%VAD{k5@VOscQP1b8cN@+wVf?) zV6YB(N?Q+@3iyc;Di$Ekb>0|c?5rw9pn%|M8Z}0LwI`2qf~$rhN?pWQyAv@(2i8GI z+~Q<<m&pTvh`?)h18?~P|LEC&cuF0h`!!O>QGq+-z)H=U$vciN*5>rjdIy`K)DLwx zjxf>Zt8j&~O2vx&xBD4l@Jni}tlwYEf9*ZoEZ;hKzfEe+kD6JZ|LG5-=!kxXetCI& zb-#HZuud()1yu(}(e=uI!Rca=rw%YuO3U1OVb%jbL2T;>-UlYYv6qsl_x|{{vHeHs zQ19`F3?cj5pjeyzsl*bsP)RuujXk|qK>9Jhw$?cZ5(8t7DPf+Y>ClRU%!d1u#8pC( z&h+dD;z!si!6Xp~>&%@n_(}#zOcjs_q0i*<Rp<QND;SiiuigB|;4L$d|I@nU_7WP# z<EbzBXCwrHWD8rwXN;(AX?KUI0z5M7_yn<K>3UYICEIw>DW(spmqwf)wwqlPy#t?u zJ&G92zgwg}lwXfYLx`3ijfv)vH8i$p;B72G)lG4x5algu6f^<I{yI?Rx*sRTDCTz{ z5&9-Ba~V^BP6dcN$$OqZrc*g6a1Z{VA4XvWvx~BQc>$V-X*O~XWS_z3(#~%4CP+X5 z1`jk|#*raIZ!(ozL>F<*n|*<ys268?m*^ig^ITU8Q4t>S5n4hLWxOl2aM1dt^66D| zmmUb~hm89n*r~sJA7lSOC-?Jv8CQN8bKI<HWbaSMy}MN2zO0q7Z4SKo`Jh$ocVq7Y z?oe(#r=XWbQ)&0B2?^O9K+dK<{+?rpqc74ol?i)_Ohu?=lF>ZqToY8LmZBA3TO5!c zx2`U%|2d9HE9(BjySu;Vl7t@G&i!?a0Te@c%;V~x4zuL&c(+kcXeCNNnSju}0ljxD z=h_{<q8?Fp*F?FMBi0SqVTrV#Mh7nqHYP4YIgLD8j$c3_cZi>*Pf&dboSR2{=uz$% zq1pV!ju?OA=476>{eDVkQViEIxV_CnxngDymNxKN?iZ|U773{~nt>fc?lfdqJh-01 z$Mnb(pr<>}ujH0psxV~BjzVjpC-%oX4?^j#F~UmHcdgZ#WRXyAokk>W#QjPPPNRcZ zxPQ4)cHGlR0?)jrXCuVd#~f*|?o@eTvtJd7E|or~`+X;6@9{b_x9+-kka@R}P0dq% z^{Ywfsy;FRX>t^e9NFy^0ok8J?_(jDB@$B?nAE=wwqJDRC5)ei{?c{chyLsHN&GwZ zJ`x7kMEn<ypq<G)QYKuD5w4Xh_{+&<;zrd&3y$lHE&qEZMpzuFNbC;jpS#JIlkKc= z5tFy)uw3OIL_L>eC}2bt<6PxIPnN+#Pv_DwnZ-pGa+K>h69-z9uxpjr9TI066xzSe zQ-;ibecT)$B&|A|_%gY!@y@2<Q1knu#5Q&@oeW)aOsNqkSRxQ!$fA8)2TPfv7zTJC zKmYl9KVCRfv&dG9iV_(#NGDKw>-&3@w5O5}3T5*a6}s*Ty(=!m6`w?%{dno=fkqkA z|BkSX#s>FTbq)|2Z*p2lz*cBd4rMp2L+Ft}XV8;RW1i-{s7`J+6mlsIaK<;1^2E2| ziEax&fQ#gf{nAN;`60zt4n{y>Sw7lg_vTL<V8lPgc?f2A!J=r1#cGJ{MW>El%-e|b zbYhu1ruN{yv7c&OTqe|?0sORTSMT5&GfivUEx30V{1tXCu1-hP@|iCSqNm5H`LMDy zS$G1yfRXo8lRe+<_O&TLqs!{@;yB;uEzF|@N7j_G&P^7^O~vveHSqkI!@ff*b2AFH zR!FW^()v?dgXQcCFLbt#q*9iH*aVN(;7Kjc<e|LMjkyrqEQM|ptI0A+0#QZ&IhaaH zwTub<n-6IG!aMIS2<kVLJ-;y={^EtZygG?7$AN?J(BysW@j<}|3V#1OG!dB5IuV<4 zEKjFX3Tcy;D8KcB0c^1o6tBg5Qt}Ol3@31ji_Ax=%m<;JR%Xl(xH?!}r#Fd@E#*4w zxTr<Z9wh~@`?Ipm+ZC`{`GD|3%9=5A<VCr5BfLqmWPQ7v0n<)S4zG_Xr5gCdXlkni ztHaLjh0kCL(O63`lspGjg$|)`*s)1EaIUHFzHm>v02ThA2^`dRkbtA@Xds`eLq+u( zu0ldczHX$G*G-HTi-37Ob|#6EAnWGah3~OHHcVbLN+(Pgl&wMCCElg`T&~%PufYy! zyUHortn997q4=s+p=|CJu<Oqwm%jKYqlz+Bu4`@ofHlVKlm?S}z)|HyP54?&4<%GY zsgZZZU>)CP1+H2r`lCWkV#2bU_v5VTpm(4f)4lT309((K^LM+d)EB3(`QNiN5or6= z|Dfv>A@?pl_ZXwNLvm5&0ghH>Kh+TIc3ZtexX1FK=hbFFcPS+@l`iX@$9vdB=YF*L zYM*=UA2nO;Stc_EBx-8^npEJ?I{z&1aqk$DC-E-OZ3tfSva&T53ri(p&^u<h#`i{z zL$Fd03#?~Fy~`z&RrI`aG*pMk`ZPBG=>nA@E6~NPJtk9qnvA@oUrwU^djo=Ng4nyf zCZgN5KJRP(qS^M!SI1u#_eb9sB*4o12JS^z#71x({k*K>p?V#t;~_h-UwTL{g^@jb zH+Oz>zp-KnHRJ|xJav!~FsrNbGv3CDbR}W3)1yn=u>AcmKf+)35dZ)w1SFTF#7+Qr zEV!zp;<=`i<jjr_{1+O{PWvy^HEvy}v6CH_=O1{*mi|95tQ{%DKQMzm%fI0yGyC&@ zP*n$}f1`~d4jkD3z+C~%|AFrU@FD+!QG*%&1B(UA{@>IwA^(AsdP7wI8H^eFUj=(Z zNRn(qP5xmf|BGpa4AVyW2R2OkFD(fv8<cSW&pVUk-p&pD+dPxx-$jW0KkN-j%kAvI zzg-M}QP@dj9WejoV(1{i5N8JfB%CcQS+q2v0Z@PU@9%KZzk4_MT8r|*4FCw>K>{%T z@<;rALHu<$1q39;cMt&o-{60eO?MDLOeURl5d9k``#Xtu{d>>CUqO0*MH2jvB&7C9 z5M5YFiuMSw|5f>4LARl6aRk@^fT8=}zKs8_EamWb5UQDrEwjtl|6lTt{9=6oBmf`> z1OV{=M__$o7y18EW_2XQ@|UWrzx*87|6?pL_^%?ENvy#z|E=twY36njKn8~VOZjXU z+`lvaL;m`UgbV!_$<U4bzexRV0?599$ji|GG3TU~ZW1V&7(kL)3}Mn;HwF3MjXQfM hYU!l}0K$U)cMsH307>>Kg#Xs2(?bel-v0O7`9Daca{B-P delta 13659 zcmZ8|Wl$a4w)Mu{H}38l+}$C#TX1)`jk|@71$Phb?h=B#1P$&^(C?gkzIWffudBL$ zjJ3v`W3KM1uC;28k5|aoS4d(N1t@4B004jo@cE|53U=aS=|KVjs4xHkE`SJ}*iL|m z0DwXP;Ax}d<9!t)0wn?1iSfQco7*%(D+NK`&nR;#<uVnfC~rp+L;Sh!E~@so9z$m- zOz=v)+!WgU6=0zWcgB7c_SkFE91<xE)38b<BXqPmz)g#&{Bojj<fW;3nyrV(wQ)*0 zkht-z{7BTyZ4$?|0#b)(@#uh@kgJ7IAS!S!57N$>Q>k4p1I^2IE2y~|(8D}J3sE19 zby$WiP;mYh$}s>1QAW_c;hpfGscS&CIk-R*qq|BXy<ps!=tj8J5J+n}Pk(I4^c8^} zPzak>&v47s^ao@8jeg8Fg=5z4>=GKR*tI>WyVMkXLB5zNCFq&fZ{yUiYj1CV%Lkig zvV>5B!`sv9K|n5Z&N=g9nw(;!^gdJ0{&RN7bUaf>b+Zk6K_UB{S^P7~B?Ug4ZMJ<A zl?8(rdgdB|bge^DYPXG1VAGd5Qr>Y3L8ewtWqv|9Ozcu7xAqKzmGe!-QSnPpXWJZ` zFA365d<|B<7@wiGe$;*Y1(}W#4jD4tK`3Yxdd<&)3$i!3{C(mLqm-|V_ZH|IX03O2 z$EdA25=hekjmCQ=!;jf<RPP;5nALBYQt`~>sj7pxS)+cHB>EzINkHHpb%s5)px#aE zklsg87$t>~eufA3(b3QB%4Gsz;HT{rxRChl+M}lhqmbVAz*8m<r#x08evXEvU)oG8 z38b;o1i8RZ(+17%;~XXFuJBG@5R*)Z_3v`R3X?$M2aZxJ;Q=STM`D*sM}f1&!e000 z{cF2PYXpu}w$xR{Kk@SR+cux<_jS7;&_AXE=NW{`DxcB*_X~W9N|C)ER^bt61pvN| z004LZB7l{JqlN1icMEejV|NdCCvaXn4EPr$0%#2%Pn(|(S=+-K2>=0o1O)*6>#-nc z=e9oLxpmFhqIena9!VxO?rE=EI@&xxq)vOy>3TWo&Yw$N4{U|3gU6YnJb$|sN;EWq z2mw~`e(KKsDv8-?HJ$qy+v6ROUa~8ls+IM+XwA)skC4i$RCrsZUDTmBJT0?(F9_;* zD)SQQ?tb0hYc)0Ok4VgW-yeKwH3fby0}1&F<n(m<)4o5v?W2)Gi=wBO{QO=6C{!$) zcLEVb&vsPC+#cUOJb1eLakK9)-ra1KdBNL7Wc`|GL-bTmX29<scPBIXwyq6jV##XM zwf&3Iz&%%9(qNx*wo4pOp5}^HJrx9mr_}0QdOlb@`aaH>s(rm5P#|qOerXiX;GwOA zaiCCdFfmtol1e$eATe%HY7}3iQ6sPWjbr6?is@9oOe<T_(&})aAiM1|?b5=&+IN5# z*SIE^MMi3k8kg7hLT8>7QS76SW@fPw1z*@tEEnBDIlWR`b)!u&sinn^*ho;9>h9Kw zN9K4oTK!@`r6i1(hqi$p(n5482;)lr)q+3@3A_>e5gn!jk>Pf|`}_0mDcZdnt(rev zm)yd#*)?gUqB+axu7Kzx?E6hfy?5wX{O}_~w`!`<04>f6zP{$kqC!x6(!^=i+=7oQ zOOM{H$g8)FntE=m6k_6a01aq@F()rpJ#}YYoQ5v`;%%!)_WiI!qw0f#^Veo=Znlu$ z^<?7(dA*;kxaJsU`M?Wps_sY|Y9Bg~N;<o|1Y#Geep<@WRmyJp69!4E#h2Jo+xCo{ z?6cTN7}!H?l<qzKlG-KFhj2M8y~0m{CvpQxO5e(pH~W$cJ56phEOtSXKd*RLls#&8 zn?nT#%i5~YU7v)5Y8YG+^*sWM#7H$UF+0mAC^Y?kVUWwBn<NbZL@ScJJtuCPA?BO1 zq{6Qx5s&5y@akQdmddW&U`0M}AJV@Hp32UQkAL%TS%G4$CG0z7tso-C5%`wKsLq?~ zYh!Ode6j^3yFUB<`TPRp{iX7U`6SL~@WHLF3vIQW$DI7hR?+=2>;i3KI710lk`*D@ zv}foBbMz@K;guz_lZw;QXP&gYGrjlf-q$|~i>f(@+qrU&a|Lu2EvGz!>ySn4q6k%+ zNd!*lZU;kDn%lD8TR7nLl?APqK1z!KeJD~HIevU!VBgi~bLs_Xq?Ny7>2TmWAe8{2 zyv$b90qp60c#iww_*=a684)MlJD?@jM^!sG?|GnO<xw^ZXU7vo3xhN`Kpehelzm<< znd9`gscJ&FK}dY>^oVKUMU2LYU=zQ9@{wPx@o3!|Q!VJbQuq>3ID}0pUP`r6Ye0)* z{#Ypgiz`%T`iTYTGaAiQ70ntX_v0aQ)5J7*m*wtLu&;=SpRivbcife>yobRK!i!kb zcHir|8w5to@l|fyhHPTbw=w9e(kmyXqk!-N#amAV^h}<<RYuJlJI%CGBCM$9DaLmd zt8jY8<E;Zx?m*4s5aW#>9Lqk-gOEOw-hULSJEp=a7^5ITQpOj<u)Brun?t~|>n~9& zGlS)!r%UHi?@Q;-MZs2so-$o$6Y`8NlOBS<S_}7d>ai&grk2i!>b_?Q8Mhcz#8a$w z61fgmW<FVWSy2+IDj(%FK41Y2oQD;xqM7Nir03YB=j<yn&W2Nj!+HHq=1`DJchC&v znAB~^LH%x^Ph{t^N5$hL8m4B%L(l9PwQa8T!WOKbdh?>#)<iz*OtZBnA>|vy22W{Q zQfX0_pzui3QmQUhghYB{3!;zB=#!cy_v;SzNu;~AX+*e25jI2y)zhP!YEH3M-jmJz zA^c%5MP8-5_rsjTlI6;VBhq+ZLNvKpV+mG;WrnQ-)SR3LNi)thh%M8=kAslC;Gcx| z1bx$RB>o(5)d?x4PtP`}K;4I1fvGnCwJ#+foB*4|#!5WdD$<!D55yEj`)FFu(o!}l z9b#AP2=2T@meqlQ6`HN`Q~iz|<%#$J#2(r|&&R-*PtB1`xAS1_vx!;@@nyP@GNdA- zbKEHgwdDm3@s0)Z1kB)KY9*#>*<copT{5$ES*RF1VHmlV6}zV;il@QV9hM9%K$}wU z^0N7Fr~EnoedjL5nc#`}hcpW~wv%J-t)9Y<T}Es6^i9Ywh~&e0**J4IS9~ys)B99A zx@ez$X6JV_{P|BwgPLaSO;L3`k^*+A_(n@j(62(RV|l6{EDGH!T75Uv(md7H`98am zkLkOiMwJ_tw|y~Z7NUv}>*d^%9^X^?S8PhFR=SVzQiYa^3ck6wb+gLt4~W0EZz#>8 z_9qdTNP2AH`iRglNEAbN0>7oUl~<x*D3BMk%<eT`pdjOzs7$hN8r6h@Oom7OuJHL* zK$r4}qS&a_{e7{NvZ53ow2hFIDEt7tmN_Dc6*F{0FnKQMWhb<5qWOopTWGW>38Zg8 zehH+y!*zl;L@Gl=v$H1Jm_$^UeUj+*?n6ejH`=(7t&(#zq(W>-cxpoonTY%|;A^%l zx0&WgB>-(IQZ|KR7oLP30B0hmt{Tt}qLio!RvuVFqJT~w)w+i)2Xt}3XzR|ulp{#c zP!08wCt=FXkiUk{W1Y6+_Jy3PM-lZG6>=&#*ES6eLpl#sf^x>8(yR<0EJD6Zpo?<N z^h+O6N2<PmYQmSoqTg}D<*ac>u(Z2~>Bcc&t*$0CTL|;gD%v2+(3p-~z+IUIsczMZ zyI7gKa}Z8ifu?X<yz$>rLpc{FkY-k(P+bKJGiUUMGyeR!Rqmg3$bB?y?02D7P2_E9 zc^{INJ+dd$R-99)XP|0H>h7C(Vo}(0jH?1S&c51X^?qI|S`ww9Qk{e6&_#>bNH3Bx z7|KMhNVAAy#a7pWu=jU5;g#qGp>K)5hvRlmO@5boAGdxt$NG~8k?A~B&bhZRju=D( zpDAkXjUV;^9~OO3!nCAe0BD41s}Q{Q79yU^bKDI-S+~cWER`X;JV|Vz>q}4i6z5Qo z<_ja=tYYU=RKMKUCP+A$=dgPdK^8?0KOjLi#EpGTh9a3NRUqn~-uzt=gwv|^qv#1G zpBI1bhe_-9ui*F>aYRa_c;ufd3qO*INjeXseg&bT9gpSJzu(?Wjy}GI5EDS6(!b$F z6nQd<reGM?9lEwZ9CeG{!D>9kU+IT!VG;>`SAPx2NGl8qYSTAdOkTvgZ${<i6TqMB z#h;Pgq+iQ17qOil-l8>^1O>X&CS6HX=F&xVW1bQ6kHXp8UP0Y{OeU2FjIxasqDeN1 z_5dnd)T9LMiW4O<yu&(H=B`qli3V=0R#+@`G_TNQ-vz@)b&MpBIAKFM?3Ki|xdqII zVBLe!1*C@9nDCnz67O8XwsrmW#h>se@E{u*l;u%^1G>^I5-gw+L7Q08PNKN*-Jc{A zx8dp0r&4y{;STG^grX<-X_YZup>WI}QrHP^G^19rhLD5MKVgjF*kLf77Xk5pF=_GZ zX9jzD_Y8;54X~2kPBbfHdE=;;qv4!sX`k|fy)4_S6_5fog2~cF#o$#fQ7pHCxoF3I z`f$p;&XD~GfJdxg5Ed#?#Cdy$P)Nn#lj|M+A^NVj{=C{X-!6YX&R`n{-HzzjVV}6G zuR{gR9E`{p1_xN{c##xj0?^6asUnewNJDO-B5WLDDlCl7`8_R#5c^n>qcd1Pg{Y-V z%_AYAPBAMOPn%+#%=KD}1%<?baKL>BfK=O0<MaVB3}lN|P>pC|gE4`bW(G%?9CWH* zs2yApqQlQduLQCCEz`jMP*@!*k3lX-g))ngU((eE^KN<gd}}=8DGK?UwRAnqYTIOz zEv=<puoS7KJ$i%2vJ3$YA_u%Wn-V85VGF4`RZTjJ^fa**?91Y=91isAUcn;f{o*X- zrF7;ssplbKptDz8b(xHG-;B&j-9iYz?(IP6d!y+;Bw}yNsW_&#o)Gau3pOt&%-d`Z z6AkfzhiHIK6f6>-tO_}9X$@+POSM=J@rgrO;vX*^`U-8QTv)5w{Dp)ycMx+dMj_|< zj(hakNy<bybQm^j4(mKWgc)aFL3AiiIm*VRsQkGm2oAFc6-cZHSIB|hA4j4Ni}?kg z?j$`J6(^QhiZWQL=%`+bauz4PP$E{^G~XI{Zp?|PA0s_$GF$EpiF+WHaBa><wE56w zym}0D-?U$Vf{{ZgX3ouu$MpzVzhOq4xh~y7(czucRK`90ev-|YH$+4=I^bcN1jO@% zSSZ&AT^#|;4{jdxb4tnFp)|!<BJ@=FJ543z%B7W)<XU`Cgk9L2O3pt`3hAl|npLbB zW)v#RO_7B#r`m?Y3GvLdC7bw{w=It=P)?&+x;s~pX0riGq85Ha=SNnZli{JI>(#H= zjUIXzQR0;R;vWo>)lFD+L4%4+EZM^5T02t*orx(>5JAq8!255v#*G$R?ewII{aMqT zCu~3WyeCQ7<yLmdq)8A4Nq>ER{o{QWqM6DZ)X0Nruuh?gfzYLR?_|OU>n-6|cjH9b zpuBk4`LdO5_=9vi7Dbz<a->{}giCuS$fG9z%a8gQCc|$1d>F*RjbDoGb?DMhqkX5d zpswg`<7-uqp1#sv`6p&cu{ty5qXa_22fVpBFEgAui!MS2oq3bvP#~PHngtS3_T+5h zcI|X{>_*+6kT9VnXLc<UQ!owt24+#90;mHTs*R6W+!G1MQx=aMK|SED@3`*TDN;7W zSdb6({AkKBmcW%pxc_)Msr?}>sZ(zX6jrzD1_3jQP9cLkq}tbdCe1SI9MT2qTlH-! zEQp_e<hCR}i>frxKf-IKq)PsIDTR6gbH>KI-o`#ZYJWS{o;3`Tm?Q5)%4hAb?+C3& zWZn=PlZwk;f#S1@_%)6mKvqh4&_syz1Spz+h9pgeg7yCGvUM#J&qd+3^#q9uGPAjd z_MnL~!sE>#117mh?ixAp&MM*JORGJh6L;uJHIW2N_eF@OI!@HvDO3@m<lhr(#N|;a z0{lT8LZN5agq$~9tsLE+X^Y2uI${0nJfy8$SN`Z>UYA~QgLRy{mMG*YVlCC|Ri`Rb z9Z|(2Qwe>hv>w(<X%GTyjPrUR$x2wYh+&`TMdUl!Ak9MU6d0}&b$BDi3oQ9Xl(f1N z^r57jwC0KQ&M+ZC(MSc#ZwT^3Dh68iE;q2r5;6|B&FjtW*iY)sKx8Pr!cxD4yFw*G zRkK+wq83e@h>nOCY&=wZhKCd6-|m@}kmK<ace+4tUOBO@!A5z$5@=CSS5EO|>51Zt zWI7^c!Arz&UiFER97bw8^tH3acAiw^AVq?Uu{ti@!DTP3KAgT-SO$A!Ozc5+y%aGr zwwE)a?sr;@m7EO?191qs3UyglWNWlUmz@WLf*FMs1nr66T$3eZ)La;BYi1T2K}dS> z5gc1p$;cUZ_x-`Ym$BeMg5n&dG0+#Hy7mHD@ngPOp@%RuWBMtCIc>-bt!RDZ-h80j z>o<0M3I_D13cfNUKoEu>^kAO{Bh>N>6Ot0C&IiPH6zNsxc#aZe%Ul3gq+E|jY_oOs z5flC1uxehLhwGb0ikdZBO*6Px!mL^oPuU}DqDmtf2-VI8YjX_}HA7ofqdND<;w2KV zTD+vd&2LJhPODYm+GhOz1*Tt(c#@~_8_bjpeuiPwZ6dXnB8eH?@R)J5)9P6u1UX_< zUHwvvU99_vbm*1e;s9Rh?q}X!$Dx6sX-CFFQOq26H@HuOtVPIhlnP8T@znY-fg`_j zq&Fz*PRZPS;W=191r;+-axC-`WF-}Gal@S_OKo&?eKV~;byWjuFm;CqX_$(WUZFyO zq$(}0WN<`D%eBU4oC@jVKLH1J@K7!_>GSa-qA+b*aDfv0vzp6JBBB{IVEyD<8=Ayf zI-Vvm@;U~?>xB){@BmW-QZm<&W!_K55oK&m?3BG$4VFD1GhbLG;;|QbV^!+7$bhkF zy=-!rBzysnSYbTISe7^#d2S4YC;LRm5z!-nj&tivZmP32Gy>jD?K%2yGf0xiLq;Z@ z+@CZT4rBwl4?Tseq&s>WX0_i=#xh43$kqC%*w`?I#lOd(w%EZ$q6}*BDL|e5BzenI z@}9y&6@NViJ@=$a+WK|lK#E9GY*d!kZ&HR1sZ7AYt)SCYF5h{ea09*&R(E0q3^<^w z=Kel{2Q!S}MVr&{*AbejIEtPx2{NgW5_cjR)bi$(M&*5^AabIm=+iBFY(LEU>1_#Y z%({SI&Yjzs_QfAd*+nSmCe#wY*r}W1l}~_dwOZUk;rUR_k@6xvO+qR&3BJ^8%G57l zkMc`ZhHJ^`wG*DN0k<Y6VL@MG>dpd&IuqNaLkTn2hDK6}%F7`ZfpT$Gd|S+#s$VCh z&#^K`;@d`Cifdif)ihIke#mZN3z9U3eZpjjrW4x+nis5HNpj$m;djohJfAh$g*~md zRSu+rdcG*bSJ%th)x`wo4z=a7uc0-b7&DDI1>_$mPe#P~#o91>lXKh|3i9IJWR_3b z>F~niFZ6!@BpoMyUQB+1xQfBE$xW!)li#Sl``&rr_&9O(QC@GLjrfEyfh$Xk>gmW0 z;QmTw5ru9}$HToXqyX(BF$zu+JHLVn|IUI4+7q&OOZ!<Q#&{jHopha7aPRe=w&6K% zwbz&a()OfO)zzOaH@G@A@(p5m8&jtE{0b5KeP#00J$r9Q>;v_X_w-K#+cdS>TR+4R zUi*WvX$=#Z7jdT!!)OSrdJ~w7+vc-AFfO4@Z)QZp!Cen6)ejTvx7w);W<3^$`}k83 z=z&Dgz9(-aa9r2DtfaS%ow%1QG#{U-se1{(6Vi)yPHW|CEN||WaCily+5Ssa4c)Sd z_Tc71OPk5J+CO>}PRl+Ec~?GA{jYf29V5m?^W~;G1M3;}(H!cI?cE=czYEy81KkdL zcoi*4=<q2Vt;bUoyF46vIPN~aG||evfPmuBik0mUa<x|$93L!1aHuEu2IB?RD)ZXA z<t_@OuIMv1t~}HM2jo$5Y*;gSBT?n<)7O%Fc%oUgx?Oe2?I;Y-7Rt5)_oJo5XGp5< zmPdn`HE_Aae;jXjd*TIi-r#;vDN=Q&%EppJ2igEJ^&jsb6#(raDzOVNOKoQWP@`6^ z`L;Z%&Eis&Ig!H&e*%JabycVU1O5GD8ur4R5mbB?H&cNIj*Qpy7S$C5nyjU_Ma%2^ z+K_L0y&F>IpAh<COYI2-xOn>DqRn5kQ)`~q`u@&)e1@Yg3$S=82A>+uM(_60TC8Eb zc1GiS1e3>6_;0kHR+gK*hWW5;K|dW#Lqij4fSmp>$`0+r%mq$<GTq=cQ)~nz;%w_& znv-aJw{I&^IqG_Fa}lp7J>pa4F#FjwtJR7aY#p4XH*UR-wgaCbD6e0)!*Ijmzl?v* z0#*Uz;lg0S0-*^Qfpsj1mi5^;e=NfrIsEwxkM7nSJSymgqh3wY*CAOXK&dX4WS6`l zStAu4s>d#$-b-$kUGbZ>$m^ibaNjt$UJS|?5xa^fa;|)d=wYKF8b?}1-)w3+599C( z*98kJiD6S0p6z#K{Fk?Xs~3+5$Q3{JPfj3G<>#|%#8j<421%IL$s5n(O0`2m#1Utv zpAyQF`~FOHY`0*kvMeR=1L>9)ZfebY+h9`Bh7chobvM>ty&QgI9a${?$o>o%7*R6$ zv>rA&>D6|5GZQ{G!xwOKo1OE1!^Mk=q}zUohdS4K0sE7CEcEi)sN8<@tSe)n^Suuj z)ugb{ED37uv_ToWeaHHuY(qs%U*8qeTQj?D2$BHz-P=4LA(VoI3xrBj#hVxMV)g5* zz-3|R4_irhUCzPm4Xa11iL1LJ8YVR5=%bX4ROp(;Hy1ba%L8w3mCAI9&?N6S;Ljw| zywbTHzaQWG6qhQPM)f_>RAOW59dv@BILNV9x4s;&Xl{oTs8~gM-zs}Nze3GI_WDWx z0OkYN)X^~ZP;il&c0uRwhtXQOTPvrbW?D{Ka&Spy?;nkQOIZ$~jnZ?DSznm9PQui` zonb~Y^p#oU@L}YuFH|7vWFs(s2WT$SyO8m(@uW4Q=kF#=ejtN|OSb6t=HG3IHidl! zq`OA<q7J#9HhZ$C(pJIom69pngXFy}mB4p93r==!UuuyrF+hJEK1XkqI4w4+#14ph zOGy<{hq*308x!F4$=~M=>{oSN_D6RdQ=YUnb5cg0G%zD8yw`R!1~~5VK5RYKu1M|! zRGgDi%xM*888QpaHR<T7#naRqkeaE|7WlVW8j+HQUXps>l#JcZ5t8O66v8!I#)K?= zeSNK-pFF0u9za@TD&NKkC`asB3f<Trd5SiG@c^!*R~H)I0SmlWUd*OECc|a;6Np%; zEd7nW)tQW>Hf8*2=-;ipBPTSo-+b6R4T8-^Jr4|=cY&~_`A8&Xv$}l37T17f>7@j| z7PH}xh*$b6M+5{|(|X2(oWAF(9sWssp9;Mqdaa3z7|_Pd@2o7d#sP$Z#QY80EDLH! z+1XtgmJ)27-fKJw1sxU#0q-fyfz14REOT;1MmhMuei|zUkIfqr&XXxNpW(9tl3XYI zN87J6j?w65VkLRJ+{)}f92HiCVj--lRs%kTs1%8+TFUxoeuWr%L!*Ci@?UG4(GX~n z*h0(K+yId_>d(AixgnX10zS?m)Ad%ruzcbg@JPedNYlt<oRO*4@NoEbtq?r&G#Dag zfnZ-mG%RLD8h_$&hJ6d6IihK+j*(SG9|V8a9McyN!(4uVfd@7{h^BaPjc>_<Nr@Be z%=;uf<cGmI<iPPQ)K&(C;NscN^$pHKa!JcOy$aM!QH!GqBZh@1)7V;uUBr-c<@tL- za`#Qij^{UOQkW0{<Lt;@OK{e?1dX&Bl#0fiyT=kP`p*m&w1-fYw{j<jl%`Z+rgjO# zk&A7IH1RL$CGi#&uV1ZfebgV_I)WVf(ArI`-rufTk7#acU6-%+Ft}>SrON9N@X}s5 zfA@hBm+wUrA1UOgmx;(q15-v&vYX-e7|oi#ymYHyZ|-z<iQdCLyR2wMORg+qe1)o@ zbFXk}j_n$#GRs0HC%eKg?2Uo);t!R9mo3jY5}g*lQ)7Q|ZV!BLGL_=B&k+p9{llPp zbE$*#4WxYvd<(%}&E+&<_76l&8EZ?Tnfd}^AHU)Hz&8w0P?%Usox}AXFXU9-2qr9s z<J02-lE9z=tgRXhgCQzW`XjVx=2du`qC3(Jx+Psq$9Ei@IK|~32AyJzp5i46aG1RF zMergL`pD3Tg6paJu<%}#N4?i9r93(u)QrmyP%n*Z)lpTP4T%_WBJ1U#C6-5g?bJXY z`~p7$1f>whUBkv1gr8yT!)_XB(VYvjo_&_N03~hFpVU@D{tQJajvb?vC*PwJE7(Sc zZV<tTh(1mA4@i;=+4y@Bi6Rbt^5|a`Pa+JPB|A~FdUQE-Ohvs`;i&fC-pA^W@$g^B z@_Xm(^KyfAq+W?mr^Y})<}U%ti#~!Bpqp7ZLnh)iRy>up${eh34=4ws+TsSnVLKPc zeny9L#NH?@q4Ke>Pf?xo_;q*(>{01oFTi9Mo6aem+w<v1F>zRjrO45NVI;6)7kV~v zUxEDi>zHtt7Z+pOXUV*DXlU_UUu6beFj-%kt|CJNrQ||SgL2hPSp#-E7lc9Up5_8T zg8^LOAtr6Veh=v%-vv)KeA=y^?etO~e31f+$xuF=E82SXKZQc4>{hH^X4<bNpTwZa z^AUot)`&=k(oxej3?c2|;}w}ql_kR)W#|e|mJb1UxN!30OXAZWmWL$j*b4TNxZl4e z$*k*(Z9?*jXR{Ffsp=z>--QC<(n7&~x4RI_W|7C5653BiWm3AnEb;wC{YH#6@&ie} zgkg)lL^|l|R6MYG`w1}6p$rK>O|Dp#_^rFzdd5v2N)$O+3-zVAGH4;sig5+@$}hqM zVu?;IMPRb;Gl%x%UC%d0C91PM{T<RlLlr>-2Q4p}7?>9KK8D3tvTy4kr+ix^-NkCM zMm1Xu5gZ{~!?@Ue1B4%J8~D%=3HR!(dUW+V4-sE3nT&Ako?zthn3LNcPy0CbH)|zf zWDl1v(Ar_q!XEUDg5z;tzmPY^kuoQQ)sTAy!EnBH-X#Xgk_?H~bjVVMGGetC6K1K{ zO%k6qy9Xh6%DjBmTRZdtSziW!jIctzUzA5^rOKX_+B+JEeO(;O^p`J#{;JHJ+LpQ` z$@GL{Lj$wub8IrwS&>$CdRrc)de18Q`{a_se(GLzZvfjRM5ktHhEOm$)Ze8Z%)3$@ zs&OyzEPIGOX*lBUs*GC;W3V~p)-T0O*p2^qV|qtC5NTb75+|nz^0eRuHv4e<W17Rj zvaG0wWY@{AkFf7FX}ikx0eVyP3w?Yq_cFcV(<R5TA%2ynU&np){q&1c61Df!qNQ58 zQV^f(H>)p67ni-SIAf5Z;|upD5flka#=~3B{~b>^@xziN+RngDpFzI9bgF8ZnaRC5 zMyHwdn}qhk3aT9!NaM8q^+yCXWf#B6%9rRpHBR7^Tct><byX9;hmMjWAWFjO*z|lz z)%`207;tT|XY6-sh*_{Gqf_Hd%c<TOjh8AJ_7?j6S}3Ha3F>rng+7*N1&5}Xbf2>g z-FuMDD!QP?50PyA@ITk~llGr$s58+-FPy4O5e}x}rLA|<LGgcNPaw0x36^Pb*tQq8 zKOq%JZCzk=Les7xs=DAczohm2adcdzrT!K4GvyR!m0ly;LVDiVsxC-;#~NU~X5Ei^ zE@Y!WNS&BoWx#=JJ(Th!6Q+7x5?Z(F?Xs#m%<c=>sO>8PIHB3RY{paWOt9E@xYTkh zGJ4|mZ!t3#2iZ%cqe2p#jwpEDKJIb!eWn51iZCCi@86G@D9~Ta)P-g-L#0im1XPdD zeXz05%ItNyvdh#iL^yR$D1AkXACOeQZrJ5vlMcWN-XG*RFhKI4WNfY~(X&!o^3<}Z zf6iId`A+z#Y0>>0u&7t((fudw%z7^`sHc(jlWHWb2#BaRFR&!~dB@xL`LUK$RYruQ zN5m(f>rK*!C9)-~A;Jx#qu;efkUMyrH-5iFFG1?)fUNza0%4bfoQ&$3FqtuI18EL> z9%g(m4IjBR6_V7_XB!t<V?N4i&2rgg3K{Z)T^eS0pFo558VL0+0I5^@oSw7@h+!%} z^I3hd2Z^;PNHG^1q|%+(dU&d?8N7WVNr#lBBxK#nUy^`;I*7}&Z*b8?6#QC1z~h(- zgze?s9>z#8MKL<;A$y8mtCzRZh)22w9KrVcV3onl_v)jj0?9)vaZ6+6mxx6v-HQxF zC!V&ipC*$U5AaRh6f_^5wV=Opv1?kpvG5GWfV}aTae_PsDkn73W9N`1℞GS+K7Q z%`+@f2!-4^Yw#10&}9to?RA=RB~TPbq$YldY!(>j+BuyV)=&Q~ADuV-P!3Vl;@>^T z`YFD#zPg(8`g-sinAf_r7NjM&m_l~1N_sHHF*f_h)trW;{r6^gRzA%&6jrTnIa6=c zC1^W3ru0{OPB@`7?uQ$Ux2Ih}E$z}xV2Vxnh;s`u!+CenSE%ODR@hCoqootf){@E{ zcH*yLOZM_9?vfKsm%^OK!<j+xr3b;KFzV^mUCpp_v^fM}aaED_pAGEJv(JSG<0*zw zyMDX}WlZos9≧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 ArT_o{ -- GitLab