diff options
366 files changed, 44586 insertions, 0 deletions
diff --git a/chapter11/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter11/src/test/java/com/seaofnodes/simple/Chapter11Test.java index fdf56b56..02843c85 100644 --- a/chapter11/src/test/java/com/seaofnodes/simple/Chapter11Test.java +++ b/chapter11/src/test/java/com/seaofnodes/simple/Chapter11Test.java @@ -296,6 +296,7 @@ else { } + @Test public void testPrimes() { Parser parser = new Parser( diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java index 12e089fc..ec38bd89 100644 --- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java +++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java @@ -21,6 +21,11 @@ public class Chapter23Test { testCPU(src,"arm" , "SystemV",-1,null); } + @Test + public void myOwnSake2() throws IOException { + TestC.runS("print","Or",0); + } + static CodeGen testCPU( String src, String cpu, String os, int spills, String stop ) { CodeGen code = new CodeGen(src).driver(CodeGen.Phase.Encoding,cpu,os); int delta = spills>>3; diff --git a/chapter23/src/test/java/com/seaofnodes/simple/progs/print.smp b/chapter23/src/test/java/com/seaofnodes/simple/progs/print.smp new file mode 100644 index 00000000..3bb86268 --- /dev/null +++ b/chapter23/src/test/java/com/seaofnodes/simple/progs/print.smp @@ -0,0 +1,8 @@ +int x = 1; + +int y = 2; +if(x == 1) { +y = 1; +} + +return y;
\ No newline at end of file diff --git a/chapter24/Makefile b/chapter24/Makefile new file mode 100644 index 00000000..6547a73a --- /dev/null +++ b/chapter24/Makefile @@ -0,0 +1,180 @@ +# +# Makefile expects to run at the project root, and not nested inside anywhere +# +# cd $DESK/Simple/chapterXX; make +# +# +# first time only - this is the only thing that hits the Interwebs +# +# make lib +# +# any time you want to nuke everything from space: +# +# make clean tags +# +# run the tests +# +# make tests + +####################################################### +# +# Boilerplate because make syntax isn't the best +# + +# Use bash for recipes +SHELL := /bin/bash + +# Remove target on error (no broken leftover files) +.DELETE_ON_ERROR: + +# Keep partial builds but not partial recipes; keeping them speeds up the next `make` +.NOTINTERMEDIATE: + +# for printing variable values +# usage: make print-VARIABLE +# > VARIABLE = value_of_variable +print-% : ; @echo $* = $($*) + +# literal space +space := $() $() + +# Decide OS-specific questions +# jar-file seperator +ifeq ($(OS),Windows_NT) + SEP = ; +else + SEP = : +endif +# Find a reasonable ctags. +CTAGS = $(shell which ctags) +# Hack for MacOS: /usr/bin/ctags is unfriendly, so look for ctags from brew +ifeq ($(UNAME),Darwin) + CTAGS = $(shell brew list ctags 2> /dev/null | grep bin/ctags) +endif + +# Fun Args to javac. Mostly limit to java8 source definitions, and fairly +# aggressive lint warnings. +JAVAC_ARGS = -g + +# Source code +SIMPLE := com/seaofnodes/simple +SRC := src/main/java +TST := src/test/java +CLZDIR:= build/classes +main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java $(SRC)/$(SIMPLE)/node/cpus/*/*java) +test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java) +main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas)) +test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas)) +test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java)) +classes = $(main_classes) $(test_classes) +# All the libraries +libs = $(wildcard lib/*jar) +jars = $(subst $(space),$(SEP),$(libs)) + + +default_targets := $(CLZDIR)/.tag $(test_classes) +# Optionally add ctags to the default target if a reasonable one was found. +ifneq ($(CTAGS),) +default_targets += tags +endif + +default: $(default_targets) + +####################################################### +# Compile just the out-of-date files + +OODM := +$(CLZDIR)/main/.mtag: $(main_classes) $(main_javas) + @[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main + @# This crap is really just "javac", but with a beautiful error message. + @# The very very long list of java files is suppressed and counted. + @# The required output "Note: blah blah deprecated blah" is suppressed. + $(file > .argsM.txt , $(OODM)) + @if [ ! -z "$(OODM)" ] ; then \ + echo "compiling main because " $< " and " `wc -w < .argsM.txt` " more files" ; \ + if ! javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(OODM) >& .out.txt ; then \ + cat .out.txt ; \ + exit 1; \ + fi ; \ + rm -rf .out.txt ; \ + fi + @touch $(CLZDIR)/main/.mtag + @rm -f .argsM.txt + +# Collect just the out-of-date files +$(main_classes): $(CLZDIR)/main/%class: $(SRC)/%java + $(eval OODM += $$<) + + +####################################################### + +OODT := +$(CLZDIR)/test/.ttag: $(test_classes) $(test_javas) $(CLZDIR)/main/.mtag + @[ -d $(CLZDIR)/test ] || mkdir -p $(CLZDIR)/test + $(file > .argsT.txt $(OODT)) + @if [ ! -z "$(OODT)" ] ; then \ + echo "compiling test because " $< " and " `wc -w < .argsT.txt` " more files" ; \ + if ! javac $(JAVAC_ARGS) -cp "$(CLZDIR)/test$(SEP)$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(TST) -d $(CLZDIR)/test $(OODT) >& .out.txt ; then \ + cat .out.txt ; \ + exit 1; \ + fi ; \ + rm -rf .out.txt ; \ + fi + @touch $(CLZDIR)/test/.ttag + @rm -f .argsT.txt + +# Collect just the out-of-date files +$(test_classes): $(CLZDIR)/test/%class: $(TST)/%java + $(eval OODT += $$<) + +####################################################### +# Base launch line for JVM tests +JVM=nice java -ea -cp "$(CLZDIR)/main${SEP}${jars}${SEP}$(CLZDIR)/test" + + +tests: $(CLZDIR)/main/.mtag $(CLZDIR)/test/.ttag + @echo "testing " $(test_cp) + @[ -d build/objs ] || mkdir -p build/objs + @$(JVM) org.junit.runner.JUnitCore $(test_cp) + @$(JVM) org.junit.runner.JUnitCore com.seaofnodes.simple.FuzzerWrap + +fuzzer: $(CLZDIR)/main/.mtag $(CLZDIR)/test/.ttag + @echo "fuzzing " $(test_cp) + @$(JVM) org.junit.runner.JUnitCore com.seaofnodes.simple.FuzzerWrap + +# Build a Simple jar +release: build/release/simple.jar + +# Build a Simple jar +build/release/simple.jar: $(CLZDIR)/main/.mtag $(CLZDIR)/test/.ttag + @echo "jarring " $@ " because " $? + @[ -d $(dir $@) ] || mkdir -p $(dir $@) + @jar cf build/release/simple.jar -C $(CLZDIR)/main . -C $(CLZDIR)/test . -C $(SRC)/$(SIMPLE) . -C $(TST)/$(SIMPLE) . + +# Launch viewer +view: $(main_classes) + @echo "viewing " + @$(JVM) com.seaofnodes.simple.JSViewer + +.PHONY: clean +clean: + rm -rf build + rm -f TAGS + (find . -name "*~" -exec rm {} \; 2>/dev/null; exit 0) + +# Download libs from maven +lib: lib/junit-4.12.jar lib/hamcrest-core-1.3.jar + +# Jars +lib/junit-4.12.jar: + @[ -d lib ] || mkdir -p lib + @(cd lib; wget https://repo1.maven.org/maven2/junit/junit/4.12/junit-4.12.jar) + +lib/hamcrest-core-1.3.jar: + @[ -d lib ] || mkdir -p lib + @(cd lib; wget https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar) + +# Build emacs tags (part of a tasty emacs ide experience) +tags: $(main_javas) $(test_javas) + @rm -f TAGS + @$(CTAGS) -e --recurse=yes --extras=+q --fields=+fksaiS $(SRC) $(TST) diff --git a/chapter24/README.md b/chapter24/README.md index 03056897..c9a70775 100644 --- a/chapter24/README.md +++ b/chapter24/README.md @@ -343,3 +343,75 @@ if( !test ) { // Zero-trip count test } while( test ); // Exit test at loop bottom by default } }; ``` + +## `&&` and `||` + +The logical operators && (AND) and || (OR) are short-circuiting, meaning they may skip evaluating the second condition if the first one already determines the result: + +- `&&` stops if the first operand is false. +- `||` stops if the first operand is true. + +They are syntactic sugar—used for cleaner control flow—but they don't create new nodes in the execution model. + +The `&&` and `||` constructs are simple syntactic sugars that only modify the control flow and do not +introduce new nodes. + +Consider this example: +```java +int a = 1; +int b = 0; + +if(a++ || b++ ) { + if(b == 0 && a == 2) { + sys.io.p("Or"); + } +} else{ + sys.io.p("And"); +} +return 0; +``` +- `a++` evaluates to 1 (true), so `b++` is not evaluated. +- As a result, `b` stays 0, `a` becomes 2, and "Or" is printed. + +```java +int a = 1; +int b = 1; + +int x=1; +int y=1; +int z=0; + +int g = x++ && y++ && z++; +... +``` +Here: +- `x++` is true (1), so it evaluates `y++`, which is also true. +- Then it evaluates `z++`, which is false (0). +- Since `&&` requires all conditions to be true, the final result `g` is 0. +- All operands up to the false one are evaluated, so `x`, `y`, and `z` are all incremented. + + +## Stacked relational(Operator chaining) +Stacked Relationals offer a cleaner, more readable way to write chained comparisons without repeating the same variable. +```java +if (min <= x && x < max) +``` +becomes +```java +if (min <= x < max) +``` +This syntax saves space and makes the condition more intuitive, similar to how range checks are written in mathematics. +Eg +```java +int score = 75; +if (60 <= score < 90) { + sys.io.p("Pass"); +} +``` +Expressions that mix opposite directions of comparison, like using both <= and >=, are not allowed, because they create ambiguous logic. +```java +if (a <= b >= c) +``` +This checks if score is between 60 (inclusive) and 90 (exclusive), without repeating score. + +## SCCP(top-down)
\ No newline at end of file diff --git a/chapter24/docs/18-grammar.md b/chapter24/docs/18-grammar.md new file mode 100644 index 00000000..7b611fbf --- /dev/null +++ b/chapter24/docs/18-grammar.md @@ -0,0 +1,132 @@ +# Grammar for Chapter 16 + +```antlrv4 +grammar SimpleLanguage; + +program : block EOF ; + +block : statement+ ; + + +statement + : '{' block '}' + | returnStatement + | ifStatement + | whileStatement + | breakStatement + | continueStatement + | metaStatement + | structDeclaration + | expressionStatement + ; + + +returnStatement : 'return' expression ';' ; + +ifStatement : 'if' '(' expression ')' statement ('else' statement)? ; + +whileStatement : 'while' '(' expression ')' statement ; + +breakStatement : 'break' ';' ; + +continueStatement : 'continue' ';' ; + +metaStatement : '#showGraph' ';' ; + +structDeclaration : 'struct' IDENTIFIER '{' block '}' ; + +expressionStatement + : type IDENTIFIER ';' + | type IDENTIFIER '=' expression ';' + | IDENTIFIER '=' expression ';' + | expression + ; + +PRIMTYPE + : 'int' + | 'i8' + | 'i16' + | 'i32' + | 'i64' + | 'u8' + | 'u16' + | 'u32' + | 'flt' + | 'f32' + | 'f64' + | 'bool' + ; + +type + : PRIMTYPE + | typeName '?'? + | typeName nestedArray+ + ; + +nestedArray : '?'? '[]'* ; + +typeName : IDENTIFIER ; + + +expression : bitWiseExpression ; + +bitWiseExpression + : comparisonExpression ( '&' | '|' | '^' ) comparisonExpression)* + ; + +comparisonExpression + : shiftExpression (('==' | '!='| '>'| '<'| '>='| '<=') shiftExpression)* + ; + +shiftExpression + : additiveExpression ( '<<' | '>>>' | '>>' ) additiveExpression)* + ; + +additiveExpression + : multiplicativeExpression (('+' | '-') multiplicativeExpression)* + ; + +multiplicativeExpression + : unaryExpression (('*' | '/') unaryExpression)* + ; + +unaryExpression + : ('-') unaryExpression + | '!' unaryExpression + | primaryExpression postAssign + ; + +primaryExpression + : INTEGER_LITERAL + | FLOAT_LITERAL + | '(' expression ')' + | 'true' + | 'false' + | 'null' + | newExpression + | IDENTIFIER + ; + +newExpression + : 'new' IDENTIFIER [ '{' block '}' ] + | 'new' IDENTIFIER '[' expression ']' + ; + +postAssign : postFix [ '=' expression ] | [ '#' ]; + +postFix + : '.' IDENTIFIER postFix + | '[' expression ']' postFix + ; + + +IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ; + +INTEGER_LITERAL + : [1-9]DIGIT* + | [0] + ; + +NON_DIGIT: [a-zA-Z_]; +DIGIT: [0-9]; +``` diff --git a/chapter24/docs/Makefile b/chapter24/docs/Makefile new file mode 100644 index 00000000..12659b8f --- /dev/null +++ b/chapter24/docs/Makefile @@ -0,0 +1,12 @@ +GV := $(wildcard *.gv) +SVG := $(patsubst %.gv,%.svg,$(GV)) + +.PHONY: all +all: $(SVG) + +%.svg: %.gv + dot -Tsvg $< > $@ + +.PHONY: clean +clean: + @rm -f $(SVG) diff --git a/chapter24/docs/d3-graphviz.js b/chapter24/docs/d3-graphviz.js new file mode 100644 index 00000000..7439ba65 --- /dev/null +++ b/chapter24/docs/d3-graphviz.js @@ -0,0 +1,2014 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-selection'), require('d3-dispatch'), require('d3-transition'), require('d3-timer'), require('d3-interpolate'), require('d3-zoom'), require('d3-format'), require('d3-path')) : + typeof define === 'function' && define.amd ? define(['exports', 'd3-selection', 'd3-dispatch', 'd3-transition', 'd3-timer', 'd3-interpolate', 'd3-zoom', 'd3-format', 'd3-path'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["d3-graphviz"] = {}, global.d3, global.d3, global.d3, global.d3, global.d3, global.d3, global.d3, global.d3)); +})(this, (function (exports, d3, d3Dispatch, d3Transition, d3Timer, d3Interpolate, d3Zoom, d3Format, d3Path) { 'use strict'; + + function _interopNamespaceDefault(e) { + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(function (k) { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + } + n.default = e; + return Object.freeze(n); + } + + var d3__namespace = /*#__PURE__*/_interopNamespaceDefault(d3); + + function _arrayLikeToArray(r, a) { + (null == a || a > r.length) && (a = r.length); + for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; + return n; + } + function _arrayWithoutHoles(r) { + if (Array.isArray(r)) return _arrayLikeToArray(r); + } + function _defineProperty(e, r, t) { + return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { + value: t, + enumerable: !0, + configurable: !0, + writable: !0 + }) : e[r] = t, e; + } + function _iterableToArray(r) { + if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); + } + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _toConsumableArray(r) { + return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); + } + function _toPrimitive(t, r) { + if ("object" != typeof t || !t) return t; + var e = t[Symbol.toPrimitive]; + if (void 0 !== e) { + var i = e.call(t, r || "default"); + if ("object" != typeof i) return i; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return ("string" === r ? String : Number)(t); + } + function _toPropertyKey(t) { + var i = _toPrimitive(t, "string"); + return "symbol" == typeof i ? i : i + ""; + } + function _unsupportedIterableToArray(r, a) { + if (r) { + if ("string" == typeof r) return _arrayLikeToArray(r, a); + var t = {}.toString.call(r).slice(8, -1); + return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; + } + } + + function extractElementData(element) { + var datum = {}; + var tag = element.node().nodeName; + datum.tag = tag; + if (tag == '#text') { + datum.text = element.text(); + } else if (tag == '#comment') { + datum.comment = element.text(); + } + datum.attributes = {}; + var attributes = element.node().attributes; + if (attributes) { + for (var i = 0; i < attributes.length; i++) { + var attribute = attributes[i]; + var name = attribute.name; + var value = attribute.value; + datum.attributes[name] = value; + } + } + var transform = element.node().transform; + if (transform && transform.baseVal.numberOfItems != 0) { + var matrix = transform.baseVal.consolidate().matrix; + datum.translation = { + x: matrix.e, + y: matrix.f + }; + datum.scale = matrix.a; + } + if (tag == 'ellipse') { + datum.center = { + x: datum.attributes.cx, + y: datum.attributes.cy + }; + } + if (tag == 'polygon') { + var points = element.attr('points').split(' '); + var x = points.map(function (p) { + return p.split(',')[0]; + }); + var y = points.map(function (p) { + return p.split(',')[1]; + }); + var xmin = Math.min.apply(null, x); + var xmax = Math.max.apply(null, x); + var ymin = Math.min.apply(null, y); + var ymax = Math.max.apply(null, y); + var bbox = { + x: xmin, + y: ymin, + width: xmax - xmin, + height: ymax - ymin + }; + datum.bbox = bbox; + datum.center = { + x: (xmin + xmax) / 2, + y: (ymin + ymax) / 2 + }; + } + if (tag == 'path') { + var d = element.attr('d'); + var points = d.split(/[A-Z ]/); + points.shift(); + var x = points.map(function (p) { + return +p.split(',')[0]; + }); + var y = points.map(function (p) { + return +p.split(',')[1]; + }); + var xmin = Math.min.apply(null, x); + var xmax = Math.max.apply(null, x); + var ymin = Math.min.apply(null, y); + var ymax = Math.max.apply(null, y); + var bbox = { + x: xmin, + y: ymin, + width: xmax - xmin, + height: ymax - ymin + }; + datum.bbox = bbox; + datum.center = { + x: (xmin + xmax) / 2, + y: (ymin + ymax) / 2 + }; + datum.totalLength = element.node().getTotalLength(); + } + if (tag == 'text') { + datum.center = { + x: element.attr('x'), + y: element.attr('y') + }; + } + if (tag == '#text') { + datum.text = element.text(); + } else if (tag == '#comment') { + datum.comment = element.text(); + } + return datum; + } + function extractAllElementsData(element) { + var datum = extractElementData(element); + datum.children = []; + var children = d3__namespace.selectAll(element.node().childNodes); + children.each(function () { + var childData = extractAllElementsData(d3__namespace.select(this)); + childData.parent = datum; + datum.children.push(childData); + }); + return datum; + } + function createElement(data) { + if (data.tag == '#text') { + return document.createTextNode(""); + } else if (data.tag == '#comment') { + return document.createComment(data.comment); + } else { + return document.createElementNS('http://www.w3.org/2000/svg', data.tag); + } + } + function createElementWithAttributes(data) { + var elementNode = createElement(data); + var element = d3__namespace.select(elementNode); + var attributes = data.attributes; + for (var _i = 0, _Object$keys = Object.keys(attributes); _i < _Object$keys.length; _i++) { + var attributeName = _Object$keys[_i]; + var attributeValue = attributes[attributeName]; + element.attr(attributeName, attributeValue); + } + return elementNode; + } + function replaceElement(element, data) { + var parent = d3__namespace.select(element.node().parentNode); + var newElementNode = createElementWithAttributes(data); + var newElement = parent.insert(function () { + return newElementNode; + }, function () { + return element.node(); + }); + element.remove(); + return newElement; + } + function insertElementData(element, datum) { + element.datum(datum); + element.data([datum], function (d) { + return d.key; + }); + } + function insertAllElementsData(element, datum) { + insertElementData(element, datum); + var children = d3__namespace.selectAll(element.node().childNodes); + children.each(function (d, i) { + insertAllElementsData(d3__namespace.select(this), datum.children[i]); + }); + } + function insertChildren(element, index) { + var children = element.selectAll(function () { + return element.node().childNodes; + }); + children = children.data(function (d) { + return d.children; + }, function (d) { + return d.tag + '-' + index; + }); + var childrenEnter = children.enter().append(function (d) { + return createElement(d); + }); + var childrenExit = children.exit(); + childrenExit = childrenExit.remove(); + children = childrenEnter.merge(children); + var childTagIndexes = {}; + children.each(function (childData) { + var childTag = childData.tag; + if (childTagIndexes[childTag] == null) { + childTagIndexes[childTag] = 0; + } + var childIndex = childTagIndexes[childTag]++; + attributeElement.call(this, childData, childIndex); + }); + } + function attributeElement(data) { + var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var element = d3__namespace.select(this); + data.tag; + var attributes = data.attributes; + var currentAttributes = element.node().attributes; + if (currentAttributes) { + for (var i = 0; i < currentAttributes.length; i++) { + var currentAttribute = currentAttributes[i]; + var name = currentAttribute.name; + if (name.split(':')[0] != 'xmlns' && currentAttribute.namespaceURI) { + var namespaceURIParts = currentAttribute.namespaceURI.split('/'); + var namespace = namespaceURIParts[namespaceURIParts.length - 1]; + name = namespace + ':' + name; + } + if (!(name in attributes)) { + attributes[name] = null; + } + } + } + for (var _i2 = 0, _Object$keys2 = Object.keys(attributes); _i2 < _Object$keys2.length; _i2++) { + var attributeName = _Object$keys2[_i2]; + element.attr(attributeName, attributes[attributeName]); + } + if (data.text) { + element.text(data.text); + } + insertChildren(element, index); + } + + function zoom (enable) { + this._options.zoom = enable; + if (this._options.zoom && !this._zoomBehavior) { + createZoomBehavior.call(this); + } else if (!this._options.zoom && this._zoomBehavior) { + this._zoomSelection.on(".zoom", null); + this._zoomBehavior = null; + } + return this; + } + function createZoomBehavior() { + var graphvizInstance = this; + function zoomed(event) { + var g = d3__namespace.select(svg.node().querySelector("g")); + g.attr('transform', event.transform); + graphvizInstance._dispatch.call('zoom', graphvizInstance); + } + var root = this._selection; + var svg = d3__namespace.select(root.node().querySelector("svg")); + if (svg.size() == 0) { + return this; + } + this._zoomSelection = svg; + var zoomBehavior = d3Zoom.zoom().scaleExtent(this._options.zoomScaleExtent).translateExtent(this._options.zoomTranslateExtent).interpolate(d3Interpolate.interpolate).on("zoom", zoomed); + this._zoomBehavior = zoomBehavior; + var g = d3__namespace.select(svg.node().querySelector("g")); + svg.call(zoomBehavior); + if (!this._active) { + translateZoomBehaviorTransform.call(this, g); + } + this._originalTransform = d3Zoom.zoomTransform(svg.node()); + return this; + } + function getTranslatedZoomTransform(selection) { + // Get the current zoom transform for the top level svg and + // translate it uniformly with the given selection, using the + // difference between the translation specified in the selection's + // data and it's saved previous translation. The selection is + // normally the top level g element of the graph. + var oldTranslation = this._translation; + var oldScale = this._scale; + var newTranslation = selection.datum().translation; + var newScale = selection.datum().scale; + var t = d3Zoom.zoomTransform(this._zoomSelection.node()); + if (oldTranslation) { + t = t.scale(1 / oldScale); + t = t.translate(-oldTranslation.x, -oldTranslation.y); + } + t = t.translate(newTranslation.x, newTranslation.y); + t = t.scale(newScale); + return t; + } + function translateZoomBehaviorTransform(selection) { + // Translate the current zoom transform for the top level svg + // uniformly with the given selection, using the difference + // between the translation specified in the selection's data and + // it's saved previous translation. The selection is normally the + // top level g element of the graph. + this._zoomBehavior.transform(this._zoomSelection, getTranslatedZoomTransform.call(this, selection)); + + // Save the selections's new translation and scale. + this._translation = selection.datum().translation; + this._scale = selection.datum().scale; + + // Set the original zoom transform to the translation and scale specified in + // the selection's data. + this._originalTransform = d3Zoom.zoomIdentity.translate(selection.datum().translation.x, selection.datum().translation.y).scale(selection.datum().scale); + } + function resetZoom(transition) { + // Reset the zoom transform to the original zoom transform. + var selection = this._zoomSelection; + if (transition) { + selection = selection.transition(transition); + } + selection.call(this._zoomBehavior.transform, this._originalTransform); + return this; + } + function zoomScaleExtent(extent) { + this._options.zoomScaleExtent = extent; + return this; + } + function zoomTranslateExtent(extent) { + this._options.zoomTranslateExtent = extent; + return this; + } + function zoomBehavior() { + return this._zoomBehavior || null; + } + function zoomSelection() { + return this._zoomSelection || null; + } + + function pathTween(points, d1) { + return function () { + var pointInterpolators = points.map(function (p) { + return d3Interpolate.interpolate([p[0][0], p[0][1]], [p[1][0], p[1][1]]); + }); + return function (t) { + return t < 1 ? "M" + pointInterpolators.map(function (p) { + return p(t); + }).join("L") : d1; + }; + }; + } + function pathTweenPoints(node, d1, precision, precisionIsRelative) { + var path0 = node; + var path1 = path0.cloneNode(); + var n0 = path0.getTotalLength(); + var n1 = (path1.setAttribute("d", d1), path1).getTotalLength(); + + // Uniform sampling of distance based on specified precision. + var distances = [0]; + var i = 0; + var dt = precisionIsRelative ? precision : precision / Math.max(n0, n1); + while ((i += dt) < 1) { + distances.push(i); + } + distances.push(1); + + // Compute point-interpolators at each distance. + var points = distances.map(function (t) { + var p0 = path0.getPointAtLength(t * n0); + var p1 = path1.getPointAtLength(t * n1); + return [[p0.x, p0.y], [p1.x, p1.y]]; + }); + return points; + } + + function data () { + return this._data || null; + } + function isEdgeElementParent(datum) { + return datum.attributes["class"] == 'edge' || datum.tag == 'a' && datum.parent.tag == 'g' && datum.parent.parent.attributes["class"] == 'edge'; + } + function isEdgeElement(datum) { + return datum.parent && isEdgeElementParent(datum.parent); + } + function getEdgeGroup(datum) { + if (datum.parent.attributes["class"] == 'edge') { + return datum.parent; + } else { + // datum.parent.tag == 'g' && datum.parent.parent.tag == 'g' && datum.parent.parent.parent.attributes.class == 'edge' + return datum.parent.parent.parent; + } + } + function getEdgeTitle(datum) { + return getEdgeGroup(datum).children.find(function (e) { + return e.tag == 'title'; + }); + } + + function render (callback) { + if (this._busy) { + this._queue.push(this.render.bind(this, callback)); + return this; + } + this._dispatch.call('renderStart', this); + if (this._transitionFactory) { + d3Timer.timeout(function () { + // Decouple from time spent. See https://github.com/d3/d3-timer/issues/27 + this._transition = d3Transition.transition(this._transitionFactory()); + _render.call(this, callback); + }.bind(this), 0); + } else { + _render.call(this, callback); + } + return this; + } + function _render(callback) { + var transitionInstance = this._transition; + var fade = this._options.fade && transitionInstance != null; + var tweenPaths = this._options.tweenPaths; + var tweenShapes = this._options.tweenShapes; + var convertEqualSidedPolygons = this._options.convertEqualSidedPolygons; + var growEnteringEdges = this._options.growEnteringEdges && transitionInstance != null; + var attributer = this._attributer; + var graphvizInstance = this; + function insertChildren(element) { + var children = element.selectAll(function () { + return element.node().childNodes; + }); + children = children.data(function (d) { + return d.children; + }, function (d) { + return d.key; + }); + var childrenEnter = children.enter().append(function (d) { + var element = createElement(d); + if (d.tag == '#text' && fade) { + element.nodeValue = d.text; + } + return element; + }); + if (fade || growEnteringEdges && isEdgeElementParent(element.datum())) { + var childElementsEnter = childrenEnter.filter(function (d) { + return d.tag[0] == '#' ? null : this; + }).each(function (d) { + var childEnter = d3__namespace.select(this); + for (var _i = 0, _Object$keys = Object.keys(d.attributes); _i < _Object$keys.length; _i++) { + var attributeName = _Object$keys[_i]; + var attributeValue = d.attributes[attributeName]; + childEnter.attr(attributeName, attributeValue); + } + }); + childElementsEnter.filter(function (d) { + return d.tag == 'svg' || d.tag == 'g' ? null : this; + }).style("opacity", 0.0); + } + var childrenExit = children.exit(); + if (attributer) { + childrenExit.each(attributer); + } + if (transitionInstance) { + childrenExit = childrenExit.transition(transitionInstance); + if (fade) { + childrenExit.filter(function (d) { + return d.tag[0] == '#' ? null : this; + }).style("opacity", 0.0); + } + } + childrenExit = childrenExit.remove(); + children = childrenEnter.merge(children).order(); + children.each(attributeElement); + } + function attributeElement(data) { + var element = d3__namespace.select(this); + if (data.tag == "svg") { + var options = graphvizInstance._options; + if (options.width != null || options.height != null) { + var width = options.width; + var height = options.height; + if (width == null) { + width = data.attributes.width.replace('pt', '') * 4 / 3; + } else { + element.attr("width", width); + data.attributes.width = width; + } + if (height == null) { + height = data.attributes.height.replace('pt', '') * 4 / 3; + } else { + element.attr("height", height); + data.attributes.height = height; + } + if (!options.fit) { + element.attr("viewBox", "0 0 ".concat(width * 3 / 4 / options.scale, " ").concat(height * 3 / 4 / options.scale)); + data.attributes.viewBox = "0 0 ".concat(width * 3 / 4 / options.scale, " ").concat(height * 3 / 4 / options.scale); + } + } + if (options.scale != 1 && (options.fit || options.width == null && options.height == null)) { + width = data.attributes.viewBox.split(' ')[2]; + height = data.attributes.viewBox.split(' ')[3]; + element.attr("viewBox", "0 0 ".concat(width / options.scale, " ").concat(height / options.scale)); + data.attributes.viewBox = "0 0 ".concat(width / options.scale, " ").concat(height / options.scale); + } + } + if (attributer) { + element.each(attributer); + } + var tag = data.tag; + var attributes = data.attributes; + var currentAttributes = element.node().attributes; + if (currentAttributes) { + for (var i = 0; i < currentAttributes.length; i++) { + var currentAttribute = currentAttributes[i]; + var name = currentAttribute.name; + if (name.split(':')[0] != 'xmlns' && currentAttribute.namespaceURI) { + var namespaceURIParts = currentAttribute.namespaceURI.split('/'); + var namespace = namespaceURIParts[namespaceURIParts.length - 1]; + name = namespace + ':' + name; + } + if (!(name in attributes)) { + attributes[name] = null; + } + } + } + var convertShape = false; + var convertPrevShape = false; + if (tweenShapes && transitionInstance) { + if ((this.nodeName == 'polygon' || this.nodeName == 'ellipse') && data.alternativeOld) { + convertPrevShape = true; + } + if ((tag == 'polygon' || tag == 'ellipse') && data.alternativeNew) { + convertShape = true; + } + if (this.nodeName == 'polygon' && tag == 'polygon' && data.alternativeOld) { + var prevData = extractElementData(element); + var prevPoints = prevData.attributes.points; + if (!convertEqualSidedPolygons) { + var nPrevPoints = prevPoints.split(' ').length; + var points = data.attributes.points; + var nPoints = points.split(' ').length; + if (nPoints == nPrevPoints) { + convertShape = false; + convertPrevShape = false; + } + } + } + if (convertPrevShape) { + var prevPathData = data.alternativeOld; + var pathElement = replaceElement(element, prevPathData); + pathElement.data([data], function () { + return data.key; + }); + element = pathElement; + } + if (convertShape) { + var newPathData = data.alternativeNew; + tag = 'path'; + attributes = newPathData.attributes; + } + } + var elementTransition = element; + if (transitionInstance) { + elementTransition = elementTransition.transition(transitionInstance); + if (fade) { + elementTransition.filter(function (d) { + return d.tag[0] == '#' ? null : this; + }).style("opacity", 1.0); + } + elementTransition.filter(function (d) { + return d.tag[0] == '#' ? null : this; + }).on("end", function (d) { + d3__namespace.select(this).attr('style', d && d.attributes && d.attributes.style || null); + }); + } + var growThisPath = growEnteringEdges && tag == 'path' && data.offset; + if (growThisPath) { + var totalLength = data.totalLength; + element.attr("stroke-dasharray", totalLength + " " + totalLength).attr("stroke-dashoffset", totalLength).attr('transform', 'translate(' + data.offset.x + ',' + data.offset.y + ')'); + attributes["stroke-dashoffset"] = 0; + attributes['transform'] = 'translate(0,0)'; + elementTransition.attr("stroke-dashoffset", attributes["stroke-dashoffset"]).attr('transform', attributes['transform']).on("start", function () { + d3__namespace.select(this).style('opacity', null); + }).on("end", function () { + d3__namespace.select(this).attr('stroke-dashoffset', null).attr('stroke-dasharray', null).attr('transform', null); + }); + } + var moveThisPolygon = growEnteringEdges && tag == 'polygon' && isEdgeElement(data) && data.offset && data.parent.children[3].tag == 'path'; + if (moveThisPolygon) { + var edgePath = d3__namespace.select(element.node().parentNode.querySelector("path")); + var p0 = edgePath.node().getPointAtLength(0); + var p1 = edgePath.node().getPointAtLength(data.totalLength); + var p2 = edgePath.node().getPointAtLength(data.totalLength - 1); + var angle1 = Math.atan2(p1.y - p2.y, p1.x - p2.x) * 180 / Math.PI; + var x = p0.x - p1.x + data.offset.x; + var y = p0.y - p1.y + data.offset.y; + element.attr('transform', 'translate(' + x + ',' + y + ')'); + elementTransition.attrTween("transform", function () { + return function (t) { + var p = edgePath.node().getPointAtLength(data.totalLength * t); + var p2 = edgePath.node().getPointAtLength(data.totalLength * t + 1); + var angle = Math.atan2(p2.y - p.y, p2.x - p.x) * 180 / Math.PI - angle1; + x = p.x - p1.x + data.offset.x * (1 - t); + y = p.y - p1.y + data.offset.y * (1 - t); + return 'translate(' + x + ',' + y + ') rotate(' + angle + ' ' + p1.x + ' ' + p1.y + ')'; + }; + }).on("start", function () { + d3__namespace.select(this).style('opacity', null); + }).on("end", function () { + d3__namespace.select(this).attr('transform', null); + }); + } + var tweenThisPath = tweenPaths && transitionInstance && tag == 'path' && element.attr('d') != null; + for (var _i2 = 0, _Object$keys2 = Object.keys(attributes); _i2 < _Object$keys2.length; _i2++) { + var attributeName = _Object$keys2[_i2]; + var attributeValue = attributes[attributeName]; + if (tweenThisPath && attributeName == 'd') { + var points = (data.alternativeOld || data).points; + if (points) { + elementTransition.attrTween("d", pathTween(points, attributeValue)); + } + } else { + if (attributeName == 'transform' && data.translation) { + if (transitionInstance) { + var onEnd = elementTransition.on("end"); + elementTransition.on("start", function () { + if (graphvizInstance._zoomBehavior) { + // Update the transform to transition to, just before the transition starts + // in order to catch changes between the transition scheduling to its start. + elementTransition.tween("attr.transform", function () { + var node = this; + return function (t) { + node.setAttribute("transform", d3Interpolate.interpolateTransformSvg(d3Zoom.zoomTransform(graphvizInstance._zoomSelection.node()).toString(), getTranslatedZoomTransform.call(graphvizInstance, element).toString())(t)); + }; + }); + } + }).on("end", function () { + onEnd.call(this); + // Update the zoom transform to the new translated transform + if (graphvizInstance._zoomBehavior) { + translateZoomBehaviorTransform.call(graphvizInstance, element); + } + }); + } else { + if (graphvizInstance._zoomBehavior) { + // Update the transform attribute to set with the current pan translation + translateZoomBehaviorTransform.call(graphvizInstance, element); + attributeValue = getTranslatedZoomTransform.call(graphvizInstance, element).toString(); + } + } + } + elementTransition.attr(attributeName, attributeValue); + } + } + if (convertShape) { + elementTransition.on("end", function (d, i, nodes) { + pathElement = d3__namespace.select(this); + var newElement = replaceElement(pathElement, d); + newElement.data([d], function () { + return d.key; + }); + }); + } + if (data.text) { + elementTransition.text(data.text); + } + insertChildren(element); + } + var root = this._selection; + if (transitionInstance != null) { + // Ensure original SVG shape elements are restored after transition before rendering new graph + var jobs = this._jobs; + if (graphvizInstance._active) { + jobs.push(null); + return this; + } else { + root.transition(transitionInstance).transition().duration(0).on("end", function () { + graphvizInstance._active = false; + if (jobs.length != 0) { + jobs.shift(); + graphvizInstance.render(); + } + }); + this._active = true; + } + } + if (transitionInstance != null) { + root.transition(transitionInstance).on("start", function () { + graphvizInstance._dispatch.call('transitionStart', graphvizInstance); + }).on("end", function () { + graphvizInstance._dispatch.call('transitionEnd', graphvizInstance); + }).transition().duration(0).on("start", function () { + graphvizInstance._dispatch.call('restoreEnd', graphvizInstance); + graphvizInstance._dispatch.call('end', graphvizInstance); + if (callback) { + callback.call(graphvizInstance); + } + }); + } + var data = this._data; + var svg = root.selectAll("svg").data([data], function (d) { + return d.key; + }); + svg = svg.enter().append("svg").merge(svg); + attributeElement.call(svg.node(), data); + if (this._options.zoom && !this._zoomBehavior) { + createZoomBehavior.call(this); + } + graphvizInstance._dispatch.call('renderEnd', graphvizInstance); + if (transitionInstance == null) { + this._dispatch.call('end', this); + if (callback) { + callback.call(this); + } + } + return this; + } + + function graphvizVersion () { + return this._graphvizVersion; + } + + var io=ArrayBuffer,H=Uint8Array,Qe=Uint16Array,so=Int16Array,qe=Int32Array,pr=function(p,c,d){if(H.prototype.slice)return H.prototype.slice.call(p,c,d);(c==null||c<0)&&(c=0),(d==null||d>p.length)&&(d=p.length);var s=new H(d-c);return s.set(p.subarray(c,d)),s},Ye=function(p,c,d,s){if(H.prototype.fill)return H.prototype.fill.call(p,c,d,s);for((d==null||d<0)&&(d=0),(s==null||s>p.length)&&(s=p.length);d<s;++d)p[d]=c;return p},uo=function(p,c,d,s){if(H.prototype.copyWithin)return H.prototype.copyWithin.call(p,c,d,s);for((d==null||d<0)&&(d=0),(s==null||s>p.length)&&(s=p.length);d<s;)p[c++]=p[d++];},po=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],T=function(p,c,d){var s=new Error(c||po[p]);if(s.code=p,Error.captureStackTrace&&Error.captureStackTrace(s,T),!d)throw s;return s},jr=function(p,c,d){for(var s=0,f=0;s<d;++s)f|=p[c++]<<(s<<3);return f},lo=function(p,c){return (p[c]|p[c+1]<<8|p[c+2]<<16|p[c+3]<<24)>>>0},co=function(p,c){var d=p[0]|p[1]<<8|p[2]<<16;if(d==3126568&&p[3]==253){var s=p[4],f=s>>5&1,m=s>>2&1,_=s&3,h=s>>6;s&8&&T(0);var M=6-f,I=_==3?4:_,Q=jr(p,M,I);M+=I;var Z=h?1<<h:f,Y=jr(p,M,Z)+(h==1&&256),z=Y;if(!f){var q=1<<10+(p[5]>>3);z=q+(q>>3)*(p[5]&7);}z>2145386496&&T(1);var X=new H((c==1?Y||z:c?0:z)+12);return X[0]=1,X[4]=4,X[8]=8,{b:M+Z,y:0,l:0,d:Q,w:c&&c!=1?c:X.subarray(12),e:z,o:new qe(X.buffer,0,3),u:Y,c:m,m:Math.min(131072,z)}}else if((d>>4|p[3]<<20)==25481893)return lo(p,4)+8;T(0);},Xe=function(p){for(var c=0;1<<c<=p;++c);return c-1},je=function(p,c,d){var s=(c<<3)+4,f=(p[c]&15)+5;f>d&&T(3);for(var m=1<<f,_=m,h=-1,M=-1,I=-1,Q=m,Z=new io(512+(m<<2)),Y=new so(Z,0,256),z=new Qe(Z,0,256),q=new Qe(Z,512,m),X=512+(m<<1),V=new H(Z,X,m),re=new H(Z,X+m);h<255&&_>0;){var S=Xe(_+1),P=s>>3,ae=(1<<S+1)-1,J=(p[P]|p[P+1]<<8|p[P+2]<<16)>>(s&7)&ae,w=(1<<S)-1,j=ae-_-1,W=J&w;if(W<j?(s+=S,J=W):(s+=S+1,J>w&&(J-=j)),Y[++h]=--J,J==-1?(_+=J,V[--Q]=h):_-=J,!J)do{var ie=s>>3;M=(p[ie]|p[ie+1]<<8)>>(s&7)&3,s+=2,h+=M;}while(M==3)}(h>255||_)&&T(0);for(var b=0,k=(m>>1)+(m>>3)+3,se=m-1,oe=0;oe<=h;++oe){var K=Y[oe];if(K<1){z[oe]=-K;continue}for(I=0;I<K;++I){V[b]=oe;do b=b+k&se;while(b>=Q)}}for(b&&T(0),I=0;I<m;++I){var L=z[V[I]]++,A=re[I]=f-Xe(L);q[I]=(L<<A)-m;}return [s+7>>3,{b:f,s:V,n:re,t:q}]},fo=function(p,c){var d=0,s=-1,f=new H(292),m=p[c],_=f.subarray(0,256),h=f.subarray(256,268),M=new Qe(f.buffer,268);if(m<128){var I=je(p,c+1,6),Q=I[0],Z=I[1];c+=m;var Y=Q<<3,z=p[c];z||T(0);for(var q=0,X=0,V=Z.b,re=V,S=(++c<<3)-8+Xe(z);S-=V,!(S<Y);){var P=S>>3;if(q+=(p[P]|p[P+1]<<8)>>(S&7)&(1<<V)-1,_[++s]=Z.s[q],S-=re,S<Y)break;P=S>>3,X+=(p[P]|p[P+1]<<8)>>(S&7)&(1<<re)-1,_[++s]=Z.s[X],V=Z.n[q],q=Z.t[q],re=Z.n[X],X=Z.t[X];}++s>255&&T(0);}else {for(s=m-127;d<s;d+=2){var ae=p[++c];_[d]=ae>>4,_[d+1]=ae&15;}++c;}var J=0;for(d=0;d<s;++d){var w=_[d];w>11&&T(0),J+=w&&1<<w-1;}var j=Xe(J)+1,W=1<<j,ie=W-J;for(ie&ie-1&&T(0),_[s++]=Xe(ie)+1,d=0;d<s;++d){var w=_[d];++h[_[d]=w&&j+1-w];}var b=new H(W<<1),k=b.subarray(0,W),se=b.subarray(W);for(M[j]=0,d=j;d>0;--d){var oe=M[d];Ye(se,d,oe,M[d-1]=oe+h[d]*(1<<j-d));}for(M[0]!=W&&T(0),d=0;d<s;++d){var K=_[d];if(K){var L=M[K];Ye(k,d,L,M[K]=L+(1<<j-K));}}return [c,{n:se,b:j,s:k}]},vo=je(new H([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],mo=je(new H([33,20,196,24,99,140,33,132,16,66,8,33,132,16,66,8,33,68,68,68,68,68,68,68,68,36,9]),0,6)[1],_o=je(new H([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],Pr=function(p,c){for(var d=p.length,s=new qe(d),f=0;f<d;++f)s[f]=c,c+=1<<p[f];return s},cr=new H(new qe([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),go=Pr(cr,0),dr=new H(new qe([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),ho=Pr(dr,3),Ze=function(p,c,d){var s=p.length,f=c.length,m=p[s-1],_=(1<<d.b)-1,h=-d.b;m||T(0);for(var M=0,I=d.b,Q=(s<<3)-8+Xe(m)-I,Z=-1;Q>h&&Z<f;){var Y=Q>>3,z=(p[Y]|p[Y+1]<<8|p[Y+2]<<16)>>(Q&7);M=(M<<I|z)&_,c[++Z]=d.s[M],Q-=I=d.n[M];}(Q!=h||Z+1!=f)&&T(0);},wo=function(p,c,d){var s=6,f=c.length,m=f+3>>2,_=m<<1,h=m+_;Ze(p.subarray(s,s+=p[0]|p[1]<<8),c.subarray(0,m),d),Ze(p.subarray(s,s+=p[2]|p[3]<<8),c.subarray(m,_),d),Ze(p.subarray(s,s+=p[4]|p[5]<<8),c.subarray(_,h),d),Ze(p.subarray(s),c.subarray(h),d);},yo=function(p,c,d){var s,f=c.b,m=p[f],_=m>>1&3;c.l=m&1;var h=m>>3|p[f+1]<<5|p[f+2]<<13,M=(f+=3)+h;if(_==1)return f>=p.length?void 0:(c.b=f+1,d?(Ye(d,p[f],c.y,c.y+=h),d):Ye(new H(h),p[f]));if(!(M>p.length)){if(_==0)return c.b=M,d?(d.set(p.subarray(f,M),c.y),c.y+=h,d):pr(p,f,M);if(_==2){var I=p[f],Q=I&3,Z=I>>2&3,Y=I>>4,z=0,q=0;Q<2?Z&1?Y|=p[++f]<<4|(Z&2&&p[++f]<<12):Y=I>>3:(q=Z,Z<2?(Y|=(p[++f]&63)<<4,z=p[f]>>6|p[++f]<<2):Z==2?(Y|=p[++f]<<4|(p[++f]&3)<<12,z=p[f]>>2|p[++f]<<6):(Y|=p[++f]<<4|(p[++f]&63)<<12,z=p[f]>>6|p[++f]<<2|p[++f]<<10)),++f;var X=d?d.subarray(c.y,c.y+c.m):new H(c.m),V=X.length-Y;if(Q==0)X.set(p.subarray(f,f+=Y),V);else if(Q==1)Ye(X,p[f++],V);else {var re=c.h;if(Q==2){var S=fo(p,f);z+=f-(f=S[0]),c.h=re=S[1];}else re||T(0);(q?wo:Ze)(p.subarray(f,f+=z),X.subarray(V),re);}var P=p[f++];if(P){P==255?P=(p[f++]|p[f++]<<8)+32512:P>127&&(P=P-128<<8|p[f++]);var ae=p[f++];ae&3&&T(0);for(var J=[mo,_o,vo],w=2;w>-1;--w){var j=ae>>(w<<1)+2&3;if(j==1){var W=new H([0,0,p[f++]]);J[w]={s:W.subarray(2,3),n:W.subarray(0,1),t:new Qe(W.buffer,0,1),b:0};}else j==2?(s=je(p,f,9-(w&1)),f=s[0],J[w]=s[1]):j==3&&(c.t||T(0),J[w]=c.t[w]);}var ie=c.t=J,b=ie[0],k=ie[1],se=ie[2],oe=p[M-1];oe||T(0);var K=(M<<3)-8+Xe(oe)-se.b,L=K>>3,A=0,Le=(p[L]|p[L+1]<<8)>>(K&7)&(1<<se.b)-1;L=(K-=k.b)>>3;var Be=(p[L]|p[L+1]<<8)>>(K&7)&(1<<k.b)-1;L=(K-=b.b)>>3;var Re=(p[L]|p[L+1]<<8)>>(K&7)&(1<<b.b)-1;for(++P;--P;){var Ne=se.s[Le],Pe=se.n[Le],Ve=b.s[Re],ye=b.n[Re],ke=k.s[Be],be=k.n[Be];L=(K-=ke)>>3;var $e=1<<ke,ce=$e+((p[L]|p[L+1]<<8|p[L+2]<<16|p[L+3]<<24)>>>(K&7)&$e-1);L=(K-=dr[Ve])>>3;var me=ho[Ve]+((p[L]|p[L+1]<<8|p[L+2]<<16)>>(K&7)&(1<<dr[Ve])-1);L=(K-=cr[Ne])>>3;var _e=go[Ne]+((p[L]|p[L+1]<<8|p[L+2]<<16)>>(K&7)&(1<<cr[Ne])-1);if(L=(K-=Pe)>>3,Le=se.t[Le]+((p[L]|p[L+1]<<8)>>(K&7)&(1<<Pe)-1),L=(K-=ye)>>3,Re=b.t[Re]+((p[L]|p[L+1]<<8)>>(K&7)&(1<<ye)-1),L=(K-=be)>>3,Be=k.t[Be]+((p[L]|p[L+1]<<8)>>(K&7)&(1<<be)-1),ce>3)c.o[2]=c.o[1],c.o[1]=c.o[0],c.o[0]=ce-=3;else {var Ge=ce-(_e!=0);Ge?(ce=Ge==3?c.o[0]-1:c.o[Ge],Ge>1&&(c.o[2]=c.o[1]),c.o[1]=c.o[0],c.o[0]=ce):ce=c.o[0];}for(var w=0;w<_e;++w)X[A+w]=X[V+w];A+=_e,V+=_e;var Ee=A-ce;if(Ee<0){var De=-Ee,We=c.e+Ee;De>me&&(De=me);for(var w=0;w<De;++w)X[A+w]=c.w[We+w];A+=De,me-=De,Ee=0;}for(var w=0;w<me;++w)X[A+w]=X[Ee+w];A+=me;}if(A!=V)for(;V<X.length;)X[A++]=X[V++];else A=X.length;d?c.y+=A:X=pr(X,0,A);}else if(d){if(c.y+=Y,V)for(var w=0;w<Y;++w)X[w]=X[V+w];}else V&&(X=pr(X,V));return c.b=M,X}T(2);}},bo=function(p,c){if(p.length==1)return p[0];for(var d=new H(c),s=0,f=0;s<p.length;++s){var m=p[s];d.set(m,f),f+=m.length;}return d};function Eo(p,c){for(var d=[],s=+!c,f=0,m=0;p.length;){var _=co(p,s||c);if(typeof _=="object"){for(s?(c=null,_.w.length==_.u&&(d.push(c=_.w),m+=_.u)):(d.push(c),_.e=0);!_.l;){var h=yo(p,_,c);h||T(5),c?_.e=_.y:(d.push(h),m+=h.length,uo(_.w,0,h.length),_.w.set(h,_.w.length-h.length));}f=_.b+_.c*4;}else f=_;p=p.subarray(f);}return bo(d,m)}var Mo=(()=>{typeof document<"u"?document.currentScript?.src:void 0;return function(c={}){var d,s=c,f,m,_=new Promise((e,r)=>{f=e,m=r;}),M=Object.assign({},s),I="./this.program",Q=(e,r)=>{throw r},Z="";function Y(e){return Z+e}var z,q,X=console.log.bind(console),V=console.error.bind(console);Object.assign(s,M),M=null;var re;s.wasmBinary&&(re=s.wasmBinary);var S,P=!1;function J(e,r){e||_e(r);}var w,j,W,b,k,oe;function K(){var e=S.buffer;s.HEAP8=w=new Int8Array(e),s.HEAP16=W=new Int16Array(e),s.HEAPU8=j=new Uint8Array(e),s.HEAPU16=new Uint16Array(e),s.HEAP32=b=new Int32Array(e),s.HEAPU32=k=new Uint32Array(e),s.HEAPF32=new Float32Array(e),s.HEAPF64=oe=new Float64Array(e);}var L=[],A=[],Le=[];function Re(){Ae(L);}function Ne(){!s.noFSInit&&!o.init.initialized&&o.init(),o.ignorePermissions=!1,Ae(A);}function Pe(){Ae(Le);}function Ve(e){A.unshift(e);}var ye=0,be=null;function ce(e){ye++;}function me(e){if(ye--,ye==0&&(be)){var r=be;be=null,r();}}function _e(e){e="Aborted("+e+")",V(e),P=!0,e+=". Build with -sASSERTIONS for more info.";var r=new WebAssembly.RuntimeError(e);throw m(r),r}var Ge="data:application/octet-stream;base64,",Ee=e=>e.startsWith(Ge),De=e=>e.startsWith("file://");function We(){var e="graphvizlib.wasm";return Ee(e)?e:Y(e)}var Je;function fr(e){if(e==Je&&re)return new Uint8Array(re);throw "both async and sync fetching of the wasm failed"}function Jr(e){return re?Promise.resolve().then(()=>fr(e)):z(e).then(r=>new Uint8Array(r),()=>fr(e))}function vr(e,r,t){return Jr(e).then(n=>WebAssembly.instantiate(n,r)).then(t,n=>{V(`failed to asynchronously prepare wasm: ${n}`),_e(n);})}function Sr(e,r,t,n){return !e&&typeof WebAssembly.instantiateStreaming=="function"&&!Ee(r)&&!De(r)&&typeof fetch=="function"?fetch(r,{credentials:"same-origin"}).then(a=>{var i=WebAssembly.instantiateStreaming(a,t);return i.then(n,function(u){return V(`wasm streaming compile failed: ${u}`),V("falling back to ArrayBuffer instantiation"),vr(r,t,n)})}):vr(r,t,n)}function Hr(){return {a:Qt}}function Tr(){var e=Hr();function r(n,a){return N=n.exports,S=N.B,K(),Ve(N.C),me(),N}ce();function t(n){r(n.instance);}return Je||(Je=We()),Sr(re,Je,e,t).catch(m),{}}var R,$,Qr={172808:(e,r)=>{var t=ue(e),n=ue(r);o.createPath("/",C.dirname(t)),o.writeFile(C.join("/",t),n);}};function qr(e){this.name="ExitStatus",this.message=`Program terminated with exit(${e})`,this.status=e;}var Ae=e=>{for(;e.length>0;)e.shift()(s);};class $r{constructor(r){this.excPtr=r,this.ptr=r-24;}set_type(r){k[this.ptr+4>>2]=r;}get_type(){return k[this.ptr+4>>2]}set_destructor(r){k[this.ptr+8>>2]=r;}get_destructor(){return k[this.ptr+8>>2]}set_caught(r){r=r?1:0,w[this.ptr+12]=r;}get_caught(){return w[this.ptr+12]!=0}set_rethrown(r){r=r?1:0,w[this.ptr+13]=r;}get_rethrown(){return w[this.ptr+13]!=0}init(r,t){this.set_adjusted_ptr(0),this.set_type(r),this.set_destructor(t);}set_adjusted_ptr(r){k[this.ptr+16>>2]=r;}get_adjusted_ptr(){return k[this.ptr+16>>2]}get_exception_ptr(){var r=Yr(this.get_type());if(r)return k[this.excPtr>>2];var t=this.get_adjusted_ptr();return t!==0?t:this.excPtr}}var mr=0,Ar=(e,r,t)=>{var n=new $r(e);throw n.init(r,t),mr=e,mr},C={isAbs:e=>e.charAt(0)==="/",splitPath:e=>{var r=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return r.exec(e).slice(1)},normalizeArray:(e,r)=>{for(var t=0,n=e.length-1;n>=0;n--){var a=e[n];a==="."?e.splice(n,1):a===".."?(e.splice(n,1),t++):t&&(e.splice(n,1),t--);}if(r)for(;t;t--)e.unshift("..");return e},normalize:e=>{var r=C.isAbs(e),t=e.substr(-1)==="/";return e=C.normalizeArray(e.split("/").filter(n=>!!n),!r).join("/"),!e&&!r&&(e="."),e&&t&&(e+="/"),(r?"/":"")+e},dirname:e=>{var r=C.splitPath(e),t=r[0],n=r[1];return !t&&!n?".":(n&&(n=n.substr(0,n.length-1)),t+n)},basename:e=>{if(e==="/")return "/";e=C.normalize(e),e=e.replace(/\/$/,"");var r=e.lastIndexOf("/");return r===-1?e:e.substr(r+1)},join:(...e)=>C.normalize(e.join("/")),join2:(e,r)=>C.normalize(e+"/"+r)},et=()=>{if(typeof crypto=="object"&&typeof crypto.getRandomValues=="function")return e=>crypto.getRandomValues(e);_e("initRandomDevice");},_r=e=>(_r=et())(e),he={resolve:(...e)=>{for(var r="",t=!1,n=e.length-1;n>=-1&&!t;n--){var a=n>=0?e[n]:o.cwd();if(typeof a!="string")throw new TypeError("Arguments to path.resolve must be strings");if(!a)return "";r=a+"/"+r,t=C.isAbs(a);}return r=C.normalizeArray(r.split("/").filter(i=>!!i),!t).join("/"),(t?"/":"")+r||"."},relative:(e,r)=>{e=he.resolve(e).substr(1),r=he.resolve(r).substr(1);function t(E){for(var G=0;G<E.length&&E[G]==="";G++);for(var x=E.length-1;x>=0&&E[x]==="";x--);return G>x?[]:E.slice(G,x-G+1)}for(var n=t(e.split("/")),a=t(r.split("/")),i=Math.min(n.length,a.length),u=i,l=0;l<i;l++)if(n[l]!==a[l]){u=l;break}for(var v=[],l=u;l<n.length;l++)v.push("..");return v=v.concat(a.slice(u)),v.join("/")}},gr=typeof TextDecoder<"u"?new TextDecoder:void 0,Fe=(e,r,t)=>{for(var n=r+t,a=r;e[a]&&!(a>=n);)++a;if(a-r>16&&e.buffer&&gr)return gr.decode(e.subarray(r,a));for(var i="";r<a;){var u=e[r++];if(!(u&128)){i+=String.fromCharCode(u);continue}var l=e[r++]&63;if((u&224)==192){i+=String.fromCharCode((u&31)<<6|l);continue}var v=e[r++]&63;if((u&240)==224?u=(u&15)<<12|l<<6|v:u=(u&7)<<18|l<<12|v<<6|e[r++]&63,u<65536)i+=String.fromCharCode(u);else {var E=u-65536;i+=String.fromCharCode(55296|E>>10,56320|E&1023);}}return i},er=[],rr=e=>{for(var r=0,t=0;t<e.length;++t){var n=e.charCodeAt(t);n<=127?r++:n<=2047?r+=2:n>=55296&&n<=57343?(r+=4,++t):r+=3;}return r},tr=(e,r,t,n)=>{if(!(n>0))return 0;for(var a=t,i=t+n-1,u=0;u<e.length;++u){var l=e.charCodeAt(u);if(l>=55296&&l<=57343){var v=e.charCodeAt(++u);l=65536+((l&1023)<<10)|v&1023;}if(l<=127){if(t>=i)break;r[t++]=l;}else if(l<=2047){if(t+1>=i)break;r[t++]=192|l>>6,r[t++]=128|l&63;}else if(l<=65535){if(t+2>=i)break;r[t++]=224|l>>12,r[t++]=128|l>>6&63,r[t++]=128|l&63;}else {if(t+3>=i)break;r[t++]=240|l>>18,r[t++]=128|l>>12&63,r[t++]=128|l>>6&63,r[t++]=128|l&63;}}return r[t]=0,t-a};function or(e,r,t){var n=rr(e)+1,a=new Array(n),i=tr(e,a,0,a.length);return r&&(a.length=i),a}var rt=()=>{if(!er.length){var e=null;if(!e)return null;er=or(e,!0);}return er.shift()},Me={ttys:[],init(){},shutdown(){},register(e,r){Me.ttys[e]={input:[],output:[],ops:r},o.registerDevice(e,Me.stream_ops);},stream_ops:{open(e){var r=Me.ttys[e.node.rdev];if(!r)throw new o.ErrnoError(43);e.tty=r,e.seekable=!1;},close(e){e.tty.ops.fsync(e.tty);},fsync(e){e.tty.ops.fsync(e.tty);},read(e,r,t,n,a){if(!e.tty||!e.tty.ops.get_char)throw new o.ErrnoError(60);for(var i=0,u=0;u<n;u++){var l;try{l=e.tty.ops.get_char(e.tty);}catch{throw new o.ErrnoError(29)}if(l===void 0&&i===0)throw new o.ErrnoError(6);if(l==null)break;i++,r[t+u]=l;}return i&&(e.node.timestamp=Date.now()),i},write(e,r,t,n,a){if(!e.tty||!e.tty.ops.put_char)throw new o.ErrnoError(60);try{for(var i=0;i<n;i++)e.tty.ops.put_char(e.tty,r[t+i]);}catch{throw new o.ErrnoError(29)}return n&&(e.node.timestamp=Date.now()),i}},default_tty_ops:{get_char(e){return rt()},put_char(e,r){r===null||r===10?(X(Fe(e.output,0)),e.output=[]):r!=0&&e.output.push(r);},fsync(e){e.output&&e.output.length>0&&(X(Fe(e.output,0)),e.output=[]);},ioctl_tcgets(e){return {c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(e,r,t){return 0},ioctl_tiocgwinsz(e){return [24,80]}},default_tty1_ops:{put_char(e,r){r===null||r===10?(V(Fe(e.output,0)),e.output=[]):r!=0&&e.output.push(r);},fsync(e){e.output&&e.output.length>0&&(V(Fe(e.output,0)),e.output=[]);}}},tt=(e,r)=>(j.fill(0,e,e+r),e),hr=(e,r)=>Math.ceil(e/r)*r,wr=e=>{e=hr(e,65536);var r=Zr(65536,e);return r?tt(r,e):0},D={ops_table:null,mount(e){return D.createNode(null,"/",16895,0)},createNode(e,r,t,n){if(o.isBlkdev(t)||o.isFIFO(t))throw new o.ErrnoError(63);D.ops_table||={dir:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr,lookup:D.node_ops.lookup,mknod:D.node_ops.mknod,rename:D.node_ops.rename,unlink:D.node_ops.unlink,rmdir:D.node_ops.rmdir,readdir:D.node_ops.readdir,symlink:D.node_ops.symlink},stream:{llseek:D.stream_ops.llseek}},file:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr},stream:{llseek:D.stream_ops.llseek,read:D.stream_ops.read,write:D.stream_ops.write,allocate:D.stream_ops.allocate,mmap:D.stream_ops.mmap,msync:D.stream_ops.msync}},link:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr,readlink:D.node_ops.readlink},stream:{}},chrdev:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr},stream:o.chrdev_stream_ops}};var a=o.createNode(e,r,t,n);return o.isDir(a.mode)?(a.node_ops=D.ops_table.dir.node,a.stream_ops=D.ops_table.dir.stream,a.contents={}):o.isFile(a.mode)?(a.node_ops=D.ops_table.file.node,a.stream_ops=D.ops_table.file.stream,a.usedBytes=0,a.contents=null):o.isLink(a.mode)?(a.node_ops=D.ops_table.link.node,a.stream_ops=D.ops_table.link.stream):o.isChrdev(a.mode)&&(a.node_ops=D.ops_table.chrdev.node,a.stream_ops=D.ops_table.chrdev.stream),a.timestamp=Date.now(),e&&(e.contents[r]=a,e.timestamp=a.timestamp),a},getFileDataAsTypedArray(e){return e.contents?e.contents.subarray?e.contents.subarray(0,e.usedBytes):new Uint8Array(e.contents):new Uint8Array(0)},expandFileStorage(e,r){var t=e.contents?e.contents.length:0;if(!(t>=r)){var n=1048576;r=Math.max(r,t*(t<n?2:1.125)>>>0),t!=0&&(r=Math.max(r,256));var a=e.contents;e.contents=new Uint8Array(r),e.usedBytes>0&&e.contents.set(a.subarray(0,e.usedBytes),0);}},resizeFileStorage(e,r){if(e.usedBytes!=r)if(r==0)e.contents=null,e.usedBytes=0;else {var t=e.contents;e.contents=new Uint8Array(r),t&&e.contents.set(t.subarray(0,Math.min(r,e.usedBytes))),e.usedBytes=r;}},node_ops:{getattr(e){var r={};return r.dev=o.isChrdev(e.mode)?e.id:1,r.ino=e.id,r.mode=e.mode,r.nlink=1,r.uid=0,r.gid=0,r.rdev=e.rdev,o.isDir(e.mode)?r.size=4096:o.isFile(e.mode)?r.size=e.usedBytes:o.isLink(e.mode)?r.size=e.link.length:r.size=0,r.atime=new Date(e.timestamp),r.mtime=new Date(e.timestamp),r.ctime=new Date(e.timestamp),r.blksize=4096,r.blocks=Math.ceil(r.size/r.blksize),r},setattr(e,r){r.mode!==void 0&&(e.mode=r.mode),r.timestamp!==void 0&&(e.timestamp=r.timestamp),r.size!==void 0&&D.resizeFileStorage(e,r.size);},lookup(e,r){throw o.genericErrors[44]},mknod(e,r,t,n){return D.createNode(e,r,t,n)},rename(e,r,t){if(o.isDir(e.mode)){var n;try{n=o.lookupNode(r,t);}catch{}if(n)for(var a in n.contents)throw new o.ErrnoError(55)}delete e.parent.contents[e.name],e.parent.timestamp=Date.now(),e.name=t,r.contents[t]=e,r.timestamp=e.parent.timestamp;},unlink(e,r){delete e.contents[r],e.timestamp=Date.now();},rmdir(e,r){var t=o.lookupNode(e,r);for(var n in t.contents)throw new o.ErrnoError(55);delete e.contents[r],e.timestamp=Date.now();},readdir(e){var r=[".",".."];for(var t of Object.keys(e.contents))r.push(t);return r},symlink(e,r,t){var n=D.createNode(e,r,41471,0);return n.link=t,n},readlink(e){if(!o.isLink(e.mode))throw new o.ErrnoError(28);return e.link}},stream_ops:{read(e,r,t,n,a){var i=e.node.contents;if(a>=e.node.usedBytes)return 0;var u=Math.min(e.node.usedBytes-a,n);if(u>8&&i.subarray)r.set(i.subarray(a,a+u),t);else for(var l=0;l<u;l++)r[t+l]=i[a+l];return u},write(e,r,t,n,a,i){if(r.buffer===w.buffer&&(i=!1),!n)return 0;var u=e.node;if(u.timestamp=Date.now(),r.subarray&&(!u.contents||u.contents.subarray)){if(i)return u.contents=r.subarray(t,t+n),u.usedBytes=n,n;if(u.usedBytes===0&&a===0)return u.contents=r.slice(t,t+n),u.usedBytes=n,n;if(a+n<=u.usedBytes)return u.contents.set(r.subarray(t,t+n),a),n}if(D.expandFileStorage(u,a+n),u.contents.subarray&&r.subarray)u.contents.set(r.subarray(t,t+n),a);else for(var l=0;l<n;l++)u.contents[a+l]=r[t+l];return u.usedBytes=Math.max(u.usedBytes,a+n),n},llseek(e,r,t){var n=r;if(t===1?n+=e.position:t===2&&o.isFile(e.node.mode)&&(n+=e.node.usedBytes),n<0)throw new o.ErrnoError(28);return n},allocate(e,r,t){D.expandFileStorage(e.node,r+t),e.node.usedBytes=Math.max(e.node.usedBytes,r+t);},mmap(e,r,t,n,a){if(!o.isFile(e.node.mode))throw new o.ErrnoError(43);var i,u,l=e.node.contents;if(!(a&2)&&l.buffer===w.buffer)u=!1,i=l.byteOffset;else {if((t>0||t+r<l.length)&&(l.subarray?l=l.subarray(t,t+r):l=Array.prototype.slice.call(l,t,t+r)),u=!0,i=wr(r),!i)throw new o.ErrnoError(48);w.set(l,i);}return {ptr:i,allocated:u}},msync(e,r,t,n,a){return D.stream_ops.write(e,r,0,n,t,!1),0}}},ot=(e,r,t,n)=>{var a=`al ${e}`;z(e).then(i=>{r(new Uint8Array(i)),a&&me();},i=>{if(t)t();else throw `Loading data file "${e}" failed.`}),a&&ce();},nt=(e,r,t,n,a,i)=>{o.createDataFile(e,r,t,n,a,i);},at=[],it=(e,r,t,n)=>{typeof Browser<"u"&&Browser.init();var a=!1;return at.forEach(i=>{a||i.canHandle(r)&&(i.handle(e,r,t,n),a=!0);}),a},st=(e,r,t,n,a,i,u,l,v,E)=>{var G=r?he.resolve(C.join2(e,r)):e;function B(y){function O(te){E?.(),l||nt(e,r,te,n,a,v),i?.(),me();}it(y,G,O,()=>{u?.(),me();})||O(y);}ce(),typeof t=="string"?ot(t,B,u):B(t);},ut=e=>{var r={r:0,"r+":2,w:577,"w+":578,a:1089,"a+":1090},t=r[e];if(typeof t>"u")throw new Error(`Unknown file open mode: ${e}`);return t},nr=(e,r)=>{var t=0;return e&&(t|=365),r&&(t|=146),t},o={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:!1,ignorePermissions:!0,ErrnoError:class{constructor(e){this.name="ErrnoError",this.errno=e;}},genericErrors:{},filesystems:null,syncFSRequests:0,FSStream:class{constructor(){this.shared={};}get object(){return this.node}set object(e){this.node=e;}get isRead(){return (this.flags&2097155)!==1}get isWrite(){return (this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(e){this.shared.flags=e;}get position(){return this.shared.position}set position(e){this.shared.position=e;}},FSNode:class{constructor(e,r,t,n){e||(e=this),this.parent=e,this.mount=e.mount,this.mounted=null,this.id=o.nextInode++,this.name=r,this.mode=t,this.node_ops={},this.stream_ops={},this.rdev=n,this.readMode=365,this.writeMode=146;}get read(){return (this.mode&this.readMode)===this.readMode}set read(e){e?this.mode|=this.readMode:this.mode&=~this.readMode;}get write(){return (this.mode&this.writeMode)===this.writeMode}set write(e){e?this.mode|=this.writeMode:this.mode&=~this.writeMode;}get isFolder(){return o.isDir(this.mode)}get isDevice(){return o.isChrdev(this.mode)}},lookupPath(e,r={}){if(e=he.resolve(e),!e)return {path:"",node:null};var t={follow_mount:!0,recurse_count:0};if(r=Object.assign(t,r),r.recurse_count>8)throw new o.ErrnoError(32);for(var n=e.split("/").filter(x=>!!x),a=o.root,i="/",u=0;u<n.length;u++){var l=u===n.length-1;if(l&&r.parent)break;if(a=o.lookupNode(a,n[u]),i=C.join2(i,n[u]),o.isMountpoint(a)&&(!l||l&&r.follow_mount)&&(a=a.mounted.root),!l||r.follow)for(var v=0;o.isLink(a.mode);){var E=o.readlink(i);i=he.resolve(C.dirname(i),E);var G=o.lookupPath(i,{recurse_count:r.recurse_count+1});if(a=G.node,v++>40)throw new o.ErrnoError(32)}}return {path:i,node:a}},getPath(e){for(var r;;){if(o.isRoot(e)){var t=e.mount.mountpoint;return r?t[t.length-1]!=="/"?`${t}/${r}`:t+r:t}r=r?`${e.name}/${r}`:e.name,e=e.parent;}},hashName(e,r){for(var t=0,n=0;n<r.length;n++)t=(t<<5)-t+r.charCodeAt(n)|0;return (e+t>>>0)%o.nameTable.length},hashAddNode(e){var r=o.hashName(e.parent.id,e.name);e.name_next=o.nameTable[r],o.nameTable[r]=e;},hashRemoveNode(e){var r=o.hashName(e.parent.id,e.name);if(o.nameTable[r]===e)o.nameTable[r]=e.name_next;else for(var t=o.nameTable[r];t;){if(t.name_next===e){t.name_next=e.name_next;break}t=t.name_next;}},lookupNode(e,r){var t=o.mayLookup(e);if(t)throw new o.ErrnoError(t);for(var n=o.hashName(e.id,r),a=o.nameTable[n];a;a=a.name_next){var i=a.name;if(a.parent.id===e.id&&i===r)return a}return o.lookup(e,r)},createNode(e,r,t,n){var a=new o.FSNode(e,r,t,n);return o.hashAddNode(a),a},destroyNode(e){o.hashRemoveNode(e);},isRoot(e){return e===e.parent},isMountpoint(e){return !!e.mounted},isFile(e){return (e&61440)===32768},isDir(e){return (e&61440)===16384},isLink(e){return (e&61440)===40960},isChrdev(e){return (e&61440)===8192},isBlkdev(e){return (e&61440)===24576},isFIFO(e){return (e&61440)===4096},isSocket(e){return (e&49152)===49152},flagsToPermissionString(e){var r=["r","w","rw"][e&3];return e&512&&(r+="w"),r},nodePermissions(e,r){return o.ignorePermissions?0:r.includes("r")&&!(e.mode&292)||r.includes("w")&&!(e.mode&146)||r.includes("x")&&!(e.mode&73)?2:0},mayLookup(e){if(!o.isDir(e.mode))return 54;var r=o.nodePermissions(e,"x");return r||(e.node_ops.lookup?0:2)},mayCreate(e,r){try{var t=o.lookupNode(e,r);return 20}catch{}return o.nodePermissions(e,"wx")},mayDelete(e,r,t){var n;try{n=o.lookupNode(e,r);}catch(i){return i.errno}var a=o.nodePermissions(e,"wx");if(a)return a;if(t){if(!o.isDir(n.mode))return 54;if(o.isRoot(n)||o.getPath(n)===o.cwd())return 10}else if(o.isDir(n.mode))return 31;return 0},mayOpen(e,r){return e?o.isLink(e.mode)?32:o.isDir(e.mode)&&(o.flagsToPermissionString(r)!=="r"||r&512)?31:o.nodePermissions(e,o.flagsToPermissionString(r)):44},MAX_OPEN_FDS:4096,nextfd(){for(var e=0;e<=o.MAX_OPEN_FDS;e++)if(!o.streams[e])return e;throw new o.ErrnoError(33)},getStreamChecked(e){var r=o.getStream(e);if(!r)throw new o.ErrnoError(8);return r},getStream:e=>o.streams[e],createStream(e,r=-1){return e=Object.assign(new o.FSStream,e),r==-1&&(r=o.nextfd()),e.fd=r,o.streams[r]=e,e},closeStream(e){o.streams[e]=null;},dupStream(e,r=-1){var t=o.createStream(e,r);return t.stream_ops?.dup?.(t),t},chrdev_stream_ops:{open(e){var r=o.getDevice(e.node.rdev);e.stream_ops=r.stream_ops,e.stream_ops.open?.(e);},llseek(){throw new o.ErrnoError(70)}},major:e=>e>>8,minor:e=>e&255,makedev:(e,r)=>e<<8|r,registerDevice(e,r){o.devices[e]={stream_ops:r};},getDevice:e=>o.devices[e],getMounts(e){for(var r=[],t=[e];t.length;){var n=t.pop();r.push(n),t.push(...n.mounts);}return r},syncfs(e,r){typeof e=="function"&&(r=e,e=!1),o.syncFSRequests++,o.syncFSRequests>1&&V(`warning: ${o.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);var t=o.getMounts(o.root.mount),n=0;function a(u){return o.syncFSRequests--,r(u)}function i(u){if(u)return i.errored?void 0:(i.errored=!0,a(u));++n>=t.length&&a(null);}t.forEach(u=>{if(!u.type.syncfs)return i(null);u.type.syncfs(u,e,i);});},mount(e,r,t){var n=t==="/",a=!t,i;if(n&&o.root)throw new o.ErrnoError(10);if(!n&&!a){var u=o.lookupPath(t,{follow_mount:!1});if(t=u.path,i=u.node,o.isMountpoint(i))throw new o.ErrnoError(10);if(!o.isDir(i.mode))throw new o.ErrnoError(54)}var l={type:e,opts:r,mountpoint:t,mounts:[]},v=e.mount(l);return v.mount=l,l.root=v,n?o.root=v:i&&(i.mounted=l,i.mount&&i.mount.mounts.push(l)),v},unmount(e){var r=o.lookupPath(e,{follow_mount:!1});if(!o.isMountpoint(r.node))throw new o.ErrnoError(28);var t=r.node,n=t.mounted,a=o.getMounts(n);Object.keys(o.nameTable).forEach(u=>{for(var l=o.nameTable[u];l;){var v=l.name_next;a.includes(l.mount)&&o.destroyNode(l),l=v;}}),t.mounted=null;var i=t.mount.mounts.indexOf(n);t.mount.mounts.splice(i,1);},lookup(e,r){return e.node_ops.lookup(e,r)},mknod(e,r,t){var n=o.lookupPath(e,{parent:!0}),a=n.node,i=C.basename(e);if(!i||i==="."||i==="..")throw new o.ErrnoError(28);var u=o.mayCreate(a,i);if(u)throw new o.ErrnoError(u);if(!a.node_ops.mknod)throw new o.ErrnoError(63);return a.node_ops.mknod(a,i,r,t)},create(e,r){return r=r!==void 0?r:438,r&=4095,r|=32768,o.mknod(e,r,0)},mkdir(e,r){return r=r!==void 0?r:511,r&=1023,r|=16384,o.mknod(e,r,0)},mkdirTree(e,r){for(var t=e.split("/"),n="",a=0;a<t.length;++a)if(t[a]){n+="/"+t[a];try{o.mkdir(n,r);}catch(i){if(i.errno!=20)throw i}}},mkdev(e,r,t){return typeof t>"u"&&(t=r,r=438),r|=8192,o.mknod(e,r,t)},symlink(e,r){if(!he.resolve(e))throw new o.ErrnoError(44);var t=o.lookupPath(r,{parent:!0}),n=t.node;if(!n)throw new o.ErrnoError(44);var a=C.basename(r),i=o.mayCreate(n,a);if(i)throw new o.ErrnoError(i);if(!n.node_ops.symlink)throw new o.ErrnoError(63);return n.node_ops.symlink(n,a,e)},rename(e,r){var t=C.dirname(e),n=C.dirname(r),a=C.basename(e),i=C.basename(r),u,l,v;if(u=o.lookupPath(e,{parent:!0}),l=u.node,u=o.lookupPath(r,{parent:!0}),v=u.node,!l||!v)throw new o.ErrnoError(44);if(l.mount!==v.mount)throw new o.ErrnoError(75);var E=o.lookupNode(l,a),G=he.relative(e,n);if(G.charAt(0)!==".")throw new o.ErrnoError(28);if(G=he.relative(r,t),G.charAt(0)!==".")throw new o.ErrnoError(55);var x;try{x=o.lookupNode(v,i);}catch{}if(E!==x){var B=o.isDir(E.mode),y=o.mayDelete(l,a,B);if(y)throw new o.ErrnoError(y);if(y=x?o.mayDelete(v,i,B):o.mayCreate(v,i),y)throw new o.ErrnoError(y);if(!l.node_ops.rename)throw new o.ErrnoError(63);if(o.isMountpoint(E)||x&&o.isMountpoint(x))throw new o.ErrnoError(10);if(v!==l&&(y=o.nodePermissions(l,"w"),y))throw new o.ErrnoError(y);o.hashRemoveNode(E);try{l.node_ops.rename(E,v,i),E.parent=v;}catch(O){throw O}finally{o.hashAddNode(E);}}},rmdir(e){var r=o.lookupPath(e,{parent:!0}),t=r.node,n=C.basename(e),a=o.lookupNode(t,n),i=o.mayDelete(t,n,!0);if(i)throw new o.ErrnoError(i);if(!t.node_ops.rmdir)throw new o.ErrnoError(63);if(o.isMountpoint(a))throw new o.ErrnoError(10);t.node_ops.rmdir(t,n),o.destroyNode(a);},readdir(e){var r=o.lookupPath(e,{follow:!0}),t=r.node;if(!t.node_ops.readdir)throw new o.ErrnoError(54);return t.node_ops.readdir(t)},unlink(e){var r=o.lookupPath(e,{parent:!0}),t=r.node;if(!t)throw new o.ErrnoError(44);var n=C.basename(e),a=o.lookupNode(t,n),i=o.mayDelete(t,n,!1);if(i)throw new o.ErrnoError(i);if(!t.node_ops.unlink)throw new o.ErrnoError(63);if(o.isMountpoint(a))throw new o.ErrnoError(10);t.node_ops.unlink(t,n),o.destroyNode(a);},readlink(e){var r=o.lookupPath(e),t=r.node;if(!t)throw new o.ErrnoError(44);if(!t.node_ops.readlink)throw new o.ErrnoError(28);return he.resolve(o.getPath(t.parent),t.node_ops.readlink(t))},stat(e,r){var t=o.lookupPath(e,{follow:!r}),n=t.node;if(!n)throw new o.ErrnoError(44);if(!n.node_ops.getattr)throw new o.ErrnoError(63);return n.node_ops.getattr(n)},lstat(e){return o.stat(e,!0)},chmod(e,r,t){var n;if(typeof e=="string"){var a=o.lookupPath(e,{follow:!t});n=a.node;}else n=e;if(!n.node_ops.setattr)throw new o.ErrnoError(63);n.node_ops.setattr(n,{mode:r&4095|n.mode&-4096,timestamp:Date.now()});},lchmod(e,r){o.chmod(e,r,!0);},fchmod(e,r){var t=o.getStreamChecked(e);o.chmod(t.node,r);},chown(e,r,t,n){var a;if(typeof e=="string"){var i=o.lookupPath(e,{follow:!n});a=i.node;}else a=e;if(!a.node_ops.setattr)throw new o.ErrnoError(63);a.node_ops.setattr(a,{timestamp:Date.now()});},lchown(e,r,t){o.chown(e,r,t,!0);},fchown(e,r,t){var n=o.getStreamChecked(e);o.chown(n.node,r,t);},truncate(e,r){if(r<0)throw new o.ErrnoError(28);var t;if(typeof e=="string"){var n=o.lookupPath(e,{follow:!0});t=n.node;}else t=e;if(!t.node_ops.setattr)throw new o.ErrnoError(63);if(o.isDir(t.mode))throw new o.ErrnoError(31);if(!o.isFile(t.mode))throw new o.ErrnoError(28);var a=o.nodePermissions(t,"w");if(a)throw new o.ErrnoError(a);t.node_ops.setattr(t,{size:r,timestamp:Date.now()});},ftruncate(e,r){var t=o.getStreamChecked(e);if(!(t.flags&2097155))throw new o.ErrnoError(28);o.truncate(t.node,r);},utime(e,r,t){var n=o.lookupPath(e,{follow:!0}),a=n.node;a.node_ops.setattr(a,{timestamp:Math.max(r,t)});},open(e,r,t){if(e==="")throw new o.ErrnoError(44);r=typeof r=="string"?ut(r):r,r&64?(t=typeof t>"u"?438:t,t=t&4095|32768):t=0;var n;if(typeof e=="object")n=e;else {e=C.normalize(e);try{var a=o.lookupPath(e,{follow:!(r&131072)});n=a.node;}catch{}}var i=!1;if(r&64)if(n){if(r&128)throw new o.ErrnoError(20)}else n=o.mknod(e,t,0),i=!0;if(!n)throw new o.ErrnoError(44);if(o.isChrdev(n.mode)&&(r&=-513),r&65536&&!o.isDir(n.mode))throw new o.ErrnoError(54);if(!i){var u=o.mayOpen(n,r);if(u)throw new o.ErrnoError(u)}r&512&&!i&&o.truncate(n,0),r&=-131713;var l=o.createStream({node:n,path:o.getPath(n),flags:r,seekable:!0,position:0,stream_ops:n.stream_ops,ungotten:[],error:!1});return l.stream_ops.open&&l.stream_ops.open(l),s.logReadFiles&&!(r&1)&&(o.readFiles||(o.readFiles={}),e in o.readFiles||(o.readFiles[e]=1)),l},close(e){if(o.isClosed(e))throw new o.ErrnoError(8);e.getdents&&(e.getdents=null);try{e.stream_ops.close&&e.stream_ops.close(e);}catch(r){throw r}finally{o.closeStream(e.fd);}e.fd=null;},isClosed(e){return e.fd===null},llseek(e,r,t){if(o.isClosed(e))throw new o.ErrnoError(8);if(!e.seekable||!e.stream_ops.llseek)throw new o.ErrnoError(70);if(t!=0&&t!=1&&t!=2)throw new o.ErrnoError(28);return e.position=e.stream_ops.llseek(e,r,t),e.ungotten=[],e.position},read(e,r,t,n,a){if(n<0||a<0)throw new o.ErrnoError(28);if(o.isClosed(e))throw new o.ErrnoError(8);if((e.flags&2097155)===1)throw new o.ErrnoError(8);if(o.isDir(e.node.mode))throw new o.ErrnoError(31);if(!e.stream_ops.read)throw new o.ErrnoError(28);var i=typeof a<"u";if(!i)a=e.position;else if(!e.seekable)throw new o.ErrnoError(70);var u=e.stream_ops.read(e,r,t,n,a);return i||(e.position+=u),u},write(e,r,t,n,a,i){if(n<0||a<0)throw new o.ErrnoError(28);if(o.isClosed(e))throw new o.ErrnoError(8);if(!(e.flags&2097155))throw new o.ErrnoError(8);if(o.isDir(e.node.mode))throw new o.ErrnoError(31);if(!e.stream_ops.write)throw new o.ErrnoError(28);e.seekable&&e.flags&1024&&o.llseek(e,0,2);var u=typeof a<"u";if(!u)a=e.position;else if(!e.seekable)throw new o.ErrnoError(70);var l=e.stream_ops.write(e,r,t,n,a,i);return u||(e.position+=l),l},allocate(e,r,t){if(o.isClosed(e))throw new o.ErrnoError(8);if(r<0||t<=0)throw new o.ErrnoError(28);if(!(e.flags&2097155))throw new o.ErrnoError(8);if(!o.isFile(e.node.mode)&&!o.isDir(e.node.mode))throw new o.ErrnoError(43);if(!e.stream_ops.allocate)throw new o.ErrnoError(138);e.stream_ops.allocate(e,r,t);},mmap(e,r,t,n,a){if(n&2&&!(a&2)&&(e.flags&2097155)!==2)throw new o.ErrnoError(2);if((e.flags&2097155)===1)throw new o.ErrnoError(2);if(!e.stream_ops.mmap)throw new o.ErrnoError(43);return e.stream_ops.mmap(e,r,t,n,a)},msync(e,r,t,n,a){return e.stream_ops.msync?e.stream_ops.msync(e,r,t,n,a):0},ioctl(e,r,t){if(!e.stream_ops.ioctl)throw new o.ErrnoError(59);return e.stream_ops.ioctl(e,r,t)},readFile(e,r={}){if(r.flags=r.flags||0,r.encoding=r.encoding||"binary",r.encoding!=="utf8"&&r.encoding!=="binary")throw new Error(`Invalid encoding type "${r.encoding}"`);var t,n=o.open(e,r.flags),a=o.stat(e),i=a.size,u=new Uint8Array(i);return o.read(n,u,0,i,0),r.encoding==="utf8"?t=Fe(u,0):r.encoding==="binary"&&(t=u),o.close(n),t},writeFile(e,r,t={}){t.flags=t.flags||577;var n=o.open(e,t.flags,t.mode);if(typeof r=="string"){var a=new Uint8Array(rr(r)+1),i=tr(r,a,0,a.length);o.write(n,a,0,i,void 0,t.canOwn);}else if(ArrayBuffer.isView(r))o.write(n,r,0,r.byteLength,void 0,t.canOwn);else throw new Error("Unsupported data type");o.close(n);},cwd:()=>o.currentPath,chdir(e){var r=o.lookupPath(e,{follow:!0});if(r.node===null)throw new o.ErrnoError(44);if(!o.isDir(r.node.mode))throw new o.ErrnoError(54);var t=o.nodePermissions(r.node,"x");if(t)throw new o.ErrnoError(t);o.currentPath=r.path;},createDefaultDirectories(){o.mkdir("/tmp"),o.mkdir("/home"),o.mkdir("/home/web_user");},createDefaultDevices(){o.mkdir("/dev"),o.registerDevice(o.makedev(1,3),{read:()=>0,write:(n,a,i,u,l)=>u}),o.mkdev("/dev/null",o.makedev(1,3)),Me.register(o.makedev(5,0),Me.default_tty_ops),Me.register(o.makedev(6,0),Me.default_tty1_ops),o.mkdev("/dev/tty",o.makedev(5,0)),o.mkdev("/dev/tty1",o.makedev(6,0));var e=new Uint8Array(1024),r=0,t=()=>(r===0&&(r=_r(e).byteLength),e[--r]);o.createDevice("/dev","random",t),o.createDevice("/dev","urandom",t),o.mkdir("/dev/shm"),o.mkdir("/dev/shm/tmp");},createSpecialDirectories(){o.mkdir("/proc");var e=o.mkdir("/proc/self");o.mkdir("/proc/self/fd"),o.mount({mount(){var r=o.createNode(e,"fd",16895,73);return r.node_ops={lookup(t,n){var a=+n,i=o.getStreamChecked(a),u={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>i.path}};return u.parent=u,u}},r}},{},"/proc/self/fd");},createStandardStreams(){s.stdin?o.createDevice("/dev","stdin",s.stdin):o.symlink("/dev/tty","/dev/stdin"),s.stdout?o.createDevice("/dev","stdout",null,s.stdout):o.symlink("/dev/tty","/dev/stdout"),s.stderr?o.createDevice("/dev","stderr",null,s.stderr):o.symlink("/dev/tty1","/dev/stderr");o.open("/dev/stdin",0);o.open("/dev/stdout",1);o.open("/dev/stderr",1);},staticInit(){[44].forEach(e=>{o.genericErrors[e]=new o.ErrnoError(e),o.genericErrors[e].stack="<generic error, no stack>";}),o.nameTable=new Array(4096),o.mount(D,{},"/"),o.createDefaultDirectories(),o.createDefaultDevices(),o.createSpecialDirectories(),o.filesystems={MEMFS:D};},init(e,r,t){o.init.initialized=!0,s.stdin=e||s.stdin,s.stdout=r||s.stdout,s.stderr=t||s.stderr,o.createStandardStreams();},quit(){o.init.initialized=!1;for(var e=0;e<o.streams.length;e++){var r=o.streams[e];r&&o.close(r);}},findObject(e,r){var t=o.analyzePath(e,r);return t.exists?t.object:null},analyzePath(e,r){try{var t=o.lookupPath(e,{follow:!r});e=t.path;}catch{}var n={isRoot:!1,exists:!1,error:0,name:null,path:null,object:null,parentExists:!1,parentPath:null,parentObject:null};try{var t=o.lookupPath(e,{parent:!0});n.parentExists=!0,n.parentPath=t.path,n.parentObject=t.node,n.name=C.basename(e),t=o.lookupPath(e,{follow:!r}),n.exists=!0,n.path=t.path,n.object=t.node,n.name=t.node.name,n.isRoot=t.path==="/";}catch(a){n.error=a.errno;}return n},createPath(e,r,t,n){e=typeof e=="string"?e:o.getPath(e);for(var a=r.split("/").reverse();a.length;){var i=a.pop();if(i){var u=C.join2(e,i);try{o.mkdir(u);}catch{}e=u;}}return u},createFile(e,r,t,n,a){var i=C.join2(typeof e=="string"?e:o.getPath(e),r),u=nr(n,a);return o.create(i,u)},createDataFile(e,r,t,n,a,i){var u=r;e&&(e=typeof e=="string"?e:o.getPath(e),u=r?C.join2(e,r):e);var l=nr(n,a),v=o.create(u,l);if(t){if(typeof t=="string"){for(var E=new Array(t.length),G=0,x=t.length;G<x;++G)E[G]=t.charCodeAt(G);t=E;}o.chmod(v,l|146);var B=o.open(v,577);o.write(B,t,0,t.length,0,i),o.close(B),o.chmod(v,l);}},createDevice(e,r,t,n){var a=C.join2(typeof e=="string"?e:o.getPath(e),r),i=nr(!!t,!!n);o.createDevice.major||(o.createDevice.major=64);var u=o.makedev(o.createDevice.major++,0);return o.registerDevice(u,{open(l){l.seekable=!1;},close(l){n?.buffer?.length&&n(10);},read(l,v,E,G,x){for(var B=0,y=0;y<G;y++){var O;try{O=t();}catch{throw new o.ErrnoError(29)}if(O===void 0&&B===0)throw new o.ErrnoError(6);if(O==null)break;B++,v[E+y]=O;}return B&&(l.node.timestamp=Date.now()),B},write(l,v,E,G,x){for(var B=0;B<G;B++)try{n(v[E+B]);}catch{throw new o.ErrnoError(29)}return G&&(l.node.timestamp=Date.now()),B}}),o.mkdev(a,i,u)},forceLoadFile(e){if(e.isDevice||e.isFolder||e.link||e.contents)return !0;if(typeof XMLHttpRequest<"u")throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");try{e.contents=q(e.url),e.usedBytes=e.contents.length;}catch{throw new o.ErrnoError(29)}},createLazyFile(e,r,t,n,a){class i{constructor(){this.lengthKnown=!1,this.chunks=[];}get(y){if(!(y>this.length-1||y<0)){var O=y%this.chunkSize,te=y/this.chunkSize|0;return this.getter(te)[O]}}setDataGetter(y){this.getter=y;}cacheLength(){var y=new XMLHttpRequest;if(y.open("HEAD",t,!1),y.send(null),!(y.status>=200&&y.status<300||y.status===304))throw new Error("Couldn't load "+t+". Status: "+y.status);var O=Number(y.getResponseHeader("Content-length")),te,de=(te=y.getResponseHeader("Accept-Ranges"))&&te==="bytes",ne=(te=y.getResponseHeader("Content-Encoding"))&&te==="gzip",fe=1024*1024;de||(fe=O);var ve=(ge,xe)=>{if(ge>xe)throw new Error("invalid range ("+ge+", "+xe+") or no bytes requested!");if(xe>O-1)throw new Error("only "+O+" bytes available! programmer error!");var ee=new XMLHttpRequest;if(ee.open("GET",t,!1),O!==fe&&ee.setRequestHeader("Range","bytes="+ge+"-"+xe),ee.responseType="arraybuffer",ee.overrideMimeType&&ee.overrideMimeType("text/plain; charset=x-user-defined"),ee.send(null),!(ee.status>=200&&ee.status<300||ee.status===304))throw new Error("Couldn't load "+t+". Status: "+ee.status);return ee.response!==void 0?new Uint8Array(ee.response||[]):or(ee.responseText||"",!0)},Ie=this;Ie.setDataGetter(ge=>{var xe=ge*fe,ee=(ge+1)*fe-1;if(ee=Math.min(ee,O-1),typeof Ie.chunks[ge]>"u"&&(Ie.chunks[ge]=ve(xe,ee)),typeof Ie.chunks[ge]>"u")throw new Error("doXHR failed!");return Ie.chunks[ge]}),(ne||!O)&&(fe=O=1,O=this.getter(0).length,fe=O,X("LazyFiles on gzip forces download of the whole file when length is accessed")),this._length=O,this._chunkSize=fe,this.lengthKnown=!0;}get length(){return this.lengthKnown||this.cacheLength(),this._length}get chunkSize(){return this.lengthKnown||this.cacheLength(),this._chunkSize}}if(typeof XMLHttpRequest<"u"){throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var u=new i,l={isDevice:!1,contents:u};}else var l={isDevice:!1,url:t};var v=o.createFile(e,r,l,n,a);l.contents?v.contents=l.contents:l.url&&(v.contents=null,v.url=l.url),Object.defineProperties(v,{usedBytes:{get:function(){return this.contents.length}}});var E={},G=Object.keys(v.stream_ops);G.forEach(B=>{var y=v.stream_ops[B];E[B]=(...O)=>(o.forceLoadFile(v),y(...O));});function x(B,y,O,te,de){var ne=B.node.contents;if(de>=ne.length)return 0;var fe=Math.min(ne.length-de,te);if(ne.slice)for(var ve=0;ve<fe;ve++)y[O+ve]=ne[de+ve];else for(var ve=0;ve<fe;ve++)y[O+ve]=ne.get(de+ve);return fe}return E.read=(B,y,O,te,de)=>(o.forceLoadFile(v),x(B,y,O,te,de)),E.mmap=(B,y,O,te,de)=>{o.forceLoadFile(v);var ne=wr(y);if(!ne)throw new o.ErrnoError(48);return x(B,w,ne,y,O),{ptr:ne,allocated:!0}},v.stream_ops=E,v}},ue=(e,r)=>e?Fe(j,e,r):"",U={DEFAULT_POLLMASK:5,calculateAt(e,r,t){if(C.isAbs(r))return r;var n;if(e===-100)n=o.cwd();else {var a=U.getStreamFromFD(e);n=a.path;}if(r.length==0){if(!t)throw new o.ErrnoError(44);return n}return C.join2(n,r)},doStat(e,r,t){var n=e(r);b[t>>2]=n.dev,b[t+4>>2]=n.mode,k[t+8>>2]=n.nlink,b[t+12>>2]=n.uid,b[t+16>>2]=n.gid,b[t+20>>2]=n.rdev,$=[n.size>>>0,(R=n.size,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+24>>2]=$[0],b[t+28>>2]=$[1],b[t+32>>2]=4096,b[t+36>>2]=n.blocks;var a=n.atime.getTime(),i=n.mtime.getTime(),u=n.ctime.getTime();return $=[Math.floor(a/1e3)>>>0,(R=Math.floor(a/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+40>>2]=$[0],b[t+44>>2]=$[1],k[t+48>>2]=a%1e3*1e3,$=[Math.floor(i/1e3)>>>0,(R=Math.floor(i/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+56>>2]=$[0],b[t+60>>2]=$[1],k[t+64>>2]=i%1e3*1e3,$=[Math.floor(u/1e3)>>>0,(R=Math.floor(u/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+72>>2]=$[0],b[t+76>>2]=$[1],k[t+80>>2]=u%1e3*1e3,$=[n.ino>>>0,(R=n.ino,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+88>>2]=$[0],b[t+92>>2]=$[1],0},doMsync(e,r,t,n,a){if(!o.isFile(r.node.mode))throw new o.ErrnoError(43);if(n&2)return 0;var i=j.slice(e,e+t);o.msync(r,i,a,t,n);},getStreamFromFD(e){var r=o.getStreamChecked(e);return r},varargs:void 0,getStr(e){var r=ue(e);return r}};function pt(e,r,t,n){try{if(r=U.getStr(r),r=U.calculateAt(e,r),t&-8)return -28;var a=o.lookupPath(r,{follow:!0}),i=a.node;if(!i)return -44;var u="";return t&4&&(u+="r"),t&2&&(u+="w"),t&1&&(u+="x"),u&&o.nodePermissions(i,u)?-2:0}catch(l){if(typeof o>"u"||l.name!=="ErrnoError")throw l;return -l.errno}}function Se(){var e=b[+U.varargs>>2];return U.varargs+=4,e}var Oe=Se;function lt(e,r,t){U.varargs=t;try{var n=U.getStreamFromFD(e);switch(r){case 0:{var a=Se();if(a<0)return -28;for(;o.streams[a];)a++;var i;return i=o.dupStream(n,a),i.fd}case 1:case 2:return 0;case 3:return n.flags;case 4:{var a=Se();return n.flags|=a,0}case 12:{var a=Oe(),u=0;return W[a+u>>1]=2,0}case 13:case 14:return 0}return -28}catch(l){if(typeof o>"u"||l.name!=="ErrnoError")throw l;return -l.errno}}function ct(e,r){try{var t=U.getStreamFromFD(e);return U.doStat(o.stat,t.path,r)}catch(n){if(typeof o>"u"||n.name!=="ErrnoError")throw n;return -n.errno}}function dt(e,r,t){U.varargs=t;try{var n=U.getStreamFromFD(e);switch(r){case 21509:return n.tty?0:-59;case 21505:{if(!n.tty)return -59;if(n.tty.ops.ioctl_tcgets){var a=n.tty.ops.ioctl_tcgets(n),i=Oe();b[i>>2]=a.c_iflag||0,b[i+4>>2]=a.c_oflag||0,b[i+8>>2]=a.c_cflag||0,b[i+12>>2]=a.c_lflag||0;for(var u=0;u<32;u++)w[i+u+17]=a.c_cc[u]||0;return 0}return 0}case 21510:case 21511:case 21512:return n.tty?0:-59;case 21506:case 21507:case 21508:{if(!n.tty)return -59;if(n.tty.ops.ioctl_tcsets){for(var i=Oe(),l=b[i>>2],v=b[i+4>>2],E=b[i+8>>2],G=b[i+12>>2],x=[],u=0;u<32;u++)x.push(w[i+u+17]);return n.tty.ops.ioctl_tcsets(n.tty,r,{c_iflag:l,c_oflag:v,c_cflag:E,c_lflag:G,c_cc:x})}return 0}case 21519:{if(!n.tty)return -59;var i=Oe();return b[i>>2]=0,0}case 21520:return n.tty?-28:-59;case 21531:{var i=Oe();return o.ioctl(n,r,i)}case 21523:{if(!n.tty)return -59;if(n.tty.ops.ioctl_tiocgwinsz){var B=n.tty.ops.ioctl_tiocgwinsz(n.tty),i=Oe();W[i>>1]=B[0],W[i+2>>1]=B[1];}return 0}case 21524:return n.tty?0:-59;case 21515:return n.tty?0:-59;default:return -28}}catch(y){if(typeof o>"u"||y.name!=="ErrnoError")throw y;return -y.errno}}function ft(e,r,t,n){try{r=U.getStr(r);var a=n&256,i=n&4096;return n=n&-6401,r=U.calculateAt(e,r,i),U.doStat(a?o.lstat:o.stat,r,t)}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return -u.errno}}function vt(e,r,t,n){U.varargs=n;try{r=U.getStr(r),r=U.calculateAt(e,r);var a=n?Se():0;return o.open(r,t,a).fd}catch(i){if(typeof o>"u"||i.name!=="ErrnoError")throw i;return -i.errno}}var Ke=(e,r,t)=>tr(e,j,r,t);function mt(e,r,t,n){try{if(r=U.getStr(r),r=U.calculateAt(e,r),n<=0)return -28;var a=o.readlink(r),i=Math.min(n,rr(a)),u=w[t+i];return Ke(a,t,n+1),w[t+i]=u,i}catch(l){if(typeof o>"u"||l.name!=="ErrnoError")throw l;return -l.errno}}function _t(e){try{return e=U.getStr(e),o.rmdir(e),0}catch(r){if(typeof o>"u"||r.name!=="ErrnoError")throw r;return -r.errno}}function gt(e,r){try{return e=U.getStr(e),U.doStat(o.stat,e,r)}catch(t){if(typeof o>"u"||t.name!=="ErrnoError")throw t;return -t.errno}}function ht(e,r,t){try{return r=U.getStr(r),r=U.calculateAt(e,r),t===0?o.unlink(r):t===512?o.rmdir(r):_e("Invalid flags passed to unlinkat"),0}catch(n){if(typeof o>"u"||n.name!=="ErrnoError")throw n;return -n.errno}}var wt=()=>{_e("");},yt=1,bt=()=>yt,Et=(e,r,t)=>j.copyWithin(e,r,r+t),ar=(e,r)=>r+2097152>>>0<4194305-!!e?(e>>>0)+r*4294967296:NaN;function Mt(e,r,t,n,a,i,u,l){var v=ar(a,i);try{if(isNaN(v))return 61;var E=U.getStreamFromFD(n),G=o.mmap(E,e,v,r,t),x=G.ptr;return b[u>>2]=G.allocated,k[l>>2]=x,0}catch(B){if(typeof o>"u"||B.name!=="ErrnoError")throw B;return -B.errno}}function Dt(e,r,t,n,a,i,u){var l=ar(i,u);try{var v=U.getStreamFromFD(a);t&2&&U.doMsync(e,v,r,n,l);}catch(E){if(typeof o>"u"||E.name!=="ErrnoError")throw E;return -E.errno}}var Xt=(e,r,t,n)=>{var a=new Date().getFullYear(),i=new Date(a,0,1),u=new Date(a,6,1),l=i.getTimezoneOffset(),v=u.getTimezoneOffset(),E=Math.max(l,v);k[e>>2]=E*60,b[r>>2]=+(l!=v);var G=y=>{var O=y>=0?"-":"+",te=Math.abs(y),de=String(Math.floor(te/60)).padStart(2,"0"),ne=String(te%60).padStart(2,"0");return `UTC${O}${de}${ne}`},x=G(l),B=G(v);v<l?(Ke(x,t,17),Ke(B,n,17)):(Ke(x,n,17),Ke(B,t,17));},ir=[],Lt=(e,r)=>{ir.length=0;for(var t;t=j[e++];){var n=t!=105;n&=t!=112,r+=n&&r%8?4:0,ir.push(t==112?k[r>>2]:t==105?b[r>>2]:oe[r>>3]),r+=n?8:4;}return ir},Bt=(e,r,t)=>{var n=Lt(r,t);return Qr[e](...n)},Rt=(e,r,t)=>Bt(e,r,t),kt=()=>Date.now();var Ft=()=>2147483648,Ot=e=>{var r=S.buffer,t=(e-r.byteLength+65535)/65536;try{return S.grow(t),K(),1}catch{}},xt=e=>{var r=j.length;e>>>=0;var t=Ft();if(e>t)return !1;for(var n=(v,E)=>v+(E-v%E)%E,a=1;a<=4;a*=2){var i=r*(1+.2/a);i=Math.min(i,e+100663296);var u=Math.min(t,n(Math.max(e,i),65536)),l=Ot(u);if(l)return !0}return !1},sr={},Ut=()=>I,Ce=()=>{if(!Ce.strings){var e=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",r={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:e,_:Ut()};for(var t in sr)sr[t]===void 0?delete r[t]:r[t]=sr[t];var n=[];for(var t in r)n.push(`${t}=${r[t]}`);Ce.strings=n;}return Ce.strings},Nt=(e,r)=>{for(var t=0;t<e.length;++t)w[r++]=e.charCodeAt(t);w[r]=0;},Vt=(e,r)=>{var t=0;return Ce().forEach((n,a)=>{var i=r+t;k[e+a*4>>2]=i,Nt(n,i),t+=n.length+1;}),0},Kt=(e,r)=>{var t=Ce();k[e>>2]=t.length;var n=0;return t.forEach(a=>n+=a.length+1),k[r>>2]=n,0},Zt=e=>{(P=!0),Q(e,new qr(e));},Yt=(e,r)=>{Zt(e);},zt=Yt;function jt(e){try{var r=U.getStreamFromFD(e);return o.close(r),0}catch(t){if(typeof o>"u"||t.name!=="ErrnoError")throw t;return t.errno}}var Pt=(e,r,t,n)=>{for(var a=0,i=0;i<t;i++){var u=k[r>>2],l=k[r+4>>2];r+=8;var v=o.read(e,w,u,l,n);if(v<0)return -1;if(a+=v,v<l)break;}return a};function Jt(e,r,t,n){try{var a=U.getStreamFromFD(e),i=Pt(a,r,t);return k[n>>2]=i,0}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return u.errno}}function St(e,r,t,n,a){var i=ar(r,t);try{if(isNaN(i))return 61;var u=U.getStreamFromFD(e);return o.llseek(u,i,n),$=[u.position>>>0,(R=u.position,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[a>>2]=$[0],b[a+4>>2]=$[1],u.getdents&&i===0&&n===0&&(u.getdents=null),0}catch(l){if(typeof o>"u"||l.name!=="ErrnoError")throw l;return l.errno}}var Ht=(e,r,t,n)=>{for(var a=0,i=0;i<t;i++){var u=k[r>>2],l=k[r+4>>2];r+=8;var v=o.write(e,w,u,l,n);if(v<0)return -1;a+=v;}return a};function Tt(e,r,t,n){try{var a=U.getStreamFromFD(e),i=Ht(a,r,t);return k[n>>2]=i,0}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return u.errno}}o.createPreloadedFile=st,o.staticInit();var Qt={a:Ar,k:pt,h:lt,y:ct,z:dt,w:ft,d:vt,r:mt,s:_t,x:gt,t:ht,l:wt,i:bt,j:Et,m:Mt,n:Dt,p:Xt,A:Rt,b:kt,q:xt,u:Vt,v:Kt,e:zt,c:jt,f:Jt,o:St,g:Tt},N=Tr();s._webidl_free=e=>(s._webidl_free=N.D)(e);s._free=e=>(s._free=N.E)(e);s._webidl_malloc=e=>(s._webidl_malloc=N.F)(e);s._malloc=e=>(s._malloc=N.G)(e);var yr=s._emscripten_bind_VoidPtr___destroy___0=e=>(yr=s._emscripten_bind_VoidPtr___destroy___0=N.H)(e),br=s._emscripten_bind_Graphviz_Graphviz_2=(e,r)=>(br=s._emscripten_bind_Graphviz_Graphviz_2=N.I)(e,r),Er=s._emscripten_bind_Graphviz_version_0=()=>(Er=s._emscripten_bind_Graphviz_version_0=N.J)(),Mr=s._emscripten_bind_Graphviz_lastError_0=()=>(Mr=s._emscripten_bind_Graphviz_lastError_0=N.K)(),Dr=s._emscripten_bind_Graphviz_createFile_2=(e,r,t)=>(Dr=s._emscripten_bind_Graphviz_createFile_2=N.L)(e,r,t),Xr=s._emscripten_bind_Graphviz_layout_3=(e,r,t,n)=>(Xr=s._emscripten_bind_Graphviz_layout_3=N.M)(e,r,t,n),Lr=s._emscripten_bind_Graphviz_acyclic_3=(e,r,t,n)=>(Lr=s._emscripten_bind_Graphviz_acyclic_3=N.N)(e,r,t,n),Br=s._emscripten_bind_Graphviz_tred_3=(e,r,t,n)=>(Br=s._emscripten_bind_Graphviz_tred_3=N.O)(e,r,t,n),Rr=s._emscripten_bind_Graphviz_unflatten_4=(e,r,t,n,a)=>(Rr=s._emscripten_bind_Graphviz_unflatten_4=N.P)(e,r,t,n,a),kr=s._emscripten_bind_Graphviz_get_layout_result_0=e=>(kr=s._emscripten_bind_Graphviz_get_layout_result_0=N.Q)(e),Gr=s._emscripten_bind_Graphviz_set_layout_result_1=(e,r)=>(Gr=s._emscripten_bind_Graphviz_set_layout_result_1=N.R)(e,r),Fr=s._emscripten_bind_Graphviz_get_acyclic_outFile_0=e=>(Fr=s._emscripten_bind_Graphviz_get_acyclic_outFile_0=N.S)(e),Or=s._emscripten_bind_Graphviz_set_acyclic_outFile_1=(e,r)=>(Or=s._emscripten_bind_Graphviz_set_acyclic_outFile_1=N.T)(e,r),xr=s._emscripten_bind_Graphviz_get_acyclic_num_rev_0=e=>(xr=s._emscripten_bind_Graphviz_get_acyclic_num_rev_0=N.U)(e),Ur=s._emscripten_bind_Graphviz_set_acyclic_num_rev_1=(e,r)=>(Ur=s._emscripten_bind_Graphviz_set_acyclic_num_rev_1=N.V)(e,r),Nr=s._emscripten_bind_Graphviz_get_tred_out_0=e=>(Nr=s._emscripten_bind_Graphviz_get_tred_out_0=N.W)(e),Vr=s._emscripten_bind_Graphviz_set_tred_out_1=(e,r)=>(Vr=s._emscripten_bind_Graphviz_set_tred_out_1=N.X)(e,r),Kr=s._emscripten_bind_Graphviz_get_tred_err_0=e=>(Kr=s._emscripten_bind_Graphviz_get_tred_err_0=N.Y)(e),Cr=s._emscripten_bind_Graphviz_set_tred_err_1=(e,r)=>(Cr=s._emscripten_bind_Graphviz_set_tred_err_1=N.Z)(e,r),Ir=s._emscripten_bind_Graphviz___destroy___0=e=>(Ir=s._emscripten_bind_Graphviz___destroy___0=N._)(e),Zr=(e,r)=>(Zr=N.aa)(e,r),Yr=e=>(Yr=N.ba)(e);s.UTF8ToString=ue;var He;be=function e(){He||zr(),He||(be=e);};function zr(){if(ye>0||(Re(),ye>0))return;function e(){He||(He=!0,s.calledRun=!0,!P&&(Ne(),f(s),Pe()));}e();}zr();function pe(){}pe.prototype=Object.create(pe.prototype),pe.prototype.constructor=pe,pe.prototype.__class__=pe,pe.__cache__={},s.WrapperObject=pe;function Te(e){return (e||pe).__cache__}s.getCache=Te;function ur(e,r){var t=Te(r),n=t[e];return n||(n=Object.create((r||pe).prototype),n.ptr=e,t[e]=n)}s.wrapPointer=ur;function ro(e,r){return ur(e.ptr,r)}s.castObject=ro,s.NULL=ur(0);function to(e){if(!e.__destroy__)throw "Error: Cannot destroy object. (Did you create it yourself?)";e.__destroy__(),delete Te(e.__class__)[e.ptr];}s.destroy=to;function oo(e,r){return e.ptr===r.ptr}s.compare=oo;function no(e){return e.ptr}s.getPointer=no;function ao(e){return e.__class__}s.getClass=ao;var F={buffer:0,size:0,pos:0,temps:[],needed:0,prepare(){if(F.needed){for(var e=0;e<F.temps.length;e++)s._webidl_free(F.temps[e]);F.temps.length=0,s._webidl_free(F.buffer),F.buffer=0,F.size+=F.needed,F.needed=0;}F.buffer||(F.size+=128,F.buffer=s._webidl_malloc(F.size),J(F.buffer)),F.pos=0;},alloc(e,r){J(F.buffer);var t=r.BYTES_PER_ELEMENT,n=e.length*t;n=hr(n,8);var a;return F.pos+n>=F.size?(J(n>0),F.needed+=n,a=s._webidl_malloc(n),F.temps.push(a)):(a=F.buffer+F.pos,F.pos+=n),a},copy(e,r,t){t/=r.BYTES_PER_ELEMENT;for(var n=0;n<e.length;n++)r[t+n]=e[n];}};function le(e){if(typeof e=="string"){var r=or(e),t=F.alloc(r,w);return F.copy(r,w,t),t}return e}function we(){throw "cannot construct a VoidPtr, no constructor in IDL"}we.prototype=Object.create(pe.prototype),we.prototype.constructor=we,we.prototype.__class__=we,we.__cache__={},s.VoidPtr=we,we.prototype.__destroy__=we.prototype.__destroy__=function(){var e=this.ptr;yr(e);};function g(e,r){e&&typeof e=="object"&&(e=e.ptr),r&&typeof r=="object"&&(r=r.ptr),this.ptr=br(e,r),Te(g)[this.ptr]=this;}return g.prototype=Object.create(pe.prototype),g.prototype.constructor=g,g.prototype.__class__=g,g.__cache__={},s.Graphviz=g,g.prototype.version=g.prototype.version=function(){return ue(Er())},g.prototype.lastError=g.prototype.lastError=function(){return ue(Mr())},g.prototype.createFile=g.prototype.createFile=function(e,r){var t=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"?r=r.ptr:r=le(r),Dr(t,e,r);},g.prototype.layout=g.prototype.layout=function(e,r,t){var n=this.ptr;return F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"?r=r.ptr:r=le(r),t&&typeof t=="object"?t=t.ptr:t=le(t),ue(Xr(n,e,r,t))},g.prototype.acyclic=g.prototype.acyclic=function(e,r,t){var n=this.ptr;return F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"&&(r=r.ptr),t&&typeof t=="object"&&(t=t.ptr),!!Lr(n,e,r,t)},g.prototype.tred=g.prototype.tred=function(e,r,t){var n=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"&&(r=r.ptr),t&&typeof t=="object"&&(t=t.ptr),Br(n,e,r,t);},g.prototype.unflatten=g.prototype.unflatten=function(e,r,t,n){var a=this.ptr;return F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"&&(r=r.ptr),t&&typeof t=="object"&&(t=t.ptr),n&&typeof n=="object"&&(n=n.ptr),ue(Rr(a,e,r,t,n))},g.prototype.get_layout_result=g.prototype.get_layout_result=function(){var e=this.ptr;return ue(kr(e))},g.prototype.set_layout_result=g.prototype.set_layout_result=function(e){var r=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),Gr(r,e);},Object.defineProperty(g.prototype,"layout_result",{get:g.prototype.get_layout_result,set:g.prototype.set_layout_result}),g.prototype.get_acyclic_outFile=g.prototype.get_acyclic_outFile=function(){var e=this.ptr;return ue(Fr(e))},g.prototype.set_acyclic_outFile=g.prototype.set_acyclic_outFile=function(e){var r=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),Or(r,e);},Object.defineProperty(g.prototype,"acyclic_outFile",{get:g.prototype.get_acyclic_outFile,set:g.prototype.set_acyclic_outFile}),g.prototype.get_acyclic_num_rev=g.prototype.get_acyclic_num_rev=function(){var e=this.ptr;return xr(e)},g.prototype.set_acyclic_num_rev=g.prototype.set_acyclic_num_rev=function(e){var r=this.ptr;e&&typeof e=="object"&&(e=e.ptr),Ur(r,e);},Object.defineProperty(g.prototype,"acyclic_num_rev",{get:g.prototype.get_acyclic_num_rev,set:g.prototype.set_acyclic_num_rev}),g.prototype.get_tred_out=g.prototype.get_tred_out=function(){var e=this.ptr;return ue(Nr(e))},g.prototype.set_tred_out=g.prototype.set_tred_out=function(e){var r=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),Vr(r,e);},Object.defineProperty(g.prototype,"tred_out",{get:g.prototype.get_tred_out,set:g.prototype.set_tred_out}),g.prototype.get_tred_err=g.prototype.get_tred_err=function(){var e=this.ptr;return ue(Kr(e))},g.prototype.set_tred_err=g.prototype.set_tred_err=function(e){var r=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),Cr(r,e);},Object.defineProperty(g.prototype,"tred_err",{get:g.prototype.get_tred_err,set:g.prototype.set_tred_err}),g.prototype.__destroy__=g.prototype.__destroy__=function(){var e=this.ptr;Ir(e);},d=_,d}})(),Do=Mo,Xo='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"';function Lo(p){let c=p.length,d=[],s=0,f=0,m=-1;for(let _=0;_<c;_++){let h=Xo.indexOf(p[_]);if(h!==-1)if(m<0)m=h;else {m+=h*91,s|=m<<f,f+=(m&8191)>88?13:14;do d.push(s&255),s>>=8,f-=8;while(f>7);m=-1;}}return m>-1&&d.push((s|m<<f)&255),new Uint8Array(d)}var Bo='v7#aSXal?Dk_E:R9nY4y_2i"i;~[]K^kgo:$AFCU{J9IkELi.B"R@=S|<$rj6@;VSL8/Umet8FXV"yuga|s:|JQV!;h,P5abpC[?a*=<u$ZXlD4Lbrxa[Ib/?jYqI)1M;VFbX[JB</82&UrU<zgYYsy3h:`N&O)!;Lg^4#0uD(d1xmoCzK{p?Iyq8+QXYsA1iULN(p:x=#}lUp7wIjp=ug$1OZg_BkIqb_Ax~?]rx^Rk?6{zbKC_4mJ@xg15uTA%Ize/jhEV(!..*!"Jw>c1nj7>l<jb^+#ufsTpbVFn!E?>/~153Sz]>dVL?<tO&mW2lNDzMrphmz:q/S6`o]2>!}DIeTKcnk6:ic!fxa$*(?dlM`efH89dj.[DNfg@Jkl:rw>L6:bw6!JWh{k>e3k8:yB.5je`h89|9H/I(98ri{8]*80r!av]f,2h`5&hPSP}C4|s=%K|R3%>kwl?jD&UK5Aq~d@fD8c6G=2MD84&D9Q*PmG`X:$L9=r$<:(F|V+Rf8:vEe9gB8)ep$[]$9E24&~7*7w>]^1]6rtla.7/%mH}6sxrwkU`qs1MU1|gjoj*C[dy0&O_UTB%.zmd=2[eX>p2?1@KN{5zNpcjV+2&Jg>#P=|{)6kbAPBexKuEG7eTamP8Ae&~hS&vJnQrY,`!X*}{Te@xO|}7Fwu;0R"dSbJ]L2ZxN^EQ+LCrxY9/k37~>ZQ{!wwu`c:n^Xf0"7WBfA!_#9lfb)$ndH3Sr@y]]Ot&/f%!NZ|bWd$`CUXpyHA|_M4fFy9.s@.$H4Jh53nNY9ss~/mm_K;Ukd}n/9>8]TR{8dva1;b:5HFK7XfsuwP0;Ry1*1?8~/Oh<0{@.,%g*gV#XOt_ohd;}i@2O^s&aS2anY1/ss|@B<Ly;fHR#:x~/n?;cltzX|DVh.`8Z+wK98;+R.|oQ=]EbVZu[2B&nk#,Z=ibY%$7!hsTw&M3I+z:lsT@L@I[cY5%Aa:&0SvKd3]Mmm2@9B}Vh|k1mo(vTgRlbU,q4>n7w,=Um_vV7Z7u87=+oTRh<0I]B$5j&q>p2auqxoOMgKAaQ}Olg>kKP:<`^9EQ:ZI}D[i20<j}b2QSHV9QVFvR%f{5r"7AH<s?d[4w8O`i#Yp640f@hk;Um?$bCRw!$fWZ`75Yb)G+jerdNDVKF:d!1S<vls|>j],e;x0_`(?q:nC]f1/hT+8$0f0_)Twl3t$/d}*KOqJGikUZ#6$7?N"bf3o/?>6%]`4&nT2@{S9IH[!7/{82Me%26v/{Rb/$6fF(R2np{f,d_~IbXyvl|<=X*S<dTT!?@TMD2V0^Oy.dmhYuAk@UCrI5v<FQ)m|=p[JMebn3Z)?6<6dq6O1M}=Kq!nVp)_T.bR`jD{.rz.0fcRK#Q:h{^2@4asOlPpSpu`D.IDC8%]"Gd>SFZ[]`EV`EA=?|{qX1a6$l`j!36?,/%zx9]H>rC]GjYu?aUV)i+)|`&U$`]`1<hHV{%D"5T9Qb%wGm*o]!bbC9W^a!05T+?pjTm0=hpLIJLY,,2XBL`qy,&5W}Czl?q7VVG_tlZ	>tKnoq.0py*.],Ra9F$q^v*/cp3hHxp^KURMWc>G>6W*BUfd.BB<N_Y:/+UbjRj^*3!db.,mlYd`w@fGZXq>u9JFY_`kR^:f.1[p[]:Xk$qd@M;Xe(16Hr%KCoH)Oa3#.^<9]M).$ly<QL2qkzYIMD0+0;G}J$M(16D>t*}[&=pZi5=Gc[.nJ]ED/60?m27rK>KG7c4HE|m8K>{Zz3:ne)w7fI)a;Fc)7L&F}c51$z@i+aRz61SGGRBYvNwX_Mzq$zy)?8dq40&1|,%z1VA]OZ_Vln;dZ(64@qjom:mYr3r2j2FNN><}g.+2g6g1pd[=)Gu(o:U4:{+BV_#ZLy8s.Vd2jdT27cugf8&]KeOo,I@+yoSWy$UZ]P|jur"UcEpGOp02gIL:Ud&9Ae!ig8!@oTruE5x|xlT$_iC;iJH85|82e1,PNHN4wqFv_5%7Q*S=e|B8KLq9y@8G^<{_6:xm5t1{re:>Yb#8/6l#[eEF}=M@XOWw`Mr$PlyT]%5KC`h0}ofw_fSt$`8#:dY&Fke;3BN9.z;OIS]Pt%L4@%`6t_;srz2nqD)oSsh_|8m+)25tvYHSR}IZ"033JF8/5t#QeN7]w&!}VPM&x2B%s{O<D1~OiI9NIG7&2b/k9i#QBOiEJg{5zS3NOyI]ZwJr,InxL(okA~<n*4"yQNU:.<bGcet%zY_`,c1(H[5c1(oeVD0kXgi?Bn$xr0i#I46;bgyik953a?!p{;%>Nw7e{q(M(=]S{rqMzKa~krYTcydVeTPq7.L;`2;p0vGGg/#QvBiW?!h2(4+7!JL@M85WhpDG*:XJ3M%JuMNDt_A}]Ct%[!f{1Q}t]mDVyT|W2h1U_j,FJ;5&gIl>$5p7K:*SP"%~8aa8kvu;|dP.flC~l=|I:yM:xG5&0C&=%23%$MyuW2xJAhe"ne^[Hy#/_azlDKq!Gv0?)/}7yl<)4cFQP{UZt;Btx,Fw?fVC0#<T:B%6+sZ&xe<z5ryA.fmYd37NoGQ[`6gvYmwq3,7L3]v&l&NZxseNBH2o$SdnST*<yc3}Jop!1T"Xh(b!4aOTVl^lz`/$tE[li0bzSZ3^F.zHa{Zv!1I2P[4S<dYmA.;Y^RqEk$5$gq?`<9Yl.q4%Y?5@^anqu:j)PKG(}]/}0e=Wo;d`f;nmkmmb6Q*c2#rmhffav:+Kz<b$5tzr|+hJb47GdeH8R4Xp6%~ddOfb];(g$]_0!`w&#&#]<zaGZxpf|N:1OZ_mh8mb54O[GFzKMrYE8$YF0xu%QqqNJ}<9?ahlf}VgqG=yP[X}Ah[ZR~ND%5jpl4n%okyT"Xg6q3ed8+`NWyle6%t,]lkyRbYpHSw%>&MeB8GSY9t0cmHN|otEc,}:@6S~<uay)6KgdVxrYm#NcY=cznjlk1*/*5oKQ!?8Rr}ozKc%yk/8j+;)|<@<c]tmhzzph1_M0!_1dlV?F_;V>84rjj1nGQ252Tx)dZ%)F{uMn8o!muNl7x*.dqsVkNnyFoH)`INu,8vnj@X>VK/e=WNKr4eVPp8:[Z&2C4DS(]M;>1p[jTx~R3o9@iYkpmQ7n.5K,&;;$5PZN+td~qx<+&6eR(#:k@"`V%Xvx~CI/EeVkSV8i{[8f@u6F{08npL?@UY92?5bpy&LhleHRJ{#yjbP0L_Mfy(|Wyzp36W,bYE?*fP]Ybj7w#)Ck<IR.yVYbG`4|GKnQqN],&5z]n/"O(k$G?MO{U3<oDQu0{{8S&|GKn}+vU496~U@N.Nz[0$qSFn2,SM/E&?Zf3u.=qk5zHLOnDeUg:zTD@~T^lWr"p,w(.{=l2cY]SXk~mT*ch]Zr[B2mvJNU:"^NMA;ljkB2,d@AX[ZBJ@5U;lj"^76(2JcQ`0mX>clX>&>0.F7G/nRr6!t}ov})aTPX0dZfy:SOp`=HUGn~4`nYZ&PiSbqI{.&>|x$JcF{yuIqpD$LbzO|pyhfD.sI^<7{7ENu3jKWL*I74Tylg1i0P7cnMlvu.qqw){01h~(@*=*k<^3Bo?t@OG!_L9=,Ky8K{:tYPZ`<o,b/.LiPJY<xy|EQPWqAFMf@^7G5f:6M7ZMJ"kOb{]#Gp1C_x|&cYmKW%zR[/yBqd>x1zT/<Q]_r+a!?wsNSbz{Y0M?q2K)#)^uVEJXq0@"`:nT&ioVr4*.xP<TnEN3[rx{XB%KL_dj.Y:k{j.z^^e,Eg9&Yv$Dee}F3yoTNfd:R)`%)"7d?TGJ}k$LeCW[jT`ZU"8]Im&[I83NM/L29`UG7bxVPFn;U>N`]}z<$PO]ipS#vkX<3}a_XEz9Xg@$9x6v?/nEg[)>%iGn0nG*s)]s.G@]iuMp#?ZU_L%4h$n9:_mJ]42=0xs]^j.&%(mtlgd25c:g<2@q{O|7^J$`si7]y~3{=F`<UeVXp<{B5"[J.WTV7XTIVi{#2z]I9<q9apyDy"_~3f(w3:n$r4eu|/r#f@pLil|oyk./B|ntjz}am&Db^uC>us;:vF(d1;7|}D7q[2VDj;H@5F&[iz=1$_Mb_Vgt*i^iTgh`M5qd>KU=|1d^#f=4`K>uNUoea/6l#BLo%VX]C^!Tv6X]ChauT@)uN*oiYWb)e5SKUhBxirnpRk?16EQ#2A]?kUo[x;R.^4t70I]Zkj2TtMxF#8,>1Qs$zb3E%YmqG{*8zE5X1UmkybT(1@kt&t|M:j.1S7]B^WW?{9DN8zJkyjbazl>2X<srzRmP_c+0@CaoF!jA{o@|bUl2?eU4&ty.t|od0{/c{uO]rV$jQaGin[+N.r}L=9aRnlSJ$u302h0bz^4ZQA|Z>z%;j#19VMJM*+b&rL=dq]{x1]1H3St:$@KY2nSKU@Y>#3q{Hf@qs5QI^GrV>{_,^v&.n_J7GQ*b!IS!94lYX1MUoWaibB%Xsx<vvyr~0y^#a<${5XUS5od1Mm&c>4?xlTe.xfN*7]Yu"{Y[Tl6rP6D?Zr67!tL+H?!%*RjqAFfGXOIbr2RvLfElj??e<+yKxRhc}:I2+6YjJO2:ln+!Y^Jma<1/y;C1sOmIfTX1T=#_3pZq6"e$Avx>af;Tj0zsDx4kEdjkXsOmi98m+uu)Y1pUjrX%PBB3R7"iM#0xhSCVj0X6UiwuJBm+ylEY^eeVj5XQSEg4R=LtKf>kEej(X`T(z5!bzGF>[88s+75KZqD<48<i/aY+H@!_0ig2X"Dq!O2j/BB9QPTSJ+yTa/3LT1p3kztGQRz98bjNXASl398l+oullQ8ZLg9vLYJ%|NJk/LB=gx`!<k/LvTJ|DR2l4nCsq$co;3EU/XBcjTPU9$k7t^I,p2egSe?VvQSf,bvgS<WkFW6J.U/jB7Wy6h#>W<FF92xtg8AlDlv1xV/vBrmwo#<p4WZhGVNP2q4[Eva/*4k>t,NfrcS{W@JX5HbX/;Bje$c8ft4<DQ!;PY/~B@nJ=cSBXFKP[n;5k,X!HyhaC6k1)|K+Ge#EX;Iw<=8Z/WC~N<U/>r41E|b_06kPB!Kx;0EbQ>WwJ`=g^a/7vfV(jbC7kYuaUl5,0PtNvNLap0kf4TANHG!GOMt]AOOdZ4WrA?PZlvWuAcIaScLYAmE8<ZLuAXCNp7yZ"IC=h=x/.NtRB>m5FeVzA#CZR~PYLcADF|Lb4dA"ID8.o0WNB2Ky:Et;*AP}}XLgAfJ*BYLhAnJW!NcRAMDz|/`Ft*B:yMcSAYDF%7yRAcDVRZ4mAtHD35Fe",By6wwOt[B:OxdGt~BQ$5FXA@D|5Zd}L>yk,ZUbpK16nLy%eKs3e7nPy1i]Smg4)/Uy0K18nxEk/ya=$hvGfk!3e!n=E{^m{mgI@8KC?bP>$vvzowYQV{nOFzsj3oILt<DhVoYiNu1Lt]BTfN/VA_DdhXLy&E0OtPCSma]0(LBptBEptFE|(LB?E*B<OWmVxHt}eF!c"REptdEWip`~;ZtqI9(WBAF[t+*;Bb,u2ZI;hsXkD7?ZE(?,7Ktr1dtGF]"KFy]GON~(^ww{GB5$gqysFlC5J{iD,H<m<m<=n/thGYY#Hh/pdsigc^?YDv;We/h8A8F(|Xr~eNYKGrY7D^d@$`XY"|CtxrP]h%ApGlR};<FtYAE&gj|{)Zwy""I*Bwx$IH,(nDYMGNuoQR(tBPc[/VRF*xLkCwTY@+5O<JOb*`JBG]vMX<I@<,7}vNXVFK.RVPcB5v+|)1L7x"KvzJO@L.C#W5dYRJtuc^vnM+E|(iM}CJYzPa4u2^K+CVtfTv7+xATpnAu(FXDNc=xq1C?QCsRRlxwg4tBptSF7jtpScSBQJS6q1bt%EO!:i_94"=E@AB<[h@AOHrfYjsiUt<DLrUE^h^AmHGeq1Wt@DG:i6:hAjIBMg5*:hXBNK9%ww4(yC+QFBK73tZEy]hN;hIB7R{O^95"aFnZLv|9g",C::hN/hRBBGV%A^3(1BOaA$/h=A[GN%{x&T_>5tuvXTD%*[D5dcWxLUm0j|x?;FAH5u)Mk.+[})#4]I|od`}Lj7iueOGa)nG<CiJuTP&d08Hh[F^u7UY!X7~)WGCvYQ{i)0t?MwxXWK,er`;,BDA*?LDF5o*5ti|y>NqD:4c<z+DN:DZbqNSjHXeK7i`J"L]FKZ_IK.iq~X;L!E:lB*w+")=L>Ejq??qN8!zLUF:46lk+quKmxJ3RWzMD4zOmn+&udd$YUjpX[P_wf<@yFEO[f;UjxXrR3X4R<L4J%jR$2kytjJ+GR2p4*wRPx`d#]4/En7XLWAeE}4vW1ApRJ`vW(A/R|LwWSBzT2!wWXBYUvtZ4Ao5E=!}wxW|AbF%P8M:hP)`B%PS6p1*("AddE)p1NtVEVVgoVx[h6AUF~1),2(kC3K7zs1&W*E&e~1};146uuOD?+e8;xnjC$j?frieVaAsBpN2]SVsitL`,n4BBa&vD[vUBLO&mqT9KN!+4gX/>jP22+G<ge<MUBJ[*BXqt*}:o~;}Q[1[*DXmt?adS~;BV=F[*_[O<Mg"KY.dBaBE2/k_9>[*RNkUuawUTK0|e;mxN{BzC+Mu4BXI*qoz:zPQSsYi!_4uii5%!WhLnSMd.xD{F{v7[^9b9SFI([dSO.$Y>q;b*3<~Y|miZ`EtnO6ueO^ywqQ@#Qy!UF+"0v5_mjO&4ic8#2:ec^PTHKhkyxr7DmUyC_PF$nf#1:d0Du<8fB?*|LdAkT10*M$A.RxLio,|BC%|RWX>Hso{dMjP7n?8Aj8[e$LA9(F20q^.&m*R>OdB8Kg[<ruzHH4{<zec64aw7$,ROtQE`Aqj&S>9@i8Xs({B8Ae&pk7O_doM9vlS5xV}N~7Kj:F&6Cp9UU6uKC9kyd0H6yO+waYIri7NAXDwPOvN8aizSH"pAi!ZjXdG8iYvO4]VPdY8?_ISZ/cos3.*c2.yRT+Z&aO<aCd)jW5;;gP&wV_+V<a7ijc%pRFliTcaOAS0@J1ouR>ju:]zXnB{E`Wt*0$%KP^ggL<%n.lGh]0~P8BkAi8)uk<WBT|T^*H3[~%PX?KB2Q3Cj753L*qQ%o$:W$d+:_v+jwldx.wG;]>Kx8H+Lv<lU:Uxq*;DggkdU{j5X8k[IJeyRX8ahkQ$4S<!rW+~7_!4p^%$TpXn`/v/KSe~NT3;opq&BPPp,cPB#NXGdj"NBj2(#y,}7:j!@Z5)im+WIB8j*|./YcEs8z_]=_+*F^IlxisE{"gjLaqL8K|u4js7$S_MXa|Um8f}.8^zhq[K83$+KOrQgXa%Dv0MINp{eeE`]wjmFSxtq!*4/FkQ3GAa|5VXA:{xrQoS2$+Y7iUn*Jyj&|If]o,3jg7UZILD(%C[K/%`{x|FEg$Ky08MjZ#77kdj4E"OKqu:D`|tp{RufOR6$mLD8yQ|fpGPvwH*7mX,(@Aaf8k,CDvIM!8N|T3"UP0Ue$1Z<&%TbDH]f<!Tg1p_&i8K<NcW1:o;$2iQ3lC(K>rkMNNdZDn7_pMS6:gK3:rb8A1"HAvz3>,JrC8K|JPW1Z4rEw@D8,%Lg8^C(|AQK|f8cO1mey_);XBa1J82(z9"!Djy8J?!(M8[CA1xW5FjHa[yqkhV^PdsTDgd/B8+S~lZ8OR0RKNO*Kjgg>TN(/UrGI3k`hGxn0|.#V$`4#"S_C`yrv?17oBF,IL@],R/ikpVR)V@V5;oif9<hRsIKvX1P`)F!DI6l`w5jc4`>O;+_JpV@(&^b73P^;Vs[Oyg1>TK?uuJW?SK&^biPz$t`);4^n8Dn@4DF"g>ry!58^!1$SnzPk_Qr*]dUK|3l@},?B;S9Rr0%]HxP5{L;0*`_472^[wyh1wSgZ!KioQp,x,ta!#>=uL|7c/dUK|uq73+>`P]!sd6|fH*=6%M(xC&o?^$7c{Hp[HMLyI<.:`O}H_Od>L%AT]yr{bDe"@/K%=Ae<&U!78K`Z5s$XaZ?%UK|E]hujH}z3.C`45)W7b~Pksb>c=YW7LA_7}h$>^F4]^1y5DJEFP<`0W=tsl8B]W9II7XT[gEDtj/Tx.mwX68iU*E:`hU*bd`hU*Y:_hU*#5^"V:mwKxfB8NC8f"EtD=.0&JXTC9Ac62GW^G8N/XhJXT|u7NdbkYgRE8W3)7MyV7*K`z/G3clw1v.GPy{oFr0Uk2FZ#}ZBTY(<*NjfMU#2_8ow6.gr1HcR&W]l_:0H:nOf|uIOf36bzc]"IO8NcKQ3&SEH1/}o}6Ap^zkD/[d[;76dU/lwQfViu1r@KO2<r4JpXxK5B]~5l:Vcw@;;+6IHOFH3:SF0sDxbVbP#^8ugG36UeUL{SY+Bi4D,2N1f][!23#7NcKQ3q2Vp|N][d[lwkeI={qMy#dr@9Vulk:LpJ;{q=3L5SY+b{(z/%{ymrVW*K5]P`+grU]7;wc<<Ye6%>(.kPJ^DkJmyY57^BxkXkgdc=+EDC/7HP{ovV9P75<$y#7E>N_X+w7A;Mw1vOF&3t)>*pcbnOH+ZZl5V;$6gCna`aYoGdJrk3ex+kgdcY=`5lvt]]g5UgL)SojMZ$nVOG;Y=4nTYPFi?Fhs!Ub<wI}G9mn,"[N_X?za9J+=zgaKr<e+?y+#h8O}u;Gn28S|;4Vx(}]f)v!zJWw<])eBhJ.O/SYmpcxG5?DqldT|>(z|(}eUs}Voq<tq=hn9k8S&6c^+"$pQSf"?*gD+Qj:7p]uz[@V2n@+>w,6[&:u.g>c;i:!vLk(86l+W1Bnr5Oo;WGEu^_uDRj$o7.Joip&wTGWx[1K[EOwj<`Nt90KVI[,wH"kP@Z~VwQl_]S?<2j)ps5_S&0Nd(EvMVLl]8!7sI{Xy=vyk.]265X;{Mc{5?u6=eTG65c`7t>G7.q9Io}d:5[pT=.Hd8#$BRPOx=:#a^F1zK^6/pAcfS<i,Ki*8Sn5"7VXR?E3Fb>$#f~QOpf%!tkASg$E<z/D8QzK>Z$y),QT"p.JlOi]Ir})SiM<q7vHQfhM95v>Gb3[#9w<.U,>u?W>.z:wxpUZwW)6%pFG*4~c&LIHafYPb{]$#p:/#pE#9Vh,P*@+%(%jO2m6XSp1uWRn#6q|315}Gqnn*t3}TtAJT,%VIkL102.P{kz!^ddo:DC8zVm*x"t5eX,@"mB.}7Q^2`DZPQIR:lT$9N~^0!hc~qPC;[4$z>cCfX23k>;zk4F{O2*(GA>ic$$<u0![v&Ek{>=MXLy?JY"n/Kl>mHnm&qH+JqHSv6xyGP0M6JXLz)yjbzmCJV~#6Jh/TZjgR$0m2+?8NgxL*fOgd"TJb$1)#[L=Txx4nmYJfDON?p!k$#00I&oOj<}?rvUbk9x{b7L(!+f_8@i+PqE{1B]?WhXE?),G>q}+GQFI2^ICj]hfA|j+72a{BWWEJ;S~5B_>0[MC.^hSW2c}UQT]0mL=2$Cr0iObQFbM<g4lh>u]g_a>g<w=UTt@A=))X$I5AgLZ@Sf`8u/N*=dA6:c1!+R]ipvh_)@H><o;F!4}x1)*Bz)+s>**@zBFf^rzYPJ%0kQlQmpHQC#4;b;tZibqII}h#r$jzWOgl^xv742X*:tmE(Kw9pO:`krFs/r7gqk/o7zfTfQD&H(g?#9b:rTHt@Ar8o5j>6`n^N9U#4bp"[iOE#(*83q]K{h9QK"[4@LuA@e_<sYmS!ibR!"@4mVT_*ljT6O#L:6vqlz<F],PE{Ah7Y`gyTD42.gay3BOG$NgZUGBz^t]_+rvFQEQ[(BffFL?M8Q2khq},|r$MVGi0v<w(KXnRt,P|y[YC[7bkB,T+MW+vv}nY:`7wii$oa~+,8!ch]p^@C=%*S(}D/X]Q"5`:7{p42V8I#*jjoaUtnWuSHA+5p.]7%&LYII|7~V|jUF+I8j*R<*c91+Ud[$.`#H}%N"G(=>?W8u0o,IeB8`37erip9~c:!l/_f+jwV_YVYHSmZ"bO5!wQ{<naY=<dY>=E/O5Wk1wlX,T!BSHH2?%9s2Kh.`C8o=^2.~g(.dUuL0M.NNV5rAw">Ol8Hor?CU3}RN_X6YN`*HZG&vZd=r^(ons7U+o<m&bA;R[51wihZyk0M63"L+52^P3rwlH8~Y>Yz*DdcA#}+O4{S3+z9Y]c(qKITQ#,qcPP~)i*Ll>q;_)jovi!%smwOb3F*jUBr#_yZ&lqi(2==*Idb_Zr]gM_e;e2.{U[T*g[$=&^Ze@XB(&ZvaX^99>v*I%71vxF$$uksw=5@&xu!X9$Ex!|9mark^8|.2}&ojm>d"G(<0yLPmYR<8H(<sKY`$ERznBeJ&e#I~O~njm{V^]iO.znOxWD!UPN*=$xf"*iTV#(,PvM8UwK/;<j1.sS6O#nJ}}dE(iSj693W%.a/0<JiJgn?aFW7]6deS}&_i*V}&_MEi0rS>)1K(/G`(]?)~O?KEl9$f})77K0<1KD]l7=aETI6~q(>mykVT9TH%X5qzBX?Wp47>YCppZ/EvzR%Q:%GhO,?ScbVZBvt8;%Jag+PLz=X_36U2={H|R2Ngz8na&^[xBwb!M^cQM7>TM9V]c4tYE;M6`D1XEB{3Bz&JGr7_k_]VVaY3m]<G1&b>/RZZErqUiee<RF<A;1R4i2ta{Y>hj[a*HNegh0MtO]&`=V!+lk+1mXC5@#{FSW2+S/)MsMUzVHRbV=f//}[}1@b.Q(y!kOZ1Xf~!C41CJQ8J{dHlLQ,0]Pl|<BV|%8tyG[oTu6Oa(qjA,LxjHmq[pfJLoM?)GN49%d0@#^<GW|%hZ,ZtB`*J@xgoL~6/nt9teDV$mEq]{{Mt[6Z8GLb`<#6f307]W#9jzJgmfy]B&jEg(J~9||WyG,{},QVeNE|lcPo@y)+Dr;%5R"Jd(ad|>1r82k(@nx:*eva@iq/0;_2[U75/{lj0kY,o@/ni876Hpyn+36yl9y5#kU;Fkp]t;)D@T|bo5)US}w*YTkTX3;m?lk+CJl3HJLY^DaR+Mxy9L}DyJtn)ijqF%qptpBGS4n^?Bqla$I{&.a1x<@gU*]Td).|yN8mE8e%b:X[E#~Y",f:&H7&iU3V*A]a%T*!mr^!NwGMA]vS@]_^~9xU]it_od9e*lt[E=)coYNFEil32<!_w^p"KkwNP+uYv{eO(i$SOu;9vzw.R%jtKn$eo_LQ&YmY]KvYN0!HKV9nb#ycJ*EDwk<wEoz+T`k[tm9Zb2iWn]Z+1S?MiW2ltvj1]4A@E{ZtK/P$++CgPsF1F$:_YsS<HzDNg?|wV.d6*Z3i[..a_uuk0CFY=JdF[kbDgVOSp]Gaoqd@lUVfwWb//YR/M13QDq(~c^D[ib++@6dSk"R>v5SNO@6/F0h[1CFYDn0Cl#05SNn`W^}1[tA~FcTYH&:Nq6)![lJj0CQ>tQTS1P7qErzL3ChDh<Q0q3?:.o[X3UNM29![)?IXla[V~%m]D,uQ,5S""$V+?H^:brt6m4W+8~%GkSi[4xy/Q+bKT?1>A2Khg/NFT^#Hg^MjN,/GTUx@Pa]lr[kP`|bKqY&SK%jtP$ADijB+%7[!sGXj&R3{~p!O*A/n,"g)ED(7<TkQ_lgZ&u<:<INX:b&S_z|L/zjSz>}5q)B5tTUbN*s5)sO@abRuf:|}eajyG5r3G5@wD>.1!BDINI3"eDK/+r;1DL^<Stl3r4M#uVn"kKs4M#]|uhzgw,%.J[14~crJ<zNm+Hs9vz[]w#)CXD&BV<:FPYyrF$Vi|vD$,u}h6y)SnDZX(5Y84bbml4^?@IZB{$c](H0C$cQp+toDXlzb|bG,Dxv?%VeU.8P<Ys83r}T&,WFNF3Ir8]VKB2Eh;)ih.t~B2,2`8_g#TR&P|[9f;F{LpEDQOwo(zBz&?*#Czac.xt&{+k[&{o/fxWG1KzR]M{(ZqVx4@6U$]TN#54h.a^l8Z/2_O?B&Xsd9"4Cws,q;ezJo1Y_%=%eD)+`=>8l^8(*NjNQDA]r;#Ood{<0hD)UwL*i_LQ_M!Og>?#_|V},Q8p|"81Qt;Y)n_B@/oI<YxyQoDKNEGDPwVQ+0.rqFqU&Y=6<HqU&Y;0:*zv:f]Z;xLyAok+UJ<wc>ZxS0uJY,d5+nhpc`]6n2[0Q`C~vvC{Nq"z?cc6121P&:a8wxjkTHe~bCU5gVkXQZP=|bUoWnpjZU(5aG{Q5xI]"duIw4~|dl]ldxNMIz+Kt_e.!g{_$&Rx"^FL:Lw*OVKw(<*MMi*fPV#57e{qIzKWmZ[k3@nlU`d$|i*7LooZ1YW@h,ZpB>M^Br;qTT:{jy+5"CfZ0MHSy=Q*rfQ@EY#c]k*GH0oGVXPDL*~F^j@i_QIMzumzb]FZ#=(W(9y#bjg1ZuAh|zGxLVt9SzFzPEp.SYcWPvay#v7V)?"WMEEuf!(O*#IoL8#ym8hxGYvj&Mg`FHGGDGq7)Lu^B&fw_kh;/2"MxG>iS{JkEUzuEIq7Y=s2n7Kn.kF%mD(=_dM*BUK(&Uzu^c{_nt0tMlfSbm^>2XUp4nE5NSL#_p<cqK$7~|~=zxwA]%:NjZ6B&62._EcJsHmY@s;Ed&vO<wth1X_3uq^u}$A*,{>%7]$p1wRxr51+zPmLQ,e00>pu.FRXi}})%erL^s,@GYh~L[y2=O==w%)M@]*lXbc9g4$ml;WFyfqG"%cNbYq/prx@P3}B_3AJVU96z99OpS28Xj:XyGt8Qqrpk8]YO5b3"B42KgH~o3Y,e%ju!wA7{o18io|feT9L]Z|jM5kV_p/q:/eN6,i%G~A;0!tcF6;VEX:g1_e^wgeAPGaEkZO@k6lH2q|5t5#i%d)PDyI/rsw:GPI:Z+0k@NuT[v>ENtZ.5wd`cT{*h>_y[O3prtU$hqQ#cRH4@$vg1YRzVObVKJg^VVQG2sX#Cj{je`hp!)(#crBcLgm7d8Wp3q`=o]~>a.*54MrG9P6YFQf((znlUV)KX~R~>H7dlYt54m3p5Jm/_iu,ZM/|)eGFn;%%]pwcn*=Ug%39t~a+Im4PfNf@UgBxHd<+B/}?U`8N2|dv~AZRmtP.g`*kg|E;#XjeS1{m$pEIXM)m3O%kh;z?W[91EZ_o,tOC|9o;>B,[x36sanWsA`Z_J]5<g.f.K}w<<^cT[U(Mz^B#/<YVj`,3J1Kvn^AD~]$Dk`0KO%3uO">iQFNX`;S9Zu2xU$$)8hB#"bs2yuh|61$@zBQcZdHg}%*np:F]9QiLxyoZs#()[KlrnuC5l?4LO&=L[B[Kiua>yr^_3yi1P<aWAzPD,IHYo8$*D8+Iu^Tf!*Cy?(1v+j|"1|Iv(<ebOl1uxepEXI8:(j7m&8x]q$NbDWsb3]a^Q=;ya>Z{2cT_3>i}k=MYe{OVu88+_%r|/KkJ5EuQqGEjy~+6`wOkI#s$x,V#s$)Onl&;@S[_f;b.VV<SfKcfO54cC8*MwZw)NimzO0J|TPk=.E#&JC+Y_8;CYr4Uj;_3Q#)LfCq*5],s`UP/hKy1R~n#b5#/U={UP/Bp,"JCdG5u_;n2D!S1gZ[]*Fem2gxg?f:8rp#oTwu=p^GAKe@?4sb2jluFk),gTLxM1#VG7V+I&N/EM9MzLdwxGSpL0qoB5+&r)soMIJ#:yXL>8:mI@n:c+Ksl$7eDI9i#ID}`Zl1)JFfB`44ZPTCxz*.o?0fE$4X_zQNs;zjR/K86OTWM0JK=.(i"."tXEiFRV|)Y9x15v_5C#ma)](erGxn{|%4g3~JX7HhG3,h]HM;:t,mmgRX3/Z:6fNb$829=)@ws%mU1S%PXjdPk(F{1UXRD4v.y61yuj!k^,3krW$U/xqYk$<SG[tPTzuY6m5V;ya[p!Y15ta<Ifv+?7)(g=3e=Q=w+(ec*bsQv5pt$o]ZTlyCbV)C2@SoB|oO*a)(gwlZXz4XG|o=gS@Z1oSHon(*/<@i:y+c*e(:,;r~;{+gq72(BR#V8+^Lv^FZ:{Pr~z|`9y95TB7zMk@VWYl!O6}O45J,VhT7Gr|x2w=yJZVHT__#sjCmg/|euRBb1mWdT$QgYz*G>Wd,i&61cPDQZHOc#PTVx(/8F.LPjuQ9;Mj&Y=8;*t^b!/znDSe(GDU9w<[V#89krbz5jqGr22?Q,gq^Zzpfb7%5Ku7/l3v"bjdr!{p.U^7Gw,V9z%{R*>5i)hh?t<L<ncPWEb?{"_oN^lbc%QnqZ&0W{{3c^`=hYz0p7z1rekgbAgZ)E~^v&P?YSK0EU`=zbN4|}D7Uve&)m59<Vepg&cX8@2IV$Q}`yT=A8Nw[(Sh},s.QS3Jh|<m{Mo{1oY~CxZ;0+CtPTH{EO6U!;I8~J87]IE>j~bYW`*ztvi|DK*&MIPWEr13)6ACV{~@Es:Q*?rS3J>s9,g;6v=2w&1rd`c`@.`Nnv,oKSyr//B>G}`<dV=HweA/J(0A4L})w7^K:?e@AV#/,^|j[?zBZQXy1*EDSe45!!lP^.0S(O;O;@{|Tm+@q&8a]_8^a^E|Fnb22mgnjw1yaYT+5&eF5<77%7V+OlQ{nh,Mg4sBZb7eylS=Bjd#vkWygwy=GRcP|%6Lc]vBJ6Dp.tI_]nDMBq0QI%2|t=mxJ*7+sgaVHS49j>"GaG/,yGo6KCiPau5q`^^B7_`5U0AY2_7w0ST]hu2gC!;o!9n*_q/XA%9oUlT=rh%S4?Tpf.&mK|UY,/!Cw_6Kok0pFyvV.c$1jF~<Ybh.Hx(SEr"b"<~<XBN.ps@U!<]!x*hF.{R#q[M,zm?q!?f5OT?e+iRByvKab!"LFgR!/_e%C?gj">y=ruXKq:QvyGn0XM1MV$+6egS@I&hwCthhFQI%16VI.r>CgG!9m1jZlW64/M15|(8~`=TYZ>oc?8iLDr6X?[j<cOI^;k|yEsA_2!ok_d;fi&/,=8Hp&Y[b#Huc_[,BxI[HJrWlqXaY`+2~%*KFR*$V:yx;@Y:#"T`{[T]<+)(7py0Tz~X17m&I^<NfU.>.e0R=Qh*$kbJc:]LN#9ui5T0rTBo&O+Hx_3_/Qvcpt<f8{WNn8aKL]R[21ttSd5WM]KSC$etP#2&NLmFoB..]0,OaSHC:sPn9^@QjDH9k{yr]??_SGN6:m2%XG;!uw+h_+e%E9[%S365BeJc:M^y+dQgTE_M>W[T<n.D)Z`.)d!s`VRjF|qb#9rR)4.6Kh<`x:]<.nV,A5{PO90?O(`XD3f?jV(Vh_Jd]D:g^h3^MJ~f^uo`|.znO~4PVovF7J09.5^IwmQnx$+QZT5uZ}p*)g/M:z}9MezE18>[>qUMSMi"o8txN<f>q8+7F]IvUcyu"T,8U1_f;zyRL0T(uEAXlwIV$DzM&Qq8hSHhcib!LYFT|(jN:v6HQ.~,^j#d;5e,Ib7eX)mM>~o$zL($@GYlsp*/rmhXy%lL?yMJ{CDM*,)R8[jUr,d2Qu_W/:ROb)au`17#3p0l8=Z=HCW},bYC`)S+P}yFe1f+vi/d7]6T+U6o#K8NAz&;x*7Cr&c1|Czu:8O3ut{.$7qL721=yUCH`%FHhMrXzHPb]#Q.L"O<@1q|yu%PN0ai{L`0#ml5C@5U7;+[m%:[xG}W2ASqL_MAnzji$H`Jg+LV}Eb^2=8Ym"O!PY]kqFQwra{Q:,ED2iGiS)kY,Vd?/GOi{GMhuX,~IL;.zoYHxp_r]l5nuEd8X=Z;T&./Y(5X+XiUH*!3kW(7PaJ%lF/1gJ:;by!Wwm/l;]+&XTb16SlKYzAf6JK$4;NV#@VBHKLL@MfuIAzt7vS!PiNE#n;k{@oqQ]#F`#Cu6+l#{t[k8TH#yh#)j%vBrK67etPa$ft_Oz!$vBr?R4j&[!VfP)HFIk*7pR#NyZmU/Q:[GoPcKnh22@WCNK:F:nsA+v6SB`4l4/mq&0$I7sa[[3Ld{^"l*:*z8}EUJ7?7HV2h9x*RFUJ<zY@/5|hi9$n_n*2+E9]w?AI!?iw19/S1(?6u90)n/QF1mBqJZ0gUH)+/x?8u1W:caA=1v7~3jE_(HI<g]7S0Yb7n)~#?pGa>KJqN=X?|>#&6;[Df@|la}bZ4B0Fjbzs%UDTlW2PW1`4SkITK#Z]_.uoIqNZcWc?z/ixf?7s,,cM[/tQPt+xw(D#<[q|]&k,cv>0X+,JmL1~x5o}Fca?ay5jHZYR4$@kn3J]NB=|]n|n<|/4WVxck3*S"Te/^bdE*50qi0$sRRS.BA"=r,!VlLr04.yzdVzvqlOt`y%yoTkU=}iy<`y68_ids,m%JfeHb4Z+o03+3+g&XQc/j2$3|7;`O<z2hq[pPTBzAMk`}qvb9c_CmYB8[L[*{Eq,yQH6ww<Js5[7NZWuRo"}d&!.]J=$32%c/iNkz:6oV9u..<r_$RaS,qB+$pExB?%I?iOhHw+K3`=8D1(vn=k2|>^xNl;YAhPFK~6E@4=7)E)+Qs)=v1W:B7B_QJKs`5l&W[J2mqK_L;ngr<Y*pm8vRxA~qQ26o8x|uYZ>m?.&SeE(g>:{fz1,2~z#n]Qg5~_g_MT$M?IE$d#CrGQl,ph8)+ibvT2ptIaFRkbc:dwV8Lo{;f>]:QC&NZxsR(K5k"_?Hz!{x}ibe(!7]IyoqhWy%l:g+5,R69?eY!/nj5=],,z+W"1M$52$m#+>z[A.h[P3b><VrhN|v|]<,%ox^._?K|DZbzG5"[Gp~EK]}mb2W!U/bgAe/FXN8KS+UmtL>I060LQHW,X16pJVxr6nX7r]7!WOR7NW("[Z8sW32X^BUAGu9HPv*fxi5lDCzn$Dz5zy=R2ov4gS1!`f)]7i&;6Wi:Lb0NY^XQS{N`?t&C(f9cr70Z^Zc7hQD>6qw88:x`;J2_)<9/2Ti]HuWqaOq:ZZLDbyC6$v(Si+m1;tbvTE[$<=/[5d]|G/yn#v`HpLI6A=^3W@O[W!.hP5Yj_.5:N{UY~;zERRG3>J`rYf+BV,](nX!5N,iAS?R6ttVh3mN`tQ6(?8qG?*iCGX3aKfyC;ggu,hrPPXx!5Y_U"?YCX@wT=>t8Crw?iAMl~,gSi{QX/[~|klPg9Mg]FW=|v1Rp`bZn~1UIN^qu=zDur#bwo@q:qyXI#!q8{8kMcpZ%e$Qnv]FGWwFn/}3wfhub9EMJP?CwdhAhi&H&A&B>ihS_"ZKNrX=gX6wq2N$H/09r&(cBxOlh>`X{Eb0;|={nr%@IE`>cdvT<LKs&M0zZPxHG^&2/>8~/aK0*;[qK]4S(li.!1KZX..dB%[c_JR$;B#nfNRs=aiMT)lFYPDZLdGUQq?pLcV,4aIyqG!bC`3N^;VkL5y0p|O1R>XVQ5yDlEpMPZ<x82a}VeY:tLlJW0iSR6?gV~//)N+#zy&3wK@*2Plf?<=i{WJNm?|c8bPUW[bvoAe9.`V>V>V>V>V>V>Vf]KQ}de:f=bS=?wv"=YRc<S@1!/@li;.}C7`e+X@n?s<dBG|dx9PK3VW*LgF&,4KTR45NVW]kHG%EFI_kH",y|a&4dO@L`/1SI8FW;z)kL}5=a]~XTy2`h{H(,db;ej&xpJ{{aK(fv>iGxKV#Efe@/9w=a]>ylt%qWND*#7:Gna73:Fz(7.%<G=oz!l+yc],p"fuPX317K+(RR)dO@(|KT<fn`h&_JwCZbTDuC0K*L~y^@liZO,||XYFYF;k_6E5lS4jxXI6QCyrU@3R4jli[PhEo6s>7bXFtq,Nm,h|31:!(!vq]*"b9O&|sND{K]/Baqo@>nyt:,Wj5vl+4KJKXd_ic_7yh+o0y|31wSPVR./zR:JGmCq~[*)?G@HBV>qmJ(]u`kCgXWYCL:[g>6QfqQ+?mL`$F`AFBYXp/?NmAMT@AMR@I`L?uN3`cLSzSI8lI{D^Q+.({oFQTce_LL#Qep[3}iW?|>Y`F/[hV2r+&f9)8`QI<!qXN_GmXkl&~Sg;aZ1#J:]6g:kafso*7+)pb?SfWy_<_I7>rraX49,&hoo6yyUn4mhf(e]tJysjWbh^RUp)z`nmfhMTs$ePfd*p@wL.I*&N"x0Wgq]0dKpsV`a+T@[g)E~a9|K1l+m`oQu:HZc1?Om?%qUII:HZaLcVlir[ub1Q%yh+.%s0+}vmRC"dxO?8fwOjxGI?&r%Q3*Z".LGU(.A?vp,B_6{6=Z>m=jwx<.h|,}]pYT%+s1t+loc<AYPZl~tC8C[YjzIN#I/vWCEv#XKI<VM$~$8_OjUF^YjRK%Vmp"6mhQ!,_G1B,{M1?6fiB*reB0vx9230*Mn0<,R%efLZ,MFCu4<PKYLVR(oZ~w0Qc[j3y|3V?F#a38;@I`*2fl7xc2.ugat]>coWs!c7w#G@BRV2aIHy}xwik@_)JIOPoSnP]IYgi77/XP1IGvC{O^{e}Ik;Vi|$S>~lV*LS80FJGyv=)YP?ih`RS}WUtxK$Qx19,MNUSP{}nf9N;O99ZdKOLA"7}DpZg0xr2Tu50,b_=Jpszr}()gNW/jMIQ~NmEo~gak+izZ/R}~z,HNpMOb:y2SUXrB(Ez&m5[3}QAj)a@{Kc[fp5dpXz:?W#&"wmm)}+pFo;3&|@i9oSMxD&4,YEvuNphw0N0`/$gR~CVD}5asjyx<ko#oX$Az@me3D`M65If5uCR`H^mE)FNvccv88(XpomkS/FOu?(<>3L{C7S?DbS%F6Y"ES@979/8uF%9w6k89]KulPyuthdh8b<HnO.]i;vNZNmNVDV;x<q6b3bsvy;/L=CS":CZVl~DgRa[nw;yz]7BR~L>?.1C2*r405Yz?u9JFb*.<K@(ge.C2$i>bNivF<!`V}<(5RRGiUp8gYRqNI+lBJt:CS"e+6?UR;l}6AMnM/thZWO(yY*$q8,QhBH>^iK:)^bCFYw1pz,K<R%i&?@QX;x+iXFF=,i<{h[5~x2L$0*gso0SV(E{pYhD`d8v6g37OhA{u0L#k!XYkTb!7I;isZx/R72*<fmPD0VD8zlfLB%0GW.~L3i4SBhC!n_=ZJuAr@E6y.+_d16(eRXnOD8vmp?NPT2Zf*)<^d7X37AzNbJg|6HVFbJLT@kZ5io$u|h,G$q%%Uo#nytw=cQ3sOK`2@A`I}4w|cfIIu?(}nj>nW%rSNs!_PRKau3Mj9}v1&GByPVUAK}/,<8}FS{#xrnE`<ojF(M^tPLSH;"aGq6bQ3BZL$ddQW,I%TX]CofAP?0?C<P)F<&P4vLUVxaZ[]tu2>q0p$esO]&>v]&D8o]HeT/E,1t=DA84{OfgxcVn9i1,S*gmS?ko[kXfweT)3O{du7V$p2VKMj`~peMT~OCDO7pr2>q(SrmAP#vBHF{/Xe.e~ulP0J!4]#2G=Mom_Oz&j?A*u;e|0J3!4j1s2qCPe,EY7#3TuE;#X7{T,^FBw2goJ:InO`O!XAM@)[&~XD5635<?)m+?U*kMX`GY!<FEOoy"X7r4<zm&8Y*q&m2<!"/mNBF~:mNkssCd0[njC]{Yb25xqNmoqLLy,U+A~.@rx"|a1ft,fpt2ywhnf//3w[rA(`Gd+lU]aT$R@X:z^3g3&>!?G.c#IK3RL7O,il`EJ^<rgn#F{)uz*=%PlNH9SZV5{L17Q]R%KhoN`6LYfV1>dJ]kya*Or8A~bB!|;<=U(4x<e9+z6`#n]Iu[cCoaTA9JF[6jC.mSI9]fmn9oScoiGG6kHyhvc%tPlVy(fjRb7p2kmT}:x<L,+cvf4@`;N|xPVG8i#/gcQQ$=4X$&x:G9kP89`L5SyH58C^COpcM+Km`4UN`cbPU%z"mu&L2.L8qlxRq;U4?nj~Q696=q(h0?FWwGk:LUM43@kQ_w<g.7de6{X?{w3[*cT1yw)4E.ryxBq*$RN^ioO(Es4gT:*>Q4gy&@Kc{W)}k[6k.&=>Wg]UCnR##r~[h6)Z!n6<gwMEsp])l;:TGI*fUfMaG[Ct7N|c)wc`+(Fd{z=n8c:malZ[]x&cdYU*92;DDSs4?Zdz9dH%$WBNu]]$l_CP?#{|n0~YXFD9pg7Aqj+W+*fsU"lz]J4>Z)]){NM(Cnwuu/XmMtTQ,Y#1KC_+pO*aMk"0<|2>9tiwl"j0My>p!|2O9%mYm`r6s"Y,n7L6~Q]uYO>h:fa_c*21jV{TYLVPp<{v/T>1<%/sO1uS^V,rbyPi]ErJ8C$KfdlnKW2Gu%+w`<F5bXp1`DYN4|}mankv+JcOgC5vbjhIz(?n3!={QrqS+=tIEf@!6mO1Mx]oZO9W2aa<.D*`pZN&.f>TlFW;7XNdydVm8j6|^i{BL4bWc=a@G*+(SK&.gxuqm%ziN8y^l9IXK.fL~}JEr.YW}DK7W/K^j/E.l6N}GMzjR>|KIPst+f@}!.RfvE1x_i]8ex_t%!W3n1O(bHtfXoCQDuL0Ucc?bb#IHNXq&Tc3_BFta:^M`0![O<9?gb/P:;lhCWs042/.[Xu.ybQY1NUNoL`r9m`fmrV^K)[zR:?Td`4s,=X=+g,F0eY=Q=,6>dy{VQ7d8sD&Kq@ryJM0/;ly,cb=n_#/mGUIL?}D},&mwUQH=6;@KWTi*{jT0<wFMF2y^zcj&R:+voajRlC3j6Up<{q=P)[8#*Vmw&uZ&+^&zl#Z+L@$2?ba+&~&zXQ4?}!*GjR+vdrSogg"2vb<oJFq@QT45+a+iJ|t<yz.hy*g.FI//?`|P{fE{1BJ)L.sot/tc48>JULGr<xhQ:`/,9S`&I82Mo2QHR{O|l+yxf5k>e%d"x"Sj59BDTET_e~SRhO2_VS_M$a2b*9[NHYjXSZ(#dM<C)vXxA(3Ej_YRN_snNy|}a+>7(AbK>cznAy}Tdxf2.znv5&*;QWbk,&mpIyi3oq{aijF&<.@m3`LSpEG&or:dJnRrfwMlc&,2X]yh+F2V{<%j*;w::=iO$eF.HW/sQMf4$%hP@5K/.&SgmY:Kl2oU]QDop%Z&l?#&6ef:wy3bV@l:h(3.Xf=2aTNh9a$9Ja*;l^Um{+sm=EI=qFq5j=&8kfe=M*k[M*t{youM(5#s{qG+Ab^4*6|5%|[l]zi[)@{"y^r0I(1{DsX+mhHSHS6Jm?Me:dxyZ8G)V7]*4jY.3J&nyrDy[Kjo>G`#^qKTUiC[jbamhS=gd#O=!+IFO$.#JoT`&b<~[ZW{B7{^J%l9&67g0M^xNZOo?mdbgMOw:#GCO/g<rh3(P,Y4zm0aKLXHLZ*SA6PNvZ;GW969`s9!m?{vPI6L5L4MnJN?g.+2?73P##b_kek%.L&A{pe[]Kiu&{^v25>;LERu@F>v1*bA`qx<ZF947u2Uzo41^Cz,ocZLX7O=T._vr,]=tbt[qD0n(NK4VK&o1^tV7Jegtl$<Vi{MEqkxX`7JXgjo[=xU"Flv{zhO][?^IU,W=&=h"J5qdG^<YP}e%mkm<%xeFoab7h[!joF|y/U{g.4:;+,X,}{J"%;gv]bp;E:CC#APi^W$]%E;"P5."l$p6hb$T.&kwC2#8G%mdz:r72l();nmdh<]vmImdSD][!7q+a>hVKbUQ(}Qdj]}W83(Q_8Qhan/&#Y8YwcX*?~o.5)H9xz|&)}Wnk&MPpP0@_y4E3=nsj"1y4>JQqGT]iP{cP"YfSXo3r%EF?{JF7,bp4?ol400A73TiZlq:R/^>1Kln8&OU[M3aJapBz~qOwzKQ|G:t	ch"97vQVq5*m#y,JckT0<w|heBt?kH)7S+]B7V%LGuai;U`WS;PW]|=UEX8LyN<8Q(`d"T{x;Il1i0G2U/pAJB@QKew]AAgSXL{ND=;_zh)k[/tQZc*UuXhCR|/h3kFj&:gpp#KVLZCW,cjil#1LHqwE>=TBI:|eUILOM&#zq2yvx4Vg(5{>X>pdF]=eC~x;4apZUZP_vXSwy%6/u38k[TI;rwhZNMGjd)p/3`uB6PxI3Ed!Oi&k<EpGQC<L=fv&^O}7LF#kzP7DH}X/>8A/mzMv`lkyP=!)[fdj@%GBR~Z3vL?eUf.cZ_Y:SL<A,rQ5l"ur@T4`OZ`*(S;qRdsTi:awY=*#PY"COwG*J|{Id.*^$xrnT_YA&nYfWO4G$HMMK}*7*Q2%iR3xbpt%Co0{cRT^nNa)e]8#Ib3sF3}XRnx+rGfmyM#5jIP_<#gr4H]{5XoyI|2Xv5Kwo&<7Q^Gr%!fgsG@{GRCtpxa{W@{Y$+R=#5_^sP2PNfCirU/zBZD0rbv5Z]*o"Uk7yAsc9O%d2cyXr]*?IeSwd:!A:OJY>5nEnH6E|	LDR^Gi<oV]P3Aex)os;sT_kbM=;yC>TsswhZBX&]UXWGM*J6w?sY(b4^Gy%2;4^tR1{$*Vg:M*:*M2vLxTm[d&O@.r_4J{Y[896vd+Q~ZT1KKhaT1K+%mN#CCKiW(Z@!0M7W`52gLQ(ZMWDxilgbY`[;{|&zW.5Kz:cFLW]+?o^ktEwb^$X.Ly+i{oej"b<EMqySvKmL3~Ll,J45GwvidhsC,{x2#!09vi5I[P]wO!zP2)@WO30_1id.14_b5%wxd`h|qckpT!_**K/z|J~5@{t7zf)d8g15=[X*5MtuDIi*=O$yt%IhjL>5.CM7!C@:L@Qq$n:xwV=z[7h2Fd.f!t)d:g,iN~~c(SlQ:_SI=]V#7Y<Lg^cdPZj:aO=5E/FLG$cH#y,|O[i/rN.jdHy*CpMIJ:&#zv7lbu@!z6/=<DI?Y2wGI^^%j866rS156L)a9Bw+3lTo0r)Mv:j.s=MfAVGUv~#/[LA{KgrV!PPe3{yE"k,YCiRTw_%F3P^9:imBYMAg/H3(DkDZ]owfkaIbx^L2[F.jt&KJ)+7>]zu?r#]M]uPyuKQjh7C4hP_XL+zn_<!8IK)p@Gxp{[6ML#wXEq!_h^KGv3"U[6!Nv=3u8pk&[2r,MD|w,Q/({%B7E/Fn2E$`h&_Deix7WF:%qG1)2XZ(vX^*q=$`e}:WdHz`@lW@(%vXnF7I>xl|`5zML#{PpjE$PY=YsEt~i{bXO*"7H!gx,38x&:9m:t.U"Fum7IFs6dPpJC:=&u}UvLQ,!_GwQQY4Q`:kSZT{N5!4|Z8r&_7vhLW7T?dF#w&uu0j,Sti+nV7Z,:%oEap*.f3U;tuVAl}`=q"eCNDdJjdPr^C{:G.l6b@y!xb/!{%eTMycMuBp@]4K&_LnF^P#M3G!q2&)6xnFhOG,yKkOd2]3#/~Z8r`+23b5458%kc5)BpQkLf&:|BR.LmIWBzjw}_XDZHQ^,elY%N7$+yk^}Y:aC1gzwV)`$wfEM_`U)(CUL),@l5w`"6sdjm+=]TQ6Kj&fL@dr<_7vcq9vBqRSGr%`drdr#NG?aF`$7K[]S[yUqEo&<3odu~~9%3gU_qT[dtXKG;$jW9rHx!$KKxhwUKG6Y[&(IyF7Uvy+J[xrkQ4:{y&<ShpeYwctC^WekUlVT9*Z_Jrmq)lk|Q*y^*S@ADE7jwk"hjpI<9@[vzE06#55cb/{tV5Ty;D%+NM40uRM;emL4V7ZF)1G`1b#9;,9<W&UJi1hxry:+k1P~}*01Wzo<#0Wlu[cAkC9f{8L{9)P@S#.nJBNt)f0j,vS19+#iOnO[ttbWWw|l"K4J3u!yuUO8=FX"8;m)s1ob}2mVCz&BDLH^Tpc31D?P3RebwdOdx&qPucg9G_^F5_wLkhqNQzMZz/;>6{o0@}nb`/(PO}p6Z]lt9JOj[G,H0=w"y7dk7iwzt,3<8Y=V^aOcRWWx4S~k>~GcD=9S5>;GL4B[yDc&N|E<fwDgWSa89mmSx4m:F7ZFQ@^5Q.L}N)a$GIbF3#Ku?,a:.uLiNQD50;p[.;%l]i%|$74R|x1zWkad#=%]W_`ZL0^oabz@:huluZXX]_Tu}>/WWB@qF5_.E.+dswAk!,754eD487tV3|yyXL^VP6}o]}+vGuTGVjRvVYiC}pga,:`<"r.tDCp<z,0[F)q]F?mpE@G!c>98as$oD^yDN87,=(3C.gTA?p.rZDOg7AK_Z(5{S36X<SvT#*G2?Ftgku.ii2c(:3S<;cUv3nLy%eyn3]`8.=`Y?+y~p7OA^YGVgk*X{C;eT36`9Ih4b/ELFG~"%7UIp*@+g+r`&*/f#^Y|CtV([uv4=1Xpy*4Poi<7czMsSQX`KTzIlGZfc/[/$sQhyBhr/"0XQz+,@E3/@fmbzL5!r$UR%k#f+?o*MjRBqY^VULIG|}aKx%o}^^?dSI`CLrKfGTM+!fSu/0wV*Z&a[jyd+L6k~cF<zvgM{Usbz>#_4!dK@H`*33_0,F{T*Z&8;1)V+z/T/cF+Vr/myq4kn_E6"mnzDu?<>zyC1ALNSjdKjmH(B~g{Kxrp5pL6,Cri)eF%UjL]rp~0MMB,x4d%~dy{IOmyGHnVs|?/}Z&H|gsMQJ]kDgV3,K5!t*V1LTYqD8rlV8C1,RIO`1},1f5maKnyKgVH|Nh"cs,P@2!xYs,E2y%!Z22ypvJ7mjh8]|b=N=|bKOwc6kN@bxk"o0M<6?=$KIr7b@b"fXFJC.zHF];vJwIK*PCH1fEwk+iKi1lhXeZ*a6KrD?/^H{CZfjRc>g/R2R5jRL[]+D{GYkD@pdK><7nTr;gDe&8jo47U.5q3n"<C/Oi,W.XP=zTRMpJOgI:6Zr_?p@c7HOpw>~c*/5Z+i}6XF*/0."+{?v3#!o]CWuE;FiNJ5q={8RZvqfyi2e9sXR"*r0PY{<fP6cFweT>A8.]xWG#KyTYw$,Vdb(TG*oa6_E<m(MV{)+Q4f^1O;:urNg6+T@BSHIN$d_;uIjZO=[O,<$]UT,<MlB_L;8[$U<?qcs?3U9o!Q8v9p~%R3Tg8z?}GYV$vPgZx8#<=wC~O&R^$&99:WjxGz)`qd!y`]n@.#1(Aev!5D2jRS2Ktc@M%!k8WhmDTHmJoP1Ah#<GmO)xtD3b;WbKJ:wzKh}RhpQtjl$I#%0W#S0Efa=$dv]grtMb8^MFKwh=NF~Tz9uJD[tlG)SH=eaHl2b_cO9?!)]H3W589QmY.g9HOp~E^;B~8X1sZXnc{fo[n*=U~+x|^Zw;uK~?5caYK$!})4!Se(Cg=]#xa9;#W3c_:*]$%3O)}]Q=~9T*g;;sEZ!m/Deiz{m[je$UR#nN]tw?V+}eu=b4,qfwvm>NDZCHgN{MNMs{%kfKNr7c7pifnJUJ=7`Yv:;gnU0>sF9$$p[a71c>`*YWY=$@:<"pj|;Bb:2n#YNn%5A{sjEHi{C.(fKMt7w#BR4t^8iGNu~q.a:YmIqXW;_{.8b$cY)u<d7bYh~S;UZerq//(Iapub!x=EVlyfk:[[77562c_ndiUB41}dF85=z3#FcM6ksxsRE9kN6y!.kpPn,bbM1`#l1w}i(6ym7&;i+qCodi&Xz_q_6>z3*7``_F&<)M&>Xcg#sSh8C!?4Zq8*ckTYC`tsF|+lXwzs]TI%9o;gqEfr<xG;nd_rS6G%:wPvLl0BZLBaCU$#"Uu4!;`L_Ms#Dwx#}<Y=8d0WsmkH060#A&wLBr.aCAAW_OLb.lduR@~V4BdZ4gxub7^cIM+b:/9#Uptn!m^0xNVX*L9{./O+WF{C1Ew4;y85Q3#MCp[d1*cvY2x*1%^TWK3Xf:AkWykwD3Zz"CzMoXidbd@6JP@kQkT0<w3nSGu<EN&?1Xkgj;>h0L/<&B$7[&D#,2GMgVDeID1R*h8fz)Wb0M$e|j+b(yw`S@!E*LEJT0DOw6N`+*{(}ksB{M86e${(i^m}]`(BN!w)lqLVqouHO/7"U28N%0a!g|?JoL(r:;u01$x6oPt$)M%B8M~>V0DcrDl7G5>H2k71}631v(sIJ7SO2v1+k&^C/R+K|pJV^dN`=An7"8/8:dYV+M3q+KoF^1Dl5S11YQGiKY1>gdVKkz+7^*%Pk7PX8G)f3_LyQVgd;B~7=ZNNmy<Rie3)7j{"p<66A^?g;DXKsYb}]E+fQkSg2ye9tm_*Z$N9b2(J=)0Rt,]<;JEJ?yNRI<QtPJx{Jk6xaF4/U/ej90~#CZ:R>RC~cY<q"6,."7CM:nn%O]]N%3_UUgw=5chRQ)}q~Qh}aa8zOZMrgV8btN~/1fw=<CkZ2@35r*GoG=>a=V#m%40"CE5*npdQzKR@K.|d`*>!#40?F=5ip,(JeD7ZKTPYsO/R^m<vW&s!$Rb{h!5jy?=[^P2HQmiF&nr6qG3_r,TJ1KoMFf~y`4QD8v:{Vx7~P[KI?go9%d9;2?RS19gLYTNhbBEY3RNV#v92#tIATvbyx7[?t+}gG"BRb@@Ieq;x,*fflG%&:Lzy2WF^)eyCH(*?:{J`;9kqU2^O<{qUzZ|=L?.I=M>X4R`j/MgJE7d)CBD#3e,8K,IwMch5+>HA|LoiISeMoFQ)dx$Y5X|Xt1Hi0Q}L;IjAyFq|iy0+!W@!H^IewzlEA0mx097B{E9>?G0KK:1>k{;huhd%t^x1`<NjZO%}/9Q$Vbi?G<LPa~AR_dG*)$q_6>e5Uy#zAD@t#_G}rasZgY78iE<5bCyRgaIFAunZt~[tw4utF;2E7t,r.?kSdR1BPK&<WW&NhAw!VJQ+aymWG`OKw!jFimc_!5/XHwjEL<LSFqC]fS%<54?oA+#qGa}y;*PZuSfVsY=&79>I?5,/eE_WVV1k3r"J8?;g^TUB6vuKIejc1YQ81cEj<)^h0M[a,SBe0z9[Ib7is.E`G+Yv`6.o8{zcHsGrdXn|;fb7RzIDF%?woLpRmi,$Igw3QJ{E0GwBW/d%YG1KOu<(NZ]k2NyF;GPVJZ;M<xaF./v&a!1KMqAIcv&k,0v=vHPVPZY*fm8#z+2WR>(vK8f|0nFQ:FA3b_ko:BAk5_<0UGnmIKHZrUsTtf#nt]Vh+UMT$?Y:/Xf@<T|835^=7tsMp%0SfS$~9^o3&YO.^1=g<^ISYP6/Rb$m!q%Bjb@o87^1bU;d9m=KLzubVhNe%y5j$@?G2aUpexY9402W?El#O3eu:k|p@Qj64;KlR]Yr4JThJ{.e",pRQQW(AEPj.|rF|#a9m`xE8M6?Fh&_L%RHv^4OHBFdc0j<5,Gdc03lZX;uv4m`*3%(Z$ZQR&Sej@c62Sp);*,l!,NlP6]=G=Ya_1KOhE<5A(55JM_M[SN*J%<4OL)ajdnU{oM@!pOorg2u_/vd,UO9^*l,DiY>>ldr?!OG?o%}UCu#u1zTn_gkE~wqt9/<^1RlOZgXHiIz_<n,.G0C1CSgPcS1bn^cf*NEyPwBVF7UxfZ5.ErG]1&^pFO!D@LtGngE~3Xe,U~/2}GD$zKMoMiD)acyDI4MnJt#[u/[O2fD9L9fWE&G##/<9//2fV+Vm,+HVDmA]&T}Pk}m:V$+0Xz1rL+V!v#!_]_ug!jNZErGVz9rlvDIJd*^UM<c!oT2EgT_tv~!8PmS=Z,cXkgEcGfyT<,%<VD99s0j"B|h}>!V;7THJ5pgB*|jph[ZR~[ZG]swPtc|j#H=r%,H)a@+%bf0a%VQn)i^D(ljV](2jN^6.M[6U~Sihjt]R_q`:Yj}9*NZS!=tWuC{2n#E$/TX7%TI)u`^fH]IZMB=h`Sy0+bV,B1KYBYJ%::*7v[k4T&I&_nuT_+VL|SPd8=_1JT>=;m=%CXg=Ep5>;6JyRrdeCHY*IfthmI;^?AT{<sVK@bk?iyf.c2$"+o]3!ADJ)._`YH6MP}^0k+kh?KN<]0kQmq,l;p5VaN19Gn.pAmk<3P::*5<QjJmBIu*o;,l&j8a+ju,Z3a?98&fY?@041Q:0!)vej.{Z.|@dqfvNk+X!S|`k{Lt006KU,T@i/<vayE]oNe[5D@kV+/Y//DZx:OzFVjV|(HsNzLZ~%)`f*NZQf7mEzmF?poZnOo%VquczD6Nbz=z9PNHZ+L.gHWY+*?8kQ7Q+aLlvYs[?3F&x.$Dy.Cxah4KMrh:1ozN^OkKC8JnkWA?k=s@n3IyNfG?hG@jhfB2zmx:&1(z$r#8~fQV~g33+]OF^m{=`ZQbM7;Bf.scY^XlDM4UTDfK<:(k=YU;~,&%#5cX.2m~y6,=1;N4}wQ%,wx<2!+d,oGKq[y&/6[YXyH,=U./|22&aGBqj"<.9o2.k3#K)%PSk%W=n$Sn.mtL!?v<UpBJ1bDaD@_yV{O!:OB8dHLV)SWqzD?9Ldb7$LAg(vpt"CupDGJ!y%"XS@*bBnFa7%>gLkyMOiulRD<5z~aKJ$&Y&VfNNT$x2$cmQ._D3|P*Y$^Lvm0B{p1;QDBq;Gn;.g|>9lMTXM_oEI.tE~eYd)%b.V+puZP9Kp<kDG6KR1=5I6URbD?8(?SJdqPRc`/$j:L%mTlus}4b611YF{8uP.g/y_hF2E_W^4bL}aiSNZT_7=<WjFR+bc$FCd=>NB~X2r]Tbtq1y3.T/(gw4x+mb|rV$>]?kM[r9pqixINw~x{QB&.Jt/0+bI"Vk:[wK)Bx/cdPpi?f>$q[*kTZbqc_f53UD;{_p=g+B%n9k1MXd%3P7!ox"yKJ_=J#wL"!CLnu[Z,u*/9?y1^j6.n1:%?%^:lXLuJ8qxv=(;7pE6s14O+?t_kkEY9M3P:57S<ihxab0M>64yM@yTdz)}2?%M2HQ%r1C`4!1YJug,,:IbYQ:Q@}Fvm+M1E9XNaQ?jsld9p+oaro~gfNF+FV>xGE|&g|/wl[5cN%oIR:~2;RxW#9Y][TSw5dkOkCsubz)i(if>x@3RWmcM=jgmKoW$D^:oUm=ym#[@{P8FHJLTx/l|t]qo1r66jRgms<oUZt1M~J:iDu:4,.l)@8cJzJZtJI+c`oSe?EFCBU/uGEc^[(fDUJ5.=GUJIt{JEr{!@7RvJ6/[xg^vIgsI2|vfdChJDCtq}b<=uZC)qUMS~QOo_nkiy5aFcQ+kTZa9@o%n0|SZC(>s8,CyPVn0_!$/#2zSz`<F~c;yi1+/z@[k$o#I/v^rr`*xJ69_Bp#Irkjoe.G)Om[L@RU!Wpox0Z[?f?dS7EJ)3|=xO^CCoiUaDLMyCM$L:,Q3ZF<[mi2Y>?7/nH&_p+6+/Y`N>)X@ni;5_n~y7KTRZwAqd<|(V`m+0Xw/;bT0f,xue:0Wij!n`;4n3e4]vrh`S6k~NDD_^B+(BuWJ7>q74c!:p?@J,t"&O$<&%TDR#e*pm!L#K+B(tBVGU,oU&W9[:KIt]+Pac~PC*X)%eH3Quqf,ya}xCRnm=Zry+$X[|>Gr5`mi>f&QjR}^d5e+x>N;$U{66#[(It]+A78~~t24U%UiYO1cj&iNX+D_@)S{iKoS%pn*bCoa#n1t(?<i"x>IPHc<6S,E6XMh6u77xig7!7(upPK@CI4VCw)+i8de(.HUUJ"FU;U4XN96cYu`1t[&PrNEv(M`F{q]Zo~G}5!{377`j9`2ngZU!p}p(N4ilotDc!Wqo@#>|EX@mi5uzdVj9v(]2dBt4*PC:4k0FUhqhqu5iFq;HsHTC;`DN=csQT}7SI+):Gj2@t_Jxv;qa6L.5q*=1(2|=(|ETUVd,is@#&_@C=?TE3^tE53l"AaG~UzC0M%;j5ay/=pj5Lw(b@W%FFrbh=$$22YQGDJxioh@]/NzKxH~!rIEfTrF^3NE>GJId]s<Mo@r~LF[qL{0"Niu^rw2/|&m{V(K31]j7dxUzK`Lu(LWUY7/9=35=Vo[+[UK|;356eU@9tjiB*GO3rgAe?jCOCz,HD6P#Im^WRE"Vvy+wo(furu5q*(AxFLwFxtEHYGF&l(V:e(QoSaG.OUKFbQYAp<cj#/g]>Uj+,b%D{V[1Mjs*^LSs#|l(w3|(|c2aPA+_rz902%;P8s%B2^_CJkT>QFj?0NIkOS+*RHD~o2%.@jsG`wvAe#y?US"2CB1T!oj6hAS8+eFCQ>s;DEx{/}CvvIK~+>4F$Pld+v:p<5R=PS%9NAGb`jbAM?;mwEYwghu}<j2ADLleSiq9F#;xfaGfL7KbS9wSQg|Sfj1uN#EuC*|ohMTpi&B><1jW1ek3gC*@P82wg(Q.c!eCx`$Ufibvg*#%<}m0;_{Z!^Am8A=f*bu.6w._$4]I`H?.o:~R*,{Z&z2`aILsp?^;b~=gWYTCSI=o){t"#S*/C4&Okq}2("JB&MQ2#x)`dSw"kyKNDji7/01Jxr_=Zn_7v!rO>{X:,5i2`J]pwykw4)Kj522gq}@18SRf0Fmr<quzitk*{P.&<`FM|/jdKFrnia5rwyEqbeymGaV2h_M(85K#[&1{K)[_ao{h9>Rqt+XZR<n+X]W)?jNQr!efkx#phTfD1!lx<^#hQIvxv3DgDUyHVrO{M|vNoJWhlgd8fvmLf+iXF,E{w>,GvSu:)`@mVp5G@qonnY9O>#W<nO`zB!wKzzMVh7z{k1,us)?zBTF<U@k});$74zjr=dcaz?p_QR>v=#W)4:uUy3Ei|li`T/(g_Lf@k{q{WO:ym{tm+~gB8FSAYo&bfWWcm(1}Om1C<3QCKH/#YLblee_fd!Y6f$zQ:@Ii58~[3zJFJ8riC#_{xJZ+3~*VJBS?6aG~v`=yrYe?B+w`$g7p;=]SqjTi@hQ]CM?10y]:M`J>wKz$`|)uIngb&{W(%#N|T0y9!z7tX1,{TyCM?`SP"a{QT;YM^~~B5G5M^`0azgRV2|$}$roch[D;y&vp+%<MoR(*~SJ+)?XW@UU`>n>4qhngF0xL.BSKw[kW@l1@ke.8hn1f=T]oYTYL5ngH|Fx*LTY4iYQ{KGE;q5N}G[qmWr:fs)3*p?rr@^y^U:m+/#v?O:v}cjyyg+p!$<354tkRa9(vyRLx^;d|aMIm5[K`gU^mihG$<ZThX!G[)@V"X$:Fo46{q|vj7KjpjfpJ!)%HYM=4H(fPKpEvHui#LXVID^d4M^gAp,bNZ:2OYxePH)/by<Ip,I78V/#)/4ZI+LK|a0m0jmBUhtttlQ^k?WkKe?MD.YT}VbyJ%VJml?hFrM#z3"CF_nvZG3vBCkx{;%?c:Zae/PueLxy3wbtqGhV.(B8X)@Vhl89SaLgYX!<lQAG%LJZ=!iTNf_wmwhb(twetVR;>dMmfm[/.DV]lcahsD,)k{gG5Hun_q#AnHun^9%N`=w]4(2UDN1?CKXBp#;P}.{aeJ""I,KKD@^C@/#yC)aOW"03WOw]Ge9![BrAU7YOzG7eRf}w.H*?@>/oZF,Xf&{R"&{R!ehX`y0d59DF&4j2QHdqKyNfuR,cy4h{(Rbb=,2.EL1)xt:{LQof<Ofl<tf{l?_{}#H{p;TYpP~L]u[wq#cr%H.a19Y5nfj!o]+VheEiRTx_,^yz.t*2!!f:!B4B`MkS&98GB{_qPSu51k%{62PX+?#<ztPloyYTX>}3Fo.[xUg^d8sD"pL`q9N3HT,6Jx]dH[nlyrg4@_v&,_$Km%I=i$PT,n/4b/1zfEXq:|9L_IwBz#NQ]Dl=Xi_H7G$%{<t9*;a[F1j3!oeQo#7o#qL<sO(b%f[P7d:y9RdP&w}Q#Gz?6)IMI7]>O?A]e@mYcK=k}:PW[2XhlL8~Bn>E9ZUr>_6y;sX5h4#~R|fb_Zqx(@ZOIB0_;>$IlB8c@pL:GNGj7[dO~7UMdZwH+4%i.jfM*^V?bYsH8m92I|a_(ex}i8:w=#"@(]3Oz`f{==y~?!7i6XL|+ipzol0;M@X>`Kn{M=LI^K8N,iomjlW#4r%}P#+!`W|w^v"c/hY[)]rM2|GM!3$4(!QeuY*mBPY5&`xE3%7Wg}a^CjEHe5@fLB>ClJ&cQuFV&|$:&vQDP?nmrT,^zu]28.PD.V]pekKXS}(%RX<>u8[G`dG*oDpr&$XrRjAgiZiJ`<#+mMRh]Lwl9l)5#xJBkM!#Xin7zI,^e@/)MgF%L_e@Eqz*P;8u)y9,D^:!?F$jt$pN$5R84#<d}mMukrE;r5eX@NnEW_GAC2+yMR_kh;J3.sVa3u5~a$6X#9%5];wGI;D53("Jfy(vp7(*L{>K0;"d_^Qnt&mv|)$eXRcDt7hb+=?jmB{pb!Z]"Frm~kI5eSP>gT{FUN^[{xk$idCwrcCD^[ZMo&2~{C^[#m0iR{rH]C#?2Orm{T$utbozE5?37PfPnmwW~DOuIE)d,]`[4],u.&_7n"gq8W]oyW}}`#Hwq{Y>OlOZrq{6b+p.d*y3x1"O%>zud)Qq~0%2my;Ke^P+K84mj36yERjH~TT{vknBBDiNC9J>^JTHEDv_;wL,F{=z@8]I0fg?RfN`np$3!<@cj=AoL@+:vV#G>pRJDYt,N^&.v*BzNR1`PvqlqzM.[S^wz??zpNB4]u+0k8Q{TW.$WTk9Krl=!.xra+Vy}o.KyG*=b"wkiqOA45?lsjXr%pBe8bq|]x$IrEuRlZj8%2HtO&pblMf7~)]8X=#aSeWR_@z|EegHtv1EBquF"uiHhd5[g^B|2uEsz=OGH%LEroHzgIUJ?dZa0&H@K[rg/5L.gPvSGx`U?]R.EM{0d.@G&82Zc;{hQnq5jN+iu}gY.&d@+Z(%F#sHLm{.T,#7KbCJjMI~)M;e=:`@*5?bT;c@Q^wzn<X?8?e3l0v{3JhqXQC<*gBR$1*3Pl`EO<M(66_T73!_1U1V:x@V_aK{9`|^|vc>dKmg3m4xuYE>0+"GGvaq}U42`pTY$:yc:x1pS!I`R1k(mZ#I8hLwNZRy6JG*SvgnObZ<QE|ow28&7=?<&!rz<zA&FsyeNg8NWkTYG4zCts92"<4OZjw|5K4fll?kBG^[k&EQt3}SP:IljPMfA8~1P!Z2Dk5SPssmygFiF3f9~&$?EW~/Bm_Ws1lNqkkwZG(+gmCcPg{59eL166F3*FbY&QW7GGz5ad>:H302B;(61cr3|5D=X#8F^syOQ89#!:MBe;`86g0MDG7ZvuVz/F7ZXIkOtTj<1>Qw/UC%/{,y[<*R}m@lY@$*j|o@YIYvLo#Qr9*yn8<[*3wno>EN>,=*^e}4?2%;5/s&3tkw1[bdVNIU1R0@g?e+K&KkoRPWB|VW^+VXfvv$GZ&j%S:s}5T;1h&oTX+75o/e=`gJYD8Sa&=wtn>E6q@E"Llc64mYpjx<[ws$`tm7Wp99J~YGA?lwPoL>T*.Oyy6gCvn]m2+cGh9]4NicQje98lQbT+bKdd3QOft9b|O[Df=Bzl;=<:%@wuDYde,yu63(D.,z1%YS1>|MXy?DfK`i9(~I<Ext[y4:4URq.t>`+}Ag^HJBi413fT26A>:SC+m/T9LH)u?4bxh#BQ0E"t:(f]gI!)zEB{5|_c1ot)2(Ahetc]i+keS&d5dZNn[vVKn0baqKCftK1DX(Vr,O)QuHY|uq:R@)tt9Z{lNohSKE98U>2ky6_uFu&NcIC!%gFIn9WI(_16DZLZ!&ukWybrxMu5HG_qSJ<wtb/g`4iRL@[?@W!{>W(<Mlagp.#V<nC5!?1v7OX$]>BEWA[ac}bImY]uuYMGFt1L.UMI3S5%lBlU<ci^%?gD@.Q]aS<p<w9%/|d*Fwh8ZG[k8p"`vVClqT8^<w[9#7&<JJ5Nw69H>ZX3e%ep7m9~G6<px;g8MV<SyV=^t@n=o}{[&;I!TtYPic(bGKhJkaOT=<yaQs=`9yVS!I%jA7<;#4xq0AN?JC:Nzj*=Nl5sKgGu{]VmxY;h>7>GJBvtk7pbkEQ_$<T.z/aOe{hnr.liGQ%dFXK}%D):A_i]sJ=7GB069dY*l1C&AD*t6OG#PjKa@$>gqX/Kkzl9[f!cYH>cTKUgrDV..Oida3k]`t_Mp6>ym/BRSAv([NC"{E*MEim!<)2EwsUA,L@*FdAH]ZlLmXRv[FYAAAAAAAAAAAq}eF(rLo^}b$Y{REhVEO|K2x)UtbPJe@5ZT|Wp;6bRiQ11s_y{NV/D9q[OZHYZPy[v2hFXn/t~N[Y.0QM8{{/7#ql]iICIO{{=b#1PWrb>(/?YP{8.>s|RN0a6GF)5y6BE@.}lS8wq=Fi[$MPE~fF<wBg94OoHA9g&()rv|q6#[}Vn[fVl3V?/1|"I(RZuj$nRuE4<Nu4a[c!hxo7tI+f4s;EqnkI#7TA2CVt(*rsI2.eQBVy@0Plvq(I[7ms8QlEI(M*0E(7SDV_SQgs;L9h~C#Xn%FQrCr7`CKRfb$,F=bDx!,2(2UeE]{0oDo*`U4E7(m5(*v>/NY16m=L;*n3:Y058yl1_Ob"5Ja|WQ1p%xH!4eL908_e/wJ!Xoc5"igcGMvZ94m&:Ed7O.YCxt!:^J|O.ICt+02z5taJP5d<$uRIM4f`vMw=w5y>!S#+["K9=*|X*W8##G^zh5$;yR2xK:pd%4~NF0!+mhYEJ$SI;?3z:<|2Nd,VH:Ju|9La=_H(KB1Rf0P@9.]<6D|~#9I"5P!8dOEMC`e)D>H}R7a]u|g{MRU5>YaY}]M3r3/A~<loy#ht*^btvZQw8n4tupwZlx%dXs(!^a<jQ].i4KAxO>l~KU%Z:o]I5g@qU1T*fYi],bE[!zw..xS*BtGkS2<qpp2S,oN&rVz{9.K$XeVEY&eW[sgon9Z=;,=B~5^ckDqL{T}%N>a1FMiMUor!vF[q^i<Kp4XReg`RO&FI4IPppNHwKNV#Q|1m@"u%HHrcgwc$q?MuvLB9xrA1w*vR]l@3>IF%>:?kAUzdMR.BBRfs@C#zPWnoO%">.HmOI/c`d#FtO/*Y`O.$%!07LaFExniXHh~?/QLb/jm?bgeC^+uDWq/LdDMHa%l?p@5;wB0|%``NP@%y~S[#@3ZgjObv;[^X3j%@qr}+U9+lif)R?KW5rN8*T,B#cEf4t/$JScp`m[>Y_?(xL>^p]Z=QZ6ljFZ0Dz4T=E,9ifiX%]oN7gDu96X0(qP0<l|}ZiUHxbf0Hr;c(7.W^KJFy&*Q:13D:O=G2=LXukoO!L+ium`|%O"]a=3YK:Txj*xUdC@WxNgf?;^x?ktJ2i6^wD3@ZZiiIEq?+eA@v>6xa+KjH^SDB}FN8,^Z%Om9}c6o]c<k`B,,!y4a{5+LV6q}va>c$/eu#$ju%F[(Ad_NZ*bR!;;B!_Dw1u`cGUC^h22]xVpnW,XM_Nyf.hrxUEE_R*yAE=9zB4><=j5pqL"j%o+wxjq1`h]{WL|Udn!pIk,N5Z8[W=vUo[<8c$[lON,3@tsXa*Q5[2xIXqcI&16Ue6Ezqw30[kx|Cp:<mnD5C:3Ig|tJtC%+6LsVu"$WcrX(sR2>g|gb8I`=Tj],[AmJz5._4fQ*Egru56@*pQh~2Xr([iz+pUkm1yOs%5vz?.`kXVyreX]+rNxav[qR1F!3z(vQcvK}+xnM=V(GAlba0RS_1}H89mzhUjTJxK7/h/=%r8)yiha_Yyo.Y5Oj`.e%)!A{vDStNS<%hL%;Qf~d2I{DNKZs0V..8Wb:=p71Nt^NkF@}kT7|_KccsP3eieO^zR,4x9||*ZIi?3"?w3dhcRxBzQ7&.!F<P^7`,|:FyUUFpb)Upn_5%y>_/QKPrE6d!4bo)_crtI|:a+Fs9~^62KwMWrlWzl@^Pp#qvhOx%,&#g&q$tdm,O;Pvtq{S4H`+XY/]HAtFgL~8*>pq.OvL`l8P4LQqZ`Z*l&9xi;nY.m.}3:L_~hjM{lAM59J4wizs0pM,+.F?#Mc7K,Sb"5rji}&(ZZqP[.$XD6_;p{wF=gG^+{HbKAkFGPEtk0av@.h:zCUdsISIw<]U[r&e22`%kD0PxnA;UtYQnPkIWwYuC=.=xk]YUW0].kj4Q.PMXA0`3b*|/&mYdd{|{1>PMxMghI/^c@3BU51GYaq;tK(5/=+*Y(3mVR^gvO>e`Lo3AYNpbtEN?QvQI`XGF`1$.o)lneu|hL$fd&D0u$3r&RFkvJ1hNw)R|]{IGSh4uTSwei$Uv}q@^o}?7cX&K>HQ0+Oz.1&uFU?~WiawevSMvQ*(atO6J_Rtck)|uhKx]u%JY{DxQI&h/gL}mP2a]]M%oV.o2&8u:tEW|E,u5EZG0bha<o6l@9w8=S3=)bhv[$mSPx"sJcHD@O!+2h]]k$D!,lO(xIfygYha?Lv;GasBGA!XL^Uq"S>?rhCP<J4}R{(@^g1WGjlop{k)PVM.@=9`Puks*_V?QLRoIrfmCt{OW^aNN,tX)TSl(Mq*=tYre_.7k3vP}O3prI`u+bLX?SF$4UK0j?/tilr_:FEldysYcIgy!YuG)(T+TwuJ0~;/TP:]hSMbLpAjW+m4aa~Ap8m*kJO)nv}|j3pCD;GUVEL:q$MsD#)}Wh%VX7:P+Q.dOu"*L=G/HN3i0z}4c67/co6KQd,lj+Kwi0a/qfn*#&5i3#NlSj@_Jad"PcPP!Ah>*xwo9kx|G.n.zBKkKCE|7Ek7UlWjm>2/`W#*;4{/Bc|R;K&grD^ReBk~Y|S2!:Eh6q2rzzAgmmDGhw;2F"v<4wfi~[Qo"dpE&44H1jCIpIb4Ga)nIvKG#;zK`d.6KAD$_1"a*pb0uH!gy0j1e>;8(IzQ[WQ;zV*v?oTlG!p@~&~c|vc`i?L:?lA5%:Eh+g}/dVg0v#IR0JVXTq2wB!x0Qu,GD{GDT(RZ:Z5Mgh@N/sMX^BcJ#@b//(71;ekSi]G~Zu]r#w+WDQ2z^oge&~=CF{*8y.m@R!(uI,t#6/3sIN:O[SV}:]BmeJEr_Es,OJ[e(.I,[aiwp)!.EhQ(gvt5zP5@*WZ3v}.qaZux~UvNnk%qmL1)f|;1v%Zm/lG9=iW#ggGnax6Z$5huu["t/eO$9u^G4?ba}3TFqBNmEq)r.MWVux)DD2J+B@[5:(pMebefAz/)d*Pt[?58sP#NBEcNWh+gLmZTgMORuI[]y7uT>J!3)x4cKi`{X?@fz"pnDzNkV0+i4iCI%l[`xOy1By"<ixFb$Ks%z9lu|AMwF|[h)MddsN_:QCvZ$<$?)DAF?[[ZAfu/e8VhtUE%!;epj@_6!lbw||qv]Y$K*l5J[@.BF?~sja@uL*SfFY$p?VX!F~Wf!3Q1GO_7wpjGAg+O+>CP#]fg3k.wU^SgOas+M*$arn)X&06+V,d3X56b|C[!E=)}0qo2[pZ.*`*[Hcn>rs+>4HFD?&DPEg]nm9?j_du[0eAl|`#VuCV_:`cVmv6.j=&WF5c|zaHTU^n,CVW#KgQv:5n?VI$lVR7%{7+F(~a_LlHa?^^ze>L!sq5)?{Ip@3&~H^q*3e`]9M!Bsz6OFAanOu0:`a;710[D#eATj96|k!H]uq2#0_Vku)641oCmr|^N/4G&tFHpI%yDOHO~N)sS)e+B8k>LTNK^)(6jy0A&S606qoGb]lJ!N1Tkmy;F_aEy[DA!=G=^kyw;$Hk!X<:cTo6U1<*U$#Gn|;(wY+?OgGE#~k@QODAqGAc8o6w}75m7kFLv4gE8$z0x@!#1"7VXF}z1FM*3BH~[kBOVpw}3*xDA[JK|1P29__iBBTWK1[CMQKvza}i|SYZJn8Nu`qUVJ2TwM]/;Kz&i3?{&F/h.A.n*%_/R^QM;PTl1|^I(rC.y!~Fl$ci6pk:aUgG,3ZiQ@ZK3"("KG?0l5(SN({l6<Ii}|]rSTqlZyi+`MR2hKgDqJZ6[Vqkxbr$X[N;v*hbE(.b7e{m,3E5O*t8PBstu*VxqYFy~q>Ko8|+52Zn7xy866{LR4*v#b[3sgo/*EU&46M".K5SBc|^?4W#(5k=VbfZu6hJWy,KGjZ;|@fVtqZ)Fw;7E&n0z]@ymYtc3&L?_6hSxS~;ds[8be.rY(*9R0oE+x!+!c*y;}9Y<~8|D0Fu3Tf!Ee;930#[S?rO<2P6WL6XF_W`&kp3K<$?G09DKKfnbP:XaLf*TE7L)89>9J~H~Cad7hYhMnxg&bKX{hhgTq%#wStb!7U,0VItl^#~n/v0uZDOX:koCq=YY^A#qSw|A}[7eAX%)3a`y]zy(:4[aAlLJPR{!Lf@om/_`=JO&U7`B_&|g20zOE,jfyj:jPO%g=G@ouOf8cfdgVo5LCP_TI5vbVYx)>_"8Z<>;q}BC<XoVR5Z}}n59zVp[p$(g3RdmBW%*wz$lpCk@z:#Pa7~_xC{5YtraO4fF#8Nhfc~DBlEr|a><;h`O.OHLsv?U4ogGlj>{}u?QpD@A<#+!?8NqqBR8hRFhrOtD*,EPL}eE>zpx!Fq;ofCqcsf[wl.P:V,Ws,SH&ak2nO`:okC(1:BV5|Y)BhFjsgh$`M=[5"s?1swmm%]=?{qEhNK/{4OC$(+$bCuGw9p63]Kpw0J,NwFXaHTKL@o]p,Y`45<x/`%S}E!y`8?euL}V#fD}1"X&306"hF,>NTtX3HJ{%IDAB$U?!Wp@74esZD!FZ?,ER>eAR#icV!A*]5(?Y,=yKIXGx%>7y{(_R;k3zQnTqDNb"2fDtZZL+&eYj)yZ%<VDv7~/.g~pwrCH~w?&a7!!m(na2j`ls`V[&R@(4_Tzy7<d2aRI[C]}_7R5&n)#?]WxIG0O.{7G&6(m[6N3Gw9[tf?aje9JZ}e>pgQ(mGI:cNP}zFydD2vxbXAmIVuN0=/5H{=uKha.m{6@N@m:DPP<q=}V~Cl`("^cM)BsO/gu&0[v?uf.3gEpwXXzplheZL1iDv8/H|yTdN)O7c=w&eYOu|nEg)_ge/(93.tJ:7{ZsOjT0|y&hAKxnw/bG.S8xb7jHN:~r=9]MuSMoen9ajIQlKZ7Y<_VPUR1I.&iM,}8If^#:DO51N<]tR<!"C(=L`A9u!(E81#nr,b>K9&+)PEy}$?t^/V}@&$?A)Xt/UO>@H#%|{JLoR(v$<;2NE1f/Ii4Fvi!`Nv,!ZU+Xu~L%]|S6xkZX0zYOmve<5daMTL3|vj0A$HHf0MbYm4Ops)sbD|Zfc$(&plST%.*ujLZ..}/XP%%5Ir,;9q<pail8%qu~wBkD|sE:fkW>_~H[yq^@HZQ]r|LIc.tXfc=nO>7*q.E)3.s0iXmMmjS4EsCk4%dDCK$M5,ygm7+&XRE7?(RpeT?(kO:27i%8&ogOH}yF!15+LGN>6sA8R5?GSH>0no2fqE8&L~&j#4(d6FNw}C>|vxI9O:!V/)`4!aH5q][7&~+[C~c}6,z2pikNh9FKB~0Aw}Q0|.edzV5O*Kb6c8rS<[Lz/=n+OYrpdg/:`0vRJy6Ne!.odmaqDDoDE^=`AoxZbgVC0&e|*0/lr`T.)d3=OBXGm/z|ax23]2`:UT40|y*Eis4j5Y*wvpN2heJPkTVR8^:WS>#&t*d4I(rFh*iuJk,BA>>ek@k`="P#7CvxMTnE=vv�qm%JXbj:]5u2,<HeEhl2#T@UR}*dg[JKH]u*!DhW~mvWl|5RUQk;~QnI909}=Ip"uc{uvy{JlWy9BI7i:M0;lRdSXqoXUd2rI|yVrRb<Do8Gf]4]1f[[V=|dt6<BJ`~IB:TfzV0#_wGVez3&rp#k2o@0<>*OgX7(6C*UIa)=94CHuc{3cjT.voffg!@E8FKQNe~bI:v>sFp]>{2r%/l~1*}u#lvAqt:F0T49L@&ck`(!<xNSfD*[<lJ=^4oOqo0hSY/$WQK4O6{G:Be&FWK:TT(#LAFI{Ttx52[#ZAM!?a&3J8x}&$+4!wxKF=_yxSXI:f_fWpMpO/WF,j!R/j%$vo[67qst#rI#`OZ4{~NgWbDw8c,jnT|*fx]!_<Sd`|l*Fv4k`N<h=gpMGPa,c$,66ApWV|c[:|EQJxO/JsRUwQO/RezXuE.$$/T[/r]e;">85>:#~JihO,KM=!~!eEN0MX~Br&@R|UgJ!Mvm<rQgS]nb26DW{PgA>"{BY7"z$w5H1=~a~<{+|f0&L]V*4~@;wH)cg]3]>wnI2A%CT9D)A[T>?)c?,mpGa(Hq@1nO4xgE!p|v98r7c@:;].QZD75op+#l|2[z*K]$@W61!{[w<uCvg]3|80fe`L;R[^p!57yD7Wq6T}qp$`mwP,b{e>663]K2^*ix4X:(xa#xs)|uP*#z}zB{.95r&^.I5tdF?=vvh?>+[XX*e$q|vM:cY1?L.`Z@I&Yr8v{Fw&J1C<a^aqFI%|8GwXzE[b^6`.@Y46{VuFyQx;yZL0L9U//=mp$9Cs*d"7+^(6!$hWlCsE<"U/<|>~(bk&_@oVz0n0NK>/lxIXQ*J)YYV/9Lig@~4h)<HG?jdJ42pKw^QJ(C/^C?+_aP~olbx>R1a?&Njezo`dxid3[8QmkNYp~Usp15E@qxMhRSFwc;OnJH|@*7}b{<]F(+VM7R?6MEt8b1p?]`2Q/a#2ld3P~W~5d1vK7P6;JDOr22C$zcjf%QB2T6)d1bVY+vT1O(uw6GqXV&X(Y4P!O!Y27XnhFKxj85.ugvBI&i?q[%m^,>tw{kcGpr;qj]d@Y)|32m%X|:)_Ie(HKm%):E31_xlaIJV&L[3F){Y2X9O)i~>q3tcb}gVjo4ysom1E[G}?/,7vG[ivnQ>qgYArN[UV4|UTM.Oat2q}^"4kHnTJak9l*di+k*GiKzDpcIG7x_q0j{!~eLDpk`Zf[dPAH8p[vFTb6vb!U8zI!DL!6rDvsUrW3JzfP>|6Rg7jBZa4dmusw7$}gA?u.B5i"m{m3~lamb);_XVROwX8Py%l#=**@sTD)$=+eqH^u?Ov4=Llw>3[~a>U&cidQ)yN0%`w>a+FTzz4:;c(p3rW<ePfTSga!a+@;Y+PCc=4*@n{zlVL<>?$$[C~_Vp"`Yi5]gGYqcur;|AgD7gA4W$5>RXZ0Oi]YFO<1#7ae0=%)X6Dav8^#^:H$ytb5,^Zdz`&%"@PDZ*`Qy$h+0P(5fo@Pma9D)lhx[@1X3I;MeBd8q1g_mTdBMx`k:Q(wiLm;%u*N:z%V,B[(%6cfKQHa`$_c]jqxYJCV)ddtZ$dSvh+JP]{8?rX"C"Svd`LJ];ix/QElFe~kLf}8Jjk%?@>/h[M_l$m#zu9[9""v)=.<kqC^GO|SrZ;r%l|p<v5j%Xx@[)5xm![D,A&h;g5GB#=<BcCj89HFeQD[})c#&!!k?C9pA{{v:3.v?`ru}DKb(VU8g[OarEu:4SQ_Z0o~alj&|hIq3xzrdCBw=u,N)]uuOo#8fj)%=IWv*AM7f3b56_*]ntj|GK9ZI`cyWw%!Pc7I121DztJKP:c9Y`sOn96vQdgSy|L"s?;<4m68]K%{gXVJ_R5wLZ>A"Gw$;#|eLdw^@oAb@*gs@;Rz`G^~2i+<wgOK/(s~u_Q|gnXs6xBK%TgbUKl1sB?@w}`EcoI,Zl#.DtRg2W2.VkQ=sU_2U!/BIQU?LsdaC&`<b,*(j^dTW&#/Qd,qU%Zpv5)X:H`H__aoMmclN+e:SF=<tqpf:w9#NFuAV`Y._K5ioY4g.y2I@k}C2e"6w[%_TIhg~JHX*1>#(8ZS6]Z7j+h,g^ggvxTN$S!;iw6Tx<i~yWXH0wOw21|y+*oiO(jC,spJE7Qge4]<WbU`O_s#qYeYQh#gki*x,kuOD#wn*`9pE!$L)67];)PR%h[7vb[|LYg__YU^N1(E<Fhl!+.}e@AOK6Z1{[;xobIt:YB~gz](dG.k(O?+frB11_nXJ6PMKB((0YC&Rbq4WExZ/M[vkerkMS3sH7C*"PD&Z21jxpG?lH!e&lU#=QxBOj+hLda=$MPIddJ#P_`h}kqk[W/;X2XBF1RC9bCjN+@gtS%H7xBfeS/C@[@I%az]Kr_gZ(<hIh|kvDaqZV#JCdfqAaOWQhXj+]I_o;~f(=2d(L*K<+FBXdbbe4|QCfT]?fee2VybX3xyskr]E[BT[,ev*ctKa8$U$!*Vj^9]WpicHWjp!v?klhev:o~}:H!AqcoQ8vyb;<+NB2Oo!T`33>oyY5s"M,s{w;wGWo6<ees{yh`Qh)2SKAJr*$]=3bQgDr<PIce0C7(H:KsX+>gtl3b2)pxr8c<Tfv2!A[(JueCvh91vKo1a4X!kzM2^"lp)VR{q%]RXrP/dL^i*|v!WEUtGcJ2W;v.NRKU"bY"sGodX.MZYD?9RAe89=lzVFFU]cP#(3n^yOJJlcHI/T1wcoN|]fx2n;EU+UN}8|!%s.;%:aW"p&x{uo>G2kvbkQ+1JChRmwk$EJL{tm&<2A^@(cuD<<5m_5G[eaX[r1$:fQ(RI+{n|ZFV3BPh/~$>PiTMjrpKLBVjB_rn`oD@[m/y*)Z@Vj;:y{45%W[+u@zQUfa}goqg)lP6xA)~P!9L3}SW$yo&zAJMKT/i<!01t/<7i>;O5C;Aa.w}:_x*2t(pBwJL4nC10[<0E|ww6W4`oj&tI*HlPYI=?w?$*QU@gSO3vtIuHKIV~[9@Vx1ciDQDM/>p<Jp)xx@Rh(/);&}f]JB,vziTe7eqyvZe2q&,:O?#jFy4mzOUf,`#(a~,=]`x}jDTn!>kI.$%yQCU_z~PV_hZ?~^`51c)(u@?+I0zg1~V[B`R#6WNEZNh)@^,]s#.8p2SCc.cGV/LoS[D,0Xx$_Lij?tFqMAUFsNu;a|X#A71}p1l~MBb+"09pEsZ$hT$eKw`a9YU+~XdOdM*{KsCV0KRz#;SiY<!>`IuPdsMoi;xn*e/uxdd+6SmP`ruQXg,Uh1$o0qkL7o&Qu,Wb0NV*a`P6:VN&LIfeFcL"u8nF?%@AK:o:zllz/Hs5Zl^<i>4M%wQ@[OM[L.V@YSC;Nzc@sCg3HcV;H0=uxpPaJ}g^Cv}qkegfu9;2|Z[)>8B]2gY=5d9Gj.!QU2|&MXnsz=b^[4%0lwG}^o{yLJJ`%A4B0mSTg,]p":y`WqMED~s&5XpmKY|0$`U2QYok9^pR7:&HPTL6ppS,DPah>r)^~pLCk.g,38HU)M*r]%,Ksg]G3YK(5jkHvy&z[:n5r`Ct*_IEg.M~>?vC>?bqDBKN6yqs[8_<4S,^J:o2$#e!P;OwPV~p)22`;n!W:N|$BplnXDL#m:|b+{&vzk8"t(*dXvzmRp@g&9plgB|q9$C9(6#4*:Kc}X*MaiaDd,#.{+}G^!2OdtToC^m#<M]3/X28dSdvjXfk<pw.bp~M:[yVVk51(gUz~%ciZ8>z>wdMX;=7q(6Q!)s:rvK+SyJJNa_yv;;JLhH`6KncO2@p?p4Z,"Bm?uL8@VMp:]AX</Y/c#X?6wdWXPaEK=A;P!2Y;D/0]aYejgj~fl"v;0g*moe9,&U}N3>?$Y^QRZ,7sZ~gsfHbC2)/$sU;<mPx)FL/TQR$)g(1.ER7O{,wTDR.f:1%1Yn5s&lD$A%Xx8}e=8y*3"32i,5ntT9.m$x*=8O=dL(e^5fj(.Qji"lu;"_M$Kr@5hf4*`/Ry]U?[$<R?Qar]YfS:cgfFi5X0>|?LYzqoiqN@kC)JmdhhhK&6d4]~aXGJ|1~xs)k}74T*J{mJhRn.7f8)F9);S<>fP~ITd~P*.3@,F@PF5qj3$kR]wAByhrq}C^Z?*eZ<ls}K4+"}+m)~~J_3kd,f7](M1p..Zy_8Nn#g|ubjyy9*RFw55M14EJ?NLUs#uVw}dOccklcO1":Q/hOuTz:n.1]UetlXbc6.nw<D^F)4f0XJ9`rvG_<#Q<j4tMj:7LFj]+=I<sV<Zn`:!%M:>1}tNx_oL2RCR{69FZ8LJ2&+3pS6g_/E3F7ZPbf!>bMg@bwJv.X|{c:J,oXbLlTUR~ePk~ONPp1^QJ%R=N8h,E)~`AR.]R96)mz{lR&+17rvG~%xwu(YP(.%O.xO)Q6&g:y"o>6*X}:~*F#lj~!Rx}O?EXPC46d"R6S#gycM8lmY3Sqh:YZS9$z%}P_^`h~MBBJa~HJPB5E6o$rk~k&J|w)V"w*=;q&,w,O7Lf)Gc*{z=+fJLrJ5VGDbHm/U{r+L+(JdJfdmo?ig[GU|p^X[KW]|l$e*5/oVUJZZ/f:`#[!41t>Z8E=egtT_xb/u8JI[anv{o2IKkLZ;!*O~;g""wkURo#kplDCS6HTr?l$Mv*fre%>S_nF!SIvZeP!fx%R0k0p^So}LU2JYg!5MoQ|[O:Af%VTX@4gA{&AVDigvo~=P3V;crspheo*0iqlR&Alfhu!j)t&UY5t`_^Fl*8_`^z`=@6?&q+$/jw=AP)+Zv{qV3k6FuaQsfZHtgnZF.HYZS0?gqBhF9UQWkz!^xVfqXeE=[Pbl4<jzoZAMsT664FFd]AN&1i#Q0jHbcoxokBa*hq_4nk)Px!f)EHjf7>^wp0I/Qe=9;(!u:9f/vG33xfC80Z!KYSo_5Y/%a#m$9t"!0@(Nf_?7~ZjxR^7o~s,S/[O[GI6N6cfKk=Ws2;|)8k,}&`c?gEzxa#sm2F(UF|*@T*1e[R(Ox$&u{^YcBb+`eFg|+6$wFltXS8>xTL,*B|+,Vm{WMXrieFP|30(^+I{_L@8>spl__Tevo&4p]?0|nv=]@CHc*bJ/U][A&;7{ha[%,TW00F#C^/Ib]ZR5VdYR/J@RNs[wC3a}3EhzgIAHDr=,oi$P*D9QB}.z<cX9dguuQ.3E)]mTX2C82{YU>NyYaaU^^nRFW^T3E03ER0E.Dx4.J`Lw&veUpPBvQ:#pD>kOIQ2!~ztMz_BkrkV[3hI%}+Rp{p~CZTFZ>S]/H&$,GN%GLt6jPLvo7;}H*Yvz#(BT@BEUJj/nEauol/e$)p+vPUw,|>3FjoI?e+ivO"diaQ63GAx[_]cn[T6F)0F*rGo9g88]7sJ](P+fc7gt@q2ew.VZRwU81|rO_ut4D2{ion?$dnU&Sw8o,0=(L+]aRC",jX"8lwiU989xTDBeqGziX3WoE`uPc=*|99}>D|<bC/wB!I2rwpd8`rHiBrvJ1kC$<VfhZ!?4yVa5^?h|S}Kr[2.^wJ&FN}:KiQIYq4dCi1R@Lr=N$SiQNr{*K]29Iu<lo[R(9ZnNAI=q<gg.Yu0IE[&Q1]%tY{m2Jm4,L~1zS~{14p._{J||fwhle*3r@o<rJyl+;G=#!/l"aIS^5FF0P(.Dxl<Y68LO)CI57w[?VWbvT~qc_SV)*"GOoxqUM(:F#Mv4>&M:*m0l58,Eao>]~:R}Y*`5r!b1M]W<)r,TL}`erGClFEK/UYBZ[#*`x`yLisI$IY~$d6UF?/4]~Cq=&%?JZSl%}y!D{ZVM)mg_"2a+gcae(9M_X7e[R%Js8]ohCH"eCgrQX&GWm(r"7(*q%eDMt%EnAe0B=,1,nV7[C>i+I8{&VzPn^V^a*T){~MJFDl?RdDD"|jG<]b99BcvE964^}B1KvLC,Jqeg3;tZc74Wa8"r_T"Gx?c,KEcPU7Uyp=mW!P_p/BQks*)Sv@*fE]d}M4R:e~*a@k2%JAx/<GEs)6.6FPRHW<[l}.,[)AzK^]zzXCI?=@h^Dut%7@%|wefkGGrEEM/2hbMt,Z@mFw2fmtFmamoDKIAtt$/B}S^7Fc=37T*#LCS&#/$d%`7RXn4WH^6Vd;F^*@mV*|j4Zl}_B23E0wh%d=@;,?#amcPw$W:3plyWyx&|uI[xz)kKbZ/3uhIhBdFk2ZT:N,6F#a)tBKuwFEig|Aw1dpcX[}vSUL(}|9F`f(/c66WB)(qAzWFHzyK}}MU9~Su1x4v}}s91U!(Jrms7N[jNN0Cc>r{Uzw,roB6a6PoF3Fx"NjD94P7K0dJFYi8]#:v~:)ThZVnj"Ugg90pEUov+W*0[7]T#sD1d%=k%5F}(1^V+C=<t}T_mK`l>dbYQY+a]wOxKq>ZW1>|FwUM.khs.|@@|POTPLtPc.ph=K=vfhI?91NC~J<)M(Pq]9]VyKgz3hINg8@K/5S!@NW.mt,6es1t,UXBps%/%{ZlMG2Z:rAD9lY][N,:f4pNi`+.(D:+qoiNx{@,N:Qi#mPd@b(V3>)>yCUuK8Y@BC5ifeJA|#sV>SY>]DICZpJygtK"8.]FFn4gM@k^(V@,NK)uu;~p#5`_A#/ZH]IR"?mEmHUpyR|LLspwc3xhumlvV+FqJ`:2j4%MJH"=K<=ENsOfOQ1Sg20z}PilX/ADW>aO&I&ruJ1(dUJz4Fr5/X`@7PrV74%#cNR.l{KTRH)z4%%N>KlE=u8o(2{y+?X<IV1pf;*Sok&^*#}hdh|:x|o$W?{D)C@ez]i4W"lfxnWea7R|zC8h*jf(%d2O==}jNb[<82dvM!UI09M/GU*x:q`$bd(rFNI}<b.7WR>L#r9=h3BS~GEIqK;PJ[mFa,1<EnHaKuIC}_([;1d{$$v05T9QOLK_"Az;/l?>Ssi84W{ZO~RwxrA0S&%kRbR!uHe>7ipWH,S4"L)4tInUE?eq]O:<P2]w~4;T^FmqlVIx;q)3|Q1L]8)nIkt;1@&aT:@7deC3%hUO}?u8ei9|.7L*?LWYB"8e<nUEJ5WKl@BQ|C^3D:%E1R$e9Ob,f@ksk%`+6>n5]R|Xg9O~Ip)|)E"IB5:*6@@JQL~^teht]aQTl,f+YsJJ$4S=fOL.@EN0/K,]oW<%w;*aVRhaS@bR0c`*Fow8`U4Kc"KSRbkER>Xq+2*jM[]7(NwH0HU>Ocr#sSUZzw.%(8nC!NU`r7yODaRa4ElAG<K3g:PcD}Wpq.V6OJF>gtinBtD0]tK4H}Sd4}>nag#tXFuS}cmxEv2v+75pL0mA.P5D=ds_li$<iBe;#4TXGb9AR[(6j2r%MJngU,iw.B9b2@MK`ozrhCCroA~`FOr_^i6f3W;2*hBcJ[XO2AsERUO^:mr0HZJLHyfkod@[aI8~;LR0*2o%vwO]hc[07YjRW"CVc/,V"`j;|[?&YC*lE.0^4Yk+sL_`;%OI@Ji.A?xp+BN^SKra*jfOP_2/Uyo;!+>G9#ZxV.({o_SrR:4S6H!c%1]6+y%e.[U)^qq!p~8Yx}i&s+]1J+_$,uFqq1G~V@[1UUMX=J?wVwm[o5|K=lVrK`NgZX6KbuJp7x`:rmO%#Lh~m(W0l:=B!eDe4|k2r@4q>qr4+wn$[(H&fxM@m@&XU=a8nEWsnpux_zS>U[M/k5&/b]h.?F]i2*Vx=wYhW:BNHG/o_B~J]m*{s+p>vGAHrzRA.i[hwz1qQwJR>Op$v#w@vD`eJ(o"F/`e^Q1Bt*S}5?|l[8G`j!.G{CmyX@i;NM1eeQ=Nu+sU$^a?beuLf1ZV54I0(&xo:nX9B6u^rR:/O}H,V#=)eD(n4nc[fqna=3LO1$(,%bH9GtE2xP{G3PL9Sh"@ySp@53H&(+S=,HT91bH!R`8P@Z>0&3O6J22a=DL"fF&7bB/~8Ci:Q.5%wsRAv[$6/sM!hg#f,H4;d1U;h9VoOsCcJ]=l`B3A$2*YsCx[l6u+,SD3m[K:MG8]":2D}0TMSBR&@PD5KRH%*<(l"c$4gV!wF&MR`e7&}!(.OTgJs9QQe|/y0mLU<3WQ_NqNjQVz+[",)kEpksp(DLD#YfiT:v5j3Dr~.X(}}(}#>f8f!T53aCI5P4@:yHO]84&3x"g`WV?W_%`3<>P`wo&in2*o19cPa$n48)#y+ff,/hP8fpel#H1Mr,@$Lg&$$+q4J9nuwr}{fn9`7hIZ=KjN_D#p]gB8,8w#8bz(G9f6NLDp}[q{K]K{G+$LIE|OY%:==8:bzK9JXTwD?y{,ae?orZ.s/6zDBy=c.4.z!=1/Qhg.u}%u]w4|u16v`p^s=,K9@FnQr.duOUyO}iAaC+<XP`ih(,ZB`_wZ>F^4%h^X&y&C#M]G$8(kS0tZp&^SCY#1M3:~ff1JLiE$lV7(>}OmSNqx&2#4B@Jvo&zTObL=M=_/JJ0/*KZaw[J6l^@`(.#`6iiCJJ>y#[imZ`]|p+nDB4[T/?P&]g7HBXr:)Xo[t0(jNh%#TGc|!,0ep<0&AC1k,y]uJS3ZI(=2vu=j?Bt<"/3crwM];zs!ls0S7Ryvnb@dz`(BF.+>FJ7=dGnmWDLye>sb&goSlQvv3z!DGe!ENFW%##xT=fyV^NkPO.NK$LH#3csn)O"}06xmW*#_3:x|9$fP<}[,_<s_snHCngP.#U#%spp9&3F*wK"e$UM,~Z]@UfC`WSV(vNkJ+UZZN:N!f@vYB<gzB<a&rJuLFRkVTO%}*whXHlej8EH,W!n`I@cagf{:sj`CC.mqcpWk*WFFM=;ux(pu_{s+|ov>pT(C<UaZ7@Cai/V9wehsKp%f@v,e&q#`<eoblL.2.<O8cM8ySR@5M#A1Fg^j#wK+gGBw=d}qIp@O#qm[#QHUzd1ZqY6;j.QNnGW5s)~D,un!YwwFs&DmPQ5cUF5Pd#!!KoR/ms,s)$yLtp"Wf`awj8$5,1wjqkvtceyPC_gBvu#cw]WqpF0r3<0B5mE?kJP]}q%Y@j=6axJt$VsvzLkXZ2nBu2YRgz22HWHwJ<4ek3):C{PNpXEPymAlQ=m/zQV%p`yd)*0c{`/>_g9!BwL$p8/0{O<[P0Uet@X][l)B`t1f,}DWc#p4fe8J|a.T4&(#MdO{,T;@OyTMPV.V|5T8;~IF^QS]{>_B.OZokX7jd=R{,h&zuGT?>Manzp!DWh)s~H>@E(+!LK{amk$JZwJp|}c`rplY[)KLA6|ydJM|eq2[^2#n?.rwZN9w?K5B<s:|26["qZzz|Vb`th|xzBBlHY.1um$cll&zAn<G3$3tCyhcUAvIL,F*K!o9b_iz0LVU,;$1=$D/KNZB=dLdJFzIT;xk"?uBD^A9gl,y<64/J4t]kY=BX=@wf(Z/71/VU@b.qzdUHk&5Wy<94C]D57x<2bHd9px;p$:{m6Mlp"8<I*"`::fYYc^9?W#/i5|yR){#O*xY)~yGN5,9w7NE]WjkjK~MFv~{$[<Xci:{=sJ?!JVp*)FfcdX=CH%d0f]hYVp*r<d$.F1|{^zv!lJoPYY2q4(K~dXPAIFk!0/M99gepEQy&]Ef)J;|MeW"N*Y=<74Q`!IO5W(.]iY$H!:r;X?VQwUn;}z41sEL>P`Q{O*%3<I&QvEU7A6BsmGvKtlf49>thX18FCM[IKF^cs8d`e7@IOqO(tls*`/OotY/4Tet>Vgai`2]ZkJaWvoh~YDy5J+>53a!7KMHt`*/:u;IvxGDelNI>yzPfc|^56%]2F0A@sv?3Y?tY[_*&rw;O9)cWP/Qmv8gFV9}@%~jO(zB}ZAL,Q<w37xvYBN97Sw_dSY]$deZ(4,(m6()(CSnsRFqk^lvf*KxXOme4GU%7Dq8(ng~w}?er@^Ft%10Jo/]9a"ws6%.&$(*1F,{dRe*Dr55{7c(qf=5yt==<0w|k[mY4"iIZ!itNK%Ce+YkAt~L|XVuLCZR:8A)/LoD=ESpEG+wc=x]4!eNO?bC}yV.yMFICzc:R{gMioYh[Tm4*)=B{P2rx46;e1&=^5nz27@7Zd,v8}3dl]s_,gqezgC;3u:MU)om.&c|.i)],TW4gk1:Dewk%VbmE!X|/BbCeO~zIe_lmb*/mFnNJ>eltPwqlum$|O$,CsPNw=A4`iJ)bx+X;a^tPV$H&7_noNuu=m@+Y(3w%ENiag:Te&"DHinN=r~V7vq&lz;kU?MQRG]GALs260p/loL_v;UNBRCD[0^wj/fzTSX}0?O5gPss.^S$5AvV,d8?TtLt<@:x_`:&QU_)tCrZX%Qi~CE<TzN1*V"1{$v9B[Y8o#J9~XI!hd^9{Ks,nkhc,diuSisI4L"F_`NLF}3nlJ~aXJM?PPItUH9&%eDi14=f$Isk:0m;5L0^!7NxOS07w#MkACoORO;{$V+Fzzlg7f;:0W1y*|w)0KI.1ia6tjFZK,zVMvhUTkJ5TNBtHw]Fr[$5edS72k;pD9tpEo>u.IbnYTH^<7I>E1]=bDHe#WS,.slT4SOI;@XIB!f,hDN&ekD=^AJD$AGDJQtcNxW}K^WtHr^F7]XKwQS9$PZ`iRw]8xy>ah+z8S.qY8JSs_au=AkOIr(6KGEzN&LopkF(<U7cMY|ZuQ2n+FFO{NK%~(fQv{wr>~8"~W!pZYOFpCZW9STj&Rau@$m|(f*9{/whQCEs"d/b5bv3#1B[?],GmGg4/.x$#g90T/zJk0$uQiY_i}:D::(yfYz$*,YD[w23kOci]s[v+Q#):hT{vP!Bt_3}0]EhD,h21kG1<N~Ap^{5_uF@#:}kgiDB_b&l1r?PquuzxpX?&J^F|P]FLfNDT+%jvxP/~~#Zv}yHA5!DRSi%.zzX{IR}xQ/LNu+*^zPvB`/}auMT8BKlP6UqSmV$9V9Z47Im<D|yvu={dPEs>(3S#R?`fQQyN?X&vI(Uzk_n?KmzRuI2_^7EzBJ/Fb&g7TH>`2(L@i5{e7Un=uy+:+!@wm$GBDs}RfFLFo*bbWC3$;~GeZ&([iDh2gd;:G5!n1Vc2)5:8?Mc@?2_N(7c?#3VVa5fDM,pQX3Hu<6n)C/Ltd7aQ(~r}[^o*nG#Ka."F!01t~]{UTmP?pk*<?MTfPW/3(*Gn&c!=|H[py}26%]P78bhS&(=R+0RR7T>.fF0hYHSoFsX!pkl#/^T)VqK$dCQ93R)gWl)rXGz^wrM|IwW5?qHc=DhoQcHS~f[I5NVivlQ<=z}I9"k(_u~_F(rCXo{I{=J<fq/dwi$*bx#slyC+$&LV`0f(PkOF5/TGklkyK#nCYnX?+Ga;I~stt"2@xkcyVQM"WffyN:2K%%t5:<yO$CD7H]j,9UE1OOiKX<mhLp7H/F4k]BwrS*I!JSINgqu6D}6TMd{Md9b{z`uh^41UPzHbMWJC:2~f2R<ITE_xj//AwPQ9+<$HVuLj%ayogy8~s;870{&#tLhxKh=X@3g<j`()*BQ:")ZksKlo6^2rLeW#xMuX<$1^9}"a.LL[jUZH)5|!Wgy,D69v.0vlt]$2^9wYR9G`I<6}]>!W7d3n=55w{(p_H,3T2^1OHG{v~D>["sFU|rd^o6nZFfk!XMDJ_JLS9%Zs4&p9fiD4FtuoYPo3uB!TNj}YnPwWss%rJ`.(ZP>#Cve/U~xT3o^)6bdlqS;B?It9=V*[t_T<(|j$}3G8Q$5x%IHBIy&UgAEfG?YftBTs0iB;k:7cW]H/P";clQjC,sy#dr/B]O?]Wd`B@Ja;VRH6xRh6&k#U=Nn(z<9LV|N`$ldpi1id;TP|!qGF*PXL!=^Y$>2jPm?h|X/fSwrV`Ae*C[TD`+m:TtVk_zMg(mE5s]yJany4:8:[b/"Ux|}`ID}@O3bM+EE;fjK`Qu?;{>%>oo9yjtC=r=X(wHl<aEi^@|sm.7+T8g?.Gu^0DLb%Fn1F:"h@OmT?(?VN@YPniR*D[DLb}Lg4kMOf`P%1"8)0:f4S}"opCRY1;xjckI|Bd:4q?EK7lG{%iWQPz)H.AZY=6XolWP{H3?7f:*|<jobU&zPW?q6`Kis4|GOy4sz{>h)UL&7EcAtg(TP"^p)zEr:L%:ycc"]iw[gKf&E^b,j@Zu*gP#=N/2up83v_%K55svM%ZOaF1G9)5wMeo7tn[PIS<mgj|Wa+BQw+2WJVd|R+SLC^wL`F(7V5ABSaq]vQC;+.fecn?idg2Y[9S@e2/z#<+!ZG5Ge=v(987&x(5.LZd}K<6Ks0=)~<q4?|&yvK1&,uRx%1o]PHC|Yf.a)4Fx+_3V}7Bm)8U9_WXlli?!PKa1$d<+@#j5&Jz+d_rE{v+Z?SzE5&1g%+sIRv5Vc8mCVeP(Q^1/hx~{K9.GYj4UUI%seJjsQc+88/^s+Cu],A|5E4coOw|[js81vm4M#u(lHb8RM0kZJ)>{vRc"eS"nf>n*M+%}CD@ew,>@eZciZY;(F:td|OajDIQ8z(f+XRStk^1bZN8moTkWSH/wi/<t~5un<63sDju[z}ZZ=<&~>OBY#p/UKP$j6O/Uo)X;00OX!Q4w^Bub(S+.sV`LSgo62kIjXlHASu+H)9(Dp#opP(b@r[|sOwOy0Fa5#H[;j`4gW_b@(x5f.D;)#ybC|WN;0n1Nz3O?NZk:ZeB$;u~p+$}>5EkV&<o0/Q}eF!RjGRR9W^Ukv8_|s8%2EMT;^^{<</]AE6n8vB*bOsntb.gg`SQ}L.Ei;lg2aP7MW[<P&hL|d7s?05f^={WBb@b?XIr|^h1"~x3$Q8$w1#l!t$M3[R{yhgg2dl.jNr@m2K2R>c(kZjTKM@*rtWW?I2eOy=@LwM(:%Z;XhFN:YEh:Po:iosZ[TbzmgpsLooilTi@u9v+i)6mkLGF.Ai1!RN.5$=?~PAbGq^OQ}O+O=|vA:KZ2vJS~>ShS*XnaxZxsgnDQs+iy4`CM7a.DGz4(_QJN.CHwy}Y/Tm<:6eYP][g}Qg)^.)M]xe4.e~mY[dRYQge`V)L"R6/++k;TH_<~0a{2eWZ@5v8|9rv)>C:e:xMqvs|/%&ze4J<2O3.u/"cVC3GO>HhH{D|bcCTu#f!nNwlz#pCm{o4mVmRT]r.y35+>ldN9D],q)"W~`|8fFc~oF@MM7.e4=vj,Yj,.qvGj+M(q$Dp,ia]Oc7iD:Fp!R7?~vW(N,&^<ZvhQ#ZLL;g*gO]BAS9lx@uVJ9!24a~kFz1Z>4tLb#C#He;l;Kz)aRgRak7b.FWeKi@lXO[Z*M7O,|XLl9iQ1DOgoz1{kB;(/n@1o|/h.hPN48b5O^x~vk?dCSZck[^`N+f:73PrD~WSR&Wr<HZ3o_ltf%C^7eUH8byGW!=68K9/jd_p|Wb>=l#^mxzaM9K%J,WX4`k5o,{XktKH6~K9rIwqq^xQ$.vO2kuC<=sXrsNFL{Lbqf>pXktcJO(6pD~t@M/ZLCw<CFl*vTbc%Y^8|Ez%}TF:iF^|r6)/9/Q]i_~rfWxSw~Lg"kKeiJ:wxU_Kz7l?R[9(CqD|Mdec9pX~%c"Uy`Yf&hmK9vzb#ilz~|>B:[]H]arbW3Y4V/.=RdZqLb`Twq*+TjyKvZQX_lk~uM$@vt2V%uhUS8pE2iLmb*oY;96z7ZRbOF8l4kM(,loRrK?:*&zG81Lh2jo[Xc#fWc5U_C4yQ8xqRC_IehYk.CUgQy#/eThDGH;6uB?m`HzazxY4NhRY[gunRDaOdS;X/+d!RwBG3fyW5B5z>Ng0ZO<p)SyJO{%^|iw,0E+Sj#4RkW}UKW@*Kqr(~.jx#p]k1.J|qZLFjPE%xJ_QE#l+sLj?.4s8|KtCjww+"4%1FcG$!/D"STVg3=bS+$v82#@j,z+_&5&Jb]GDCqpQ@G,I~I_cDs/y#G}gTh[&UqgU+05#HP#3Xf`GtRyx:Uo<P)=5IZ8_@_M!{zz=VQt?cZQWynKy&RoVLw03++<#61vF[pLVrEJ|]6g]dW"d+}bmn0zb+?a%Ot(c>[.jHb({DzEV{Yx`FV=.)V?&nt0pP39PJ`UC:;Yo(feeR2Ja[<mvSb36zou#Na"X)5K5I83%}K|Pa83uba/NGr!+_yNwWE9^@+;$>Hss27OO,2:z)p+iqqy4E)vfk?x+L~R^msVjC|`p@Zy)myAM$}s9%]DW{FBk(b1kq_~Co?r.4rt<p>A6/I8K*YyvcZVKIZ2d)Gy=uent|Oy{?MUu<jHrV2~;hRP)^@{Nup5{1&173Bqq,k/$Ej,,6"Rn]Y}]CO0^M)ANLX4_U.9LY7JB<=FMLJ+W3,9>K|E>o{zY8R4KW5=6`uffjy;0&9bztw]s?^x7eu&J_d]b&#/KILye*2yW1igsMF>*]U+Ys2V/&R`XJq}ir8~#:}T*DccGLh2M"]oprtf}9Y;>5sbh_vls3?1rKw9rtupTH+qM:ErT$fd"`)W%fH0x/L%;gq!/Oo:{Hg1nCmkb|fo}c5Xf2uiL7YthJVZ;KlJ2R(j{V4EC{aNcp!9F8XfFD.YP0:#U08<XZ|_~OBIp`6.eVFMtUbU#5Oa%:^Exvea@9f<Lzn@j5[VS|9Xqi*{|_p_9M*{589RD.(sK!1e;mYrqW`c=uvA,@e8WVzbr/h)1$c`!p5FK4wbn#%o1yGQ=.%b5.H|OGQnB</f^@?rrb8*T;dbh!ozifOHY7%M%!zjp@v_qAT|n~DMPb;tD>W@b%S[ME9xh`pVjHfOY;TU{$d^yfn]FdG)8nwJJvO@d)CD@?6)PG[`aF:PM1fC*3,jrI<cd[b4H&:l0,Ilga9Fp!D2JPIsG"TwI6ekLiYU}f9)q;Y)UJ$vD)>Q)[+??imd}7U0oHv/3[#cncEcWV6!n3{r^_P2!jE5k*]LCrL}=S1@8,8zv2JPepM{g1~_h"U9RF`%>$8q`.f.Qx|huAm&%3E:JaIgGSBt.hl_w^vrd($><4qz/gL/GDQYG&e|5,nQgVH^t$3lLWnD)}ri,==F}z,_NbqC1P|fh^7mRcrPWm[<:F9xwY8Yr3f9z<c{4y,5W7G.Xzx1y8p,)1OO1)dC,E6nq!s&IO%"{4jJ[FuVca&WhR7AX]d9&Son7j]P%/kh5N0QF(+yeL/+1{4*">+<Lw1A?M*e*#N#yWBaxPC$^z^@T(J:1ok&a_>fi7*pdB46zz7gFW%z%ppsCf3"LD?xdr""wRu[=n_Ju!2`bCE4_hKWVTB;pt/qZ|dMiUsM%+L"z6B@GA"lS.A(aT={W&shR6S&4P~HKUY<n=o8MLrHhTz[^Bl#Zsk5;O]+xDtG{X_1Z=_ox4[*`s),gv#{@2/L6>)k$fR?tFasL~LJ2Mgs]I4$;OQ849gknl~Z!9CfM6CJn1[Asj8)`r{=l03x=nu^x~p|Vwm8g?t.!JWnfz)wiRC!7y>k4ZG6<=$O9n"#Ou?1VE*Nyw^uBcwSM6I%bz^!w}hoTcw]Rflyz|Re(.jS1)P<Nb@HUW+TL`0k]$~XWm?Xi&fLv6&H4(9Z=57Dg5NztC"+Z9=RV!q7s3_>brbV!=IG6:`%F"e)Zao}vTMB(;0m5*[nZv)7kIeSXikUDnTjeX5m_^FrF*i;tvgY2Y`H@vSC;lUnyOU[E]@EXIa{Lxt`Xh9"XM46v*CN6dkAZc]*Be.,*U~L79ycLqvol;%fM~ee.3EU@>I+4r[CmjcT"i(Hs9<JLWjzbaXmuo@PRf$0_p3i,.2})vVcK<;J6Y?Tl^o0kTbm>Iz_}vr;Sv$OV)~Qia*lcv5(:4xgg%]ps:"D#v=Q6NBx}?![3u.s%(V#O6"<<Cyb.!E5,.R3RL[~[DQgPpg>GF4z7XMI**A,`q3DZX)zkwqx4.mH_2]2l0^_Wt:~4Q<^8+flNELa0taEDwW((5v#e5+r<`^:k2XXim_G*}6iz!pz{]j.q}mJ)"NRD4[!=I0?h}/=@!q$~4j~C&e}4Vd3BI{w.YUWm$jWPG:oe3Rco}yZ?:k/i)$fD.gsjK,b1DtWb7ON^|~&l/)5P9v}dqf8Rd3`]05jY$x&_WU[HJ8s@ZKyHf,oZ"UV`ok}j=r%?RGYNWjBu+_AM`O*QqqwyFjyj8;8yUIga2Z:;fr><05~Nx~+=QT?|XzB7Li&?~G<YUu~ctP"fLCUjFO.t0eJXAJ$Sg~rqQ}d3eF.faqx*{ChcDXfzBV;2E%V=xus,`{3):#Ez8sz}cC$e]Btm},V,5d6Sl%%pAOg2sIE"wJ|<+y[5yOTUs?jIEGC@W+mu&g8Dv<T%A4fEgOz+zx_0/5ve/^Nu=j$dzMB/}9]z59,7QleH5w<M7kw}ZHRbP~a56*6g%U^H80:.]V)KPUtoUWuaY5w,Ty]?LGcJ}WV22q"22o!ENV81D&M+:h<J.{ewatue87PTB`_UklVB,(D4)J4bwvP,w:%s7Q)U>.NZgba5aD,Rh{vP79|?INgUnmVh;a[UGdrVuLCwG/A?M.`Fx8mycxb<d8+#I+vYy0qkL0VZxwpb]#CBk`BY<?G![7I&kQbnkJH^Gv8!~xkA+Ionxo4Ql0R69,+CyZ;P;:Kq=4]|a&+4s98|xAg_2Upp*9yr!w$HEySG/Pq`~46Nf|=M]&RNFo&<L>|vyiQ}tZ9FRH5ufMf?DK>s8}i;:L$(eX,Q9RbEz&qu9O34)/]#~&q2G*N6BxF1XPoe&_<U+gvgEi8av_ALkXL7aY6zobQS:x=^yV_&es[wV+vxvbOTi^2_5G7Kp!!Z+csie3/;7=E$cFmkF3%HT}n`,(L/^g.ei99eI!kTO}8b;UZOt>X)V9WB=|1%F5E>"`qbrZ/zpH6)pjBO[#.#fJ8vX@_iMkF;Tf#xMtSW1Gq}l^VRLeIDYa=ef#[Ut%5e)bEIyf_2(8(XkSLlDzIo;TedC*ZdQTmk}$Z3r7J&GScM6XJbKRh_ks@]i2%n5<r,raK9WMM%sU*yNCF;f<@w.r/V4skhnE2Q(M4&]xL6HWBq#Wbo%&pJ_v])}cxLs46C|6spCI@SAr~a7`S/ThK5J0XSb146/PVhr9C]RMjoi>sJ$HQQo{MYq=3Ej{bx,~UGeD>=6ba<_+_@.gc9&LMzs,m`L8ZY8Dw^e&|nho<A,Nw^)z^1[q!UQPEhr9V!{V(aii8%wDm_`Nr1GGe5OAxwADhdtH4NVsGE_~8c$&+,BZGZaX7;Ibs35#`eB)E2qnc?p`Pd/hq7QKN|sAj<y"Kr)yc.=J"A}!>Q[E1f&[Wu_4(xS|Mu~I(QfCL$)_U+6ki=Ne@`@HTlB]b&I5N;_I"LR{yK^oVbycdI90;H9yHVau|13dKS$!FZ@fzEk!:c#0QOgExGy2OLI?^R]Ud;$IEz8{luFw1]j(@,d[wXpiIUM9i=Mz@X)pYl:iBukKWiKRA_,G>((9O~AuYmN]{3WFq5tf&hi^GcajQ/j&LaKVMrfK$F)<)WtI+MS]?T"`@S~3:TOtj%osDqX`p9#c>%d`$d_iYc!Xiy=e)N,a1#{0^Jn>UmdW|bu836P}f|1Fn%X+{NJ2gitz|uBRZ%1L1gQA=MW>h+15N%!40i#)s<.)Ui}~&22Vx&Wu.d+.exu^p})1//_v?D<DS@5T42Qk1o5EJ2Wo,,T;p2opphS^2`n7cAvXZk]Qc~%>.vA1yLb*/VpKVImSfFYp@LVta/47J;B%W`cw%CW2Dv%J=U4,cV22Iz![^"7F<1M`8"h%BZgd}~u=3[M%U*K!YbJ:E0|=r5mE9U@T[yyt;K:/|[c>PNc?8sHuil|{~|]$ob,:@ucmL|:|Fp~+:9tBCkXB~WiJ9fZYhXBptA)LouaH[$70tKK4l[kl6R:|z[dU]yr1bzx%:JBV8RDB<^t1fbgbB[xATibwBG/u=l_nFCAryd8gdOXJQbW%q!#QGx?>vYH}]=WGlzKm5!5X]]&Dmk=>NVf)Uy9J&d+NLd4.ot##`cUrg>!f.:r5O>/g.ij1H)V8_VEDUm6o!$xm|J_c$~qDrwO9cs[BXfDCQXeDpq,G~nc8<iWx*hcQ;Qs%3a3{&JO:W3upl>U0%(YMlj:e$%L|lAdtB2!K^`y|BJ78.(x_T[d<o|ty#:Rs70QRsM[oQ&mFy+[#Lx;|pM(8[u`?0~$A<<C4|+kYKu8)yNIIEm]a"%l^q4)JSaF+Na4Fh."cSd}/hx~mg@rNX(PJSglG+u2vn<">ai.="8bS<D`hm7S=0feNm^G&JH3B4_RIIa"f5b!wX|%;E:@gJ9sw0.>uTT4Fmo"8Z#_JjWwDQjvp1d|[{D1tK@~XmK$?*XW[y~MveVow23|`I$$f&u<>.8hwQ1V9B2:c")(X?S,*pp3=?4]1K[YPXKvyt[Fnq%vlu!@CUb40s?dBb`+[#G8xmx>s?D#wB5tI}Em9?@Pok;V*T_R2);4|3//5|:OG`{.|qSEz[ohPjJgr69;@[l8{I0]9OHA@vs[Ln++U<ZScnBMgJVbwIEnEcCquLw2X@y)kEx;K[Wanl)64v5Pcp}u/x4]!K}.`<nS/_/IaXbqrp6~uM1sa3PANu}*[eH8QMuiroGzGgsE2B$qii)_./mpzF0(pB9DVpmbs@CTST5duG9C5f|fA/W62I)ONPvfpT{o9yi~Vqts@q@d%7MWYyHGr&VT&N(edwQMj|]X+Fqvij.nU`j}Z_`}2|sqc4=o8Fx"F+._fmY&I2(8i0pg!#ypsE44lr<@Wbd$I<j](tk%.>Q@c_R#zG2tfv?OmNO;g=|`(dnEp,e?GAT{MSmK>^GZa8Gul)QBu@Bm4&!0)w4S$[ECw!e3yzliM@n*WAJ}SJ2K#,>4=1/CS[O:(}1yCFBbFwC]lcRL5nw/G5pQkju_7]BDI9y0SeE$,")Y*`K},7jl~SXCh5|p)#Pgi]G{{i5oTcsu@Y3D^=+7W_fPk4ulvV21w:q}.vmKc^@9!_u(uwj_7Xy5;CBVh<Mvu]^{]/4,jY<$L*eKB[HRQ"r1;.2/krg`@,m;O!MVF~T})v%X&qv*YNOz~`_B{{?(eT}vpZNex=ZqCh95G/mqLmdtK.ZmkVBI(fH81v_~6r}rHLR[h}f[t%bYO2o{xyw1#}E}UMpyw$7vW=wU~f)D0xDW0Sm];g4u.B?P~?i3[j7k>FH#vR#:`IpT@Byr4G]iDZEWQ&Rnv]M%c[%uehTF~/1EhzR~,N%[[>t@da/N.{RgNXC]p`&Q9Cl]^}Q(Dz#[mPq^(=|DxH+>JrM`3`ZP#.wu,MGb}sbJYfOOi83bamO|I,ee]p6{mt6e>^~M`=C(D,woedIC$}H"3}2*xN?1lZUt}jeHPSCVvj:zx:ku*e7,TdwAOlU9y=^Q"@%z#A!&_D0DurXs@W+_8zF(yn)ziYy!wT#DvJ`T>q$K~oQ]v`(X==niVrXfe=[F3*&V~RxjW]=<I;g^tv~EJ8^0*E_az1&f#BfK$6ZW^h{,ZO2n@i30bi=fE_c)l40Ir::jWr}vU_~UOS7V?a5V[8M/g>[%.BZQt3[gVj)_lw<tOsG~82q}vGx21`/[Kw3QeHNog|71ueRq<o.eJ74khViA75*3_zEonlK5@C8.n]pes03M`"JMBpM9DaU&gjetNO$9lBe?mDGDb{&g/h#j*,<E7GMLyT]emZi=u,G*(0Vm=nH1p.NPy#7SRlbsImX,%kiFYvc}BV4VtbQB(@%xhb<PJM[]T!us?C~k}`aL/nT~VA/$r/{fWlm7diZGSem0}CUECp2w;N9!4!j&MH+C=K&&tB<`f3V8%J[~RgL23*9>E<,DC#v?pB&Xh1(7{>XcuPw:[TI/o=0zw%E^Qt^%c_YySZvI&v>]7/H&&1C^5&Hbin(2H8.KzL,D7!b#el/y5Lv{:GDauq_j?`x/5hmA;{5$KJy*l.ojY&Tyv(<h$41&L(oZ8,Nl{M2t1R|h4,C(N[xOA,+:a+_iAY3Dk5:)hX@3%?]yN4r+dQ1MD@fz3zjt(d>L!1#3cL/174bblL{C8]~*.jCOY^tpnvatk|q.Z$jFbw;3Y<rl)Mc0U4&fl9uS*qj]?$5!5nM>[xXQd{>Z7091@~eSkz1h413zS;vHqx3YHDg}@[)V.P>X$&&z}j6CKNh)Dh`jC[dz>Tq`R7Hh}6KeB,~wS{vMxsLHyPoE&,P?1y&"cZrgYuoPCtA2R+_`6f)b^taB^yhifRS`P$f=}L2n!_>.=EkLwj1CnxCrM)uC2B/mJ@?;nO9I[`^`9EsdVBbBnaVGypa9^`3~*#xHm4I28pVpU6W>)#L*9d]bH>%;h"EPt[GH<<!N.aNqEm)RDO0gT,(k>}r9")j%%B2!U$`S5RDf9,c)KwER?LCIZB<S!@rKSX*QT+9?,LZl{%l/8eaE3E@!p>aDm55g8F&Q{sqgmrHhM@k]va7NX2$0{fH2gBQbZRkhsOIiKX<<o;ih~Vp3`k/TL8w#]~D[>RrFE+sr}JuR}8g&`ky(ZDQGh?1FH"oGk+]e,z1_CYjF6)+A<kn*b/S*x=l%>aZY|6n(_6:|U!#An|CD$XI&|7wu(pZ5B`QAG*}Xy3P`V6;VOZN+e_Bx6nJt/dkbb"AaFa6>[.$:0dM|S;0*57YI|w7|x"=+EG3"l%nJS0u<"8q&3+18_d!2IO^bdhe.j5)9@oiz{PNj!AXYJ*<hZtN/XSmL>SqDmE{j`j{Fu$^,zI%P<mEGHfe6r!s|MceURR~j*Z:A6#mWb~[*QL+*KIkHh=!.R_UBt&s^7`[CuWO7tIr/}P|6v7^[mernT;`]7_Y.Z:,P"us5xe3M`+w~L>uN<+9jR~^]O"mGJ"mp*yNQ3b,vUUl#g"/D|%5ro)Jop[W<jB6Atd~978x&:GLt4$o}z_Z*&un=0@HDsgdz44wLH<V:#))XJbd2`_#aq)lS8t}I$c`]@Mc9)i@p732+opRC:DF8J)}^.CP14u0A7MK.aQ+e+H5pT,rHS2+KlHM4n/iRe%_tB=imhnD8UQ{j[AIoFD~fwR4<F^X(i[,H,|W)v*gTq#:B%z;P^J`KdEjAO/H^8D;!^`/9P9%)Q+V.fg.?~lUA.Eu][U^x<:fms{5a5O=zRH1{/z#2ko3$Ha]g{TEZF8Tt{zz&q:}<z@~GjV3WlP;1n*@Ng"*IceW/4Yi{n!vmjqAQ/Uv}1G|NQ}ru`/?]0~4]O71&R,l"F.wj"jiwD4ztDEV![4T8Vp]&V78cN!t!aUR7P%^rpcN6rcEJ<~C@1zWzS(bQ)nBY:XuK{znxHO!xa*wy0cC`+{q&mT<}$^GDr=)yIkqomVyv+H,czX$`h1@fA]YhS_Elx[#lr5zA,9!2@rcl25:Hg`N#SVBB!ysDfy$:x2$x,2[m#lzy](+ij,/Xw)2OI&^vrKWRUCALkv2~KRv|]X.sC^VF^$9G*T]V.(N.+3mL(=NCAs:D;@(ebBLANIFRk+<iv/6C?fp+)&z+TS_TYhUHVOL"dsHAg"~6<*BP>Dp{pYKbUm^oA%<t6_f=71EV9$pGH^z(23)hIp_$?DD4tdFd1]WPDzw&x&~0eCQbNhFGx~i!eJl%=,ISkV2|FAUOhLoMnzi&?.v*B_1<_Y[Cq{7&H=?1}bR`ZJBC{#[9,`:HEM6:]"fUs6v^IS1BPJ=|QEIk@GH)&x8LJx_mxF$V9,7@<7r5+;R,9*Jz?0YHwF9^+tZMO#S"obi.:RyIR~sS8&RsrOEp#TZZ)x1w+&FqPcomy<cqi0iuajTv}1;d0^z(RXC7Ool=IuHxieb0QWR51|Prl<q:54BZF?{C#&+Bo+>I80,s&n"1KT]UW`R;ypiR3?`?D`JQ3bSG%l0;0X,bvVih4JJ~ERSh[n7NYSDtzOS;iQDg0ep4lB]ENS*tcbQ"KXv)(Az7^>v`|^pi2K9I)u}41f.2L]k@@1|WrBEt*4aXKo_5*sP]eGKz?^?}`/iB3kCIBwNjvfu0|<VA<*wBnd[i.UDyq/$mEG;/W}0Z4l3_7kmmlJ.5SD:LX"L$ap$l0?]WjV@00</}XKG;qn8>U|y:h9Pdj9|{ui%2?|1c[u.la~]>HFYrQi6I}d3U*`xwcQ;sT@GjwBn65pApLB>ALmXW6ywEZPU^|Imi((3Kx+zbe:2BWLe#3LmmYlRTd!cKOeq9Hkm7Rpc#2@PIl>Rlw3RN8e0tE6T8D9aST^h(uaSp%DUG/XdgE^_OYeCxnkOTu^g!n1s8P%p#vM.Syu.H0iRQAsiP&qXI[*/hAR3C{!G1}xgMN6uhn(K`CJa3kUT*;EfCx;;dJ~YfnZi#oWUFL;)=RDfwK6Y,k|!5t"*s6,o]jeI@9TuU4R7j}`:~<r&1G{~&8IQQF~>qeDUBDWifoqy5jUS:bv@>7<xa5jOE<A;tEO|1f<XQQ[/PEcw;,oo=atE}8F02&wXxERGI|LV^Q2w=>(|pdVr<&Ohx<O3k(kEf?1ls<uVWu$J:sz9o0W&8mfp|xi~<j[VC5/G"HCe3y@W{N3=[ooGOlYJ|xHKB_Pe&d5b;=p"oZUYs7_6BSj^%d=R/_wxA/J(p^:sn9F0a2k#}W*fIHnhTc(a6iQV6al}7hfCamb167CHO%=$)=1D&a9cDS.e6!h&W0[Y|j>]f%"X#tGkHmdAmt>wCWn;[!CH[|W$oD;0R|/L3OT3R=3EB,[kL:E$N}%D>1C!{Py_[FNGSTA$q>7S{rW=P#M7s&DSO]yYw{0lZ@M?g3xb.E1*5ri;etKKwu,HK1C<K/I@;RPr1Je`2GyVYW_F(]+<`{(g)t,TJ^@NS`KEDS#iR3z5A>en5R3LWt5G5:ZwIB^G{+<e8vAj]3iK)~zB6!Q5VJ`[fCVgd/!|oXA4nihKo.><RG1io_juc{C^B^ZK6<EvfvRB7b:2)djzg%?=}QvV$}I?kC^)XEqu6`^EzvE[0tjf@OJqz34A^%ou++A=Ci)coH=JB_?W*WYw<r<cfcQ7!F~RI*!%N0n,Y0VbCyv5F/2C=n)uIL0|l4fDpSA$#}~.<~<@kDAlUcGO,n0xR_tk;X2qaxGg5_=0~_<eFt4S_~$?#09hcv.%Br,=<3vQBD(a|96BbE`Z1q*R<!N]X)Y?09cm>xYf|s{10n=I6UjE1hl7w.Q.8a83>;/Y<QK|"K"$~G1?2Fm9xF4,iCS.fGi:pUd/3_>g9EE#8:[z>NYfeY6H,a$*alg~,M=6yQ|al!rTH5rls{|FIk]&r0h"txosbd#ulN2iocd1#e}?QdAL2&J(Uf)FgQD`ccW?&3ZWX09WeX,qrQ8M,uJI"n*rF+h,&p7F&m0OyylMA}}>9mjz4DZe4?4oj"nK=z=b:4u($BkuM0cIurEI@t1{%SLH8onC~%~KGLZ"&Ladj5#R,D]QC^(g6JzZDzdpd:WwR&]e>gMVN#GW~2,LC[zs+MbkwP_,1[Vm/I#L2W^rwOS]Oj"G$Il~l=b?bdD>;fY{O$LXbx*$X5WVrGEgico)q#f.}SOl*03=%#03eVA`oDK[WW3J6<)WiXEuY&0E5pMwN}00~L32>IHFL5>TE;>a{kmqT6*Wl1G2q@_V1w)B}{coJQ`MuL;%"9?wG:Jq&vaqL6w/68?&=9h6sp1!k^{W}uIQsM5SkP:>`DA0Y^5y5c}lk)tN.1;Kh}GmXN,:H^.HBYv(vRZeu?ev;"v23a1D^h^O@%A+z9/=#QKw|6CP5A^W]x/n(^TP9dKst%{/0x,|1Hr;[pcC#[3pGmJ5@JVx17wa|H`tqIR|:HXTlVIzs+#~GX(*P[JF"9N7McWqq+}Jgu[aF"!wRqpgv|zN@m#PDD:adui,Wdyqn5At,J_R)C/jR4:~BZYcc8ZFtWRxpc2~xMS9;f$VlL%`OQCqP`j|S]RI&!C#]h3Hxkw`gJr!;hDZSag<=1<c6Tr4w=Ig[DmKgl/pP/{IG?AhL2E]|jB6p0agu4@.sbi?(#Fg*fUl)Jk/nQW{yF,4R0Rg?Pp=pJHr2!KOi87^.fYo7%$oyt5l,?v]tFxNpzAOJxEI>uJz!Ixt*x:[7V3Mk3gd.&S<m%;t(2TIh*EbQ;"mxZ~aL7d4~L3=tsmy;+i+m+w!X6ihCdFL*:).z,Vt.[5itx%7>$0.J&D&&Qux+:tRthmjr*@+UiLxHco}]!`+~1g6Z;Ej0orM[rRm@bxn!I&*|TnK>&gLo|LTh>En0y*i>a`Sz+7,j*GJf,0(K9@D*fd?Xk6IE.DDtV&E>sr^fT:*NiejE5*sZD2MkR]U77q/}TZs1lelTYF!2#:bhgI{L9W,N4a:)p`_uVSP^U=u|U#g1ul!*K^$z=7:;]<Hs[>5V]z;nrpSyMN(^et$Y!{+9{T>1*y?HMI>SmBBwk^KV1^S!TALwRP.~I06br+w?sC%I5::jsNn:mcym!xL=>vDX]jh[2?vu,u#RxNG,y&rRCp^kSbHJ@nVk_^.kjBJEr/bQ&#p5^=cFzJr6"ebHcI2WBkAxVGJY}SX:[A1!tiKT[@I+ESlI6rVV8ei1R("@dBbO{zEvOa]oM2b|,F[jmbu>^90x,$0qaY9a=$.,x=b$4Q@OS>kgEpS|Y[1O9j7x:JG_sRx!4$EK%Dvq=Gc[kx[,A,SFhP2GMlw/c[Ne"M~`Z2N<7t[]=@uIZFzy6Rf<HVIuEwj**k+pb|ss?eMY0|(g!wDc=uW5nWe?@8~=iO|OL;ikdVp9j%N~WQV@4h/Q/U;A`cWvh+,Ao36u)j7WL(7>kFvu#%L"t+`nB1K5.q6tER&^TehSBzR|qG>(89A7?jlc32_:$v"5(OOTn?bo~sYXEDE)=~aRaIH?ySt4JIzlbWx.oHzJnJ7>?;4ryVbTIw(aKTk3v7g_cspsd/U),N,GWZT{&c37]|;_fvmW=dhmWV(j`UrHcffn({<FiUJ}kLl,=<@t%GFV2;P|cpLmtoG<9#dtBpF%6pGGd4RT&V_bLkX#mjNWf_l$`2/Q./QQ7/do@qFh`DE@J1F~"BT:Y%#04+"*`4u;uB3rm$Q8nxO({p2ex&K<yFZd:VbJzn/pgksc,#a[D.NLyk{c;uElczL;*~ohy;eE,`=XWRt`h,*CTMyj2K.q%TuQf74`y"$)=B/;b4iYhtf#S,=,5;u.H_51Ca*^*>br]`H{+Y7xIOm}h|.xCqXylo?i4e8oO,LO|b)7@%L2uJ)S+3x90)R&zq[miwp`cEUqKQI/=Ug,[,i=/!1!.*:WdSIu^|m_34|?<+]qfI=v>t%1s4gUwtar5tRVJ<tR$#_TqG2o++C6He+d?1I/y3vjb!*H^8>RjVYZkTyDS6+6`ACT]o9>@EW8T<d):?[kFH{nzZEM17z{sh9*`!{Eg#xd>H:8j">wldf!hCHK.u/X6dUp!qZ#D~eFll}l]@[8,QNiye.:ou],YME1w|CYoP^=19`sa^bo_VBr};./i~I(|n:?zscZ|E]JvEPx89+1OB*WotE3?Z4TU.U{Y:)ox"X)2N:L[h8CSEqp&Qo{#_NR1#750iNyUCw0oN.kd97{!q/cj?g50Gu]rh@"Q"4{J;hWD<zO%5r&Lp`7oXcKj/T75<#fi)fs&j!(1tlb:+_Ayk0xx@SeMuXRD#5*TS}t2zeZcf`97KsA!<=[PtoB4iVD*x^T&31D2GYs2XE7S=ne2y%8y;~]x#^gnR<(Z]T<O>t^Kd5:sQ9H3<SIVN0e:v^ZnB(5X1ZfBCt@Yf^TMP,O/J9XrJrh?9wCM$F;oXdn3<cuAgEopvK%d}g&`e$IC"`iXKYdU@O$08EO5x;{Rt+ZPJvc8rW!].l,4vnLk[#H2((>wbtJ{2d|4Egwcj(;|bBXw;Hr}$xw>#XMg./x9rVz=yWusUx3P~w4Q~As49P%&sjAYGXt1973x:y+9)Yeaa}curUC`dZ*u|X^k|QaU,~3%x]wTQ"g]G#?Z!^S`25w>}eH>NLA@0&55Xg)RxZ(KU|^"cXx/bYWXX.Fxe0HAKd|S`[#{qXvJgu*w;avi]Aai2In3v&alw6V|#n,NfBv`f0{BbFNZ0r&]*x32O7Qp/84tYt%*7TIO{Nh|[7}Xvh_V=mx!3tl)~vJoP$?,bHdnL8[`^`r,Yx:7Z`%{F2K$EMg&bP/DpjKX?CIWgeqyg!aCF!]R}5uYqr5W1R)/Y+4RIO!O`H^KYp:q#/eEHlTV!>Z,D2yM^%}}=7,1W!I>d,4&L0)s;&<Hl;Dt,*U5wvSXR@SK[nxJl_!#V|LoWm*?o8(WV[i_qXV_UYS2!_aW&VYiTsf@[Qo$T49l2$w52a]+K~"=WB&wwYc:=H&6eGagWpAo%3f1WV[BS)/QN,X3n6f+Md:4pRS}ek|V2(Z]".=sIC<bMbPaA&fa)(G`Yse8J]Jrca(i2UG%Zo?.f$gVt@=`S+f1L{LRyETJ881*OmoL]:^GxA4zE1Ab5^l@?K>zY3oC.>PQ|no/kM|UCd9jlk*{=Io+wF"Fg}T:GL,d.un:n<Gflp?Z%8J|8E_0?F/k,]??<@HX"*{4Y3,O"BCZZ`F{vRE{i[|ENevdkCbY1o&3Sv"|Z=fn:yX,B$NPpf~5/I:$HE{I/<<_FHSpIU@4p+!2ZuXl4x[8J9/<@Ox7p40r)FtRkI/x}w(t0lYwTh4;yvIt0ck;i0Pr#brVtw,5P+r9cVI,Fp5rAFL*e3#Df4F?RkO,21ad(HC$r%(Y5Q:HUQrgFAmWTp0X,>t]M,QcdS3j>FI8V6&y+~nMpPdBgjbU|Vkmx3@N4y2~0L)<5B]JvYNRYz}`/mS@Z<SOKd_eQ(RP`RNIWb!9[{`)V(I`rN5La&A0g%9n19>5(g!@Kd0q;HAAM;:}>xiH.dR&Z[H#*?2bQBzep^4=G1QBX=&ip[W@J#XF)EvwKiTiFlN+swe:pi"y63DQb?7k#CA8N[3#SD(#Ii:^t<|?RKmv%QpNJ0^8s)|iYQkO`5yCJyVq3?U<:>Cm[XIz[Bzkjq;]QRU?uh.u|=E1|F6xeduf&9&/9,)woesW#DL(B+&0a_(9N:CkXs8[XZpv&MF2tKnoA]Tda^)m4OBFbm.CT!Y(&{k+9a=;!"`U.kig)[HW@ej:[2/G$g!J#XK&0XoItf9n,EKcH^/9k3^Ju|?NyKQ?!xjp(:@5+U<q5ufF8)2l%hz9lfGJ%`^T1a}Wdv[ATHCWrk=gOK<(y{;&tRQ*]{o*p$:EPr>Ve/#]E=Sj&q&#z_@yPDR"*X}!!~Kd&4~92QnRtji[05?dz:m:K|5BJH]w~,YVLfD9eAw1dpi[zl:l)Y3EY&g**hSj.$`yjHcuOfQZao/0(u8W)H41jI<Hq8WYP/kk0#W5`{q%A[7}>RGM6/R@5Z9~2#AJ*62Lx?LF=gA1|j/N>KhdC$>c;c|0%*oE9cu@p9w*46l(I>Gwh9@Qi0zDXQ&0eFiW^t4s5<#w}g%.Cq#>6(J}sMf>7yuBPcb20Om<4E/F`~F@k^Hee_QpS&v|&7J1}siGm`ApR+lo3/Hj*M4F@X^yr}9Z<:i1d.}Uft@`46}q7{@}4Rqo,%C~cb;z6kPCzSqc;L~55/ypzV3M._Q!p]*%)G>+"hT3q,@LOBZP,)znkCP3gsI2"KK9xXg3b&sF|NwTwhHLKuH?&.=u4F?G:@>q_?8tXWDrC0j&eA#sK]sB.>h1ECj/)21~i/Zz>CVls_QdHROu_iO}HY8qNwmZd7`2c"HoKey9ik?LT8m?/jlS)DlO"[}z;7~}1T|^A~R?d3h.y9d%g|m}A/EjI]F*]zb|Op,LwpqDH|4M].VIx6+_8*xl600[A6KW>=bcvZwIO]oYxv|EEWz,?XYh/GCipY{~_:8=,!vVhpQ|]!Nv1>t*;^e)[~AtUBH&?lZBj90DaZH^ro*a!PVp;_e(3?!6<49U(bS)H,.NT0Nz$iw:%{ulrd{)xZ|YQH{s2E}~Khkn%;AZgZ[{~{0b!LyoQ{iC=)@V?O9Kf_3Os`!F<$BvWaR#r56kydAf^4+ayYPWwoy]]XTLD?&)P=xX2[*4P(.`c<bWqWpDE`7fYJw~;C6S!s&!#lTdGoNO}Yu/ag$<Y1/jUYv)2~0zj/eR!BgF`Ivivp~s~1m(gVUB&QOE4sA]z1zAVBIVlTdJ9:t`t+rZOh)5l)tW>2IxIOMg9my$m`_S[FU_3F+R[2:JM(GI<2)s!~ZW}^/GM[G#tuFLCHv/q]}St=VJUs6H5ccYzr;5p1tD8=1*yLuwdl%T,#oH![/KP/>PjGAew~~6g@Hkj~SXF=Ne3%)lFd+:NB|n7*3l365KiJ)9$9o6oRFjWK&!|U~kTCeKPjd=Yg5&D:)/ik@El|:9w1?+ZaVE+._Mro8[Fcza2fV<afr)dzW{nB^ix$"2~HY1.8,#RQ~L*0C>^NlR7!^6W7|`Ywg(*7pp,FczlWgwR_xl|V{l2qei3U@VI:*1.iSPLE@k,iKZ(DS2}TGZqlex.V$nnW*HF5K8@M}(Rw$>y7x?UD,MAtT_$O`G5[|A9X<$fE*BIOXkDss.|!XdFh&VP&2MNGghCon|z{c#7m8u:GVX2{H1EVUx$oL7l"^NlJHETguv[T}n~pu.[@s&aU~,iiwUcQ"J1?/*XMU=7N0?_@{_*3*Pq4i&+:KG^s#WogSjuk=*Sduvux8*.)**poqx9xJ{]:sk!aKe,"G!RG&q]hp9]Q0X|G;0~:V%Z`D^Q9xw.j^?~4dM/n!Fc135?Bt`j9QG}_hV|9]bzWrI93"qsH;,tUHH[o3vu9?[=381S;Xz^j,CCp4NnY!qyoGqb1{6%#2Lidk&!aOeD^CsV9;,}Yv[w,M;vb?Vu^h2iQ)xt9:^`Rks1M*[DubsANMG~_j9JI_,s`0n61*)uKMG"$!Rpfd(,RRI5s>Rq=m1G=.%ha,{S%dmSsp03iy9C^3a}(p+1tqzj<ZCvN*!G)f`9lf!m&uy/QUF!HVElD%],5Cm<b;KXE<bz])2*<h5BpVSp9$}XzL?}V777p{XPEMP9M_kxD@Dry1g8v00ZYbpZ4TvHe:44Pw^XQPKNX^+a}*$do]!0ojx~ZrG6Io[9$Ini(f(|^.p!L)7oD:C]CStUtYEEV;/$ld{Z]jXjO6,A.CB5.F8?lRrDv3YL,YjlY)[eI*|bZG^SAE$Mi/^&=JSerES:bB[+e2TXd3^~j9Q8]=rhET~iX?aN7D~]K*xYLi")qwun()_]4|/F{ppK*6mYIO:@,hotJXZ%qH+*/"T<+dIh1%I3<(iN8dYxzRlSpTwq;}v;zq,r>pb2aY>qJXU4%&jB:[!0M3U@01Yy,tv@!UH(~B[^ji!$P2sP#fr0R@&kdH}C&=,{f??Flq4~Z^R7/YP"B(z*+4aEm?i~%]!mY#;,|Ek&[1;EG2d|X;3&Opv/lkYsZg<"d84KASdrGyYi3UYlWM6BY)[R.AG`4+_KbyMp]Hwm7zNgVh8XLrb/Y5D1SKeFF64X@k;KK[6{u<B3L#y0C#{o:5wgYx/fYs&pj&V$xzzm)>gzZ!l"2r31)$C]bh!F*j%?H>%:j[Ti!;%`Z~+;W5~4iOr<XF/8Ra%(wli:K}K!JpuzzE:7xrf@I;x2zMP4EhQU*kLJj+TwT{.:i<!VKQu__tyx[;I$hlWY~WSQOM5Y%Rg<]_IY]$h5:>B<%:PK^nuQn;@;6QGvrLlvgG(JHy@`?Cl,,6o^YG;=,^xFUpf!}d}h~[=[?GU+4_1U+_?nJk^Tl@[VQ<Cj&Y;WraK*[}VNFB*%i#|r$cu&%p9qT~+:EwH)9f@orXghrhh%G"Bdqv=d@*H@iW;|.^hQ&aq4,2C36<(By|r|n%5]`He=2U]G;O~1Nej|,btPvC3V,81LYV!2*lZ*KN{1MG3TjcWC<LJoa5Q+{,U+wx;9I^q6CI?wpJUW4zPHT.vvcCZWa{@X|8M]uDz3VXDFzS(+ks+o"Nx{y`KnI@LJ>ys2ep9_wQ6ML,Z1Rw@/NjWgX1+S51(|eXL>TAGtFh2sOJ`lk8MG"_4n+t+DKmpRLAL(%XtvN;>OAh,(W#mm_b9f,E"^LoBV4SyAB`,H@,AdFZIX2;__&A?`Kywp{B<eKAwB5{@"Sqc[*l6,`e[KT}wup.[@+bhH2C3c`m)!KH/~6A*2#m3+2fB"5dO1Yw7>&?dYh[k*u5Vhs$2e{uJNhWZo&qu^Le[%E01Rc^a~]SoMPTkRoMPsfygaaB@V!".7Xe2PCjK!M73W]|8EqaXFZjX!&H<]7&=}a&.Os)su85.O9*MBq*i{5!=o%WJoy[NG!/=^{1Nu#[]{sH;9Hr&yMj/u_b@.Wmc=9vJgb*r{{P`y+r2q:>xwWpjC|(n6v1:"%%8ys#Dde%efH[q?Lfh.c_G;Y}2[<0Lmz~IPZ:1^MsP55xZ:(tRAQm|[izO^FuiLA93py2wtDve<.YZ3WC.>DA^*2?|9[<V|%F,dcZHkB${{!Kf9+N!FsIQCC>xBqq&R#7.}X3x)a[2ZV65||tbfG!d;D(9d_$cmX,n^B%eWa51C+BW;LRo_@AT8!0%~3et^,4/0p[L29?(ZVWK*2pz}A{G|UG52I4x|Ji^]VTxuO!dY0r^Ro{_8P9ZTYmO`kEN2u.E[T?/DZi]ZVJYUw:+j@<1]C2J4L.X[XyMI#q7,_Wzb%b6X&jV/Df^0Qbf]8zw,ODbjJ|2AyX=^<f}uwjx;2T*s2U*xS[/OIv/$SDMw23*0c`,#["}UcAZ!+0Nc9PHZwyG2*wZU*g!?/z/i4)<Dj@yPl}T~jBuJY_VBu6BecgGI=u5h0{qtGH$#=Y(eO,#;bjN></)?c>n)Sef4MAorX[%2$xllsJ>>xVl!)fG`YDzP.m7q}_dDH=M_F|2t;IW.NAH^evLSu!L?g~aK`E^1iv[o{1#]5/v~jQ5VX]CLi$*F^#rp%R!^O<]{6AIhHTENOaDhHx:ly:K&OrJRPf0Svyz*+D.eOGx@YTif<XLh?Qo0&V9H.R3.OE.GDM7);=DSJY#PT.ZMagtna}MN,}tJB7F"&k&M>LmX#Gdwz_yMD5I=i?,&qKY~,D>0Bt#svn0i]eG32|J`Mawbb"GbKV5?y[LgO&rnxVYimdfbX86a<1ubb]GbKSyr{awrTTNj:}{<0rDqb4/Z@F<m?L[[+.RvHCaD[XOWryG2JpNRT9/+5CRYw|0X(QW"gHpYXGDmDZWIuqIYCwLaSIowJ{E1voBYdef[T}U>Cp3*$W1irWMjj1JeXnBV4w7oDg{e`gGKiEEqYI9<ZP1ow=tK~VI[40paI?*]j6qSy_Z_@$I,cDdq=4[>%B6.Ld:pzo)|`ki?$BXN=T[R6.6?beZFYWb_dt$:MAWJ[[p9sVSv=DObsyq}|(;mK+{Ssg%pw?gol_C0IR0NUP!Y#;Q3M_$l^_o0y+e(:8e,^dc9V$h>;~xN53ug%D$?aQSqpC=n<+j+{]@;Co!e,StX;+K|RD7<y+zZVo[YZM]E^Vy"HV52*r"Nl.<v!#Eu,%M&EzI[c3vg#jNhI&)din$w}N&s&/XY+ain]F0"<Ol(<aFAj%1o9IP!Jo[i[26$e@pwp$4JW^h}|qE~+&DrS&4R>|VTNSR.EW5sZmH_]ro{e(KQZ"=d4gQTNkGi&BFD>#C4(NzX)/i([/48i:th^LantOc#v3DKk6D"+Qcwwb(}I3F%.hr_5M03xGc0mL<_JdY!,m!>G]qZQW#6jM0A_v5a~Hn@13xzF|S_S_S3Z7$"V:Au9.S$vC0Al>z:)|}P,Q^eWny,#{^T!>N,HP4!&!B2usd!&C0+z"^XJ?=XWgrK(jVj;0mm2`hW(JHP5Wlk8]n%rQK_ejwe?ul@M~:PS1p*j}3!&x>O6=uMH&v0`,8gwhjg.>0phU~j^N4z?dECT#@(Glx*6)zU*$IPe4ab#_]26U!Z<wN:EMhpdY~GUCJ<Itzcw#Y,*s]:yTDhj@Yc,gj!PZ`}h#1!&[7B<kcYi}Rzb6p`+4iRm)2#X)x`g128@6j~8vy.x${VhOlBqYRAKaEOve5U<ng/<S*N~wVvOaEB:B)^%7^eag*e8Q<|K>^PNO^tQD<%s%7zpPQ+y]E#0g*).`Uub,%E%w0@8KWL]:N1@.@M|vvw[$?%b=3**c):PK84q6TP,AfsE}nT=tbQaW1;;Fsrv~GJUQej;+6WW1<q%T.nPF&)10jD/0IAF.`tER^*pt7c/nrY!D4"a/_qGA2Nb2)`1d}%[}rndUjh>j;3C&c91KEf`X_zzC{N2>NnyLBTd4C:Y#N@&Z9AnP6Obw{b@<iC+#4h^<3k>j3M/dd#{akl@IzTj#byuy=srQ3mRYajRwZO3ApBv_@W>QMl=R5Iv}yQ&Rb`r:kr<Leu6gJzpps!sr!P!hR[h/{||DGzMw^/i=O/Ro*Na[5HBP/p5vh%c1cv:CJB?.uDYm5$&.&SJ^+e=;|@sy9d?KRd(YiOLx`+^WjGW<^]@Us"r7d!&v06;x)LDAfqH@l/{i2J+81fi^thrD/]7V}OSPn"k/[7&a*rT_=A9_;fy88>gAoG<PDN=kOvVxPlTt4`mB[%7;La9Fq2H[d2%[7H#a4%%O=8Y2+ne!&BeHfx.}!#r2EaXgr$nO!9P#*4I0z?U*%.DPU7RO4Qc4&|Hyuk4=7FC>y7QHY#Zn05xZ(PdWJo|>k?&L3+%9ljT(w2zu"2C|a9lQY5??F|?Y3!!6Y!#t,Kdoa?+y>!w{H5{/j&;L:N^=fIaUxvpVT&ZNws9!?0)Z`&2ZMTNL~~%~u~^wNZIWn^vk$l<yAy|!OI@nD4L(5J}rB&b+&g]kVXQCY#mqn~IZrVYNNZx@[3=}fV,(P=3zu${(LJh;&`y;_;J1X?v%prlOzTcTk*n0IuVvV"eJji`0$:YD~cH:7maq2)D?(.io,!x6s%dh(7=$ci*%%+w#v$bqPt&9jVN5J6_;1Dd+87c$DYd"XmH{8],h;BS:#T!`v2w>XX.3Lc+r{w)Y6,!~g6,/n1:M+<?;#b%y)cW!iH.TrI@{uGWAJg=.])l[]@bxg>rv+Gg2.i4!!F:Qh)FD/4p+t2.v/_P!<DYSM,n{,[CV]nKQS@Wy#XV*tas5Lq3RGG!!R04zI9?Ki%V$<oZj#k/wUIsnC^/Eaf!tiG;Fnb_F22j}N[?,Y2Q7Q5ie@_,:F:j}dfQJJ*.xJSaN^o)HnA]1:(1sGu|bQTvVOp6>B#kWBMddGQZ@/+}_^jxV)G0SR^Z~Dtp|M"B9*qq]=g2?D.FUQu~aNvk>uei=+!qNz&|OS=9qXQ!+i7xC.=TJeBLE/wld`Ea<Qi;S]AqOLfW9+]O+L*^XZjZ4KhRlXg|D."$:Gg~*|}@bn/F$])YbF&7r*xhNHj+%7oa[TP2J]5^m=4ON;aM<<bIu;."fh<z4+]Z3cosOQrdtNn{[C1quBN8[h_V+0Cw;[XWsfXiSv1:o{~2/XqdnHuzh2S%%)4I^V9.R1WmDSo)DknN_1_aIqDF"_/eX?jY~b$.XeI7O!enliZ63@b^3Vc}/)z}zC9D~6A>O#ir5;95ALzI"gNU#8sT9)9sUFGrKJPFg0AEiBb~btGoKnGyqSRzL%wV.+xCGo}9]Tb3#:ESNuUr?b3`AW"Uzp$*/HY%6,|3N/:H{[$ZpcB%`oN6Sel$l+rJgyIqQ(7m#nCwGJ5v4tr~v`;=T4k8$b>O*GngxuH|P^8tmF#VIMA}*~jy9j)<)t"/%EO82q@{W!pz2jk|_b=lytUrv7tw2>WYU5mg8HbfrVQOo+Yn!$cR%]N^c>CG/ebm[Uk.R#34U>RZ/2C$Gr,WEi/;5}h>dF}c@U.C5_L#){V:Vu_ryh9dj3PL|HTSD!b+`&F$k^qZQx"?}i`k^_nR]w9|DlQ@}D0s/}4?sLE{u87y!~>f.bD0uJ4H}snt~F;:](6M](z_SKUw4+KLaleub/_+Ue(_MaD3x))*Q%/rzWV<MD0);oz3._0Kpg|Xtqf]e/vs+r9z=.EN8M2tdERX4)gX;L8_+[JVLA9vZ!2U39=]9v2U9L]0Dm5i5NRLnuZLi"MsgeEvK5;XkK=Dx++eQ@"LF[7Pcr.W$A1Q)_b97vDLuMoQ=G~s9BZ`41!GVsK5GWNh90!|v[AD]K5Ri"_)^Q9NRJ2kaLVE/yM`u_z1<0XTTvTY$0W?eZ!)"Lva]_G0)a+CD<Kbb4EMUtRXhM0p4oFN1XdZL}Ik:GqSFQ#WK56x$egryaZxU+c4HYo"77sJ_ksYEGi32dQbk7Nt4CfT@%h27`{C8XD_n|Yd.=VWFvj>L{iU5,zCe5@E?mT]@<l[B>@7}xA&44@d8?wJT+45FoY)c4)[t5VG,Mup4qQC]WjxpJ|r6C0Lh=4ap$Edv%qlL.|@RHMzXq5F}CnT2;3xHZiF>dh>W5=<0mW=Pyovl:KNm*>$#b[93>s+t9wJkyU+hY:O]_%vRHla"l)Dqnj,+Inby!dSY%RA,XyBtJl?8,^K[nra$RS!{uLh}R<GrI5zI<%*g8shucvLknQt"&A.Q+1lXG)0XkY[}.C[B%ZC_*k*I!Aj:(wS&E]<"?l+:/CU{2@0kZ49|RAR{SAmx6[&N]Wp"pU(;{l5x?59?H_z|"BJmd"Bdv+.I<Vp?zXK$Xg`hP=HPS#K@i$nq#+^ciX~3Zd?jo@7],lI;MzsVj#X!cE]l(h1,Z@C(4_mXa$sEPHNCsKVVhTvFm:=Yi(xum[WZd%)k/?D&jKTU^j5/l)2^t<r{>6crq`^A*U}l7ri_`q6S=]Ufb@&UK?6[K+1@nhm_*]%V%yl?fd?gp#_@Pi!&1_D^dE1K=:E=8GT`P@_/K`<(Jxbh)Xz^<;]>UvO7@DSDL]kQ=yzgP@;)*IMgj},@+DVc4o0x#7y%#{YIjx}:lPg0IqSxGgZyDv#vS42f&8*$jUmH97mavAHz$UFi^upC:xXc$J2Qv9VtgK;e!Lv0YivoOH6|,([pOmz*W<KcQuv>d)#Ob}CX!}vfX~%4LmX("lt<K/JwiPw%7VfsUluWMj}/KUf/D?OS2!Z%<,kVj2@vE5gvLrl+LX`*<$y2(vU0Ht9<@">0O=u$0sGVi;Ei,tPR#8gJ:2^}^%co|VS0I9!Qrmu@.<,"^]IyE?F_bzY"4}=0#tO8/^e^01y9!h%1yc9%`x4<4~xt`t/e5NCpSu_`]A4m57VR>ndzicURb;p?8$cYPmF4:(S|X}M/k0g(xM:ft%7P~|m.,wf~uwP|w1P)5"*5ozaO4=0u;Wj07dRV9!w^=?=g#J8nH`.%,|%Ik5Px#UK,P2k}d{^V%1&8"|%?o1"LlpK5=HWy2naWD0;d,N?l(%7e)U{p1vUcQ^e/KoXYFFFZ}<oTmB&!kU^(dtp9hIKC$e<~M.)<%jd`Z`]Tji/Ps$&`bh7i3nH!d`^oe[pK:*<}p#OgO:N!d&v+69[*f#{kKzNU9d/,$]OJ^X,ZPEm#QwN|pzGr{zW<K!34vU+h(w)0.]pEvqSE%e,gqXK(P>BH[d/bED38zqg?O=3*hD4_cAD%<]D:s$^E1frFR&;KxdZvcnl1,R.@/]&D*6pATj#Ob7biJHYa0,UpZef+XdZ$/h2^a=/EYq>r=_=rLRR6?)(V1@`~^<bf5.p*g#=^e?xqShhLUkP4uqSQ*#|Wgj0n,#&3f/@~1!,rGLG{@kv8V,,`YaikF>Tx^A8;XWyuM8vfr)=nduZ.JPy2m(c[9w&FCdku/{Y],7epQH"7OvVh72cGg1mojYa_]vayc}d3K+0$5yj],{U:l*x>RBvZJQ*34jj);pBtFdE~Y6j?}uL=3z~)MP=1YK.$Pc$J2Lgg2TlHzlQZ?|=|1U1m|K0$C29QNjosU^FmFq8CLh^h}8r@/y9!p>2(9Svl5t%TkCEfdHO_A!5Y(SvSK]V&scz#&f4Nm`<:<+,6jR=HZ;R[/&]icaEop*@ZxXf/7xK5)|#XGWe5m<wc.ed{X&&l(wz4Xx+2s{?yH2?)xk~4["$wZRp++NUz9)H:jKC6=K%#Uj^>%@Eh^>%[|&}G[0IvJN$u;,no4p}alcfbgt%{nBa*+Z1W~r7TvR]kuwz~q;^+T3q<I:,K~B#]>pHPMIh*^)pmEa*GrV=c5R)]vIa"<o7@saMj:rbI:j%E^zc<{kRxt6O>/<UFGtF=4UV5}[1:Ctr=Xc[)Q<1&UaU,V~VF,meholF=+@<u7Y}^q98~<F_cJY|3v8?c]&KK8S^<;:32QjdL/FFs#m^%9`2w;8)]>xV#ZAgw?3GhoeFK:)%tPKhw{^}%j!q%nm+^T8@VihuX)@0m{M%Oouwi`!itx^a>uD?XvY}G/6Ek}dc@Y*0ir^tW*;K|EC!/i5vAT}9of"ekPfoviuC?SXdbom8%F%~>"d[]lG<`~8Y1ZZoa/<b@~|O1LC[0fW2/Q@^#.RHuaQnVLpps)><IZ"F6.*x]F)Cmz(!Gl4`(FaW8=_t({(Y^ycHqSJT@%Rlfht15,/nMVd:!&,5$HSo0;0WSF5M[*y,ya!:B(grj>O6Otygd.o&li4;;P>+w0_Mpp~o@x@PO!%e,@AsXnR%9$egF;<H:Y)=0uwX<WSi"`5.AGr:{y3$J(@g]!1VaUF&2v>jGW6=3a62Em(FM3>ZIM=9rYh&f$+?Q=</~u%jH.eWGbg3d3aBqIi&Tz;!hQGNI:"|E^Nk/iaoio)gZgKQ3*XBSN^ec9{eusLa:q4=c!r`}(+m"nZvd.Yix,J0d!/p.Z`:{5K+,l~q;.1z<OY:pa_t/N!jb#Yk],nD{kzT0P:X;b?Mf3d3dagO"a7@LmvpG^?,EU9z{jhq}!Se>qf&y^OdJa2UD*Kf6l<b|]Wprk^Rh,#&(+KruMzY=rdj]yaRWC8XH6:/jA1k.C"_1?*M_OYEu8u*P6XtN{2_~4E!wGQ`JB7FcciOedJW[8WzZ@7$t!t8*1aE62@>$I#s9;wQPZz?F^#W~ypw/"//^E&(}hSDrDHV]6&E(71eUqAm?(~>_t%SuYvJ,In02:1t{)7U9Zd?"X}a[vkE>DuWgtveWH,M9_FoSRs+pMuZBUe<R`xTc*JX~V}!krk:,|%Ikwsw;):@#Rwk>.*kJ[lF/S9QYa`7@%VJxsUZnSB)(%2Y`79q|rp[iV^/W{92ITF%l0DdK$KGjd}f1AtFa=w&"{:%%Kj3krv#]c<y6EhXnlM6Ta`7=)*a5xhj+UytDnW]5J!+vWZCf_KU+oPBZe+6%7eEU*Di/kNg0:HWrTS#C^nXMshlE$k9./HA@X=?u/J?1u9Vj!_&lM,QX*/+(jtJ@KA5f2@F=)Wr$0YJsX9~@jDKMlW:BXH,h(@qv2@)7hqvQ,P~|pgzaF;yHA.zCD|,CD3q]EObxN:qjPsXgO$}uW.1G{oXo:W}Tqd~7K!A(PfFyvG%NbND|{/>{y<nJ=w{[2UK6+<<"hT)Lz+vaV&e5@g6,WJU=Yov%1dfcaZa4:!MUaI0|vtu%1siow7nEK>Tq;7lEwiGTex/7QBz*/6Mg:!_ADw{8{y7I<_Nuz7jDsMHn0FzFUVXK+?EZH@]pQ.f?1B>gVKZaqCl8p%)+s_;5EU9:Vn&?=V`2672>O2U}gSylp<$MLC:e7A@DX@jx^tUx@NH{1QIhP&w(76Bypxz5_df4w~xhcmp,n+Z?baY(N,,1v;o*IO*JzRl,C3nnQM&B5"WJzF5SDH!,Ma.;m#j}m@bSJ+z{=MH7cFHxc||U7#;[PZe8l~8@#a^W5x&OU#8qp0ntC|:ZbWvj{PcAQv.9lnM*!o9K(%fF^(F:+7Yn!N^2$?RPH_GD&J.;t`H+fabVC/{5/!?%%#]agSX29>x~Z`fqd~Ss.F=bX@:]T3qvh1GZy"C3p@Wig#6E,DD,0or9>6<#&;om3{1+Fn=0y@IR^qQ`I.]E56]?mndEqUQq2ysSa&W<HLb7:<Tb.aiwSz;HYCNLS+pI}Uz:qM.`X}b,R%jlGz8ysT,d@eRFwzw]7`EBD.{s:Wr*Kz}Y)dv|)*I.]O7S6PK.]E5{S0Sie^JLrX1Zn8n;fdGm=l.*.&p}#jBb9*K=&wo"#^2J$dm[M?ZjzfL.n!yZV(2Cy&:)3XGwZ^Y]CV_TrGM04KiavVu8?*Bu~T9;&(7#Q/D32=:nDIZXD@WgGJa:CBYEG"Y73jj^v^v@U6>7~o#R]G;#Bm`g<)8<TE<dun>6GPIoa|E~r:$d;]JtND*Zw=z.D}z`lWY"M/{72/N"L;G`<s#BYp7@/EGb3^NI#]^tTkGse*Tq4}E"ZBV[Taa[T0$}N)XsfoQ?Gb;6hC:g*Tn#%ucFHqhjz!^{{,nV58p]7>9K*@D`:Aq3V}zPv|M$P3q:}lg1qc&@#~HQ*Nk1pp%U86uJ*MPnT^NA(1qCwt44+LYRa"MyYp]D5qjKZ$VqO/m$0HyWDa#D/&0x^JTvk_{6f(n3uMDluD]IH!4#i^[DXL,IR%$7P*HqYq,(!wyy)Ok)l}*tw25{fpGmI@Z_[I&PZ!77C5<8i~[!q[[a__OUVCT}]oMSfWkk{*H@iWhu+AD;FA5$M?tcu$M"caX(NnTAMid6L,nS@83tvz?FV[T~4(PrdXf(P4q@M,jC74qQuLtD9hk(.4lqYcxy<!xX(b&FwD<5$f6Mu.,a_&f0I`<}GGGG66uj|}5n|sF6nJdLD2axDRs^LfhlOLwEV:"/z&xDpK^0.%EM:iJqSWngrsF"]^Lw46R/0Xz^nEg@2Xmr7a`+RywDaz9gR4KeEoGW(#DXY*<WPSlPH:ABzu%|K.B5xIT[99+GOBZ1L6w1D8!dB"Kbz%TJ;s2%ydOV22qmOMYiwIEICvHi"U@[e$G^8=WYeQw}E:F`y$yNb}XzBQ0`k">m/T@JvJ*~}OR@v@$jllG"XAY8fqVI$KoQAWiv4K`1+rNt?ibvD4.kE.L~prjK`[N$1qej}ic8/{0=;cxKp^#a|eUU?A1|z1W3G|c/IH{tZ(PQi0+c1O<=hGwo!7lQIhX/8/rTezIzqnZ3!H)$S?M`/uQqOqhfwy?{OXn>!_4Wrl>{uUr?EecH1F:R8d1])9D00[Lm3B$.)O66^[jVRDKEWE:uQKRB3${jRQDCyE:.gC3:Y9w{]QzxtOV5,ujBlx+3p6NawOyly}cN8GGBjkuD$TVwbq~/1xuU4"8/be8bH$b~t,g1O$S:/s2@@uVm$>ht5(,s`Ik$({!;1z3mYmt,g`2t8+Z(N_{L"B1,1BOW"cD|Y(B{t1toGRYsCV(rJHEDTxvPe~lvnyodL^>poxaM^58Up2<H[}n(bQdFyd$mN$n%V~.qKAZXs#{1#$=GL2W6qo&2hgwlIGNX}*2{]WzmwG:CoQ#WO_62Qb(>O6?O`SZ&Lid;9aXK*L]/K~urbosf6a^*M_>t&l5R~K@[yNR/w?vq+x7!qvi<Ylv/>+Od$<?h@qMM5j).ZiTVWr$?6Bp|8?3t,V>;9n.rD<1C(lTG)p0{!@OcL+bENdY}iJ68I.aNi:X/iGIO,62.Z(NOvSRYN|Gn6L4sTED"{v@3^;d=1W]p@kdGX[bX4;p{RMeH&S;?a;PwmQpa;[+42f.nQJi(9Hp$@M&6K{k]DbLVRzK>giS#Ri+BiG^Uz.Z)6{aDEIxzi%V<|&*y0Yv6#%i4NW<CZZEGDRh$ONz*383@)dM{%7^{@>M)!Nd0Oq,wYt^B_M6.81aDiQ:nKI6}F=];Uv]vo~t1G9s^+qV;;dU~iFTo?rDuT_6zc/j4qu8CU~F5M<l/M4i/l/l{iLJN:xULjVb:3rDDZ5v9Mn,tyjiTMw@V8b`Lj/lw@UPkVh:+%ucHh?q$u<j[Tr!Bs0{+=>MnlWiLJ)1mjw%azliCCb6wp*A[2yZ0v=w;,f):9u=&}}jn@.Wgt&VVK)8A%AKi,pmj%y$0JNk|TIs!@skTGYb6~MU!nI`"n~idSr}oqAkPVGIAAG>,xF+!KDj[fX?Yg,|sf>=RlH1gq+}M>O8&JQFDEjUQKIF04:(szkym7W0<Qyksml``j$nCtYJD%Q?V~]pMy]nbT#9GysRB+l.#L+y@rW[9{qGGTW4_*uNd2=kGv5g]ZPxyOVj5QcikJM!3px=iHitI<9fVsuRC+#fJIq}8iw.0mb$6JZt0qHor?E0Rw0z&Ox@0mEVTIZw7<v,6RqSe$`4zI^lqEJ&x.Qa}1+NUlo:tqETaza:vTp<xO2NH6Y0xLLb%S#Sb2Nb8*df?D"(o+}e@wfL.<6c~HPA[+Ko.kV!N9r+df"4ph}*V!73h`VT,DUMwFtcf/I~I9%kLV2P.l_9l~[}3eh,z^xkPmx;Bfcf$8Nos$)7bK9+qjnCe4bH+ASbc0ucOG}MZ>RHiYXNBBij,JZu$L%Sr::(nzTrMd#DX%?ESOr6Wzc4Ko.GcCCEBX4&|3[VrS4z0Y/2&tna?$]W${;dn[~S:2+<381`T"g>Ak*qKbpG[(W}ltn[nut19yzz,2?=kM:+!Z/2xcgrWnZ;3}|s*d?ZRM/)*yO6Lt_8PDU0gMX+jN&`di%dk^&dk^8Tc,?M`Q18Iqq`jG0s`d83_~6"796~7[Wk*{2vk<e|b.5s=Ul%00rtOiWGQB#(IIGI?s7"7=PW@an[PW1b^Nb+,+By]/;kkR4aw{ij=.?06S<0/Z/YS*oR00Ah+C&`Eml>B9[<Q|Ha?O!fw?pPmQsU1iwL0sRpaVe^`g$do9${?N5M"jteCT2kcX7U~1CZEq`*?o|!F*g><rg0!/U!5C2,sSQOJ<Cbiagf+P,EvrJgl33mP|"~K/7zgNvmi>S|@mb$R0PdG@nua45/nc$cRZ=YN0DeUuDli2:$jHpQgOiLuAn5;5r]LXm5[7TOQeFN0i(i{`;b/tIO[0Yw`H&4KIZAI72YN0N*[D=b"MJH#RJ0<OB/l2u!aCmIMlxR_pMnx^N(W3Ug}R5a#cJz9MRT}Tq&*`zG&,@eqEG@<,:u*le6gO)?Zf2ypW2sKN2ys*DUE46=rq%tuaB75<fRWrp^R2.#b_5bMbj}AkU#G&ewAHxmA|TQsQmd#iS!Y%asvoZET<Y,]CUx[4*!|%as]3`,OY_{1N51,Lj[^bTUYLH8X~7E.n;`_*KBS|`nEIM<ZS<xJCj$W"yR|834K4LOAFe_b+luoyN28~^{r5?hSjS(7C?KMh<J%Jkc@:n>L?`x"mmCxk]*}?Aopum;h_52?EB%!%nI93;b~nSn4qJDv}:^6|BKZ`;j4slOl@}zp3IEnk_hM~TweVv<K2/x&!}Twbiml3.0/xPmQ*8Mu=b5,RAk4stV83",aZG0<5++X_%7r`6=V<rLU`913<Ii=D6biJTQG@Ij%7R(fraa>dE)XK?+[fp$n6(W4L@V_oD:;i@7z,@u8bVw^)pjALJCt;f()8_;^uVs4*R*SUhdqoR0~Vz*N^RU87Od}<Du<rS#I"q!_bA+$I#U+Gyulz.2(tw/W8ELl0v|$yQSC+kx*F0i8Y+}Olt1b5HC8_W@KqwD.%l5UUhgCyqH@OgEE:W{7&NTe7JLZ+Ciq+&9R.DX_>_)>BqShW)WN~6"j38Fi|?L83$=aYy@8k/Y2ZSm/Y`wIa$GEH6KDXexpXX[B"<*?dUd~~mR!Y=L@C%P:ZNf/`>"@gtpFm&G8f;v2i?RaEOv1)aiNR0IaEOv1)aiTfjR,(SQ/R&YfOIN;Y?uuMx/^[wXF67mOJr>s+]6y){`Q2CEMqA`Ja!^)%v>ki/q7yGgi>$@BzJm/YCxTZvYC{#.PqP0L6!&f>A@:kgOFpm#R]zW~y9h[:{vDyd2.aHCW2[.^~/Y,mgODd)/%IkwU4;KUT[Mn=64LPn0zz{c_SSan=eWTUcuoP@U!Y,LJUxDqx*xgp+rqx%F^x^/zx)E|^Z`gM}.C.ChhMS@h$ku~jew!&UG6_3|_*hq`,,bh((v?;*^a~_D5{hS>it#mh$c:?q|~;Cmk&,G&v$I=iF*&hGmAj"h/QYaFLYaR{vil@}w2sK+R^kMX*(4=FXw`1?Cy?T&<CRwoIwzr"rupz!~^$TjP4LPszjYN4m5OCNK+{.6~ZH**q2iFi)gyGW2KGHtkwIX_r=}e&>g_5Y0Wap*bGfMqp&%iu:5XHaD"_KtFoq#O7ek.RW3kd8:OwI:),b*HP4O,gC5R6566+1KDw`.+U7+7|1rm:?;),j|4/^@@6I[jyG}m|UU4e^aC,RMAp(`LUZrf3;1k:SZQ`7UEb9gW^Yu*)f%wMMJEbqQ!;1Q;@TrjU8%E.9VG2eI+r64AD/^ou*ATiGC=i*kD86:mr2*!pH2W^0q!,;e=&Ny=9BW33grYXW#dnD8I$X8ueGwJ<02M^$y3t`"fU#9;18QOUHo]!H#2*2ScDM]HQm,N^$m5x2QZs;,!PX!UwhVd.m/;_7UJ;eWF/;~K=WI%m+;wHO#slV5X}KEZYj8*8/ab2*T49I=_,6<81d!F!ZRhqa27xEu0p_;}?RM_2]TLUAKub$p4#@PO!H@]Pq%!"bf`&9^Y>83)8/.`[QEcFJ3o,n[%!SFaT=?q.NNQSy~Y$kMi]VOgc59rV~%9Nc9I+I|Ey6z.6[{JPW~`jZAH3{MmU9#pq^[.,@#)+ud|UuSe}%(YyvkWG8kG_D`Sy2W>eBqBvL>`._wDfFnI_W){.vrFy^@"Tt|`,eC^>Q=7gAk=xASjg/icd&xf2/,q=Sapn`h1Mkl>^0s{Cp_:7:SmCIB^vo}sq_RNu}?IP;3[9052rA%3TP_)sP1SD]v!KQ|&E%A:b$AoQ{&;]h+A[Hps%;g5=gd!,w,o,eF&y!lOybQa^][rYvPW~QvvK*}A7F@,+f3lN.1S!Y]!q&%bR1VB2%HIq"G3CW9pqG6EMX>u9qov}e|}[s&a__D7B63E=n@53rIIq$)w^8PB)o<h?A(5<qph!Z>eD8mS!()x(Yywh#J;E5SEO;9ohe>qF:bRh]%o:K%*EarmiMZiPO^A&#Qqu"CA.{Tpfc>.7`wk*2#>{6&GH*&4iC<%y/&+ei`n:yr~Ad0)i.j9&<`sAIqt~<Cnfwp=_<j+h5C8>U`{m>qJlj8Hz;$jXO^vX/_I<)PrckB0sgMTu@7oHuprX>Laj$o0^mg:1YD(,mjMS;)$m!Zmk;f;inl9l;yYxq9IGYKEG#lFW&.W=s,_3|2>Zyi(pJ<(<8l9lyv6zWd%){1^$ziywVUdV{`K@?1Ex&5G(,X=94:]}?,zusP`Vlk~prH2q}IkEPtO"0wKdoTqp_!s>=,Ud2jsQ}^Lk;SN:T=?@*Q%VhoB!ejw6ZM(Pm,`^%.m3{.R3<)s#H!=@PnD@eiu^YT%LJ/8R4Z@lgVFmTUy1`]mEL@22f,.4rDmI<G6$dFKX{mNYV9s0KD";t/cZkj=gaPzRPdQC]<9s(DSMo2eD3w6.hDp,}q#}3a&PYavX}*}#@{n,Li9+k@R1&fgq}!!oan27$LhWe.VE^GHf?e"aMNT<:N(zJ0_8B#_}EmaTI,o{M4m|9{|!|VC=|8Tdjd3UM?q99!?}67TQHcdOmBc/xi+}aU4lECB>d>gO~ssOkb~49)d"h;zISsA4WkL#QX4<84D@rfal"%YE|!@O83xj8uIc"0{WE^_Cg5rm3su41|7xJ^+Dm5C0%u=4j+8P,^x6%w~W|yfl:^wpm!syA:Rj;X2JI?xOU`??/YSx&!clh76WnW[$FGE<fHczatuM`j|!XvyXF.hop6`i@*q!(1xp8t]Fq3aa>|4SRtjB6Rv#2BUq?rt2XBKv2i]{v>iD{aYb6tcM"nI*VBHOt!]V)4l@L|~G/oaB5Y*7i5rF`C1M;/L"ZVfY.,swJ:KpV(T*btOaPhwLY%RK18&T[eOZ5X<(mCclf,I$swytofQ:uIB(GVVR^`1NlCfAA<;XIB}?l_qy0LNN%FpW~_:ia@3/ol|PLjOLLje?!(7shErIPMG7LI_0xT@SdJXGAB8v0zzqJFo>)W?aec*x671=F]pEV]COfwe:@%vJ|]_,#CZq[Y^[{=VQPO&jeM${q$p<xPZmo7{Bu6X6q2TkQ3h%P;``0Ca=%g(9A<[mumxezcqS1%C>^SH5B&q5w]E4+GR>DdT@ZH*+&%t6IrD&_x|p>J[pGb.BFq>;b3OuA_V%U%R%[yH=h2kd`ZEN)yOx]6wZnOhfR0GfnyA:/(8Jdwf3NHyXBm7p|j,{UyL.LX,/bzyU]L(@#W~V$&")Wh6g}n0l}dzzUy6;4jj^?]v?gGn:POmrqx2%fOHv]m5D#V<KVG1+1,bQf~5zq%ha$%=].@,Y(z|!>luZm:fEjwn[Q0>c9V=rCT;10Id9twp%SUZse~/5+=_;R^L1V>~Nnywv;6GEHfuw:53qTR_r=JfsoI}wsw{3!:`oj25S;16J!1^MlPz)%Y^zg]8N7.7kOWZg;{y1=S42/5{mTkmI;uv+<.VC"fuPVlnyU+f6%/U^HPr.7b!1g<BJrjyY;R.,}o91oUtf,1(oXNzknNL6RQ1HwhZ:WV0jg];Tagms0v`k$&oC~q0`w%pNx*_O>[tl"k1>^`)=rLmq.)11<*whmMRDLb"~Vn~60$^Y,cV1_%i(3f[@~1?*rGE;x1ZKJP6)~*84>J0BI<~[GpRbt9}p)=:m:]@y0),"|r7?[FZxf8?m(IQLTe>ZG6%Z!,^!v+VdMPcY{^X{4KrK?NUHS_)w{/sH"tS)1qU+?;FMJU+6q6]r9rxE7/cq>dBW!9sFgoqUJkf6uSuU{+Clzz;,jdI6f2GWMW}1|V^zOa45DJdT<qjO3*Bfb(_k~plKFnX%!n)bK_ik|v}6@J|SCZ4qibk?y$$`6qc9L)v6eHH?r5=6cjj^fu//(S.N>6Rz4gCjXJb>Ss#~m]N=0m{bx|X=7oGk8Cy%u5"7;u4KxU6%c[u6u="a{o]IUHz]!*yC?`1E_@cK5=QM(~P,2Pp*)kEw!S9oq/)#Tulq2.BbpcU9`i,$/HQHVVd8F6gyfr:S6ygrA27o*^RFJ?N=whW2;J~2%78)?:sHPY,goadA4P0mt!mv"Xn8G!J_BX_c|:Upd3jlLr@wftaiZlfGS"`7XGfqC"Y2,1[/@JxU:[HsgO^Tq/hYVOg5ZNIPQn.iSNmFga$cj%;<z$gTic@{6Ip3l2]TFA!)~Yp,B>lTNXO7l`![TQZK]*iM8=~%MwTJ[@If_^)##;O1VJ<L"g:I3xiIpmWM$<7./eVUXXpDKy:.A)!o`&~rPEW22vBtSb)/vO`YIZTa*zho5=BuZjAEJpZz}==>>y6Ll4>y<jg>8S<`l0A4~VoUe*0xz,8g[|B?ldHSDd;pJp`LsC|A,$4!B!5i;pJpQX)C~qiT^Yo,.x}{=)bJLb;)>gz%@/d6k^6pb"1tr0"^h^GhV=xX+>ag66"7_n}iDQY+%vga"Dwws7jvbgZ[)PxaAD{UMtLoSMuCgAMA>Ald0DT3IG{WY@m%$y7i?Z`Dcix4Rj4QIupL%&QIo96C>=:2XJlwJ6UM5FHKy<Y(P_I<iey$ko#7%7lP`[@)G<47*/g0kk<Kzn/x.o_$bC010zEBcC_eK;YwrhL8fxj*f7}2sRs8_(6u;M7UtMgo7GOUqIW|o@dx1_8b%Z=rpx7v;6{)kif_[,{$|:)+:]>[ZL:wD]Jk))I)UX>(uRuFgdP0{:PO?Goz]}|{e3vzDz8bOC8b%Zbp#Zb1y2<i88IU_^oJ2]ec2ZVXaq=)1r4&&Gsz}#BxE[HA9_6A.IdXnGpqBOTvR0G!&q"9|j^Cu)KhboWMq6,m,n0,&y6jSC(ywh*t5zUc_C<]vZa9b?FnsB$7vO8H{Qmz`i$G_%Z@sKDo?p;NNVeu^J|H90+NYY0{Y&1uH%,e(8pZk9rUd%RK=)H?L(#x!^i:3,q=6u5L16=ys:uC=DIMti!?</f|lbL~4d!$Lo|]09:hBSpJ0u`*AAN/X!$SD"LA(uIAbpQ7XDYX$6HHG%s6U,YTOoz`+$w}cVk91Ww@6Ax*QR8&{Ye@Cy*1*E0}y4~InR9YaX?~fG%~NoqkZ{9&pDvjZNfMa,QRN#WPHWVU$m/Ig]^3PLGOBOak;WiB++xg<0Ec=Bf4BD3rqqY4m!aejdIR1vL<8(.mE4(PPwjC7jlZS^h&uj44$dhI#O_f|:.ThI8n@7%Wyg29,N99r)/_e<mZlEvo8zNzU3THH2cD;Z1+dcnZOz.%Z9qz7!Z9PM7U&N$7A;E^J%dDl@267dd?_a!5/g4O$7_2i*Qd3aeYJKjL5u4L+r~t@M~&z.JE!^.Si(3g{4;Q+hCV87w/no,)_&$@?TFm09*tttWjE#RN=FQqTa){A|Xq+d(p.:>1e<tDZJC*kHD[jAmzeF30NN<mA8hA8>D@?i+On,%66MOfJo&GKM)%,X<KkAi8cowk~QVjA7QWiGPIE!63}@<bi(Hl4IRDy8<0h`C#/WH^pQ<KD^oQ=B|V2.$I>?`.vbE1n2GJwB]C;i)(Cl]14OzO(OzWOayHvY_liO!9vYQ0=7GrQLzj#YgrZbB@:kY`f~`(Sa1f3*F1Apez6snyC"Eh|.cU}B=@Wz2jZ&mq>Q2T<Sfc95qp1>Z^_:HsZ<{3tBXL*F]<244=93;n%h"8rD.pad.e%x&tBJ]`Nw@g99kr/Ln]i==;g6e^V<UfUk(rAkXmz__`BgL$VGb_$[eh[i~`+n&[&)%g,^=S@:z?DwAA*v$?oDC*neii2zsd#q~!9pn6biKc%2:/(%HAW2h|HED/2=9v~pR(frZn{xb54fN=tjCCtzVk~t=!?SqaQ!7Vj3l{dk;q%}xMFw6?<1k1`T5VS?9&4saH}*s!{3e]B=J?:n?D,IY<5=vz@?VjKKH,CRl=IFY@cV&NSJmd(n"lc+ii}$_)umMf$c.*p7>iMl[5k49WI^/.EEf`Tkbv.+K/AEE{O(IfbtJ%DqB9P>ik5,YrEFgXf&{1<]_ac=vzgrmr67$L^$cRWrw[xrm{~@C,*R!dg0E{DqW.9ChqyT!b8%7_nQ9ep>>{fr8os62(Z6FomFw6X:D!:?jjnfApS^`po=9&|%a%Ogf(6=3hOLAc_pGfPRV>s5ir1oidh7dqCf:r~`dk%}"B[+lr!z&!6~Er6{Er<@R]#2I?)K^4~%x*H6a<l_2Q3TG`eN&7*{:OmVgOpgwh(!wq$c<;s2g]Yxkmz939EFAJ{s5X&=rLxtH>qi}C/Ss/29CCiv/l{<Je]k;<ZSmd]@#{{qF^!VhQ~em$gPDr#YPECc(sR%5i3li#glo{_,7t)+Q[aoF#ngBVx%B$g%;<(<?{zho9;!m(,S)XRP2`ZexdoWcF5C`CJUh<yfHdJs6f~8Tsj8r&8/t{y/zm$9cT@Tn#S7sl*6KJXFS%"f6s:XL)=Dt|ML)qfE=qR_9^t99xrqtW3y;;@%|Yu^&)*^o!MQLS4RIXS(95:/G#j:2m2SrJ56[()xS(*^u`!,WS[?;E7zO*6*E2s.t.;b,un%1YQ4(k~9A,w}XY@3:}+sAJIX4R{l"n!;;COO#UAiWyz!J+vK/Kr3,58Wua)jBr@1wFdSuPQyvu.(E;1x.9Sr}nuBj@n@ItRpRtW+<*},0jGh;:b45ipv`iPs]c3{;I@XZ.%jE|np&%(hN!$;JEj5<Zm:M[D5e,|[dwlrX1/0w*65?o(iJw>XaPuyb?`wl=}G<g|OK~*[j>|pX1&JSG([An7P4ChOuU+XX$LQ{%}NB:k:g*:eGydO`@?ma*q$,MLne#5lNRIcB#]tR<+=N^(|?0gv=?e{dk0IlD`:=03CLR.*RA8XL<;6LU0~p0,C{,WuCchf;IZy{_WpNCD2jqpQ<1<e5TdiezGfkRP7zs{**1cd/}WG6a,(e}12PsE^HRaD|94lBjQ8^/qU4<<j8p$nJSziU#2z82SC!3mEbh[HvlybTYM>h(bTlEiO??OzWx<`:I!_0ZTlu#[Zun91]/*,"wZkdsp.,bnQrIHh[ksp(;@<;lj*]/[zH15u~i#Mz$??fgVUX&u1,YLfi!l`bh<2bJ`1i="w^zP9^{Im~^JTn1A[}u|IR]N7MLqXDA^NJ`M%So*xAOp!te3O79i&W:aFho$}tkq)2cU@fxoplua;1W0}84cB+_R^QM~MzLCU.TiS6,+%+_v8vl{SWu[?X3In&*B@{1;JDE39x$BtDAzL"$AR2P[fDzX1tCx,In~@i??J[/85Ma(EyejY[X=$GUkE]#MA{[O!:WJ9#*hX;?i8EY^$PX{nljMQ(pMQKk0e|``^ai]I;C#2=*{XXk=@j!Fr2PSnH+tUy1T;Zk#lLXR%AUke;fY3P#s)i=@O{,ArXcBr,dP1pCac{PR%qCj{".Yg|n1n*:}gd^0z^YvW|GG5V`%/(4Vl5xo=TSqBJnU#W8nQ+~4MJeOW6@]Iw^GsCk?=VrS?]azpBZJZw(/IPUiSn1;UL2XV/e&TiS,LtgUuLB9C17lip:ugC%rif6dFMaBo|)nxApAi0em<cQ2P1ny7Pnp0"BH6IkL^vB%e}oiQqTJXm%KakUC#}iu`6.?x+F/m1f0_QU_PR%X?)*toR:y%al(d#1:vqdnR9O4Jq|uYJj1r*iSlr(j![R!jaNgT>x,y[hSO34h&CmpowjGt$Bakj{"e{Ib8oHmufbp`7#WMuv=w9hyuARO"`E"wZkZgu&ffvx.*jo~gQ:Ar{Zq,`ws;_VGn[@SUbQ{3"lXIrqbQ38Kkt(O1RWMVl}v_<bd>uEzL[fB)j!n`Hdf>9,o`7$Cu*i*@P6=#j`B?q&`F5#*@,+2glZ%7+rtms{yXq:lfJv<Zhb3Y$mu*[z]0|@`nt|6h)6=IJ9zZ_MusX,Zicis,J0^Sx)V`t1v&0]a=w$f&2ycR~!}i{XjNQXA)+eo~Jw>rqJbQ)#FfdM_!lF|ta@OO|_qbPdVEwR0Iquujo&Hg#psp46KrR_>3f_93Zy:yh?Ws=h)2]}f%v=J_*<.)g{.S*q$A7^_Iaelvj.im59%L=I+wMzPuiWNs|d8IFm5p,+R.URk*0+CMUNH9Jg50g[tFS?qu=y.=]NcRZukd+wKiXkRGt?VV*n~V+U.y7x{n<xUpjRp5b[C+_|;,@34={d5?FU"KzLK5/JVw3xmTxoqO(50<LTnYMT*[}.E]y%!w/<LPSM8@S1,%km|@~;i&W[Z5dOkbyn460!2#*I8ODjM~_2#&s$[Tj)bhECfV)|%^|{J+1<YyleTs&U=sc=k:d0^@A^!Vw;>3Jc46XXc^NU(uo#8Vmt;f8%Dh+W]ei(,Lj728td&%[rd/2vH2FJ*b`:+|#iX*UlB:A}ryzyhxPX+*h;FnJ8E>09nPV1=CPu,w<;SZp9MF%55$qRqkk*_Me/!~KBGcG7@%*y;X!?HoDs&mbi^S51>Di0_ers<.?o,wgPG/dd&:QBC,N4q,#BBa:Gy{mh{&6Q:)y?_]W)K0]!z)e}`jogn8c(,1O|wpb(#~81]=?r!`PW9_u.r||I+!/XF4>d{rSoY~wbBkB`at~R(+?R)+Ufm/%f|NMW?!^bYO5)Xw_II>J6|vLif@L@`axbAri&i}n,cz^6VG:Y=L3i;r+rT`Z.;y|9`kvj=:%Vp[E3EtOs&@)O"xqS/iRvL@!P[{Y_nEaX.WT*A"jQqMd]$1gfB:(#u#VmAc20^K&bft+8Ir9EaWnf+IuyTP8ES5`QT!;&}w"Si083q6<AEyn)8KDf6a<dFJX!ty4i`KUBLwPk5F2gtb},M<O<6=w8m7*HxZ9+/IUt?VdZ38">~vNc$AqLN"t*9H3)hM!4~FCA(]jsLP8ueA[93L6yB?R}SNAEtt2qVj]K6yRfq?bL1E]CKt0A_kep&5]CSetM`tCA?Pys?v.WyJ[`7ydZZWkCgI}+riNBCw0:W!S})|Z*kp<Hcg<gSN>Cr#Jnv__6&Pysgw/Yefy7Ctt*9HZG"tfGB*VAp;O/,,wIftIih|Btdp|Xqi$I=tr4FJ95KBcEAuHYRd7H7Bu+O;c&<@<yPGN7i!0:O8c;$(DtuW:C1PkU6yRf2(aJLBkt^`{edZ(Y>G@4;T8yQkN"Nhi$e_w*zFy41kNJaC0AhA~wgPcA|h5R1BGtDA(]Bt"LAR[tP0dZSX;c6xBu#}$dmx8P#j4D_WuMl4biPiX,7_&g$w{aNEXjBOCcM!^NCKxIZMh,E5QXa!yQVfNzqkg<GCXPZJ&ux%D:km86[!CyEd2dfh)ouN${I2Z:ajiVTe%P%qZG5N61.%fr}b}e=bQcP*~M1U2Kh;qfx#ny#~ldWHg1ww}6gTM=7SuK/xv*uOUld2Kk:Y{l2/}/.gb1({qo,nzweI;u9V[I;S(/Z!(:=%g;Ye6FyG8P,nD9n06!m05RrC&{!OL6lm"ac656`[~/QbX3~{VhfwKvbp{_jXGljy;m:9V`d1,MGre~j`]IFv>Rnp?}r%=Nsf"!(.%j`+=!(;J0+*Zs3Cc=u=mq}Zv)*x1t/y}P3F6^$P`:XcYYSzpjF4y])laDNanR&*Pp!<<3swWt{k";(i)*NwZc,)YBt#9EZv(czyxGf3*#Cve!.,Si:|=/;?HX|2j&q5<i:([q5~8}r!tFA3D>tmK{_mWS4`YgiiD@8jD`B?u|Dwk(D2Z>BC<bKJE4mZMng$~?I)i=}GAoF?t7YU]xpCCEByVq<,@W6rar&TRV4oAUWui)kiu|!<TvC,N,*6<B]|"uB+>rBTAKfb,BZWxl^KtCD+#$|?3t$5S(!DI+.,"FD/p~qo@lv}oxs*xptQhn4q#[<3mdPyCsMm[o(@z=s#)/:%B>uG4Z&R+501vo$%oOb|@6[D?63Z457h>dpQ/{V;>KqT_n+dR3o^hd5Lx*{mMq$p~imXo=igmOw9j@ATXdE]f5qj_=CvX4t}Xt_<_sMTrfClQb{}~nX#jR}sT4(&*W99tg0(k>q!<}S>,xA=5t1~2sba>%N9Ypd(H6v#5IW|zgsdnfA`6_}?==YgqiSn6;G4q@I^f!,#Su&JIQ"Tug_l_kP~k>73kKXQUe"]V_83Os9Fq>*^&pg,2h`m^;=Qd(}]0TikbP:TM2kh)oB2D&"7#YB[+t?E~DkS>x%SKj@c2Op7VMP6uoKmAG>tyt(?!m=wjtkx;oB+3>`!O@=$Fng$m`I5t]NK5&!J"nXu|?~N@Wj_t]A%_TA@j3$(>J|"]xE[r!DoAw:(lUj[r3=E+EDbLp83g~)oF@poG@4J/&wdP~*JL4Sxb^Q*B._=M*ds=;_YWkv1ML&XG@`CRG:^%U2}s:QPn:*U+n|xrtF.qFE`^3;,qCJc~_,yWV6b+&~_Gczz(xSY=H]ZRvCS*aAAKUBA[h?Lq*XxtIYVrtILFAKA>HPh8Z[Hi+:ymR~XAAAAAAAA>ClBM<v#G#`iMEB`;c^ZtaAh$VW=jv+Z[?{w_|>|Tdxnw.*_c.ev,ZCW~tr`{.z$(%p^A%M.bY:18m,Smf$]omw(iB;A[;vS8Q|1~P>>g1l9CpU{TWcU(l4wW!;/oe0V~]8t,%Lk<{<[XI|<4i/Iy/H(X3O*2wCAy!sYDktN,}5H6=9vf0/{l[%?i2mx7BBrm_]J{(/#AT~itX;O`dM;,!LNtm+@gEjO!^;9qwRF<#/4+XDZW*dP3Mb{$y`(7eH#Z3|{[?TH/KwwCH"dCFFrTzn1{`@]rX]AVIkmexx&{GU_.B.Z3kv$YyGs]_7yLWPb*yj)Ab1n~6NtCiTTi%Gq5|8.~@4RT:,9W3JO):Htu*i=7}S:Oh;7Eo;2+mF`3y96!dT=/vt$F+({0I<oyvrO`idxp=xg*l=_ER2kf$(/P>TwFvg_@6YC(Ea8*.EfeELxPFzqTl*#=aJssEm.vx/lJ)0hd*{~>*gw<f8Q<uf9N$Y8j7)>~$lacPzEFd9e[plS26ld1H)jJHp_G8DNb{5_6;&,L17e8X6oq+:;Pt10}~#/TfO)83Nj]@4oi6!g%6YHdZq]V#z?MW/)dh$RrjX`&ZTDx6gk]txdt:gPc)qF~5zzSP[y+0DZ8C,mxi_v3$,#I:2;"?"N$AGD#N<F|O)@EeU/G=~ml%}T@&ZNtWn%3nB.OVgxibG"Z}L923+o}JwP)afygMFc8>Zbt!]5~EoUk?W95>*Pn7"15l2[wr7JtijcMq:ll7=a9T5WGk=wuNB#R&k>^m]l9Ykur[hJRVYXMzng7]G6bh=0N_p5)h4hI[>iJsCuE[yu%C,bTvy.EKThDb{aY_kfG)jmu.AI:SR|,Fn`LsDogu0h{kZao)[3+[F=Y%bJlQ=/XpM=823V4.X^u"h@@|35mwSPi}Kcxc?^"NRztva^/MAv={B.7D1RT^qkxI<CP%u.@I$o,)Au8(EV$Tx!EWR7#J05[jOOLX!P$F@Oa/c/Qe]OBSA<*M.B>fi,Nq`80rJQMDchru_?0n4t(>p{ImrXeu*g?=Halb+;C)=4o<JQf]&p8UDkJ^6otJAbFeh>KUUd*H?:aJ2XNBm^ATb69b9QHx^b>SD"=!y/;{_o}Dk6V:o0"T6[lr2;%ELB?l$p9RB~~w|~G;:PHq((BTmxIazT%ZrD#"yKUmlvx+1~9uXKk]%!#1)h+OdKw=]QDKSOlM`M+G&1O1l{RB0>P4THGa!U~r}Qj]e9/T[%v=81D)}mxJ6g7j!u)vjjJal%_*LaPyUk%|Z9A`q[K(MzHk;72Y)ap2PQ[E(QaqO<:zI3!_[qLB}7Mqo`b=iQ<xB,agmw<P?pKBdsKmvXo|n"x)c6[iX8}|>p2^@DDH:+=?)/GY1|;!?/!J?o0w>BGt%.&i%]WpjAA7w)$%03!}QPxrUVR:LrapMNJB:[JCt(u:?v&@"WHt3)u~9%qp)hN%_sHp0JT_:z4<G/hl&S55:x8R_o%j_Ci?G^_jUkoHKFQ:2JEV)qg.R@qNN105t4+ysQbJIUHa=.JuriO[*S#~x@b1isC#wyo}zKuSOvhCcl0ZCqZ|e#8?Ac?PF}/E`&caouZo4ClqTo)&2R[2(Sm9<!4+oX2p<DX<lS=Jy2x:ZsSy?BF4AD%By]6k@DwIaBb@(sc?|skYo8*`YjM&#xQ=axsHvrV#e,0ZA@LiB2X#E<F;i?#:%NzEF.eeX@_N2JEFq<n(0xg?1)2+@VD3,NbFlXeWSJOOE?}T9wv/0+>yjWjZD^aL^QR5PYYNoGgm@}B&|d=daHf2;>CVK}QiXH/#H<!l(,Q2dm%{Sd!vBPs*B2elejS0RI)tb=Iu[n<nxS7.VgPKei&=57(tU9u7hiD}553ts<}>G2w&?W~k"Hf1^B<Ei"9DfZ})`a//O5i%{@zqeYhYdXV6~XqkQQY9^%[?.ebTezsrLQTKG*]ZRw.Db4K67Nz6DIIt6/Ct]H1i@Q0j1wu.hPw;9ex(dcu+LPJBzQ,>2iNOlBu/3FyPFdcGuBDVq;.<]@E5V2s]|FSYJlVFBB[4emuk+U@4=d|4q]tzPrr#/nU*}vN25$L)._BjHt{g%kr`Kgad%4v0d*ge)8U0"d>SZKSHnNRI+3=+ftKp"V0Pg>ekz"o1hkny]#U:cxDGE_*Go!><3Lk9rl4;%+sf00BpEd"yG"=<n|Rhpn]!NjNc;o0$&o_:p$*f?PwV$!x@d$QysV]^CnT8#bVl[1he~e$9]yleb?T9$JA6pU(+`I/q8C:0n^;#M;&}#bir?Fs31:xRlmsECwWFnl[GPg*/qs+b5H{v<6=}mR/EDs5rb?Dx6}>{7!l)11?Xdx]zLZoYd``+]]ctZem6nenraQK*Y4sEYF77?K*s)U#6|J9r,"<&JQ,F!$EK3B98@(%p,?.s*_|DkhU(:#/1j`2b:0_De:q/2}Lj`S=UmWqlSHJQUFi)$|NOiO*}(H!1PgfjuLxjHn,2/2$_&O{B=S@B."wJThOj%k%gd=d_tS"=!SpxN5HOEBi}9Z8(n1~W}3xN}0RX^a3DbgNng/7l#K!~|{~F_47UI@r!1Zh_eshpmpR/zv!cJVnmhG<u|BHk$N@a%h>~c0E&^z*N/x{nvmb|R}X(MtVQ1x*ro5=M|_]p@LK9"|6&mntQ@T{PIkw*r>>{9p<>@W3{S!<^7fKA3ow+]5c]ma.8:ss#G~NLMI.M>Pj/`C?T${3uJ)zN"D%>;kQZ,RZq[:=NPp/nfg8P1z1,SS":Jk@B+tlvWC1D:P>Z`!EX5JJ*3)*Nla#S(I7!)7qS>H/AS2lk+tJ8Q7E9rGa/]0TjavHUpMi/^)#mF3JXN_s*/;!LHJqR!E5#orNqUsa#T&nVOGDm=!zdGQ!Yp/jNqPj5](3SXs<Lt.BDQ"~m&iHxWJZsv9:3bVUg{BSZn6:_+2~wk]#G_^F@|HBXL5SoRmVy~>2l^Dir[n3.`{}r2VQFEA$D6_/gxqs8NT<0|)#863,r7)8(&$g{X(2fK!.$0i/bB~`@=a&*FG28JLHtqg.1:XM$+:P0bQzp.ZXa5glhCPE|}DxNZ_J`,Yd&vwbkVm$az%eY%*)S{(8u.^7vKEu%|Jv3/eHZOCSjWx9Q<IRMk|S~SvufOJqhjm%Qnu"Sf<YBz7stF%>;bQQsM1DvuR~5%5cRx`YK,>CX|mQQ^$Q/RW#p)giMQjXto>bP~<.B6b>dP0m6dJ])d(Sf.4o2E^pmMyE2AkV[/kP<vp_`{mR}c7*#N3c3msE7Vco^Kj`Rr%tbBWa8xj}&r/?Hj!;t(bmPWb&WVpapQC>u7|q)f]188XisV^Fu*gSVX!,OvEJv){Fi`9wV#)ozr154lmy>v[t++(To,S>s&"{aDz]?EuiJlx5LxG{0{rI=|NvN0<iUUXW"o2gI7k.TLwy!ahWC6Ktge_k6B3[3tYoM(YusL&AjNk~wK+1;inB91/g`Ap{8N422:f6jLTHgd<;+ILdZ4EUeR5>#^)F=L|o)c]gCcj}D[b.[8L})xv{mK]W*M&~F?B|w.^09|wQG.2+De~Ul7|,?3a/zVU6jXaHg:ke</v]B&dKe[/KG~9c:`(FLc0Jrh7nV_[Ysk4!3?[&.@^9TF!p1sYNdFGqL5*0n,FY0}C^$+mycL&m*s"hD*q0:j!@>d,:fNZO]lq.#87j7@+DP*x[F;gIvlu:gaZ}U+B0*qrNB!Z!+>j&:}L1|Ke*nV816FuP$^/5bw2;E*IqEW;XBD}Gt01o)gly&.mojE[U054RJ^M:Qcd7QAYP(GOqcMj9cgA;Z{hv,qy*UHoJZxD*P1QtTP7hCYv]_r&s74qO@A2pD/n>8N1&HPz/w;f?s.LQ>nQgmZh)t26Yp"mhhz;@HkV7sNQ{ExSi"zkkLsV<{yc3k{C;ZTp))4_Yl"N<mAobhoWK?!JnzxQ_8x:8qYu<!EXpxQ0zaN3pyJSh{Du"DwC8tQlD70|<Ds1&l4OsI;H7HUY)]QOuXt<|ouEUq^sBSHi`C5W]BZyr6),!.F7i&cuMKwR1&~`L!4+9Et[i8ym||{ogXd=BR*Jy("oxUv+Q1IP&_M=4GTM6@9tFrIy#Y3/HXlHV@GGY|D*m)4MH1]7ov*uU~ei.%il*G^O&bd~"OW{gH:}f%I{}(Lw7&jD7Ill7^7{8E+TPBNfrE}0>JnzSV<c1c^W>$z#yCxrX,M~f5Z68YBFuu70|bl0n;dFB3wtVYlXW4t[=:r=ENJZ(e)325UNk*jsWQSWK>"L7W&nQ6nA);bu~$:mc|7vZzt$ZD#WAo?0U!w]$NrB^f$+eMyJ?p5=|cb&AO4AmN|E/+}jt?1pa|"#)Vec,x;5)[p),kD0VBLCK_P_^s!QD3y^G(VGv!+B}Jz93#,htgtO,7u%P):Y+@EW)i/)wJHui@<u6erfsFI46|qSwiXSbr"v.?gz,MEz`YEBS#U_&%z2&`<}3=1j`h:]12=""]e|i{J6K|Zg{,@`.w1;"p:E@{sR6O$L(zq22O2|@`oQm$!i*@~j}#/a.&o.j8v*/D$aHA}ZI*L|Oha18(wn)k/+v9(8zst|*gOcFy/NUK&k1{^y6W&z_`q*3<n7,qIawTRcY("LC8lM;Uwm#12dW1OTdN>6Gs(,0{MROm*2aC1;`AP/~Fe4y9hiRXZ:&NgK}|Z!y:%VP|5F]TTkE8r]et#0DBP4lbCXJ>(12qm(SH/+(@[L/EUT$+Uw=on?A@ukPTGX*J^;jL7cWjFTLnn=XgN0/uW2_XPwc=qZ<]0L3q4c8o&M_W7Z(MzP!(%)coqnlK>LsX<2BYbrh(P6kGw*h5E{Z(rW.CuKPHg[U8o=XH,@1zTLP,%@L)$.}c$n#*;rS5N5e|LMLKs>H%?CJDle//gzjhwnhWmKYY9l;#*TQfK&zIImZ3jxYVLawE6INwR^wiP9_T%NuL@nrsV}07!&IC:ZM[8:C*DH3sMu[.EpTW@(&]L]M&jHiNgM>x:%?Ep9gqi^<%l_c<Vl(8(D?)PQATpF3:J:GEHz*"4.xQQU//fSP![`J,O!qY;(/ka/<>;"*UAwNNjIL:_F|X$*CR)shG.9Se71B`ieDSCNbImS[.8UG)&<C.U;}QzpPdG1f:5+7ye@<m#Y)V^tH.D71I!gPA%q%N1;n6VaTy[8EtC>8;#n_<yOxr!L&?uF.Y>GVUCAd<j(NogEeSlMfd#iawQU=0eDP*aY1gwG/VW0xSo+|;<ikGDTnX.p>%4,0P(x&O=W3kjZX7FG$bAW8K078zm2]`t7b{nL_J7T]J.+<YB#^7*hIRbNKA7?+,!n)8q/l%V{>?|*}w2<nXw>JZ<*|dy29~h,VQF(dO2[|tozjK?c</HM@uDYQg]?Bdl^8E~</YwfP[<e}Cw>])zUIpuKSeA1GA277>SHw[L$"^LRZRRdJACmTEpx2.h#*Y],N6_|8o&c`JIgs_)(1v&S`=kas+0~x2iPhtn[VMWa^ROo{I"88FIM%^[!20eP20_.zXjeTSe~TcD]LY]:IwAdt0>gf!8?#+)Jg27O9IKbgOK>}kqG_Vub)FQ~e]#q&|l#DRDCNsT!ufdRFdRlJ:x;+_">^$"zY7KP9o}Nk;u@LVAiU=G5,}do/qt73Q=TYO}CRR/a@:o6;4e_.d}8$}<VYQG^m^xb,][P/1<c@SE]FP,uI+G3&/jt0etHHDwv*@}DZ/9DMzjGbO{bgRhm^1mL~Zi7jH#VN$.,7!B]aj:SE2(]N1AXheU5:x+i/EXlr59(:MF,|T=tu|$}i:C&8L>s`wy+VMZ/:w{TEtZ86Do[V0os?f&$wO+Jar:Ipd_<G=P.lHxj?[3oe(BzOYzQS8;|<w`nDc&k<=#%Gc>90#1V5FyWY/l+7!wG=d9m[KA1URW5Dx=vO#&.h9%x&paf6g8FY|d=f_4NKncE3#lXdE{Xv05XcWR=yNs|u08VeJc{`GbFKV9WU.,X[xv5)at:Mhl39GUk1r>guN85u_:,_FW+Tos,DHF+`gu7OApw9upJr6PF$m+:}6?t_ILW0E!Lg%2CeXS18tE~49".<(lu5XBF%AwYRU47}DcqZfAeL:N`Kc5:nik0jEfZA0!s/(]dmYCMAgQbQ]ZP/hdQiKG/?]Z{Y,R@;Ml;oXNib6c2@FJ+S>{0G]=D&hYPGb9Sl^aRX~c6MCu+PTj&]Z}7kr1vHwiu@sXwNp3HQlqY*#(H|/Gf(W^1ch3s4AhcuWM^LCJH+H9S;Q6<9D^o5QOyPjqtwS@/4thYVtq@RyM?Tn[Q|W)&XOHWe^^F5qI3ao}jL#L;gQBJBYJ}cJ[12!zM|$Rd?]Y+z+c3K6|5X:T?RX`4,>fuf.1;jh,+n!Pmv,!R*>9zWpo3r/28k8j.w8wN~`43dL4E6PbSL}b?a~JQ?Yt;}1xD^lf+`37R(KE|Zzb&Sz@ZcFl^<c;Q1XXt:V7Qw}QqvzK.L2FX/!BL>69JE+a/`=}S_S+B$IFFp$Vn~OG7iE]GIi],16Fvd$_K=L!X#Zoiibt8@/.ai%n>oiofgvc8;TY)F)cX*&^i7v^%=Y`B~M?W+dZ+wt|K*;Tp>D1LY#eOrfW5K%)2;f+LBm9S;c7cHL?YlaF!rKxtN|Mn%%`yZBG*h,Vw`bZ.5|!@6ZvN~*Vr4s9jD98i@r=x)[/(uDNZG1z9}h3Hz*O1d;_vM)7Cwp0K5^Glt|O<pRXKTQ7s15ZzL6iP8mmURv|wDI&JET=oT|TnfA~%X4?ul=t1/`w[RTLbpK;l8yFNfo&SJ443bjB,Cv!}dhWHPe|uN@&YsN#b][8g.#bVv@I*Y6Vss%O*J3rhx:EzJcuuS#mNk3r,utNVyeMvdS?!^jZ^C/F^.g"kUSmx}?,z)CQw_j^YU/kb3Z.k7p`0"m_$,A)urrGzL?^rWhFHgR2@`HO=^$0V]]t;vB+uV,D:EPs(X#M02nw+sR.w`?R{`P#XymQ5K2farrPSw"]"]EOl5l5QEx}.:R_^)R=.+[g0;`~DCIG#|a(Vz+G=IOI)sDQg/`:5P=$5;;bMxR64x7";gI_*NqU>:M2RqxHucnY}tcN|7cJp]*SPIv2zFU!HzquVAI=W&U).FrVwXZAs71Ko_@s_ng1RVX(_H)BvV{.7$/;l)8~ewS>S5jJ4sKaLsdAe(irXk2m[FNACm0bU`V:aI${`bC&]?}03qaU&YHHJd/cqc|?%b.,PudFX=RGb|T2gY%8hn=wTj%)tWOD0p(2w`>82ue]$`.ooSI2m{/f8dkliMMix(E@vko<N+*n68i(N$v~n{k/Kx)5r$i!5QlQ(d)RkU>qK*Rm[omgc@V_mh1z$}wpdxy{u]^~[HGwV8iR<5F0Km0iI5#2Gmyh8qCmE0Y8Rmo#FVpTy`[dT#(cq{x}b04wqD&zDpoH:YXrK7suL"5.r^!!$PHxws_Hh~kv*&&%chm7_Yr;:WNEQy=9~,A?fU!M6!/pI$H=5JptsfdCqjl_Um,Rasw^>El_k}I=je)j8Q=Qf`,F?w7S7f0S72l6w{tVjAOV/R?Tg0j=I}G$omzl*.hVp:?/!W?H3y(u("v9v5f8{s/g+Ran4j%!yKp7Y|7H~k8Q/aH$6.do@tYc(0`xH2V|uefyjsnD>qpXZG>zw_R4i((5)0+&$MHr22w*1Qfp+<:Efleqtv?%pAl><@O84bk7upZ1t[n!whKPv!ANGr%&PHF@Q9pc@"skqQ?{Zk;e{81_kKK3rU4*:*_GCv!Xip?Bd?kDDfPozNC6*:m$hZ!736KHS#*5J@p_?Gq{$;Pb4C?;l;Tv8fw|_*wbpYO8SvLy$`&_%;,JN78rO[w{~A!}kz.J:<{"$~_[nW;2G&<^@l~#WfMlj_Ax0E])EMMtYRh<Ny&d`Fl:*[vk6ilhld|*^7IX*~#hX5`yvjKo3S~JL<.R:R2c]bX%n%D<$!e.BwtMqaW"*5i=uBIN;vq0p8i9LCJAfYa$PjZ{"%TS`U7t!oi+Rd98,_|9ijGOzu(4Lb+Nm?];YqnEd?Fp~r~Q0jC:_UQ]mN/K#BuIe:r]Zkw~oNuk|,?ipn`ojG**nCzpD]WtzIc/4<$5@(9n%,Vi?IX%jAZ.gPe=Q][aK!=[Oa;q;.PG35f5"6~:Vk)n;8M<y3())Px7+x~QwyM%B]Lhp<@K`,t^i#Cd5>%Vs}rK3z2PL"$lID&=6MYR1TX6_YD/`yI@U?;>!]_J/%H/I1xDi|S).iRj1Li?!sjhI=c#{Z;P|[DXQ~TYLQ#M1bGA%Z;:K:L@Re^g5Q;`o3n#Yr&2z]Ek,!#6".].=&PtZTmJ1q6}HbfXI1.qq~E{8D):SnZ~[6a@n28uuRY[<skLmW!^}BcC%wXS<.7]d`5|t_L@gl[?u"d&Z|[yIDdyS/gKlws7K|}sUw7/Fh[3sm$C`nV7X!*""kTjA})7GW0@S]F.+dEMyS1HqcgI"qhze}>7[6pe*pF@j_e/AC7IJpSULHL3y7Vfv%ON3Uz}heZ?ve/~7et6=h2r~}(z!h?eN0V)"6PWPyGd]DWb,c_766L[n^o6,kiNnv^;WzK"VGq&n!N*2e3#wLfM^B"_]h1np#eB)oB8s!1@Puv6/gY2F%Ir3F#x`CBYa"f~7b>H26c3|$nb./JvVkWeEGLd9%>XX>,P_nH!Nd|IYNf),Bk(x~bd:8tkSm`OUCdhFXR,bUOa4Y{4p3*d}G)[6oL.jT+{CMrBaEaV2x3>%+S7PmI+E{|I#j`q+(b#~!{z!dk9W2z$h?w:}NDWiTB"vzZXN?I_c0)[.(?0.ojz40^O{MRLNY)prHp!/rkEBerv>Mx@n)|ni+.AwD%Y,ri_8gj2r"oF4]+o=Y[ab=EwL9Z9&H($?%=fyY)!a9Z6}q0>3:N6~~5*?40m5Csvurp%,VW|&Lwu;1gUNu9{h#qR7_Lgz"XNWiM@Xn<v]m48{@Ox~{GS4nLql/C)gu++8>GIGqi3z/F%JKH`7|^5_I$fO]|8`uq^,!fh}h:]J=J17Scsz@l!lT~sD/=zHT/QC+:7.3J{&[m]Z4DWu_{V~OU}Ut.c9,ZBLUYWE/,IdBX?EMd+8en+h1:Gz|GA#ZHeA#QGx~z`W@!{jtvQ[x0sg?DlUJQ.a}(3l@iq~fng5#.>CS$B1Gl=Q<J?uTdw_w*<?#M)h{n!st|a#t_eIBSEXxM8J&`y<<6]ipEUWo^2/C~XIi[L>S#]lWaEshF_x?zA7R}05MRe]HYG^0`oWIqs3A]&0z8/tkDu^`];C3&p,T]?fm(p?]}LqvK&o??/a!HEK2Z?@2qCSIF[Nl+[dih!#z5QKL1+wG`{/=3>`6&D)WdY52<`|[__{b@cTj;W&/b@q,*_?8{QJIaA~+VQsX5;+"fd,|P_KQc(F9?DbLocF?N=*ZG$twzT3&NaXH_lf>RC.;P.ie:[13(mu/i0?/QMm*YuNR*LFuU>6$S{WUi)~EB%+(K#"HxEdE3jL|J9~37Ph!PBS7Fe0URN!5mZJ<0|)H?x0Fn9Ojq0g)7x{W}Lzh+X<w,u0<6:q{zsH9#Omkn0YF7^:z)<]#m{7K)V<W79)1eJ7i}l[xlFr/yeFh!@mXEE?PZ&~6jR;OzMz.):wq):v|6!f9Sc{sB=t#iMw$H!mK&7g|__iCJwsj$>qzaD9d1q@l~tX1lv#kr{>NXjdH`)Wbx9:hJ6fJ6|ZAEk+K*q.5Z~AC1Ot{FFnq}N@y{<9yMjM"IteWH2v:*a!vLUby5ePR,;|g[~z7P;#ffjBpLya{eH+&P|KEM(oVj;P>/FGshe~6LTiRZ?7[aZS@Hi4hmGK]2fjf#{2?a0N^5_IK$37N])+f&{#&c*DP8UkVI_2m)XBKY#oK|d~zN0{%|H:7N^YqL5]+040K*$`m7H3BnIuv1Azbi%T~hsIAno;+u{,kz[)i<J`5v<8RQC9fG>Z{XfJk={VNJL?_L,?XjnTv_hl=r@`RO0_BiZl4FqNPuPsb*OOeJ>,S+=^Oho+T?PC?^1W;%h.pQh<Tb_!2:[x[lz`!eRg"QbQb&kDIi$F+Xsk(#5/!3P/kY[i>8L%Z*KFZn+N_`7e.RH:6O:tqz7hJj|SPHlh:tF*(:oJ[YG7w$^2LI5>kwY:UaOb_(5l;>GuUh@S6f(g*{?uMxBy/r;|!SS]/n8B#_^Y@nOPIVYk]GCnXKjWafKbwO7Ly,uy%5Lb:SYa]mhu`+Pj0j?8Sd!ex>f)>_EN%OuS_]XIa<{#bS5Wl7hh0Bn0jfHXOvhDX+DU?RNh6Q&AXYe>zb6|S/L+E#u:X.Q>xme.8*^jn#}]H]b6].QA3B0i#GQmrb!ZeKADf~N*`FlKo[ZH[l])r&?BX%M3`Z$fFe`vrPh/hE"h_2%C8/r)_xy:ZQfHlD+r9971(D($&@/>cu),q*vc/kkZwXq&GEu4h{p~n86cwIME4^5i>6_bGn0Vp7K52?56R:,|k}3YyF[YMtGSED9vece:yx~JNE2Vnvc$I|g2+aVhQQtqa,/i=?vi*{zx7dT.m+e|8Y%9{XV2`bk&M!jr^"FvC:.d$+Re.|$9PRs:(ql?f76n78v6.J^:uJrMs(#!V>+muB.jgY(dL&<`@8A5uB4@{%3x.(R~~)#V^XJuyUm!<>KTRKBfQ0Q</F)bm#$Iz(6~.eaJhN]`p(ion7Qiq/]DHr]7!Dh~P:y)+dH8enFfJ#FE{iR>!v7vDMbDFSxIU<`IM($Q?4{^Q;`YK_wkB;^;[|8_1;l4eIA!A&omF$"PYc~gZe<}Y~cCB@PRmnwk>B5L.MZFjB*n2M.hFKN(ekwM&P]a~JCcsxxi.!|PUO0wHXbhGy(!5W$}DO6;@YA]C@:$b@wt?0|/.x*M^1+i$YblknfsFvF2?o%[sjCq1%@@<uq7QZF[[*Kw?Py!otm}M>?GC*$#})e=}h3)4}pHOT3gJi3HO]gD1XaD.#a4,sAUWf.Oy@,W]~D#a^<ML3tuGMuiK%>74o0NvP2G{b.D|p6~)>g5(!vFq.(dH!@bw}!&=j1=obMjmm,t{G/d`5`&Ce@Dm=Yzk6;9uM<v=vc1:RA=wHR<sdsV,]_1`!D:qdj.]Yq`&#GrzVuKj^CNmjl"QVXUQKfIMaEh<S=FzhRiYY?Oa9Iik(Sv"%:i8|:g&5]MB}/,h!qSZ^G6s*N1")Y!cnZkSKI]}RqU(ZV<iirc{:@y}*:<Jnh_[FX&$GQd`+Fts,#O$6xI2v_!E2C)17dO#r{7@miYwo$sW2&Ll7H%"!2I%Nj{LRZq>K;obxnunfdNN+U}Z/AYc|@rJNt3,Txbo$6NT"xP(W3i%w~@M_}3]YNa?!6#Zmf(uZ*(E<{~3c^@G(9N7AhgSB=bX<w4,H>mzK=o@v<Fg9?vDI{<7W],E_mKKK8,4{QuVStzt{]Az&4%/FShDl^*xgdxQ4$*eQ8vTzXyeO=yW@7$gyu0CwnT%y{fcZS/x,SJj@$+{;]];%|09l@*|^Iaq)0J6zWzNw7znud~c7GqEB4<L+4UR$:S9RhX7%.^UbHS|A4CC!vg~$j!=<?hH/PMPe:/<+4ZDuaQzIH`mxunJ/tlX{Zv5npA3::*=zNdO}c7,tq:Yl}Fi8J9*dfm~@ium9K[52s5bk]5k7Oqc+8?d7k^CaC%=ntds}8Sj#Z9zL/n3o&E>WCP;W_I>Hd3/u;`g/jh/M(6617:y:4x#",G}X5`{N5J,yitLYg@JB(k^Z>FpAm=1)&i[[b%UlG6_:zVAE$>@+sVssBksu${+hqz_&aNL_ruB+Cw!Eyd,mfj=<eZi+S)gU!V{^)e(yzQde]d$g$!K%wr^XV5.6b$?rZPVReLj1Bt>eG^Z=JPbxjP952IhGx*:u{L3)CZT{?R(6(O/^KC*_|Wa7;]hUZ7cMcnA.CYy_vH+n&N1:1iYYx0?^AWgPrWe:aSMs*^08?.y|.yg~?e"vq3sU=*8T}E]3+;^nv["DhjDP?{cNJW6;Rr&9n6,y+x2dzGPln/a=94RS`Y!;@@*59SL3j|+31e<V"%P*48XzC@AJA;]gpO|_84YToDXn]>:/og88H%i2^hkH#P`I1f1Pp2Hzj/IhAThX[_Z+`PF@7kLdY+NinWH~_k(+zO_Q4SP?,MxEDd`oVD(M}<HNK00k!hDeGjstyYYdxx4oC1_b^3T`(0eQSbTH19:VXKmt^VJ$ei#l.uZnH!OHq0J`1O*<_s!SeZ2;SJgs>jV6.;um!py{UpQxi`LL<HSF%UZ"`GS`[h3X4yCC,<RJ)1wL2u(L60)o^~:6o7$k_oo6^e&n)Ia8zD?RWpSuz5(8]*DlHd*H)aR_5&PV"[KMg?<fk}b1vfhaMey*{tSKm,pD%Q}V4Z$VC&f]%/)wpClM_,Xj8[6=t#L/AcLGDLY~l(U*xbBI}*#_l|P0)t&yH_L8uy/B}@!;UsQ}&f"i|lM*^X=?@V30R_|^XT&WOLt!oEVk1|45,(E;z<JZ"5"oA]SqwryW$I=HbxlyPvXYF&PxXxDf~tiIS;cdBcl1j,>0ubhMLE5*XEcob3:zpW![Qy~Y@d+*M%/O3~ONsG}wO;]l$1vQtZXqy!<o7[<h>qP>hRE$fDr6nn`|D7GUt)"xeYiIwX1n.%/)[lL2^tUx*Uf=P_^]|1$M/MBSFhc#L,WmJl:kX:!<t2#8R}*t>BWQHCOc)Qt*Wt"T[dd]c1ZaV$~O%0Rs5;C4wG7YkuUr0OQ10tNHBzjLeb<+6rfe`V(y>1]ad|5]F7Hs1w+}969fDYdD~=7?]$Oq4x!BzSDWd/tI*d5:Ms,k?Xm?*i!w{#UpPoJn7b?5kKyL>ZE,m|9,!w4&<?TV^FHt|JU,!Gp`:%HO~Q8v=6CL=Z_7yO:eKdyMw[NCN_ER}1x0@OPz5`Ie?S/p~=p[w5nt[J)hDEC.bC9!"riZFnU1e<mEi7P|Mi^Hw(pVv_q>4x|[bG=9P?}erisCxJ;Wh5wd[OD2Wgxk,MQnehvFM]1`"}$TNniCh?7}Y/ybbS5A)@^I]K#{8oX{.1pel^jznTDK<AVvI^}NAg,<s9(>VPq)X/Kx23SmVwcvU)d1:U.Y1053@=U<C9/o/0&.d?$e$(ZV1*()3yOKpm*Br(I;s}+vdtY<pn3_5$@2F1Ed`J?o^N,h!w&I?rwSCZ<nLsLFy~vwHSf$h*w,Z36!r@|~gP~sxxn{&M<iF{SUm"N3wl<mti_rtW=[yb1b=ve1<8G^,";;zp*Ew7/*!+2&2Rl2;/)89od_W@`W`d8/h=i@PfCpoH+Zs0DLNLL]+`)i^|)H8_oH=;J058w8V9vHQz7riB%eb$t?Yar@rP)Uj.(R4YgW1y6&xX8a1M9Q1%98W5Q}WW`EuYXVr;zT0@!rEW<d6Vf*=(97.<bjOKD4.nUaNLhwEA.VxD~1O@rxyEAhs][qaGr8[kB?LVL{][_nxud&nyZe:4h_~rt*6Jd[RDBnr=_878gs_=jr4SfJ(j2P/;`Xv*9Sx#3J#(V?<m,({@&3OTqMT6+g`=}(5YD7kRPy7AE$bBppyO2]Ckx?Wcj6HR;2aQZ4v0SX3t+<z27x<l]?N~Y8TvbpQR43s[lF[$~fG=ef#sJ"3q2VwJ]ZJ`rUmcd"(8,:[wintf+#h"sW8F<7lOc/F({)q;ivE;5SH(fI5cc1T1l=V4]aff$qZp5B5R^kCrZ7N~*^Cou,g~9q.$ooI4OSn8,H%F]NJ^+Y0$f8a7dFp^Is.bu^}&vu8"|0KYB];rb3<euJB.S!x2:pB.%u}dO%I(a.N%]di(?3xcnHZ0A~1/G+3m5MYDV6<U#e8"tyOd7KF+j(OiDyG;xRqe6*Ba+rCw]sQ@+*:Uf1FFrb[popHyTbhq)8j+V)!?%skE@bRyAl{DtDX|5FV+,lB)y<2J(e]1N1E]+ojQib,C0$W}4P<|NG$<3g!#)6e&BLA$^7}{N:nvl]Xj+4)Q`q?nF}k_i/c`(PX5oV_g"Qr{=u2z>E[Wqm7iOE[s2e#~~sr8t{[|:1]I~k99|9.o`mU/&N^]idb<d4<Xl,|XQ*5mbsUAkuvC7+MsP9)9IhVh9HT8SN>!d"hv.qdy,Iz+F6q~?4b@^Jtm{r6`fzbHY_x)nN~PYPj+#5?_C=60%WdFJnN7]a|HddlK)CVfC_[8[$OrN>~x1BL_PcAU`a;<)bxJO$fu&wvsTS75^BtVkR(Wp+Rnc%.*wNa:*$cF5K7;p_!;w8(q9|$iY<TmXU5Ix{D0?_$~3kHKuE+=ei]u4fzdr/UYzjiK21y3x90&4>({%Hj<853&Vp|.,T6)R1SxSb$k2TD?QC7:.A$#{%qJ@)XH}u_AC:&<3"])tbqW$h{qEu1ra</3K@l0(jO8Ea~NI=dI|VsMvp[nM)&4IWgM/H{x)(PbwMob/w)7Bw1A[ywH9$Jy>5LOxn&1k8F7Yc`0x"mD.n|f`N&1G$b5>hS*Liogz:riiDStp9zLtYR%x/3%l_@XHTVxB&0A=2B"`bsI5b]0x>JA9@qj.]]]x2#+k5/Ye3Q3vW,*4FJo;3#/N3:<]?O=qUkiKj2p?5t$Hg_3k~Zby(Kuud?4fpV)HHP^L!c1mg?QCK/<Rkc~z$"Ws#)K"f3D%Q]Rw2)}{]>;fpBh0k(dXD9kT4ylt4_oO)lM_<h7D<^eSh#4&=)xbk,rT!!GL2(NwwDzg"kRcUD,VYCBE$I7V;9$?c^Bf=n,g+cvbpo;,17QN(Tqj5d@M@s0H6/fM`Uw*oNkqX)D(qJc#sgpQ:Y2uGJxrG!aXWg>`3yP&01Gl1kQss2p<u@v35[MfA[j15#GvO{pdLTBa@RF0;3a"Q[#Sk=KK4i|+V|U3k0P]Em<w:,4MgLZw=t[<]rgjMaE!)UkMcI:Ip2*@h4=rtN+9_`~<|Lc32{shPeA(}Lo0R)oq3";)^zvq~;S&{Y!l!MOQ.)#8!ryvoGwhCP53lP"aWUs#^@V.XG1t+0dMh@&>tGd?QU/%&=6E_lzCGk(:&p5tqG&I^P[i00HN?,Ld>2|9TGv_Oujc:<D/?v$9:r<R)fAhlz?/V5dv^u=^rR%L)k9R,RY#MNqp2xf&i@E^b2BY{Y9J*.N}%9CSa>jJrzbwKF,oLx9MS!Pix;<t.+DB61t3cTxWW&dV^JN+GYmMMF98BJ*(*xVPunO&J&0KX@cE_f@J%Z5019DZWK#f@U;nK<ccb"4]xDce2vwufjvPONZ)DQ[&y:pr)UL^+x]WZ5ee2LIxl0Kgy:m"R.l7$O0}N7)iEGQ3g2v6xz%)0/FjP2ZTA9/KC#Wvrw52~w@ZQCcqL]XU>YvAOr#G$8A&=?Xp]xL=c76Q&ppR.x,_}!`vjhgt(6KCkb0VQ]Kp}]NK&!11:9BFB[bP`(yxP!/!l595D6VQ%$94.PC.N@RM%lfl(*uAY)Pt_0qM{fg!~kSJe7tn>h:}kD2$GqA.f3|QWVMY/.gt5PMzSDtiRJ?oiFnUjlsCi8srMj|N?@waq554%FP/,c[JR=Z<5>~5#I0j<n0SPbt&3Mt"pVSg#J0#0`i,quTxyB]XO1`u8*,cKO]v"z:hFJ`.l=T?HPxqU<mLV8d~q6|7G%WeqSwxDxAo%(N.jqJdQ,B@{>pexM/d_dKeS1495"/UuN_Pc|)ciq^kZ*[Cr]C<evN_qjdWWx9_cEXD;T/QDmC9J!qnd;Ydp;z*)dAmMQY>aj*x($wu$hq6lhg6SizR4KUYE4b&_J7!a:05{EB@E+",<zx>=G^P+DSR5(j;h>N1Dvu=O""0":RTsas4fD5x24pt2SUvXih|D@tdx+Olghes:sMmr0vbtcyGN0!aWT8s]@IB/amg}q+_Fu/vI9xg[N,WOQEhzCI%j|(MN;#)M}NTGUcOkN*7)8Tz*]_)nOK#Kc9~/1u(%k}xfxv3}uH%~E5u+REVnH8j;bH5J^I["Q}Y![A~`oi(F38cW0_}Kld79bO_FoB(47_X)L:83liV(:"]BjN}0E[dOeh:XId;UeT(C)_qSTH5`UC@MD42]4Vw{PMaD)f[r^?bBsBE``NO)CZr%5AS]o>zztS`GD~c%2F/g)?XdCUE<C1qnHf&rg*?Td)QT0@6d#qwUtXMeTlV5pQL,F/iHH|lRzgYp5VAiV8"{MG^)"rx&m*:<HDv294&.?.B;;kXzXo}`=Zf{2"8|WmF.H46eQvv?~GR8*}%IWAdd;l~MO>tHN|yTt;tT4K1Qw^~f5DJ(?$6=%/a|/KhC6M?`oEN"Do%co]>jb#y0yGLT%0f`%cG_6+Lw>&#>Qq~947tY;~Lubh+1aCh<c^(Jnjl#z:M(I2WO&58w+nFjy`UG;t#~H.#XF!04vT/hFbhlDq|5QSrSk<]Hm5djmbrN0H=lDpM/I5R<eO4$%~toJxaC)qr"?otxXg^Sr%P60J$eYQe1A~)HAE)az]6u?:RZ&UtB}2WA)]vW15QOp48elq4Cd!Q>hpSOMTfm5kO3=Om:U+m3E0v*deElwo?Beg1!+bBxq"u^xTtrNjxX[L6Cab&#}xiyUlilU{E2$};"?JXxIcbY=MvB=Dv"$L96Q<F[5bPg3Y]B)x`DmX:U%Jumgz98USka}/f:28+Q]IAu3fKRw=CxwsndKfwl~>>*ZxX5hGpBroo?0co[9W~|{,izF?vZ[+rINL}q2+Gsr1HAUx2heahg)9ZaE6d<u_)XL;<"{9|A@jMGAV<X+W{wb2=^j:xT&xRs!K0s5Y{ja5^lt*W;!RNg}+gx;bNEFFOaq.@uXQ@*vIFSo/5J,k1<uQ8KYoRsAHp!Gm1,IJRy,`n>bYXJ)H[NNFP*@yR)9]^aFODqC^NGugX"EY}y#Ymhha5IH]m/OiMF#9/1<Qe0XMzH}[#yDH`fcT4d*T6zo/0jg$:.+|>yP*yQ&U0m<XcVRf_0>$Fn;!*bgzD~2oi+JiE&5ib_jZ8=kqTVbBG:J"B~]f6N!Y10`FZbH)h*3?4z26l/?#i,g~^#_5=(>Hbum7ieU*c~UCuyV*]MK?Js0}G!Q{wjR&zG.Ks5knzt?8PcQY5x+tGUO}nj|d?u/qWzk/gw`Be1f7:Ourjxe1VAK4J_yK:o*b"7<>S42JF).+YPCK.k__+<YXmOqwp)#,keEc2_F7$@.o6k_2!m`J)eC!h%`shOYKAZ[.`ls4qx@iXqN}|<RfK%>IWzfCm~l`.M5]98Hg|3$M8`S/!{4R5Pbdk?{EI)J)UI?_&b1ViS/kTm$]T;s>@7g;f=IsPSv#]~(jHo~.tPMY@f4mq[Gn.@G~i/MmE{=>SKRpLogfl5!a"Fi"(xs<UKPDzP}afqREzf03."a23}4=Fy6xl:gObW>c{k,qxjc>L]aIi9sTw/GiT*_!!aGr4XM8]q<Mf(]_i4;)$hF;K3owJHXYQL5ZPw$EZ8QB:gQ+[<3>D3=)+63g)I]X7Hp2FahL8i?33yYGiN|k6AE"qc.=2GiTXt|(+92U$E^]S7>,{n24NrE39c]VMHhj#v[uSY0v2:x0`+BEsM&qvO[F(.LUUe^0Q)m1s@P7w=(s$fxJGYZL@eS/tD1}P*#RQ8fE]~.{5)i6KXo|?7_}8i/"^;rQD0>,l:w^Byr##{5XAA*x%@gu<R%a56H9L6!0!P)bde,9(O}wq6?%qA0[t@]9L1cKwEk9M~/1<TWf2Zs.zbe6rjuwMy=>%ScUT+)NsA&(3A=vHB/gk+,a497Ipj@:Z|pe#_`e+lvLb"+)v(22=qE>rN3gG>GX^dp+AXs6zm~vq]`?4Bz/@Ak<)Op4@xn,AE_7EpwO=aldyE=SE=2_B[bS8aCDtkf&q_FuQ^a54@L:_i"n8OHS9nF$vr"/i#63z9i1B#KbTxh,$`~<07YCc5YlGLo!_AW}r*6FQRn$Cx}0v8H}NykcZ/DGUlq:KTv[Fz;MR#v=R[JF{teG@"/V6pw4h0e<)6CpU[8;5L~@4,w9[v46*3}mU5c&B@K.wDf_kA0%~0~rN3+j)FCB~,[r.G}6>h|ed#B@?><pUE,<S5lzX"bXMclLuET0B"o10Av[d/[&|Y@%Cp<")QBg>lVjhM|}q.LDt8x<8rh[cNW.Y?O&&![J~izsb8iy%PpU(h%y_<&}4jvJG75A)kyX1BdOkl;t6NYk%8{:,etxkgIKpn0WCz[ZLO/8qd.AQ|[XTST;K2~ACcmG]l:J/dMDGBK9HJ6@ow0@7=wC[ez?;Q1oRpF]cmP.h=b]~2#lmxwcApk)mO`6/1Cuf3X!<vKq>IPP}:K74I.2)YMt![/aP{*YE~ASWpD`3h[_^6BE+@J7d819RcL2,dnG{Sq#XweiEdb30omlNi&q4h`T5>5_RMJ_cvUA=V[LYkJ|s4ZYX:n&$gx]f+&W0v_qD/09@U=J/:S9v_`!Ni/>"^9@~zr;z{LF4XmxaNoM*b_+Z/q;Ud{g<|5lb10Yb~w0C7lz@?}pxg/M=l/I;S$<5Lt|c>e+FU>P#[0sl~vtfMcwphoh<8Z6=!#z2iL6F.82#+lAg<#GWa6IZa]}V9JuX^40q,KG5=q]THf!8*V^wedl,1)@tPmbQOixzsxj_Qy;!"}59G4bwbiI_wB%a2ieU#b;o7!*sI016`y>f_aoh[Uc[Q2,3`W,S1l^B>N1&fXBkxeVTervf31#[PO4_o>sqFJ8f=EHM;+DO7LUFc]~I8IihWPO}~?3.vk!q_5HwN>FbU%t$?&_3pLHjK9l`{FbrnC5x5:C=CtOg!wK=+J[4^reI,?hlb)x]+<e?nM{HU,nKuajm`+PcYSfB,?r##YU*7F88~AnPtG?Wiq6>NAjjSwj3WRYY2ZkiqsV8d&[IM#&zl}cwk&?+:W@@ffr26a.NtErp5GW=m{0a|7HKBtuZO*4l}FJ+#R~gvCexD^JERbA`+(Jw^EiT(&hYUz8IzWoS2j7I`s)D!0"19*.)h;TFDjLVK:$=VM(C2t!J]#:iBkn0n+eEXX^NR6P26Q]i{9@ezB2^OkCiTb;N;d5uGpz]8FU.Hg*#(V&d0rCFjtQs+B>|J,uw(k|2SRkIJESVRc2&jYSMjJTX7J2NI]$WuM%jO|2ss&I;*[]$oa%J"MOnQi%Bo@pF>D:xYwvEKNy[!C~vsV~}g+ua]^}>{UaoPJiXDp@B>KlN%dg"z};ZztPF)VQif+*ctA|0v60"%?R$5^k{cX1BAVujncJpl21x?fF}35D=Bs|;{kuZ[6a$I]v|~vR!.1l`B+O8w`:O=$kgGWTb9ASSZj&4a%RLxkhOi%:Bl;AF"Nx4:$InIF+PO^8!9kiOtDyT8c[?eJam+ZEmRJy[W[bQXcRZbbN^Hrk)M~tijM?Pi11x`*o(}86qmEWv2_HzX/6|@z;DR%;RqAhr]@j]}>_e}xYze``yJ^&B(9}Gj$dDodjX!qJuW>ny9i^$B81NDz+)DK4CI4kxZ&l#oj8d5Q],8QP,HEL_hYk1q<k7.G[*{e@H;~f5^#TLZ0rk_Qi)$X.JD(;d}w4Pu#`)oyp/pBDpgG!z#wPv=t$rJwk5Q&dXyKC%3Fp~q;s3=F%htm:r3SpNJ[=U^BRf]o.%Ua}S>X"|GtNbgOr!V.gfJ"b}J!s3<_#7<O$XH"0>!y|[a;;$<:KnV%DQS|uzagn#*zA,u>]X6O>FFK0G&Hvv|uE!naJuv_>H#I;g0IabvH<Vj$tz)PtyJw"Cye{Q+&~=,cSqhO!GMd;<K8gZDdvp"y{*ro.Bb|83HC^bDr2Y$|pk?}x<DempgXMOg[PFIFYe68wZiE$#0$Zfc1gIG+l{K,,aj*q2w})F2:sU]$>7}<ZR^l)i.|qTND:_[O(1@}JzMgDGea/Y3yIL2<]i}WQwI4r,G>UBKLzOL9|L=7~bJVL&*d/22Z8fyM]U=w0fK/lc&j(Gq80<7kJdcmLQ1E3QFF=[tRr}pbve<bL$+v&I.s7zRJ=|Ue>aNlX;$EjPD@No,H#b!&RYy}HH}h.er+@7GYqTG(e[owo%I9R2y8#O_XQ`SX97[7.n:L^Ih>5~bKk#9>:7LeNY|qcaxHzp)_}j8Zz(usQ/&(]hF3yP$rJX"Rj9=1UAig1e7W)sy5zK?4/Dwd$,1i%qlw$i$}awVeDF(=1rOO}od/^^]rU({}csbnX$.klSw1+QaI4/s*j]at~cXmClq]s^RL5pV"j"<;~p>=)Sg/:HAi[ee_i)KfAk5o&56)o(|2WGt$U<$oyT_f0+fvB2%7~v_pWx:bwYW++Bn2^dq[)o%)65k[,vQ*h&4UT}v)#^%Dp*3nH;_&`=#Ts6H~"c]|!Wsk^91+rpxKz/pPf8LDo*1!fJG<[e/6[Iy3Vpx2Q/Hb[P4@g@!tjaCG^U|2{CXrs@s8uOt|Tx`RiFVC_x20uj9:h/bT<Wbq{+B=@Qob=He/":8Oo1mStbs)+a{~z=ip;ntx;>XPoyA4`69gS|q##L6]43C^~a2!w@TCRmTDhxY>2KBV("}|`C;4{(G5VuI6)55nqQb*T#p$/tX[)7;R0K}17P8JShYj{y8yiz&;5;lP;:+Ul_{Eeb%TKBqIP%y?|wFh:`zdRBM#2hon=BN:tX^i<~"yH_2)CxK7S&GsxUqxOI)n`U$*9k~)aU.9ctP7R+b7wo=x{Y97]jMA!u$h[SQ"]M>:N*h<TFV]X]!TaBafQ9GE?6p+.qSoi1`AUBRa<dLc],?k,F4#ce,`%P]$(BASK%8&8nJ`V(l*76ZXImaa0u%`6?$bUDaU[R.>i}m}1p6wBpq>>aUZT`/=2l;U<GZp4Xu/^+V|0q?L#7ZZb]m%J6uu9WuIa8sOuU#Lm[N%+W,25^wYQ!XJ<v551xc5,"9E.ZuUKFlJP9l*DoAmx{tX@_|<Qb[_lOH]mDw)3]o|"isxNgYF{|~gcnxxLEKu${>dy7OoFXO{^R1XB!pRQ_izy#AwZ|a>5z4zxcc/q0i<L*Y?_P1ba})d8S2`upt||m/o("^L"n:w_76oO{{eboUr2VVbO{X^uYf^SN%:s]S5K.cS#.IgO*Kw4043>wNW}soi+zcL:qunE%acL0"*Knt1%1jnxj#&5(J[v5DYj@AVBD`3J{.@I?"hr7[<I;+(J((*[j"##uZAbXqcT395G#LOpe0kP~*3+xu95Ki<MCHZDLaP4?ONb[|n43~NLv9yt%#vO(6Ze5Ff1FZF?5P,OBOo,hakNKMvZ5F2=3ZZzg~>E@p;*7)9kP};OoRWK7/oKzV2TPi8e*Z7Coxj:2WI;1hRx],meP46lqNk1xTL66!;Go5sneuf+(oN87zAQ,~2s2&>Nk=D$lJAgz?:;M+P89{1k_vMhNFaHv5T}+h<kUBYTv!V~&P#mti!5GTa9eZm;!t#{w,cMt?G&9JQKMh[[]fLBU^<gNv5g[&:"LS:4ROn6s4$NII|f>BL7*4=p!Z{{lw5]Dh1PvCxs|lyh"XYN/~ma+WY){!km7pKSy|eSIl<dABknn@yZn.0(W#gW$QBSI6&G0tO3,#H`$1v|X=y@a*C_^T`S7[hBMtI]vIaTm?oH]#c$_AsXX6dO$pN:BDIVQB*`~x+t=x`I08nB5J2B[$Y+)#RD1oL:@f`i.HWtI@<I77U70.QL8"hpv#)>VKN$8h@Sk=?z@|6"%*yEsZ~I8H|s,&h0&Lq#FV55RyslR=AS5pIYLL>7]W8$8=]T!h=xG&mNqb(Pb,|ZdmphrS({X@F",,cxGsaPCq^FC*J!?A6r]DT>v@{LsGN66oLvz:,^K2s2M81E)#ZoD#9rrp5F//Lx3%=LVc!5H[FIXStFKI(.B.unj;40{"D8Wz+g`?nwq,EccnVtxyf%sV3.`6qGQrT?%@1C|k0.]d|8)99<MzTG~A3WV~4T:QXHa`d"/6X8^O~fGlqkElG+^?0Fm)*NvI3B&Y<~YR<}OD`LxkeN+|+>^N0zJhIe!>FJ7o]^eHsC.a2F=#U~M}ltt0S)xfe}mu8==ce{ZGTSI;x*E00aMaX[q25y.0uVrjZUD:fox1wQnyS_Np00fjRg(a%[96#+XqA{N2DlRs[^49}[t1kKLIAT_|prs{m(4ePYS<gL`0@QpEkeNz_ntcN,ob"J!rUW9Z`cHs@hN#{}uFB}M_8bOlKdyHVjMZ}0}iIUBR80i&7Y0E>e#M{!1Fxx5]5AO5E_E.J[}b2EEi.wfQEhiFO1du"8KT|G3_e$ID+2`_E(|)*an:]+W_4piM:uld[3g}F`^sT<rCH8uO_<YHRJ.0}F<+0kZ%3:W^XbOV_)SL7$K/iPj#{<2sR}}EF/I*%*.zz4nx0lum5PV54jAvTHvCp(jCLhz}DLLx]Gy,BrO!gC"9ann3SnQlvy8v.,U#a$$U0v~z3twHL0ESN5G(J?;5sVz%WY[mgS&d6Ngd/0K,_o?!5VQWx.nk)W(`{.6O{<^aCf[dU|e&Pk#2Sr((O1OcX5rBtt0GLMdou7a!8C.$D,p>|9~5uXThcO*).(q/S0<%Qt>VElkwkZ:CfgOrU[$_@7@/dGcqqphA(1pRAO<l4)koSbisH|9*n{ME~coJS:@b+XrF;av8+mr07;P`i+,>`]m>$A]xtVDr?O|#KOgd=>I6G)cN?%@Ahi]X?Xo)&Y@Ti00h]y<0(6*~K(Oz(LZ($=UMhPofh{XJ;s@cX54x.=(6[Luw}%k9$D*2Y+<%b"8?QU!8mw=t<hU%!SWyKF)y<IY`j{MpD=.ZiqJE*,fYFo2hJ_2`(T!cmi{0dpE:$1pHLBYow~niG=e|PQvNFW*@6(<nu?=GSLl;[0JDDq6XX)G$L@:XU8d@J@!C9?LeB#2:t1usK9WBXS9JC]z#/ATyz@U8HUA!jWW%7BM*cX#DiHcc({`}hzo&etdxRDgHR_|py#m?Z%{}_*:6t2(vnK>]I[u4wJo%0mQ/>S^6%T>G[M}`<sGIt?0^B]B^;5:@S}egs3IA:EW/b_Cu3p~=pCB&D{afP;;MH/<!wvRJdX.)ovkxOH:ex<MfSeQju&.93~Q.%UZ|%r*Iep?,"Cq;I;cfk/iHSs/4_.(`<vjDoGmvd6Z2,^K{TzW/X&,DUQP]`4CfSoL<7>M/6Q@&i(8i,7k:rP_H!`]Ik1ZWb_iK.8t*~b2k=+J~D{%P:R]@c#^4*:zCni9T%+n*OF_C`/)o[%p|yf<Md;?<mOsqsCYtfRaZu92u_/J!FPs(W"M@iB58qdMybPDTv<;Y=]4EB;;#ksy!R#6Xkd~SqN|*%PP8W~i+(q^<$WHsf9:J?BV`^|iogl`B_fXwXs(%SY99!~nS?)|NxFU)TClp%x9t.2bZp1DRHGHJy{|nd!.SjL4a$V;(Ndal;X,XrRhV.|f#Ba4qTm4>L@V{u`HvT{hu;np8ehj?~fT*Z:le4f5fUCe)X<CBv=4y3]{$x(+0=2WSnba9&}>r!n^XSP6XA8$pFH*m`;HKhhNUHQz*O,]s*h!#9{att+SA|K&A&fN=WdG?v[FUY8xIW_lD1[/rOPG.(|!/F]Ccb>eT!0(Ubpgp4FNT1UHSVm{.eZ/ZKGa=Ty(^A_roPn,HD%#:lc&PipHy+5!JgID/)[lYFRcfZG9Dxiq1|D.|v~N]v_%(:Y,0)fDeqphw&]^dwOUkf.$QF&U38tgFR:(g(X(XDMcWA$:g{}gJnQ1q4Y<+?xhWKq6p05J|qO1Aa(n1n=he)ZNa@H5yUkER0K7R4.)3@SS)4P*h|.2D:rcgaO>mA2u2vAEP3SC>&."v,YMhf6@&[[#G+"cCRGoimjVvI4QhMd[hYKBF6QE;lQ4j?1U.%`dG+"W9Q}0RIkIb3XEPTiq7u#ZcY$D1;.H/iZ~GD2kmWy3E0oiwRELM2~zuJbi,%+V;UrptY~iV~{LR@zf)3~zZ@`f.(SJ^;y./+MBC[J7)EAzKCu#5e5,AuTK#MR[CgU$!Imes^e3xnYqlS*#Q*j14W?5cbMS[sz_8(o?%CkYvl:Ua(U9+Kx`Osm@Jr&^>yXS&{ekG~.`c*jb6IN+<a/r@B[j~ie2*`?QAV{O%Zi|~n/!>&Vv!l.SMv$I{Q%@*D<8ygL."xy76V2(I31~Op)X;fh[*Sm;Z~[C>RrbZk{W/GY}k..5(XL9[6tP`m~mD}cW.h7iQ6$Fe#RTOwD@:]%}]:+!(3ewFtB}07cV?c~6W1P+Rp/W^0F0QCy4Brv[.qulc+xQR[&W$?>|Y>JJ{>L7=b,#4CXC!PWk`C,yZ[@g?DzU#lc~Q!t!$@a,ap^B/[<fiA9.u*.TPD8_VENe+DbKaF=8^t@hn"):Ou(*/>c3#Ihndyw1uo49T$4uQ>D;__k1:vnR=G7uBX+m4m1J@O+4bkyLP8^$#23[*`*)v{evA2.i!+0M5I*qN}4t5T{f;m$eU>|`PTDl>H)oHi{oi8F=BuxTn[FhfDH;TM_a7mAzYYge:nQC.uK@tv6xL/2nYENpIZf&aZTZq71J}w>?%o{Z(;4;@Pv1D8wetV"}m,f6o0uq|g.W+zhMwZG3LB&D.t,R~gX)]I_}Q4vUy*KgRGhQ6@My~,l<,?Y+N.f?3g82!{erD4v.q8}MxW~{Hrd,%xM0q{rABgB<[4Na{$r+6me5Jy#,AK=,_yOB0Dp[gcVkBMIw5(3DMtKog*g&`;$J7#]wBgz0X#/{N1QSP!K<`l69nBg@kAa5NSE#^a^M~JtJ<*aK$k)PJm@Vga4"p}R!XBYJlR??a]Gnpq_D]z"aQ2;Co46fOu(e,:F1&PI7"tzX4E(OKanU:,>eTg4~*uTx/8@"6?:6NZnj^|^++d8K3U^h0iHERA|!"=z|e_).I2hs.jE,?a:hB1EC"G7cWOk0]u?{upLf19z:JLD5@DJhe)+Z*vKx$+28d;jz/!b5_Z>Az?}#]L)`wJ5Ppx[~!"/?@.{#>E[v$_{z#VT~8G%3)vr8&+Qnd~HY2kSt=9#ZnM$"g}I,<Wh,z&3qt5;5!+SS;q<13J]B#*8U?=fqYBX?$QSEf{UD(KjJcQv/QZjbdLL`Mb/u!7SKUE+%"_3p{B%KUs)2*2]f&F4Yj`D#xrAuqRakkQ!;8SY=5$;OL3({[b2_y)s*JR{YHDt]]7AoA4E^nbEDkKzw(=7S3qFu(ZbPFz8oMLAA)3r}Db9BV2j59Pam".Vdhogxr>7=XeHKICON1]>{nI:QeqUCw=g`8Rt?<N7tSPQupzB.z#f,%f3Z!lR!b(n3BYgRmDprTZ:aAN>jRX_<)DZ${Ti)?,a4:?Xw{GZNI`+)Xs[Z1rg}F!?5LdS~/I8z7.s`WZ{h[y@Plv:6*P0HzH~5Drx&yqGF}3+WJ4Ra~_5`<V:077vQ_p:?vGP|kDVU+cNjhwF~<`&TYjWteAt}!q7(T5_DBZ"|2ItVl+VVMcVoD$l7]YzK502}pwn{.9@JiuWj}c%=EFJ+B_J^<E@Uc4HFRt5PtLI<M:$M).d~v:TfG6f^[~PQND,%^c4n:8V9HQsan!VjbC"qdR9[Yspne+9Y0~~vW]]ZGmY0Y)2FvlCGHr1?i(#pIppYje+JMV.s[m`;#x,~vFVjwy:,^njEkv]H3|J!]^WMu!/c;Zw`|#l8=wLO),knZT;ren48j.;>f)m~1KrXXWJb<+5!CwTV]7s<9>yq%fCZ,`DDcaE3+H:9f5;;YA=%"/q#;83$a6V4$@[hi=ZA^|9+#b#U+h?DCA7zM*J_0YshQCA"/*k(7ldzSc}uX)Y|R<GmGU2r_{LbRw{e9U_4HmE+KxH|B<c4R(a:A)oYq|ZotJ,oJxTTtz^c)Dz]T>^TavWGjOOl0Ilh}f)ncT;tj%BLg^79/z8g,,*AOe@3i9xljX|2P0a9T5F)DCn@`Qk9QK,{3Mnh4M*?xyJ76o/t?IC;e}Y)2CptI!.0J%?BUZqCAC)uj_kN%B3lIyLKU}jhpZjdOk?EIl)Czuc`X|`//Y&$V}W{PY81g$f5I(_yX?*iC(Wd4s(}hUC>h{G:Ijm<FfUeyuL=;J{@n^}LT+)Fn3pV{t[@gT}nAL|Xce*R{@%"0q{oOv%@>VY01Ix%p8Y7Cy[PF604++dyHnS_l_L=O?}QGomed{Sd%Eq008JOl0IE>COL)GOtxR_|hu|=2v1:Po|NnZ0smrUOHFg[kv^**GnL.I>^EYNum_p<6Bcx$,KQn&ttd!df/;,|*0jKAot(&FKa(+0[,YPQB@kpTg50Pvr=yc:`0mHXB^yTAo}Ui8sb"sZ:FY#q@n|/lP?xNptu+mou4|n7to*)&S*+u_k5<NQW&SQ1{qXMmZ^^W26A@1LZLRHGr)JVPEk]I!&2Po|;kBL%3~To>]4C^Ec+1o/q8qwTrngTL1+t<d9B|~TV.jW*BF,=`U1D@NEV^oz?*;pBnBlZZl!Psa?y4miUnV@(o?}*n$u7e.igd_FITQj*/[,:yBcYZbhm1OhB8H/`TEk"wNR<]d,M7Z?A{_jHNMDo0af/Im0D=e[tPq~Y(OzO).X8{k&E41x$`}k|cU4wsmmNaS7[0&+u>g|w6Uv7wObjIk,B~in^k)HV?o^Vn2$0B`$@3J;@e@tHlbq1*/LP)Tx~>YQ0@xq%NhGZq_JSkUa7p*>hoGTtV1=iKHK_K[57$3ob$ZC3^9]j2026}=KNm?V{^@~GLRdGI*/c*B}[UJYippBs!=(tC:@$zdiE7E!bCjRfb;d=02D*&5)1<{1OB*sEr{:W!4gc++E^>8>IUr5vK:]1h)XUK,83S3AJ).VSZz*:Q_.][vC@=[TQ_Fz`=tDb@p"nt28_dQXW9Hb|!4:X,H@YT,FlJh^9pXU{*H/3DHW)li6V9=~QXe1hqD=V3$z8L@_H<Y6[(h[_MX&pp=EhloZ7vprkcwr>PVWnEkYL_Gp?CQhiwl7gmx[W.mQd%#KDV?pQ_GkDp/a21SvBPRcWW/mUsWPDeed;(cvMb%!5fgRS>zPtMP.ZFYfx.TG~zm}Y[l(FKClh}Fi5C7[2=F+~7T@5AB#R62yw*OAi&tTX1zH=7d%l5d_qb9^drVvw.c;V8l;L_s^jE5G3eV+muG8N+Nc;)|9z4JBlKnLoFZINoZ71rl0E]_Psny`=[`YrmN:n,G(5u.;v^a]_d@F15oI=~2yn>K}|n3c~&$k>+G!X>[)m>CpUdj3zc(9=eQiq@Bpz(TmW@v^xG:2+/Q#N+SUBUwF_6!IP{btZDU8lk6h9LX;m)o?uG>c1tS^NAhEffsAq;|a=]P]qZ=)Os8Vmm4vovA1@Y;FkWs24A?dJfov/"reV_XEQPh#B>!9V^sX;D3b!Utpj_|~qLa"21lDY>D[k&$)*C)gg8F{YfEbejjgxl~s6fB$yz}Hx&*x74_uzW|9F*Q!L&T8qY;9PX#mEPp#fnzxd6FlJi1$hK/KFH_=:yVqr]B|8du_&,c8*V<1;JrABC/wxc))`c18gi#0:YH|Vaiey7`k~5*tLVu7nq,WkHh[7>=S7:>1)s(cRJ)L,@1wrrc7PGb)3j;3ZFzz~5]]3eb{:`+7=fn2Hk[${lSVeizI_O$=AlrZzdagwHtB)A),%=p6d@EPe6TL0!#{(5d|8hV;A%IpSzQ`s)bwc]SiRY<8bLfT(7xNFIMg(:I_qx%()?=9`T*5[^Y3n*u_v`MAQM8^Ifyn_pWCUw}duz#S]6}UW~k_B&1,5T@6)_TZsH`6Ng.aj6yE*7;5O}h$z<t&Q,{`Ku0y&1R;#h}7e1ZyxYpO?(0M_k$q},j^EJcWVX!p?/B%_Cj3"C1fN<9Eu;o{X[?R1rIo3+56WnE47<PqiU#|FF%gI<.brTE<KuT@tG_nz7DpNSv|c6wF=zb7&1R6eF8Fr^FQeI=EF^BGckTEj!E7m)zD^gdGl%y3_[T)^>6yC@5&r`lO5xNA!=WXB}M9dm2XSe`:?4+g"uIW#GnmIag!h_NO*y+R~u}T^>LJ0^7F$i*}a+*X/uI%s8[!%*T6bUL.dINgw&u~I~f2*5wHH(~z]V5oKHJd?$^71T?LNQdsy3yQd1.G*W91lpX}i40sHO[%DmWr]m/)U,CVz[Sm%ag>$CFuhikw0c,iq4U/6dw:K;.79^DIjpMT_%jgw&+UZ$K<j}#M!~cj7,rB:Kz#iTy_hUKHGpC]`/8<xjy{X>?eV)##2cKJhT&^m|&._.SyaPtgmlZn7DJZ7cP06oiqP?;o4LK03]wD&MS"i9eo9EU"VL@jCr*B4Uo:/sLr{CAl$lXzR+B2A&D%Xl_e:$mT*=vB^sy+[}jXjX=kHIWbNz3@dOG/N085KMY^tEa4t}Xy`WM_Yh?H"_^f#qE0I^n<I`L694ia@;,QCEIpZa])6y{MY*g}rTXl%rTsOgpQK.A0=+4Iouyg[h@{)T+J$B7RHz*KC.c!^_slyH1xr=&e(AEwLXy}C:6wrKGt+P/!V"ft(b`{R4:a|T?A;V_X*6p&&8ET_W{jQ3FK;easN^A7tL0U6tNZ,:T+!H.iEI:~a>p1.X@O^:7w{nYB.}yX4P]AmaBU!a*}|fc8k/h=BX"W(GFu{;3zW;b_)qLd7LCN*K42mv]TmW<TNC|xjLx%VPS~;7#aFP^+>d?<uwHg81Z[2=wt*NH`/BQ%ic3LA<yfFzBN*s;,G]7AV0uG%,f?::OdV&RiOXwvzT:tB+mw(/398QKY/0_(VrRoKb|^f*#UaWydrW]*efT<FSmS;h*X_*&7ei7e:>o}"F%lrV0=aI=AD+E<M+qJEK_UlkmQh=NN9RZmdUDTWrV&"*aN`h%JelZqM1?7`Z8U7cAg[;aKz7Z5Ac|Qj/+j4X3,(?*1nPR1b~Tdy?*,}&#=^$zce(M*xM&11XbkQL3=*@wK+zHg:&&Ce")uyJwAI;x<xw{s@}RdI}*FyK!G[:0"[?KqR20js3kKv!1T#ty!whT)`[fKLZ9p<WY..8{@W^s:%[o7*AuABepe<^fDt^j>/dce**Iu&Eut)sd.*WRB+<[T,,.5}^nva{PQ%5X}0xEM(}q((Jh$s8qCP*+P/&,qHmE,a^B+v~|zGnI%xBBqarU4Aw?])^jK%2Fi7+<I7%H}ZscCjg"Ti+rRj2H7[~IgvfS`1+*ME#gRv./KPB+si"aY94Mp8A(3o(H"qRX2]Jt%rYe+1e~R^Y}e:wnL%^0"8h}RYL8&@8:6GCmFMd|:9;R!E,|$W8U*o$qzkMPXrRHRlbfz{IZDFl4,h7K0>c2IbBtReD9J9`vit4iSnzx9o*NfJf:x$hj7Jk(A6<=lIOW~b8S:iP~LrlzXB)k4$TNv!dsfzX;aBn{;Lz{VhnHRJ_egoS!iML%c~Ui4"}P,<~w|567YJ<wIY[/9Gp8rrrl)<]Ykvyp$Pw;7!qgMq1wwl4!$9pBT7Kl|T%ykPZh1M_|LxVgY&&V97d3.tpf|]2Jeq$it+pB,GLv?Mo|1)yoj>oNP7qpP.)g0hv~8j>m(<ktUFs|*aampcu<c";?t&*I,Ap1xmImP.Y[@Gxf=WOEWNjEG<RImV!:BPs({u%"B,UYUl(4]?FsC{?RsFnbEcx`<BviC5WsFXXNJ3+P7YZ.8m#oZY*8a:gFwb9=$I`@18]l^^d`%g}i+IoXF<g/)D%%=MPn]m#WIhSfhH=FwI%[aD$QMmuMkY4LMZHmeU@INuVqd^+hc}~Dhd.nW?cb<81e)~g]I83R}fuyU:SmGvUIOTQgE}.P{,rqUBpj5H@$MH{a#PCazKZ1|2ws3BPZ@!##v5?$Y6xU+of*smdmW8Bp7++`f[`xr_+E&"gA%!7~J8Kq1}/MYt<AKK?%6NV6Z_0/d2@^8UPwTgt)te~"2m^E"T_<zO:kM<l&pJ_7m$^F=ONsX@/z{kDe$,W[]&:Sso>XP_J=v)lHP<TtSLitfFxEQ#5r#VAln$$JBMv(QZ{Cjg<`q>4rCjO<RT}k:j1v{RcjFfVVW?yQl6#h.1K}rX%l|tM_5:"#S{@q|kb,PITM*Vc=#wKU3&uW0FM~)k58X]]:^x;;6#U(*nT!yPw+oIWvHf)+Jdl.+*aF8k^v$nIjdZJ&?0TYM"O%?d$05JeA"!^YzHx/>$js{*bI1e~8!ci]9GMcfj_Du7IeDC>4_9b#h;~[".?RIB5kG6c&]1F*4WJe><O7^@pAnwrlgT37@U)@Fx:;0;h8LP5zO:o=c!Og.R/b8O2*ZpfxzGo542z|rGY1)mBj$KiCma>eIsi,|]k4F;gWbx*XP^!_nnEbPV`=e>pj]1a/:$7hQ5Cd"M~n&60D@*R1lJJb=2qaSEeewVRjq_NYkq(a2TS;77MFx4LX#p5%dDJ<*avFR,W*VpXl?L/A8vKEOdG]BQxFmc<#nGmB4uekQQ*<dR#x%c1&C_5k:PVt_j[*jT*ztZ/.7~>(:h/rFy(P}I6f_`fvfF.IBD1i"@Q}yO3RhIRDdC:>soB#$aE2q#qenOGb`ClESZUVfjQ~|*VC!w6~HbR:$.)`}=R5>gov4E6+<Fg6(#iZS#FN>HG))0kKz|il/FX~Ud8zr=,Z{Yp0m:_`,qLEVyQJqiV]y:1{<apD]q>DH^g)*OXv7+ZT#s)1#wK49x)gxU:Q]$fZ0%mDVbq$Z{g8zH<ZN.{)S.oip~GiTN#*Nzf7Np=W"o=1DPw^.C<OL26^U/#/=}iCfWPO;<2Jz)"TXU3jGnk0`uB!Vg6xS)|AYU/Hnbl~cl/%FLZ?xd&ft3b,l)G^Ecfr>Zd~:dE_*h2)NqJ*k=O7owHGo}h&G2.4x+lB!grPgU=:H|g0I9~pci?f}H%q9mp~$M!sfg7y)EXIkiof7nRaeLaMn:0%!|UVDxQ<aTdD(keGL*pQlGOTAvTR*#JK0;zsYz6y[ZQ<qu=ZMU=mg{D/voL(fX6W8ob3lzb&"p"w9@Q~V&yQD,yM{9Xu1OyvV"4b{%QE)+3la@jcFh:D%?Ak4;jxpZgj"y[_H)x?2mzjmOKDz8QAd@)5]oz*`QF(]pcJ0!>|SD:Mg>"h({<w]c{L+yCL+(Lh0]<Lr2;s&ibj=}NX2ZRcOBCPiI!PJf8pE0P89ctGE=P)i}|7c3155Ue0.5|Ld`~%Hf*Se;cYvdTm&%}Vkm{bUDX2K90Jc6RTO(9;t/9}u?n%ZI+."yB=#ESC"Pz}$k]quI2iMQuYG;;@Sni.FcMfOYq>$t=PRR}D9>vLO4)FOM9Nj}PoMneK<w%0kg"do+s2w^t*}NhYII5n7_zP{CKpK~k+Sl8vGyM>+MvP*xM>X(r_lKquqXOn^iA9VnU]x%Kexc1wN/~uA{G&N/[V,M[IGbeugX}s4%wq&J#y2{:cI]GO&{$7;Nvf[4zvBfs|0`U;W2R$}g~HP9"u1(ud*p]g@I*fQ</t;!.C[8f/AC:G0.o5!eCC~C}|`msS%$5~(UOs.[ty:H2wwDobq7d*^)oFrT&+<NF"B|cxk~5DJD0v<#9M"0"KL;Tv:g2L^a.X/oBn>PC^4.]Gw*ee12Xfznl7hxlE9Tyc|Q<)f,*nPDr0gh3s]Vk7t8zGzJ8e}}Czg551ThtA"{88~_6A~G=S2e%JHa<9cp)W1?FV2>F=G?N#E"Gmd1fCa!fov&:A&WYSULNuTO$VSpbNFGJsb;rCcFcl.3}o&w>4iDPu_MZ~j$K&|oIZSiC>]`HrPmlQO.]wYX0nw<!0^BrYfK+Aa[o;;,f=h9ILlv3&He}h/V^Wb{kz{$8|@{Vx/"+GD{f=bIF2r*[OO1{NTHT}3gs8k8rX[yVj,!_1dS}]%Un/HcUK&$:e3=@tV4LYPG"_Cfk78bx.Pipu1VkAj9de`"uZ[G#m6_.420JDDs(vqUb1TyC1jn~a|5T#{09;*[k7x?Emkw!Z2P.JvnkBFz8*=vx9Jz{e3cjckUUx034k<t5fOZ,PybMV7/<>[4Gr.i<7puL1J6%H+MJ[g{LL0ycP3|s<69pgsH*j+bp543LwClhK9%$)$[aKs9)qC3<mU*8>VYiJ?^9Vo?wB&%d9NGg8;tQ:*x)|)Cqh|@8^.Z?l>,iU%u5%ud#PJw9{6Xs~c(Qp7bekt=:zODZf$,ZZ?kBY_yfp#O@bNaC%:s`|=V3;,CkmXw@MX8$xvZ<I"y<*%qSOZ|gf,#rX!3<$Nf7t#8!$;vGjeZ<hbV`y;zeqeE4vP57>yNt`z/=/}3agn{ia!Zz5s*0T6@@7e4|#ad`cLz1Gl=#!Esw$8JTP1hbT$Fx_`AuUd(O@Q|zLRb=4^!U7}/AGi^=h6ba?nUJ9}YyU3:U8{*_r!U28<I<)3En+!<qy9%5lIz7>W:ss(:uXJ[BRN[iw;>0a@<z>RysymxWWukAm7JtA??:i++!N8jcXwM/UYMO?g*xbZ6@F7!?g>^ro)xvRkIXk3TS%sph~1/=CUv7#wzUZm;,4XNd9DQcw$g;]^$`ne86s/JsB`9$)"]*{Rq$k0RNYBWZ2,d(9y"jJTpM",/N[qM.!iw?X</frjasw?rPiTfYB[`]LfMn`q*PCZR+Q5[WP:Xi+<;BEPd;gRt2u6xxrPh&@cxw>4%GGf7#o/*B*0`NEwiu}%TAX)Ro/n.%25<6tiYyYh5qvVjdCxkUhI;CWPJDCZ}xV1yt;WWrLXru*0`k+}fg~Ik1JOw~x9)jP{X89x8JbE8FMtYl#Q+Pd6aSA:(,`wo^9/nvCG>7]9[l8C?oIW>1QKz&]G0m)S"9p6^^OH0"zc;]*+^n,Yf[8g=(NdXST1N!)*iSAh0;uv~CbDWM$nZj@*BWY6UMhQH*HCTU9uzg,2/?9<cX7fD{v>]..{j[}mqRMW)da`TkY.!|;=.2=HeI;j;=SJ<1O[lKE9MVRzG*rmy>Roy?xp*/Eu%_2tC`KtxMLNPc<@?6C"+!UFe@$)DRP>7`73975j1,S,QC*P4F:YRk;^8>5m8yo?D+`|2OWTn,:qj~t[~igw*$wTVp!b2q?o7Ka`H4b0!mkF8xW>y%em4sL@?IfeHf:ncsHI*zm=!w^CRIVGzSA=Fx<"I[u_l2r6qTTaq.FgM"n;W`TcTaT_QItpDVl9*A8PhaS0t+/_c</e^v+3jjd/n*u9+)H`JoUt*6MtEr/_T.DTK~e`(64v.v>&]Z`)49g}Us(KbL}=uvx_L.0m8G[&XZ$vEsw5UEE!VVd5nCGub@bdtr#@POS)a&LVng/#=I=.YX;1~H!h]x,=cx^Ctzin?2PCM2Zc.WDw^T4hPXk=.8.6aizAm8S"}8OYGE>R}dx3)KQy~Al5(2JdguxdocRR2xW7+PDhis`y<$~.NOD6|yM=WPl@~C.IET<8v*LX]=1}f#Sz}_y]mgn|4Roa~LeyU3)9;A_Tw0=2@$l67Wfd+Kf*yk~Dd7(&X}m2l`q1BgTd!M;?D9[}I8]c2iEFv#claa2&#OP?Aq{n.Df"4."M^tp7SdGCVuJ8B^HqShs@(7Ws)?o)M$gwC[xpzZ/GI+I?,_&_?&]7fu`U]=2Du>?EmXui.q@Sc;KZVibJym}1|]};Y?D.aZEi?=C<>Cq$Nv`r3v#!JYQ@R>G*:J:ruf)3ST~Hv#ScTB)[!no"rLncMlM4Pya8&oUaJ|a&BaNv.CPD]=gG[Im!zD4ed+QU[>rHt%JrL,XT}f3DWszBzw_G"fRfSko`3V)[+9[yF{xel^Y(ue|+;mW3k%yCs<E,L>?TQZr&Nhw>P{D*p_BMS5+Fe76HTL0bG)Wa|CKi*sG4T(Wi`xk&5dVNUZOi^}v.A^T,h_c:INvQe|iiL8nZ5E/G?=Z$csJ`~]g11+fl&#J|KuzGe?}^/X1dSL0]cK.V~W(eF:+![JHc$CLr3i2W@",208N,yZo6gnGcX$r,%Twm[=.o@Jdw_T84Mgy{dUK({CJ=//wV71E`>Pxc2,:yNmH;}:Vgu@7VKiV"]vwQG=C(0kfDIF=(LtQt;]Sg}u,o2`VlApm2AL{k:23VH?F75`LHaBG"{YS`ugshv01JB8Od%!U623jls},~.:>Be#`,&/oPigUz?xBzeK4ae!eL&{|O0Jc:^]y#b|kmC4_b{(3/ptnV`4KoVeqML.i9a)p0viUNv+^{*iqgdMQ~$oeqmuzxs{}dCZ12:=G`[f:vXX$).J}<2ix8vfz{e*|f9D=+Sq(X3)(0F5!gdUTH^6j;(xOy6:s^r[S+2!;TIy7&xq5`s+&#{#ktzK]JeW@W5p@b23h;fY<}L,1wL/ReDmthv]/+R"cL!f~2QCX,Z5udG.7@n[BQeJdeIC6Y@t|.pNvst+q,Rqw==]GG9JaC}%7>>6bGXd:._:w=DW?e/L8x"C&7d7JBN]t+Qhc$)S5.L,Hq9G.d*$y`<q[I.^`?nZ.|,4`"z">th0.AKvGMgZ*i;$t`7(DeQGdVL$nlE_@XFfmj/,8CfWm)YFUrG;o|f0YlrO48eR]T!:^C5,=yM)^d0_9Xd1`Dpt5o0dB/2($xFpV41EE~X[,"ak+eISA(bOokj8l=@q>J?ob_n.btaameHdT=x|^hR{65j@)@mU2)*5S*439<$`H9Y))?(l[:G+5=ob]q:g.~]Px,OarOo)<zjj1Al|{%GI3/y|2WYB,3T{x}~]$$aVmjg@GG}D1+1nTx6IDUNtXr|)=>4kD9`)N&q(sA9$eKmVit1Sep82(L*40?8[:UVBzw2%vv;xMgI|z|nc#22Q_O^lvU~DXjqo~Ji.YMxsh$M&*48/fDbz/m/2_2Zsw4VU>[?<Tk2M06VGOG)VI^LMa5YJqajweQe^SW5!jCtVT|W*Cd.E0NQh,=|7*TS)0Ew_%rZ=gks6eWek$3X}0*6/#n|XH"4bgIbt;Q61}TQ=O5Qr~XZDpk:rfHGK;{:^/ef)ci8M@ZYr=N!CLDYeUM{`D<_;HYQ[`q|IHV!+uqE1(P+^a_]F?a!xOMPtohfpL/m:G`GeWUuEq:hkdX9bY:1_9v#h:5R9mPxr(7$V*=iy7Y4}"NX/v2"+^VhdQ<r8a<VGp}*nMsX@0[{%_ToN|tqj6V/!pvH(B?JN7mlSfhWa:6p>efC?DTz}.[WRzJvCR*2d@LvJ9bz9t3J%sW=*mscGJ0$y:/uK`O_[Ze?X)g$W4wF^km=?.h9i[6yr`^ZVx5N{KhQC`o2~XfT4m]w*BjX$vi0L19nIz}h/UhPk<aA^;.Q<e88&%uJ0+C5V:4b~$4!cCilGdfyru}AY<<e2}{_hY+.ca?f!+.fO:[!R0QzCI}P61FN6X;X9oh/iZF?WdL/i[*@Q=v*o(]RE;@lu)H"l*$Q,g7bV`q4h2{|o`1k[gb?pvKU?E*V(|9m/TOWb)7MIcP;@F1dGZ?a?`~9U}$1t/e}33gMql&NAY@}]w~~L4uL]13Gb[m|V9A"z]o>{$OmcP8WlQ]Gm}>Q|9.f[R/7a$zhWIuGWL42po?XE#@&RHSYewO19Wto$x+fe:/@W3Etxo92Z{RNB9r%@^%{s1cUG/JqmBvs~)$;L}RoB^6aR@!gfB{0/vj?A?7f|H`~a/Rz*)rrE@!m%1uZ,($Vesep#a5[q(n6n8W),!w.K^CvBFyJ_`r"8IDp"x+q8f`557}2VI8#U5UNLZo/p%#{w$,c+bCHfZMapNL%=7i;Epb:I"U}mM]>k`pYy{h{1#(/cC}suZf$>S^jC,TVGUv~g/J0Obl1"lteS,QlGu{&^]d2O+;Cl3(46qt.f32(0x4tyvM/=ZQ+{=rIeHDrweJ%V(PbPp3do90X([O>}v[o]/Lzc;B_n=)q_+@VrDW$jY2ACOKP0l8sU,iLdkkY!Em*:ia+t)p*ygEBlyE8Zb1xEP6^ngoV9"8NWoMO"HU<O/7HF{]#Wwge:S/EjkX<Eio"+_;<yU`+$/}_Eau^<e270c)tcHu0alt03KBD5G<3]UhMhIIOmgLGCN7o,|VYN_u>EoV="lPFF+#XCSTka<Xp^PG"zm~oa0$ro"GM#@$<m.o*K3TZb!J&6:+0@?Ve,^bhQxw+<R1~w1bmPb?WGJ#{t;0DN5K&lrhDSq6:}f&!Ba[oosmwmlI:(qDttTDzgWmSMv4cRJBA;v6z:3Fup_S$sK&fLTaa[^2jtF)vS3&rR;RXE9p@lU!r}>goa&#cv]A#<Hv$&S@oIY/rkY7,3Du0+IfY<D@6z[pP~Wwkne2?/Ko%r?Du*w>v0gsptg</V[q=V_Uc1,#lhVUXl<Y[7Q]^h,N[|0Xc4w_^D`h$[<#5:a>v$F>1S<[!>3yiz4NAP,eThESp]gKEnsyk>)Ir7`q1lwNb%?.^<^]gF!lHje&U".y*tshKR7N<DAiqzO|+.gq);a>4[=F/xu}sj.FPPIX=lo_?%)N~heY=Ec`2o14vzv"T0NR*y2+}7rbS5ilZE?73Ie~:)f1)i3{1aN`v.)zDG}RG]W[d#SYfIwmZzTZQr5;.f(]w=9k_,%{L#JU9J.<O^f0d.HKXmF9rn&lP]j=vU5t6OkNRG]x3B&nXrci|m&v_4!$+nnV?$o1uH53:McqC@J^^Gwlb8){xsQYgY+3H3>p.yQvBt.Lbi&o$#sO{P[P~X[`@}ff"0$Lw&%<m;F|XG,Z/XEmI>kjY^`#hS5o98+RB}W:Pgq$T<HW;l|T`tB(uf4$5^y6x?(AX2]PBGh]P{qIWz%nC*20iuT/^mSV;YbuvOE|R"oDs(txlVJ^6:;}V4D/<:^CQ;PRb,RI5>9qnWL6@in;.BApqDcomW[>ayc+!mpKtrH;fc6dsnZ8xub$9f$AD&CA*M}IglZQQD{gYOzJLz2rnt:jOI7z+c3X&v$Bf*Tgw6($GgwmIPLb~?*r?_uqk+]9ZvU}fnFF[=Gyk!NEC(#z?VL*#(be4^*Vt9&U][F?G(P3iGJ$uTh*&xWN*<34G#YN(1p+x?b*YqTp6?R};*NmG3|I?)AJU13jho(+>+_RnPPWEf(P3%/6[([L.Gg|3aAxkLY2_i`JVO1!{ev_Nd@QZ.F<woJ*jpr:D?h/&rhkIkVCj$X"&C%95Lxx<R2<|Ra@N~ku`P.jQy=gG3!^gL#,!0#SWpi%=Xz9jp5kh=.FDVGvw(OG}V`@gtQ!vTddiXGt;.o;^}+AJ8rQJIT1rYbW)cB!K3BO??l3g2zJQ=wCX[th</h7Q~H4f,RLk(r8PN}_u`W)KD9*i,QM2E`$a}ImVT:?v}Iq_wrI7ZR!FBk~5bYtY@ac_oT6}(_FoD`2v{38{S]eRLZ)}.F;vm<$;|eOr33Je?$(WVw#}7z_!aeT0P*sVm+s;I$EpiOP9r_f$"09p6LquPnJQk=StJY(M]<N+pBs?C`3]hj:ncnr+S@[=V<|$+OW<CR_fMcL4::]IsNEx=4i3^ur:KxLvO},pY).oy`RsYY@5V9V(![P?,2J[`u$n4HCwjU8fGHLGa">8<fdk%AQDHMjI?/m`p?Eev[VW[q04KS$$AO.+,7c%(TPdqO8Em);k}:V(]id)876>9w%XD{5mp%|eX(wBvc!+3~KZ/0a!c.}5&5wE(w8|q8}Xttq8|1/{EH3]?cYC^ZCR#>|w]@V,|WJVNJw0q9>+r)7;_(p?j&Lipr,c?rjX%||P~H2u9u1N3rM"Lec}cuQ@EnLVit_tcN"|eUJ`0_>[hYc83?^C8$&je~K=#I0zDKTHVZ$Y|a;j:F>nCh7GsQ#iFi_uksru{#^U?WR}oL$uzpW$#k&e~E:1>.>Hh[@D0/`v6@$rf28Z&?&0>.(I,Jsb1+=N5gw3Y@7xUr.JCEt7t57PfY{H4D.iFe=Fwfv/?Ih]IojS`c{w8zaeqGc>cJ&D)+m<)tzS3fm3AP};Tf]ncc&v{X+>eSdN69IN"j$6%N:ZJzQno0ZN(%~>,"tc9n,5!:)S_aab454kf?TSwWH{roie?)qSos|b_QKa*{YwW@%&>gnQ0u:y1q,t,Q`^$|1Q/nU&/F{ISQ+L7r0hO@JDrY]C{?$/9%8a0h;1B&^LtRu0i~+/D<5u3RPE*zYsmo0^g|oPv6wlZxxroL{r1fFR3iQMn0E,kw%w!:MC{U(YS%4g_?]@b>$G"Yjy=RIiO8QrV%sh:aVZYmu_]>u4?C1,uS7v|A[|!+kX+6r`mu9F(Yobk,7YHB!O%B(Wonh+oPRgj%8B8`cP&P]lHwPN8/uz+9i`@#`$lZ*9r>BRCr=9[^yzJRY~9@n*N4Ew;%C[P8>euC)$1G~<Zy93SG;2[@iyw/P4.j+8BGS_Skx!_ONxr1@N/s8D{&R;rx_{o?y|>[5,qH:m|}C[yE&x.+`*B0W,P~XDV{PrHo$+l.tJeys*k+vEJXSkvTMVpISM+ykz?`5D9N!_3X92_0jk4Qh/`,W*c5r&kXspjG#_QVdWYl`Dj,+t>m2E9qfb,|2s]}G|kY,liM&a)>cN<O~qY)sQ_ht"6]zmL%@%`^wxll9e8%9bA.gqY*j"<k?l}VR*/Pq>PZLx0mHYR*~w%jSPt6bG$zl#.5oX48L2_tWZOVfRHerJc!*GA(fRy/F%lwlXo+wI<E}INV1.z&etXJ}SxV#xRn/BX&]igxU&BD~ug.Y>$Revyg;Zxu]@fR1T<"x9!&Jipz@S4Vy]xwK96j&I6x7c>j5]@eTfb$DP{}v*W&d[=k7TP,c(F9_s?q,C"e`fSV+[[Q^<F#:+9P3X.%IoG#MK.|cc:CNS2(>Koo8Z.,m(t{N8/52&S8ay8:@q*GJoq3<)M^nv5]4G39!WgB>cevQ8Hj$8zs]yK]iIBnvhsx*n41+RdJz5O=,%n&8KjvaGdLXY4{(g;*^po+S`!_2hGBAhQD>fArRe:ZeBc=09r5g5|MZZ&W$J19qXk6[X#ZUK0T9(K.Bm/,qV&`E&VG~EV5*<[}X=gzCB`o4ud5~PRdY4NRb3Opv)F!H"ssU{?]O!3/]3D[JPm@jex=+86s35f)Ni|`o?u>MZtGUU>q0noo||WWdfADMy.Y"rFtpw)=>]VKu1NCr12|A(w(;(x;W9>/e/2x(,4;z~?mh5`&2gX%%o#yecez;XOxBjJJa9637RLY2BG.XwY6(R=Y(=ANLd&5:_BpOxs}^j6hkV)_yj]`5dE9em={_k)p.AKC=IN&gQbDe)#(i4i"6&xe`)(82!.q/y*DD^^d.8T>`)[<P[9gN_fL{>Np%`=M!gPauM%.mzg[pD=Mk2*#LZi.+Mx]Isq?+2?yoJ/eY(J9V;Dd3PTa<TUuUvLu~()}:U#ka}}]e8c_2Dk5c|1&P.#W}@U+3^1#xi3RpKn8!L_GL3,Q"aoomW""k?3qc]uQ{Q&H3UAV8sj61#D_JV5:5v71$QUc7h,tNr,5mRWQCp0Im$:#X54V<edW|]twoN[Q>_QbvHlSREUb:cE|)NUUxa,1frU`C0(+FjuF5=|lG]myoRPjb0i5#iE<9&mp&)egQ+_QBSD%O=!wS=Z/!L22J+"K~F$_7.7Z7u2%iENCu&7G*ywLof.t?a/,}H.5ZxQR0IaE|)FNaEkN#&pJ"Z<*sDg|{hUFjV7!J<X3OdsVF4qJx8T=(.0Yj}2EZY*"o;k<FfNv_yD9cMOu:SI^JM/k.gzT3/2u:QcojI%K%;w9bHexNr[KQa;Q%RiwCi5@%kC!(q*U4}qDrvzpQf(gSScx*49&`2tXJYSw3L|fHGx?3(y|{QVWvRCew`_(Uo&w$<;UUZ"JZxdpVXNiK4QH4L%Pa)0)$<,z4}Vtcvo,AQux%QKj,H~!_I}){80$Psj<Dgg!BaB$^l.|DsPK3]baX}M0Gz&fA/b{pvc&_(Xl!5UM[Sq^Hr[{0N2I0^z>yraz7Vv2{dn}O$Znz)/pz>_%j~eIq1aL{twMgMUU5>qMooRPQ$LYF}[MN`PV==vS6YOFHb{&Zisz<)T8swAUEyD:)?EwNT@oH,Vp1TA%@BZx.{LY2<ZmwFflXsPbm/2]$7y>rJQaXnU5g#[Rp`93?D1v|*=`$&}OpyT<zP&eVv~Ed/.Nx<|rjRWQNzse603TYOf8YTjO11fxyY`9BiL=4L1XeOEwiC$rVO1qui3o@X?;.14I/8U6vhwF"kh@hNRUjn3JffWVjN]7FT@QfRZrUIKBsgU,>>78wg{j/_+ykIrD9ZdB(@_>>^T>FCg*;]xjhd1#QGCL|Te9o4%h@rMu0gKKMg7Um[7{,NNq%e>qHkEQ4n4U1F2`46PVdCyLa+Uwd)Yv#GS%8^Zj#YC|1jU8|[s6Q:x8pm5_(|^t)4Bi)EE@5[hk5g*LeSocWQ37;4u9TVZv<4aF#MP>yBgam/{T&w/%qVH|Bz`0avSYUNS1QRSj0*:c21o?,Js>BM?csYh5rOG8Q4&M?8^RkL}nW(FT*5d[5SJX#V(y,ZJBGsOQ^1FQ@ftjUUI1z.?|]6MwA&i6rHv"d4XUEYy5.a{B@<"q#5<Z3geE>|%Jg<6zDGl3kaR*+HX!rV)Exq6}Sa=a7BAf5L?gR^J/5k64Ej<bPn(rtM+wuXY*wI8O&I"GDQwMeOfq3+"/X>mU{;)H1Ec[#&F;<jAyB,+l*9MbUUSULxS]S:LK:ihxBQXwhr8yTw%DPE1?*K?fXT]}U.eCCyS2a`+&m@Pi>@M5g8N&+i;3(Yr^m/e{Qn=t6t]*&^:qua(PtQh6nh?K#*ai3IaE|)#1wIxP~jb;iEtQ?7"=Bs7GV.ua8P%[l<@7@tuyC4=[B{$8>`pxT^_dl"_+f[?N2y$,ZZ17utA;D5ApLhdyxjt?R%aC^XB]0!$n9I8Hq1q;">&24lR,G(e!^c_k$gta9!U^CwfZo5;_N:raeg#yz;0&41p%GT,6w/sYsK"w:6q+3(3#)2K=B5,A%)gOFRr4fqhmdkEMd3&edb,8S)};c<GA5Rc6p#WPQMi8Q,mZ@g!n#7v.+TlQ]P%oA*8M6$rg~0P:Kg.RiG}/OY4Z?R~741tFSJZ)@oSTAn1T141^6<h@P<rSSHvNHwg"ViH5]NiLw%}EqHu%yn&YQsLOt2k?uCdPBz&DwCCUfHf&=;?]o{lJNV!WGi$#nP^k/995n>x/ikhL{1D:46,?q8Y3c5m^s360yi1>6.zZ)/OY<pRHF5{`$M0#Y:pcc5l%UK5lEQ*;3j}|JE^YyBbbx4F1L$"u{oPHog,y0u7/46$ktnf7Q0Lp<Im4v64a%z{T#naQFGJwM*pv.t|c0C0N&/g#0v!JW)u,}wy6JYibO/:[$$fI$joS=)%m0ai,d52@[<6.h9R$"I1kDwV$1jQoaXDNKGS/X90S1,|Ka3x@Jpg<)D&n#7jvT%HRr%]G^*T{};D.8U^i(_:H_^2>Rw_u+3t}>OsJ=he@ZJ6&{[R!eWQ?Zs~=M#R+*ZQ#J0s}jz)SPLa$P#u]mYd~=xC]%U:YhaU1R;Lad37O;!t5RJj@@vS6v_uuYXwXvP#Xl!Jx.H8/]PM!UXbm*&)J{|Ls78/^5=0;]]P)xHNWd9e}29F&N^R%%Gx{t|FbKo"^=Ym#DfyY"?s=T:KKgw(eT(SY*vLq>I0YQFc]U!+(P2xGKF:!UdoUSaCjJ[QvhC~0[E`ejDb[;f|HKFG:DQ<5y/(&+%Pnz`lf@4;}sj}02w;5%R)Ea~55QTm$xutsKSRK=4_T^qdG{&u4T>mH8$3:rpDyz}bFSTDBqwKby}i1h&h,EmSuK+"&*tW~rNIRl?DsXSH.*P`Na~yr|tE.49rBZepR1`,]{3*6>)B0AwO~ioI]Aq*^ceDeop,ip,Y3^]^3+$OGP`MR,l@]^nLIWQ<VKqujr<nLY[h)3=#&A&B>Iv:BaozJ}/w:Y)WX`|8zqO;:,TwC{Wc~=4cVBQw1M~JX)|(BD]W1]WpZ=SaSg=Bh^[)aM_#iAl(_PEfM]Iz&!{_|JkR)0%$c#]|KIP;[NIloc2Drg)I_G$N/&G9SlNTU|*"m0r"+o^1i>7Np)l+YIZXt[)HR/?9B>?g&z.tRG[glqLQY3SA*kgedPl,!32ZbP0!EyIcb*i86Pn{gOHflmvn6O}@+=_blSn1TFiJ#[@DJ5kHG~a1,Ao9U{I*YJMy51Ec*QfCC%00=9^&z@;ni7@]`$7$H9BO/0HZ%UQA2zxm0"Hh&N=wyGZc}WRqvo@GSTm,aEG%bW>)|Fjl#cCv&wDeRK!}[ta*c#]SZ3x%|7Np2B[rHE6z2Gaa2d9%_d#c@F5"z`0K)b:/#)@5YwIJI[PH]4)UX]C{[j+{]ryUD~3>;f~W0o^!;{0o9z}>y?{mI`KJ|k>bgjxu<W1_Q&Eh&8(r;E"x=,l57fy:,BvVDgK#oPG?)aiO!N@f6*=~,J)|y9oFUmyHc:1XZcJ,%@x"oHc6[i5Ukf3h70+gYv4Y=Kh~vVs6(:=tx7"q=5=MWeHGX.l(;o$!f"=2eTQ|E%X{&|.2/)8V0>wOnC:AU5EkSk<9Zjd1+J|&bN.p;~r^i8d_[wCUJMEC]74CZpKbKbTHbC]nCmh_+51^Zx4Y>h;q%ECaenv%8c__fiq<wn8U9KeZP%Xw0Ls$B_`B40Nfl~_%G$S5/Z7{$x*LOgc%q(aAkvjEaAS0/.YJ<Rl0D&JJ)DK$4<4ci$4dT$Y?nF{8QeVk0I]"Px7V7I54cKM&Is:Aw<,HU$PvBlq4!aemy.vlsw:;7i{6LrSWHC:a^UvlP/`R7,QLnj~N_9j+(u&|x4CLdfSHEaXc9$0o,L?Py8kNW/uFd@p]C4LYko8|Rt4k+f_|)rJK(W+idA)*1z]%LI@BP_;lKwZu_gm)6>}:b>>&|>AS<@j?bS_b1q}1vb6]j_0~TfF!w5aN~"VdvKrb+Si}U|.19NCo6(.hu[+d^6Yw%E.`^6$mRgeAOY!d`V6K4K88o`0J)EKeo?w[cq3l2ro(mCyGNu2_Ty*GDlEeQy`d5*/DR1#%,JXciyLp9,y>n#MW),akfs*"+c6.dr),F"6g1+nPpO`+8MjuLNr.nO,5<v+Lx|m!;kFh)eg.9QV<Kx9g1lId=,#498|F!c{Q+X!h801dF!w4%Qu~kRMERNndrAb[Qt29+E|`QwtZg_TASf58^TBEli5&~c64JSw=1kl!/|/u)32c3"rwRQ{)0n`DNy=bQh7@P2s^tj`~Pfw+x@BNu_pAw7[79m5%J=Tg0cQ()gvF:?Rmjy4x$h9np`Y`:|@~(oSia9u@kC{b0hp`>(%9B)Up<!$"BN0Q:5)2JRTuI3qZc8e^*r,F{Y=]SsA{!KHLChdJ4Wb@QHUe1o&my*M/?&T"II9/wP6(s0S.P/fOdISG}bJ_,cU}O)/GZOSRbObW1O|3%@{:^n%>}wy59PK7U}R)cdQW3@pdQr<V+2/<*"=&k6xhIY!7XSt~enO4mbt@?VW7<^RP]T,rsQYs|G/P$h&QY%e!6LE=wrQ6Z(b3xPHJa$VTQV=>_wXOrW1OI4%p;W%$[*f;@Nbyht7`j/h1$ts&C?scTu$$/ns=@j*/:b>)`WM_bUl:@M4/nD7n27w,ncg01gwu#/lgT^jWu8,s`ul=^dKos"x*3EI&DqKL4Ydq1b4?rrh22@r{@=S[|KZJh=ju]tUN^)Y.,$?6nPz5$<R^!639J^7uRszyVnSB7S>fJ{ZqJByB+B@MuWHnl{@J)&nqdhJ/x`&%8|m=8OJfOsx]06YT>J0/uf2W30mZ7wxQe_.h13UtMrS;o|<c9cy,//Y`IQH%mwxM[ih(Qg*]R?S+D;5*=Eqg8GWXS!eS}S+h9m{5Q$PHNF|(x=#eW/d=pUo)(+1JW`#ap%/EZ9o;;CBpi(<l5_%mCm$FC])L@@="`*p?}4da/H=AD^l}*ul1?P]GNZvW@kNiD~:P<M4rE@@:1gI#BfYFs(`yOTL&L_Nj7qFQD,Ch!):2yV<c1"TaJ@lUz<fpk"DGjK@q?AU3FpyB{"ZlQpyy0D.{tKl#>n4#k3U7o3naQ+43YA9BGU?/[?.~tQ5?s[ni=ooGE`ls3Cav#6GOf:[0sZ]TXvUF0moESEpYO[n5@g;:f.l`IhPKo+kBG98MdQr8tL6~IGr)cuf(iF][Ek/+lQ!**6Xsx,x4J)6FjTP[2J^%|2m"TO>s2Hn9szvDw|g9tjO)6v6A:d=aYbJ%k_hxS3ZCGHnC|m9j9D>)?Y&~|35)eDM}gH+YG5I`K[o]/5&"r7y](N>&d;bEN71@%bcmOFUIXj@gUNYm{8|q9]9|pp8_V`pkfjKg75Wo}O10.7kDMV~N#+UqU}]aVxHBZvuJW}o?8[8>lH8%shyXJ(QQ|I[osjV"/h1f2/@BvF;H%qJ"p{JnXJUHXraT?IkyChcDaWg`4|~kXPK_DK[#d)ZPn"#n}R7_%5$`eRQ=uNnn$UX5TD(a*A(u#=]worVj9A?Kx(0RI~@EC/hgp=QQz?eZ%":X,";1&oBXls]5,2]Rtan4x0mCK)9x`R*!6"$thFkxc`.r,Q.//3vo6J+)%+1"gpHuW"%jcRf=O@,9U]?qf~THr@[ALiC%#n}3a(^*n3ZDzuob>C"@B8R"52^Ei^7>~@[RI2^<Kl:Yg*b2QI8BwX~DV7i/z+&.YrG}arGv;31@B0%#Kt#uqJ{[?(|3aGI<d:2NA0Y1N{YmFiG9N&#Jb_bQE&#RbjGkRRYqb^u4k1bE;f8$SQ)&TB`^KU)`81BkE>2/DdE}}1bE;Bm!!PzIG9fwAYiV9:"[nquJ*JmlhPDPzPvUS!YrP$!@?`2G8if,kkam@Xqq1=ZtS?GifRwNOe_(|[ht^+|d9}2WxgSDD["QcKXLe,e6xrKC"!.g7qfEiVxCZL41jso[rb6[ok1R0~?*THS9o7$y%zK"[Ua!tuV;Kh6,nhJ&/jFT$8[f%ivtgEV,JL)~M93_(D{=kX)?,o`6.]R%cVu{YbQkyt|5,24tM7196%Cszkp#yxlC|wq:/d$x#NN<l0x_]>lJ*/Y3]OlK2Ke=((xZ2!evmFH;SA(Q0S1iF62;/!c!t:J0l7Tg:TZ"nXma/)Jh8G(#2!e+g_lh9(%gS~TShgJq!#mgStSWjnh$}#WEaR2hen/%l6goCcj%kuU{V]2Im6g"wG1hCIP?l9N9H$;1b}[Z3W:>7}nH{"SanOM(R<4b6C+Nw"]z4DIa`O2Qspe2B#ou;KZhf%[^oxNN0c2sp3OYfDMJdW#]U"$@Bcps?nalj=0{0Krh$c11aCPDp1#>m?Yr}kXB@Nln!hu=pAKI|iyAOIoE%i|*Y#.7k%ei:#%;VC@][)Cv&1t5Y7K9[nqJyUf|`_6R;D4LJpzbj5Xy9lS<lNS~SF>)u_N0s+|U>OlZ%=,uXGos@]`ZB.@TMjS$e!6zKjS@p~gLJ0Z@My,R.xVdAc(moWh1G$?;,Pum}Ydxv#>5):;,ql2kcbhM[xO:;.gqpX&S,7z*TBrmJC{ti<`]a&Cd1`{G}mcS0_!Dd9,w_8RAZS(!J0/k9B6DOts?[P.9hWIs:ulZRG8~o^dq78xjFJ1)%nsra/;*YrG@a]R6Q$c2,u=8@iRsxK.kpt?a%u=j^QF<vPqlc=(W.XuI+lF@l[bt?cb;e(m0|M)H.i5ooH~G>4tkPw1pS,wWdOr{17o0,.N%K/,!vhI;aWmpK4g<9?N?rVShJ~pt,}Zj(f8ZK3;NW)AthJ]vWF:uGh${Qj`/(a6&d,w"/0|pz,@D(,x@BWJl%UAlf?g,[gGh<v7WY)AX(.V@Q%^b_[N,9Z+Tc=(s{,hi}u,ymia:v90RP#qCSAE~8/DGy/[Nr0^cx:}3NsGd9T~)@xOmKY:xZy&1FePgX#qOOdZ<FGyvg%,B}emYDw"k+fuKW=j!+D]&I_^=K<oiVY8~nS5M<oGjCJ8o=%x:MA}mPP}QG=wuyjhU?SRT:mPU)gi14dSED!)/#(%[@huGf5QFi<:mPKM6TbR[Q_(Ljm|"uhLd2xRcji~%;fMgq6SC"U)rewlD;"_i6h_=RmW,DZxNvlQIsSdPRCY4]Q;;jQxJM[K0vJ+4i|L:r!khafk1G*x_^4Ccg6Yk;G2PIRh:A[edg%j.kr.ksUu5,0N5,AR[a]Qq`3^P2#2Zf2TKF#uPe|bkZsEAO(|VV?`rLLRGd>gWdDAWe~FLDWRF=L+!!l<NH(|3Pk2%GF&D#/&J3;g#2SLZEZ8u1UaI1|Sk#17$C8>HQc@MR>3(8n*%r)gMZ@@>7yL:tcz9emF*!|l_(#8j0~l>W,8DP$eAhMI9363nfLj3x*w62if@%Tt/<D1RJv:q.xB3NM@x]iFqu;$:F/3cM8IC)KI_I$5U+Fbmy,;W.);0^~b)%(tI^)*3L;x]6G2oPBk,eAU0<m"NdimclV1|4_v9f2YIw,_pvNx5Or`]Y<OikkBTZv4Ifr1QJZ]xxXlSLE`E/2F]%f<O(;oAV7Vr$_Nu)p/!>J)P3_ePutDw|]`Z@dh$Ru%#`*^4{>gf>yrT_Fg$GhGzFn[q,59!K;)17MSvi{w%"$nWc<PO~>]RkCS"*kU)@E%<)QqC53CV96b%yKfN6OJZU{Gk&mdZ0o&zxh+_J<l]7~<smX$ofn9Dx[jU+l`w<1,{^9,;.orH+#qRxL@GB}x*u)uN(.}G/c&D)EscPK7>/o/8("T*}{*u==xz4E;S]Tu*j$~SBgl~*Bi#?&lQaH8+DA+EeSeiu.jK@BS%GrGGiZ=h5X=xijN~n&%?=)m<`p6*}iWkmJpy4HXS(a/;[Vu*j09vwLp7Fdg0/*B~r*SW}:k{S_cR{{ju=g]Z_LD*},XZmWMp0"I$JAy8NbN}{2Po@^]>rT^gRvSMOV9V|n_E*cW=b#Yf!XY%a%.<aM^"I#7Y6:Lv|J)>:I@"NXJZtX&flvUX)j:*x@*#i040ROjlv#:}}>Z<`|@k#3:69#4Fc2zsE(;6k*S(h@S4X+qvUizw=g/2SEeWCWgyd096/[lPN"G!FY{{jqT/f{fRL)9xInq0d~j8woYJH_OceD%3^9p[@UHgS9kiHP)&%p%]).gFQ+Dvp8t9#QgBl***S&W0RshqtNj#B1oK[wYt{,6g,Llo9+f^>As&%HlGX%clrYRB#F+F@ILyR0RF}X0J+uiMYAUO1p6F;P<[n1EZ0(&acr:y`040R$56LsqTO$z;/b!yD|CRUw!*k`TllPHpxmR2wk$lG2Jfy)!n,0L*OVa&`yivnKlGi{P;,8Yq5p@fD=G.BJe#L1Drwj,&k^2/D`v/ajcPe4?l99gt:Pn;?TmR&d`L4Y*R;nc,UCGVvfV"vn)V|($!y>hacZ]w7ITck2ws`GcyGw`;;dCt.5xG7=8{5T]RuKk?*}?sy0Va/5SC{IX}?e)D{|@*s}cRLST)sJ5emP~_+Ue5QIPC0]@N}}G&k|3atvWg@O]mmYXiXgmhr}qhzu6]((h{6I%[th?>!2YZ$!95):u^&|t,m?M6*tcZQ>.<cB/;!*;]<N^Wy$Y4NpU&G#t_PI+U]iYtp[eQ+K<AD[.Wgfhe%e<i/Tx>F(7i$=3Lk[U~9gv"SW<[g`=N87ju7*|RsMK"ZGm!z9Vi3@^pfSFRj<L)Ex#$d54~|3lP_Pgw/}HR`D:th|7e5gi6{Z~Rs]w@YhC(sZg;nP:FLgR?%gGVy3SdRrNg]$#/aeP:Y2Yn=UI%(l7y[Ob6GUr^tM1{q#7pdqz}g0=$kc!CyD5]UFPLmx$qI@,Hj@k#7Y8my0H_vwq>=)!MKgJ,w`9@VqT/0vX8u)(ZPz9=,DlNPs6_jO0z=@$pg@0({CqL;*1<#UFTZj1]5{>:86m@t0Qn?F[<9dKCng7%VO6oe]9@,z9H<@&nfm=+Pi>DLi>9*ir9C2T*eQPAqvQo|npx##*N32&*9h{;*>@Pf%#!xIPn^N!NYlGQiI*{g$Mm]h[a{AM<)6_BmU37]^]_.E>esAQ+CDe9Fxl<hF#=f;:&??g=vaW!c?,.$:}t*#yM?9%ZX;kY*s[hZA}aM<sW_77W9`>8cK2FU|&J>p`czwI3:pvAxI8jY&Lm`R1B+5KCR7]JzEQwiXTNzb@uY5J*mmvkzlf],MDu{0M),o`pT]@%qB$%@g0fn@E:_<zT="D5QP,&pG^=nc2B`YL7nlB,VL|sK&ruD=h(E,>w9E!ztC{Syj#T8*/T5$?#3l^EbYR<)_`pPd;!W%{v0DgVUbF2wm*[[iYGUmH65A+wPcK!SCGAH7N7dY*PZamw,ve4;fD:v+%Ien7H`k>XYISJP[wypAMQS>E]wmRG4U@dps?SFO9nrV6nrm|0mb$$I1q=GS|BEv+E@`;"=QSI>MqTx}@^l/3%Z^^,5N.57D)kb=er)e_j*XR,qC_h9pm(WG]uHRnaM8RzM#5y/@g0n0pK"Wf#]:gt}ds|Z&oBMUX|]0H*i3IGwHue:zPqmbrK;h>%%**qpu?SF9$o9TImMc>D{c;>|qqF%s8`h$AmF<4*r;fpyEuvS3WalvKN7Y3*4`y7#E@G"9xOfFz4X0:6.R<0H*B)n_h/tM:]F/j;P&LeG,LalH+NO&t9x,[jvQDLFOfoL5XlIXJq4467D4A2(?2)E(i/to2tP{Gm=gT2):LalPaT"HRqunVKFpZ;f9i~)9JzWC!23]yHbVcoEby?yhFM`R|y49QB0E7Eo3P2GkBMVxEH]u#@<46$k/&3!n,RtKdUj<HGi(Uk"1)^8|Jm_gq5!maJa5b9(`DE{Y}AI=}D7I;mt6BVXNX&EB9Y`P1LPwr_LWrENgrEdp/U}UgB7&`:`WgWe:a{O.w6tko,ZN*m?45K>PerFpuz;a{[()8hDE#V1_h8c3~ICF6]/;!aXdiS876~1Sx468zDGx(5<HaeMQk#(x&h_z1fna|*.9o#P.4|yisobR8]LxH3+KNvG2&n.|.m?3M[KBTe_CM7_z8)ki4Xhi@%^&ZU|S)h*6fF0}]$w)4$4,.(tT]a2B9nm7Xa5H9tk$Im1`X~}mWc3B*%[AHM)q"7i{XD(C:[rHt~};14Ie_leHH}|Jc=hAcN`Q!dH}qYv%HU*.[`m_Cw4wwgcRI|"4_L43qV`o@|+Ax3UuZm/<NO]bTRJ4Y3YxO6YTr(MJ5U=MQ2Y7..NT57sDTs8W33s5?>`Kj1lL0RJHVZhElpDYv@4|Yi#jS5.oS?BKM^GkI#[KJgiQY@!%eTj1ru3](`#Nv3kv^}O1/^h!_<`YxN)hqRh|opbTv/,}XJ>9JcEX`$Jiag~|+sSD;f7ir$J6>R:(|zx<;pF2kQIQ|h7:oR$2x8?=?)m`*&1^mS)c$h%lfTMNb@y/;nu>f(4Ls+>qe8d_Hq)nm)(W9z73LD)Fu?<%4^_4Ivn%rBHr?V<KX|ZmtF@*c|^,zMw0GyLS`w://H+]?LZ&Y]ppuO.YvZKqkEZV:El8ptjONc{h~Le,P:X}%6W%lc>CpC8f#XVL>ZKO^8J._y]T`mvMk}^@C?_6&{0yW*Zjs#}faf=DcBtA9oX(_a8O+,D(I|]Yl[(s2Hn$[V20{HimdFxv9@auIBUKhW>YZ#v_DAWg|4]%^bf0yOos4"}#L~SSd6>%>J2tk0u$cmuPV8}h8^/2Y5@hYL~1f|.P_)U<vj&bx[t#[L,|tu#TDj}Xr|$2u(E_qEhW^JM2IpU`i@`C0{wYeqaN(.N9dX#dRg#LDaks*rP/Fq.tdJ[yt$[M^4c_w[3{db/n84u1pK8[9nwVG$ivtDDl"pixJ$}Hc23DCl/q(p&3qeX/.Cu%[B0&6h18fC<c</4xQG0cvJ&%(uH,.Id|q3I~q,wQvP{&z(PSgSTlxjhy$zHE&u:TS;Da~,,|GDW44qTF@"z/4g1+|WyqNcX7Yz6f8P{}Smc0iyMV>49[H&5H|).`jcO}uXVc*"byI~}UOZ)n;oE+`~|7C`WFeM)KjF%baVnq,IB%lZye.6w?g+kC3Or`SjvO`I6wrW|Q*,6OYs2cNIzT<@Y=:o3l.e#5!q!R%QJC^+M^RJ+G3nFl(;ps?_i~U=w`xDa&iFc~!&^/*Plvy@p3<K<z+P_6CI/W/bG>9|)/J`fE^lBD^aperFqdf|SSGW0KeJYTr4bk$6Eo@&^;i#1vin!o*Tf3iuS9%EJY:#.NRzb80C_k!#F7K(t%w|o`s^,@"PhXKFeIiqey]k2#7M|AxQIM+XNl:j5"9w1<QZ&y3uXm:SIxO!c&Lt5>rsDT=#fw$KzM=R+Ea(qlgaaKTV0$aD@MY?t=FoDd]*2Fjb5S?]P@G!Y.l0e)Ihs0A+5hh_(Y9P(Y_y#4)Ts!Uqwb_45Q@vpv?+3gDR?]3_E_Sw!K}#v`R6=mMlTtT9?R*EHK9t<^@git4h#qOSwly1WqnR864kG|fW#NOn*9xJD9>H!Q)>9J^=$4NrhxNy!9>D?:!MhNDL37%Pwc{]oh=KfvB0.#e2y(,T]?[?K%qU,I5sp?(T[?x(,8HKfQWlnHZ8cCPO}#jcWh^hFTu,KjqPjh8K,YTE]C(6ABOND<O4xXnBRMaGW"TdD7VP,9!@Q?bKKqqQLDZz^Q+),!p8|4c.[H(CXr?_%hqazny1#ZiFjVyqJ,IO}yW<s.FW>pU7?M|[w:MYIulOSsdHx"*4IOC|MGYdc#K(<~9pI#G4WEY8F{a%tA/ETWE39A(]R[=wIRhA1ID(CGZl5?m!8>/e/rU}WYG>kXn[T~L/<"|qe$574}`8dS;9YC5?[[I$}C7FB0~=nemO4V3=(Hg^6KauD#!1Kwb@e&OL1Q*%_,nc7g&*9/X<qwuLrjV|{>%,3LdJY&_{dltF{:N*8!!%_`d^(sAj__54w8aOSL9lOe,Hw;fMEi"o8&bED#]Y@1)@gr|hkF*R;>_n8k*HoSn6V82;ey*DP,HE2qDvmVTb%&bq|wWy{/)Q&3[GtVx:pwYs$QN?F!#Nw1*?_EC_R8]_ioXo<;_UrS@aQ)Jv6k=_0jET^j`pkU/?]${&;]U.a?>@C#;`g}n,W2s;W"t95Z<F0XS*if(;%|kgDGlVe3iPio|wM_:6>iYCel&rtGer44?S8=/$e.ARJ/xD^g@xr!ozMF8Nr.XK.DZ;7iReZJ;n928n5Olozjy~Y1V^5}b~QL[X|7Vd9seTv7BxB_9`w&sy(6Y8?4g$v=<%nVj=8)6rRJ.}F!w(w$.)"%_&AafO(dBIh`Z9Cx7qZ3D!X)>Ej&,}e#7D4!:`Knxqt7kJvs`#aAj.S$Ex>Ci|H}CD$&/W.;#NP6jJ44#bEaepJ+%<(*K,6QW=ce)^v+XI.,yQ}cSf.spFMcQ7laxXxW;v+T+dGQ^^_FED~71L3G+v=+Y?BWvB8SwFhsMd5aio)3jS5}=jI9df1<DxzkBN2&Pm$o*mZzH1kG|_Vf|d^}vb(i7)6>)tfET.$d!`V@_7Y2R@r8X2m?n#~TaBa@bg]"O^e^2#~U,Mel1zWya>QjA*kIU]{A9[@I$@SD2j)s/"GlbHJwGf=GM|_FS/ZNlUuU}yrS%_Y2&Heh@"jsQ2Li99gxYc0KXV<IB8of@Qe_HXz2%!EP[~z3C)yC8QX%.8bGi@B)y[fH0*wSIBD[f>f7Y5YJN[r]_7I.!$S.gW(jsQoa5f>azU}EVX93x/CtK+5e(:8Bh?f%h3vo0bxd}?0*ISz^j3Y)B<W~$cF|h~KG5vSH@gzpZr*arb`9|.(g%zpb)r8j*(e+0dO[tnB;GRI($}&[LPeIX?k!7b:mPne0tP:bbg3nO&*&?;vmNBqB&a^<jXs:j3V~;#Sul)YO5O}+uIrKdYqtJ?9>h/HqrZzf%r?|1l:mxC_`:xHl5v}|sX`sZ=bukeloJ`UDyP!OwcivB)Ts,i;4/4/G61P.Oxfynx)KIv)%Br+%pBH37V$_g#E~zW17VX#YHgkCIBERXYGJ^yu<,h16MWneW*3Ir^85Y#sdqK]y$4<]=}gwKk4uQatX&r>LC`?Y?5AUKHV:te+i(?MIt@.qM&..dhsc<Or1FfrpL|mpLNcRtr`}TwgM2[CjsD"nB=1F+mBX_<CpHCS6,mBz$:W*|%|IH{WO2P+:WRU!Kc43=8;zaKsQ2vw[f%AGpZ*9NCi)UiXz$/DP/"21Lq&9NMtqUrt[?,=SpWThWfCCZ#y"d|<9duk|p$XguVd:`Q+MQ"%V)$D91omHSQdG9qZJ(0C4%52"VlxQr5/!g3*jG3*1Q$q0,rgE)Hf#V.B#YL8lKp!!iA;EI5?powaNbT.fO+JhxN^i)Uu7S~pj`6*.yG{Kk:WW%S>9,GBN1BC0^dB6H9Yni6SFQ@}fl7QteLg27zlAR[<P[V$W:T=mm/@}:~<X;mm*Y3ad$LdUd@lFqVw~.p=(Cb$!9`k,%$&AWVK5~V;e6FzEMVIRhr`RHtxte/_`["28oJ8mP}I8b`1z8JfIZTMRdyp.^?ZpD.UZnsBg}Bcj,^LwRF^31?iypo:8c;1uuX+oP>fmq2Jm*.zgNOP26RMZIsgWjAb>f}a=0(LQpn;1>@6oyRN;z}zIbu{VEheIj(h,0S.4*kIazwZoxjL*tqk)X*Z}B|X=RW8`I>q>,3cwhHwn*(mGRQ6?JE])q+6*n3|H<|1eXpNhB5g`jC,C0lw^Iij=t#GjN,,ajjv)E>%/B%Sk`$2^baO!Y+LK%2g_etOTUPxfJ>r:G1Lqf>MH+[Spm~/b`Z%RWq~P.B%Vl^*8e%<D7/whWm+Z{QQGyI!!KRzxF:00Xx`5`_h"cgVeDJ6M1BSmxXR}oEHUj,}bFRrea#ZD0HJ$/;oRZPi+KGX}=v8?}KJ~Z,i!cd7HP%<k]HJEKR0gm50_]!~1K+KpyAO8?4db32xOYEp6.:;00]/s`,<@XRL5Qy~~UWe"xwjPSNvgH+=$yV+Q5RoyWEOL6zB/%$:ah1CsZiA:e]fk~^@Im0WG[W[AiFr[RpgfK%A()4R[&4l#$x(H^C`S4mo=dqb.[k1QK_RAwUeNUp5:DV&S]UkB.E57Vptr`j9>,1iQ:s;MK*9MLb8N>AZ({emX+L@AWo$}kYD(!xy0hc]JX1)(B/lh8i&TA7bnD,>gXK&GOm9r`)K=`H6`+k_,hCJ],Ktg7vA|L/^3BvT(ybkSqnlcQgue6V=xNMcd!xW^<&^s]l(PH!fB]WT7sx{24pi2TgFI<EjPrm{MTH52&;Zi4#vo*C:b1]4&L@[JP9Hn%4!hY9s7B4C]D"vX@+a6MFewEoL)(rt]LhYM=G0<Cp_5W?Wrt{0+e<87f`)%TKO3HocU`bD]OK$<&&$Lo%iV?D)si/+Pm]@P{[(3`_aqX(%NwYyI",YoNp~nYR+3`j*?:>e!R5}b|~N%!gk&`W2eZCP]As]uBT|#;$S@nwi>MA&5S=RKf/@?Kq>QeOr+>W3rLkQh83g33@*,1;:y1n}oXjrIZbE#]6RZmdNbdxE7`m9vcm5gBg3A`R_OeqSYw!2paeihHvySOh!(]n4K~~dQ2zv~9?GF_*4&O|SNnaC.ox<DomcBtr*LXU#p%is!EfyA{en6qZ`cwHVi|:z[r*T%}aF,}PeY[|ex_#^ahjU5XHV[41)BX:EQ[~(F$b%r;KZbb}0=]Fjm|7//n_52PbhR6e=Eb_U||l=u/,50tnrV%_U;7,cCn}?[Yb8$wf90]m0g&)w8Go{;>s+%epf.jNI2go%<oU7&7e!cO<O=pNhp%A<F!JkY<r)O@+aGei=zq9d=pksx8z+mi*9lRs,Ru$tM,f~KConX@_?vg^7h3RuOXohqK$cr)5j%HXN"7J^@ORP_U19f8%H<O#qhH2,mi3HRP#qt4([_Craq!WvNh3XH@qm;E);%gLiq5&Lg>g%]U./xMFnNO@,2JenGDs$@&_,EteCe%qs?lggCP<"B_c"#%3"_#U~gC*Mc2oqs;Qn#:++.$<?cl9ph=37z?/cwc(y3$.;NTUei|p;K)ZyQq^rG9dt~l/3LfTaQpP)L6t<Bw`JXJRGC*n.]UeaQkxrAfcfLgBu;ql)IsMO$|6HMExE]oNh(R/.MS661+w.QEGo?51E?esVg0g|dZ|#%|X5Z%;j%8>x{rPW=da7e/uL|,[>HTSmdR9!nfj/_,*fB#pbq[YO+Jh&VF7a24>Zklb?oKensTzS%SF42xRsC|yWFLIPYJ[O?(b]Nb1J)3#M+[*f^o34$|BVMqY7ZnPQzb~WUbjy/]zVAQ`#<Kuyu1~(CyOlGoPmd=o:/}i]ksvr*V[bz?H_p}vr#?AgXu"Oy_mHTc("ue0&p5t={RK]})qkz,m%vKV=Cp"TV=NXMjRWQ,Hk)[3ez{I41TYlE"5SJ@Q)RWn]]SjO3C:ZmKPfWJI:k3evL+}/G@ySuZC`t$lK@*fsHp.jR{VInnh75{}}4;iy)4FY)tusp;>TOAky:vNHxn)<PNz6:#zu#M?N}?VJZoObx1rQf6;@(YUrVOX+foT]opRXZy,N(:W8|K&gimuYF+=&Z8zi"wOUv~0e"Q|}+rgSku3[#}[&UUA;Hd.Fp~d];}bPIbuu?@D))qE8gywb8I&FcBG?f#W@5:#LN@xSVw}n[Wq?q?8oo[B`i2~$u_8[Hl%[hetwB_CoX+,C`ohyk*`8#l_hAV?$A!`aJ8$#o=cUy?>mC;K7;ReOM|]:cuALE@^;w@^]!>w@%YClg)^64vQVV^2hYmXTu5r5D1[]Uu7Im,+{y^QV9^I=8>js[oVwM(CwOS,@YRxwgTp^A^J"DYY=/4!ba$qpB4E,^Ac6kllv#(t1T.0{KJ|t(~`N0.],M+<G0.],Ly.v<|>Z0y<Xa^k30wh7;AJ2Zs;dc:!&m}`.6m`&R?&{q(nyTNnbtk9^JD9DawVs.EIun`L3Mv(3fH[,,FR>;(y8CioOAEwts4T2!*1n=[?JX9!ufSbE[nmgxoO!RT$EGF_dii^DXi(myy,(XR#Bx#qiCOK,@IVB.(MSoEg5VvmY`C.h[%lRwwoNCC8n=PMKN7F[8k2It?xt)TpZsvXORR+u7YA?m![JU2QIdQ~e+q0X>Atb$Q.u[(Gf:FdO6iclQI*)vnZkaKx*hc"e)HOu=nVcT)8fT,:5{elx>I5!4Q~:!*U0El/7r,JKkwxOK7nDcY1&fHDDDgM0/nUKb{:z:3Ih.I8/xal*kSWRpB#}S+*RDV}q9sO6rP/Bh5SVGR|D6tAw3d5EtuLq,GX"XeX(d+o+bvK6)J[Jo@polCyt^`N;o?fVUD9QGae(L2D)C}T![)2E5w}a"S)M|Q4d3k]=FibS+G1s~}QYo/>`^AyL;(?3/aC%{|XSQ*[*fmX(Hw,yni&pex=0#x+$}}<+jn79Xs*]QJ_{x=E^II;W1(Q!rInbETA?0d<PiyobGFC:o?JH^@W>:E,4+j.EG9<{ZWiiT@pB;jXWooyrv&4X$2aC0=Y/1h2<Cd*UQI(!hZkHbuznD8d#AzCJYY5!0u[X6XIRA:Y")zIr+(40=n(N1Md8P4{6niPg#k),}|oDw|e;`|Qnbf{PZzC}"%KE:mlU*J.GDeWy,kMiVx#t%NBh.b[x[Q`pj/})&a,D)!aEsP5l1U0$93y@Ar6^.&*.FSDXn}I,tSXH4YK,16xx[,y>[]ZU39_`E]{lKf^%=Dz12>[koo<;,eTu)3LyQ;wh?!NO5*C[r=;g~U_{rS0VoAVKmf@ATJq)biU"ku,h0$Os(|+u;f9I|9K&"^v&G!h.4Yaq&%SIVX]C6L{]:iI8o>>p,Qe,c6fx$G$j2QCD6LZrg~Om7{1_pN=OX5c97%*ZQxJf)?%Hi9tj{:)</WK}}@rJ:[7HlLna^GI*%N,JQ&J.l^T>?y$f6x8HZ(^5>q{t=<la[@Rhq3A|s,b{5wtOaMA*0qI/Yk}S~+uH>:nH"V@Hdx0e?+2r;)A_[)eo0Nvb,G]P0Hl*!4V|/FJG=Gg}#G[|yF8FOjf#s4l$7ALd9ZX/zhru2NOmraQjg/{""hi~};V+D8lnW)9G/Z$OU|RX`S;Vq?J7A895j<.l%d9(#wU0XKQ%dDcN.Imw2:oo~t={|N]s*|/X93eKD6?gMVB2Dh4>vw#1g{.hx!E(MsJE6W|{qi|6xWaen?%<VJ_A3B?wi5r[EeA.G{tn@,O2U^%#*kL(+8>nWjKhm6uKu4tnxC*[j;.[<s~B95;4:BfhlGKE!w#}S_TN%!)@V=/@fRQ0#%Kp(0naljh}9*?@T{rQQ/:Fif4X}IJ<|qFvC6w#uf_L9g(A"99:lQX!l%!<>;Ou=BvB0v:$z1H(wFX)OCkDxt9EqAd)G^Ih$vqBpMagjfM]=N,!kK,gxjcr(k4^/X._0_;ku,`3Jh=UhhGmqrnH|yQf]nUXoP/PF4)5>n;k[8GEZ5$/A?K*T/h{ZBGSjv$PMTTPa10{OO,&*kA^zBVsL39$63Cl0Upg[gsLh0c!=A#RiVzNo;2>H42d,`AJU/]@vVMUn"SV>J$Fh)J*RRd:GbCP3ZjnMF9CL"Gz}DAAqG?(J*!6i4%EiA0G.HA.St7ak;I!9e/_D9O2o7X_NuW$1jdRVU4O|dI.8EiAVUll~WxG?<}G_)AAZIVAZKbH@udEjCv+Uq]NJF#R;LS*1EUvPFNt79CzPL^_2:2x!B}WfiBJ7Dy4Q7^HCX$r))Nwh~(DXX>[c]rP&I$_IOr&qu%5^*gGm0{VG"N/mB*,YB?<4GNN1P~1[>#r]yrmQ,:W1C0W{NLI"Ci5=baKjV}+9P=$nnlUq!93f!MI;1bNDLN@2k}GlsA_WIhnxy):AW**y,#z&siTUOT@[N40RVV}K^VhF)k#vX<2f(aw;?QWVKX_"Ho&Xva&4X&[>;;jep:Ic8d5E2R/sae}L[NlIU(=W:#*`TASLxjE$"{gc]pZ"xn8c+f2"kJWz`;CW8wuW?&6*wAMPk;&QI8R[QSEGxFn1]]+77,GS%zYsQ_Swb,5h}TJy+o0V@]2o{s=CG:>0Gm3G`$8PZI/cJKj$JHs@"|T,B/FYCPE5|4>K8A_HqCha1J|2+B[0Mg)A/8p!pz@q`nH7v90+0F[k5rD]t<(#QuIVXHD|!8cU2B.YbJdb?<XtxX)0}(l&Z,?L8+_XuSBh(Ge7~|^Mm,:yQW~M&LMkJ(^5Z/KF99#.;LsRe`U0lQ$b8`:DCK$.F*D@8*;;%TcC8rma_7lK:%yqfJo`ipz`~poML43~VUsK+vIx8Y|XWotp)i#NP`=ZjW(TP+dx7j(EE_OTwiGMn_HfHOI|$Dv(DH6/TQfFM"`:Od4(D+Blv:dooA6V9r1_N{d?F.E[+~Z~KpDzbklo5Ep:8B)QQs,uXrU]`]pfm),I5TUk#MI<qmI.4&QWDOhA:@by?b1v%_V.BPnyM.+ro@#sS@w0Pph9Om@L`#wK%d/euW!rB(/idVhhs~tluDdC}C]_CqUi~dOTL]|_6u&~(4jZ]<F~@yU8Lp:m"}uQzSJuB(/}8g/;@8vtIiZRcl`L[RiB?CWYX_qm0E"_"h?vYag#q9K`T<D+5T=yloaTU*s^tG7%Mk#*zpI1|80;n+g8G*sTSB7BMY(+_&|mH=d~[qf|Se4F%]eXrEf[kM}UQ4MCo>B(l,`iXZl*@$|jIPTuK}cAI.EWt.qqVXemIy,Z0<miVnoS$jXsO8vemKs~Xp,*R])Lb:+6(`8TfN3:w5:chUtTKcZhscY(}3dgD7F5g/c?G^Oqf[Bx:zs&BnO?aCePtSl9Et,D}/)mtH2IX(Qc^Zx`Q_p:9!vooPd$56L@}@@*dLSujA6Ba_V;96v49E*oC)f;/_}bz.:IRT3uZ<#;7:Li4AWAOS/~Z#}D&*|K3>7&xWIrlG#oiw72kM}rB%)+7oiVE"Rc#L&ROeD&~8<FhEasHBdonI}PG#^$}=MkW/2~NRchL((xxw"!Y=cU|m,^XAI9p{GS*rs~5{X`o]u_AP@)DAEc+mHHiUB%@%k%YgFsHkL""I`!@.DQ<}5T5+W/T>VM=Q!tl83^]@!C<poXLq!xiFF}SYiPJ[DAi<HABZ;uF5"kNg*4{OMfOYso@Wid[qe7C4r9X]Ww!y0GVB#+FY4M?%Oj*AW{SXOWM:+3xqb8jBD]7ia?Fk,0+&0DfqY9SxQ+05/j*?(TlL@N6;<#jlS`8pU0VH>YXIfo`lr~eGH`u8E7xOA2wX0=rm)lNcAS)|(*Cc*2b1TpFi)[Z:v=0@O](>u74wB3@YxQWYJ[rO[NTQiaY1K,B?`ReU)<n:[i5hjaTZA.B0[]2oeijW*=heJ63D&^@Ss+CQw_6ORARD6|g`Fv&(u+{j*mX:k#iMIg0}QE0UW=D%SJjHm*hKsi)^P}B)9QPE@GOg,A)BZ~wtvBlDy0Krfiu;JM&MG!Gde+un)B`)!KDS,#HqRJRL=3C7@q`ZRLL8$Pehd$.zGi4"S9C`Sy^m+B%S?h#p*?_4VyTnNCvRkFT(wZq=0@2cy8HUF#X67hd;@k|=64f>,$ol$f7>=nh<EFI3E3)5D.Xbsz0<TXOCd<7jH]O.u3U(w8(p)4jf5u%P0gTm$&;W>I&7XK:TLPL[P5}LS}h)HfHpp)w2nvhM_EFvvFtdu,ychht3t5t3t[<jI}JqK7Aqg8Hh!NP,?hw&4a*k+0CyLFeooljY_&S>OGtwbnn*$Asm1Qfts,w"fg0E!:Vf`iisoCwiHG;=p@U}qwuTn/{JqNU1aNUpaBsWTFl6/0Yh8X*?5Qh)NyRG2G2G2|n[r.)Qwu=V=yaCx~%{SKgW%ybJjrtr`4=^zIg47>/e/1i,1o2n2n2WJvSFQrl;f2jRd"qFFty31^1HYBu9EMy[t1X?Bt,G9D!}`i4?}0$I8sUXZT%=a:,dM]zA:toA}mUK5IlwM$|LnWZ5aB4{N,nu[L_+)(3zB&s!hvhzUr1,@ut{Zu&^ziYBzz%RO~Q5tfh/NuVbbf10cPTVMf3>/W&d1LJH.ZZ{N=1B.JM"5[;NyG{Xh/j?b^cv[SPY{wM*|"KulPT$U<`B/T,i2?bEK^<ro%>ZZ`2_W:(CzaLl"3tm7$m4si&=TZqf+LbeO|h<nE}rr5=Y&xw_0i3!YC[{&dTy%WW~kqFO7jQk$o6yneZ)%~[hz);9^G8*si7"mp#4m#EMy=[.LbI4eN!ag^Tea=]6zj?{vtvF]t.@Cy!%LqMqm>LJ;WtTz6yce2B}oxR)Y^Xv6%NeuH*:`!5Vl`bnks4q{u,5]pR|0<7|rH%I{$m"wt:JBf55Q$J,,!9<euEx:5BeOUMiMHRwQ4SNeK6G<4.PvHr{wpU7I>!>obRM6Erh$viyAflgvvN|9GaJa27;(`WnS*MKw:/?[QF&y[rW@xKr$~e!DKI"feL;1oZ*hN,t#u;k+BY;jiVED#YUr&tv#=,,E>Mb.9&;iS5$?$(}jqG;K<GHm~LEkX(Y^A&<h{rCi)EKCd"!*$IYRr"d`)@VXCS@F_qDoqu/F7*{$/FXZyydch*GHlSo]+lJd;mu+G(e.%GcCK:/6Np,de_t|:HLZ7R#jG[.Vn^b^>k<IH:#Qp6BP]nKGg7T9h!fRT.&g/UrR;.%RK6XgAIj<5=:4$[Xim#IGF,dFeP+$W>!3_mjHy[ScX>@a#;l43x/zEGxrT_:ZO$s5FG?{Nyk}7%(,`$3$z_S/hIa%q!gx#To/#rPD34,:PW58A+SeB6|D}j@m@@FF&M^Q#GWw@mhNQH;i{vYO8?BG:Wq%q1zNS_<pDr+d)@s`|x%v~(k+}R*q[cIY9?d/Fb#*_c1iCWoiVrN$x`n0GwYcMne9`iKa":pv*LUmfmP~dg5{#eDGnyW;>Rx;6Ta8p^^O]a?+W|)d/2Jc%bkyAOx0^^mu=<^@i{ICcCI#r(1>yLkkLz0tW):{~Z|(LY<bZKn{|t7Vwpp5,U{p#GUS~m)5*4cLtM)3~NSxFg)Q}G4NYza(Zff]MmaMxLMD0?$IiIvabg:3QXry(Wh>bVF(%`(`p?{$FLlIqxPwX*78iXb5AOo>)3h1YVJaJj,y!w&SP/I6Z2qaZ:1UQaSSrQ_vqSEl+vaR#x=^Dw,YNs%{+a>|v?S(ql26/EqrA}}<C{hl{<*d)Z^M}#%dc5vZ>@i+ahDY/,z,%E=W5RQ6)J7rUv=w;j8X7/7!sY4)$kHG~$`HlE7/a+T_&J5;[KsZxYN]3W|bcpMrKxY]Jk4)$kbj;DoE>i41/K~"f/tRlO@aPD_yl8X,cs77yo(a`}r1zz5}Sac2|zj65d02RYxj^0Vkp0~,ws{f#k+HH~?N(A3x7iOZc~/8I{J2}uvs@T.!aMr][B2kc1b:2cPTqf~Wz]C8~ctSPi,=StTam_1}|q1YE=B_:frp*&h$@xDP=!2QqES@mk{HHopL`Ju7pLMGRM"f#W2=PxPGZd7$(ASOPH,HA]"k.^`5*w2WtSm#cr~]eu*hshog)~4DIam6SO!:k2{Zc5N5*wYV(56kQ~+,0}X0rQ*v>x~TuMCjWFO>nh:e~VmCq/(QuGK[1ZuB==TYnlY|LiqeI4KFAS&>[,r|7t"9=O@)2]*oJ^n6X(hCsb$^!u)5*XB*~?o44e/F[|:]_Fg]ADj1XKz]a@O.e9Elvotw!!GDU+G]4LvJ`9r*;K74i8,b^Lui4`HrwFeP]n5EmfY{EVN<`[e_~(!4O(Q~]=I?*L#[.96?{9BD_CsrAg?f^8/lb4hZPthZPtIAuei,)qW%hUJIPq<bKCK:iOoP^>i5HXY((Y#L?46#A]6,hS[BE7+aeiHt[q{|%_|QV2A!;>X7`5AR?G?(EHttoO]OmHuJGROfe4kq2d>F0+tUeYRGEAFRoDv(+uhGPOcc@_^X4{sr@A{us)EaJMy.3B.L?ihx6FAAAAAAXLBAY4aZzh:m6alFP5nGJ6K;>=85Yb4epe.ms]$M}igCag*Z]MLr6ydJ/M^:f{H7*j=Zb+nfdul#J*fL{S48Fw(puG:,"1PA+Nd[mum5.hA:o5OP1PlFrxPK*EhYIEiIY9Mu=/xpJ>Y|.CdXVMk.6j1LPa7vT9Z1nfzEAmcs:abJRPQco7,Xb=b$ORg4ji:a_KQX3>SkS+">iPX34;nNlsAidab[E6Vp/{rGuzKkXn+p<%C$7!}`I,PE@WDi(_Sa<lj1]{.bM=nth,ts,S7IXtER5f:Qb0]9ItEjeJ<Mh&`PEyV1|#8Hu^8D=GD&#F[K,0,yUi:c<tI;}bU*+5P,IXpx5[}REK+xO<joD^!VlH~.YvDLR}7u6DWI>3v46EP8Srh9Gb)(%Hy&_T}$SJvF*?WY<8K>X%ah/L=7mKgw/I0c!b0s3@0,aIre}Bam)Qf&uAsWq/Y*jrHU_|dgF2FL=TqDl?rv(mLT[2I/L)}$cQ4|4xyr&`h>dL<6P{.h*UmPF&:C2C;/KaFx0b^]yOx=VVAf?Y;6[kr*v.AwdwaXcK.3rB@B?LUs2|:llD_biFc.8@5?=QO~HH9SLxr^q3,`L5u`dtNy4S7.x}WSp!04np<*Bk/7hB/70J9ZIK}A6xB9.6#xjh%!@{*hBBgg:$x!@m7{4^Zfo2DCrKBV_lina`;@{Cy|J9HGV"[C||h9yr2}kX;f%8!%HW?!p]#anjoi8En/}d=qhYx3=%y!vBuZFrs}8c<XrY,1,%G)DW;4`cvq5}XmOTpo@_i97n`KDBC2>fL(.Bfp_U^5JH}_(WwpOeMc[17~%m{.BQ`?*ZT;wmQ7U!owM6,MWTnZKIU{vRztn_UiWY}=%ea3:D>ScO5Q[#6$q~.@x}$&E@0*wG."^,2[/gYMMDs!CQ6aG+>dZ6P|fT2dJ6EP4X(I3.%k5!SEE*Es5$MK4jH<_I79Hwa@u.@rqgm$<ce1d3Y=GqEP;>,P6[Ff$LsZy50JMLBS|R%4Q*+>z:@I<2yu`f::Q~#*#|#mD]a.4PI^8;;;t;On{[`V(+_+[l"K)/.e[bD/0#E*c#vPx=}XdT`uOJL>~=P1}fJti]A?$F/7:GKO^suF{T@_=]f5458F|"2?>)fW^qx$[O&YH#T`n+=w$j@?Mi7wn^p{Ox*B}?r(#kT#MRSw#WbgVg[7KiMQPb5rgwj2B17qudY6soBRSO*:a|3LW!Wr?vz_{(lCih~mzjXX18a_upS~(fa1e|5M!(/_{{9ATNLIZ/`k61Dj50.HDZ9{D.>M,3kU:|e2NYk3Gut??iCWh]71IxZ12_e9S*nW~V&ccZy="gLHWgjq?`/%$[e#iZeX5tE?O<{dBuop#%)h8n<Rc61T7^Qqd!L]bNo@lKZ32XO3xsy`=}rL(D?Jm0?s:5cU%;iBB}),1(NDADq_3VUy),=K/Wk3NaDW(yqYG[Zl!.4a*h;2?#E6YvBLD{Ozg/U,?23mAKAtV*K*v?D@FUCM=Lr+Mn+8]!78=C#>"u#7%=DK]Q04CS=$RSA@DdPrFn,?^}IaV{BxD/KnHkIDmQ8U+6Y^i>qGkz[mUN~Q4t|Q%o7+/mWg+2LB~JRoynPT2Gh(uFtopj<`s,B0(SP&g}GC~%;FJBWBeVIr9RnoXAU+Iu&z>T*zFEdNE2HQM4y2BOV]O*qu}oVFdI)3Th8iccRNk*5EWRt(wWOEOegTv<??!8+RjW|t~ISJnHx4vz#wIL%v1aC1CZvn0Cd?Zu3S^aa~_xH>N7&K:tElEgRCGt>/xz>q]5EW}yzb(&yZ8e:ZX3{<pOy?ha|YG)*aM6DpQGzMF~Zd%ZYEhGv8*;@ei)F*>*zX{H>M8uRh0e_e[$8uWBS{l|T6blM)uD4`xjsP7+@>8N/2DlkA62/Z+*te(x2E{TQ86K#Nh{h,5H!03avOa<RM~Hj~v/.2mpT<"Mu$mL6c)$?b3`Z2^[HWD)A<>_i.Ag7fB.:6,K4[+D?pr{,zFxK%>Hf#9V&qrbs/roOusq5j+_"L{HElzyK[N(`@Hoguy[Q2ib1s&iCdJav^zbheVjN2*Y/`1CL5bG2{)I.,#6qmzu&9M@mu/e#8>t;i.ok_vo8xy;!8LP]u$fwh3>OFZb=w/B`xfe~):|C3xT$^BbiP}#t^$zk~gC7eruIOgQJIlU]4TJs^llF/K6jD0#TPN@F)DZ;o2]|/[lO(__{}}GLfo$^fk+b3z0L1=JFW0_476V/"1heM<GUrjcd=+^;@DH|`JVKB.EqrI`T]>nnF!a$.OXvmaU][#r^3M:}o,c"<#LFyccH{^dPg8GAKK(uZZXjhcj1[;^StAezt2I&OJWjBE+Ab?ceBqnE[RlCRHk=:f;?538H*"Pl,+a~wfwF6~1;dcsx%AD31Kq<O;JPxPZD]Uq1r`Q|a<bA0k}auLB3@qdzLK[9EOUR+mC~krF/6H+DaW6Xw7*a*W%b>5&#{Nx^ULXQ)Gn%7UH0EM}]l5%u&mjGp=_frv21_75zttfvIbkq^rLPB1e0<%Hs?rL1ji*sEI1*X#Z!)@{(7rT>|v*|r$yKl$p`rexgS?#j`%Qu&7uO`7D$8NE:GUh$Z?r~[{QqZo_h<yJla&shfPzNDUs+Y>UR9Iz&G!5&$/NLL4tTa@{R,_g+/kr%Z)AXK$]FV`[G$[EVj+U?ep..VBa$zO}L,aw+A2k[*D%XK6$ox?gsuSdF$eG2bYf,9w7jo._x~pPKkmw?kTusb,uOHyf]0uF5K*G<`2^h_}2tPtiADxZ`fwJlk82*ixz7+)cbD)/T+7eII9`8kyb,.,WcZM/T(!W5g7tp7A`JPKWlPtHQLL@ayan9@slKdq~>NIan:Li{.9aCg_9<5]FI#,BxBY=4C*&J`PX6qkCz.KI~*Q<x$>?&Dw>W;A7$cu/`u}C4#Y$H1>##}b&}Iv+5Z9quuTdKiIu4;n#T0j07/StSIO`4]b#}#O@}!RGQGaELe<;X(>]h]xP!=NQW89Y3*gLfi5qh>hd1bq*}W|MzUI.vd%ycdLA0GImIb`|4_dmJQ6Y!f4:@x,nF+_G<?<zrnu[?z3U9%xERDLv|zr#LFByeXVkBYk*f&X}ThB%dZIi1#*wMT#DwNfl6#gMbqC5HL7NPy!*yite=)R<KO}mmUt8k+$5fhi[<U>b4RDF,mmAcov7|sK)9Ku|oK~v[9+c]Qis5bW,LfTnl|"S:~+^+@DjicHg[jKl;P|]k1}Z{p]DBmBfVzlUPHIK,2k^f_2oQjnOAXe},9UF3C}HYF,5=7oTYUV*E(@j&x=Sq5YF.m[@?9^>oz#d?Iw}kPbe}cH0r5~C~EL.4.+z07d&1k|`W:uYs!w{nL@HMd]"^zvd`J=m>i=/i9l<CA+05YjeM!MfX9BJWvz.T;dqES3z7Pj@]uC{blo8fG^.K(=vrmu5/y1J/kKY)tW0+)iILk80+ua?sG.`c+VK$uUNT]3YSO=W[#fz"e1_Y@ty].TE89"v=3#XuPKyy#C%MvUctg]DzCyx)5pr<du4w[HlUl]TAEb00+!&TRkR.;wYak?7%McY%~s%NoMQ8e?lNyoYZZ@ftSDP*0XM5^aODIA</Y&cc.n&FK@,RW2x=7!!oY(fGv9o{y#pI"aI+OhK!|p{Zc!3!{?:YVfw&#_09iUb)v#&fBBx3+DnAb+kY2luQ$J%7DDa?GstV5CJc:`3(0&&B5KRB/N|u`m;X7N}tx=gY7cYfL~4`LI.C])3DNUzzAQ`B"MF+7|{VcD.%&]^LM%#)k<}zZAniWcms%=W2#.U)]fS)[6@T]<jt_YB,];{0JW;VARBHm?&]~b7l26S]pyRy6)C$kkQoBB;:tcrMqGi|(#>ya":2gU^".oj5`rvr<}FJZ0kW;BF4795b!4?u2@Oql@sP0$)D4^niTLq4&XgCcZl04!"IFPFRs5f:5pPdqJwbXr3B[NX*>*=sduxK7yX+,_N?!Na.~h=Z`cQ:=i63p=H{{lSU^{sGgTJ#uYAr^v3$ae{|ZiOd>`6wL9P+9`QD?)nV*kg0c}~^8+e{S^!p?1*3L*[4(Z[x,w)47d4:F6@dvhfP~}B9P8b$QHgwQ~"6N"}R&:wbNQHv(jF&/PAbeB_$20!3p]xjB)2t[mXUXh1$f]tb}fuOuKwS#CG#.|qBm28HFlK^k7sCkWTL^%gEMG`Dg9TgWG,^=8*G}*k0_Mp]R|MZ^Pt:7Mf_xS{,_"ZP]Vm<G*EL{>OX3JETu+EsB]NcT`0n"Y7x4ks""=>8qcV*ZX:1xU6zjHplS*[IpTRlcLdwwl[9.1G#y[OQnOh4KPeMwOEJ^|vDwU+!?g+,c0.Cw4j|"#%w4:0wdWQx("bKpFU6xFNpHP:MSh`Mc*,/K*?~c=In{=/:dKrZPCJFV_E1`9r}PYv&<%k9kWNC=87P}"(T%+:,`39RAya]"!y`~2@qmvSQ2G0=[=Mh4JrE+AsobALj,5u&oL{{*C3!Nct"e_r@]aYx@Ny~^^QCu@`;p[t]I{$pa"{!p:e:GZRYk1^IFuIx;:BC`iTAL_DV|;W@soT:[LpchSaDE#i?SD!km$};L/rO@@r%]9bbqA[K??$fm.c<3SXM}6nVv,(E;2j).u^v;v$HT?J0KK%!k^lq!~e%`E;`<MeIGAZOmH8GVyD3m8oqDG.GHPLp5|5sHzc=O4[]cvQ~Hs1gXF_Yf|P#Dr|bb,owBS6l{Z~1X2`1B+,Q;89FHo<n:L&S{$9&?tr#<ef)?{[caS!A#TxxR;Ge4yI>D%EjD$<v^g8.[iJ!EQ;e$N}VR9c&z)k[pf</9J[U`^X8VD9vrmZ@<Jgb#W`,>D4/vh/x<8?6axl4,:k<T1vKeh<)/OjbmG%`Gw8*@r&!J/DkuD|d_Z:i[/`uF=&zR]$a7j?1sr4=zrSjAA2_>C.ZFjuch9Bt;XP#]7xQF,oY{dy0[WgXyWsGkpQ7B4he3@eJpIkL:6J~vvpmJ%oh`A[3&UtC]S;sKpGiMSqgP|{5.cPaQ"246r}iQ|IE2S&LjRP9?=L)O1[V#<df+DSl}lutc)AGt:;*NFBYXT&*c)=E8G2AU(C8n;b_368==Xn^kQEPk3^B]u#zWnTT,@2&5`QE<,;1I]<h*Bw%cDY]xG}G3_!y*o8,[|)8m](Np9pNZ$,44m@xu)nbh}1W3ijT!H6>oZTyn^ZBD)FygeUj:[&YRE]dn(G0jGelTfTE8"4]YR!^"oOTHz"Nv$){q<uGu>n;g[_pe*8w4iaG8Allf%vFeI^.?3vVi@ooyU<dZGNAX0)TVg#%R4Ky~ey6yXrZ%:q~Ic|?;5@1Y_@m^oH"^^V#D`.nwS(ef0)@5Ev!UI=eZ[^U`teyeh2o[$MH6R7nUu}weacax~OQQ8KG#728"Ru!1|PJ(PJKH`?zrtU5}#zY<<[u=2)3arVKuR^MFB&Um|F~]*yy34h=s*Zf7G;G/AF"Ue<K,6>.K*q3Iu2#!e^Zm4C4me#?l"Z^2NR~&T7b)O,~H#[`^=XzsKo%k9k6R)F=Y/J^eS6f6NdID^Kd]y(iY0hDJQ6.@9$e2t[b4VIvhT%+LLD5ap&=E)Xz2WKqR}o$aK511XJ8}<:@PHo./;48q`WoCN<3yby>>#3?iEXCOO+:JQo0U=BVj/<FsuPk!CRT2vL)S+Y!8gN68c3hv+TsHaMP80!Pv5BHwoP1a+JpsW~aY(WHD@O^NGfJ0}hxBDPK[it0+sB(7&(+)CoXCDU9Mm]lwMJ?F_Q6M@!x48i;Lh6p!f$2LH#*pqr0"M`q[O^$%Bq?8^[>f2>3Z;#^SXPHoNT#$KR1[XtS:dB?x[Z@E{:A+oa/wE*tfSE>$x;OWlUBWV#o#<>[H;H".}A_HMlA|.g2pE.hG<h`H*8oY){O%neli}.^_t+IoTf/w^5egJiX{Rb#_dHisv7O2pP.7m$WV9J`+puAMsHnCnUTHI:&HYe+}RUtl8=*VZK%_2Q~NciWc%:PJe0a$D+jEc},xuG,z,=HbfuKt`ghF]$du=$l1~$oT`squM~!es*qFE`QZ|O^]GvEE1@=uHb$BWSOYNoZ1Hlg?[bvoQzNne*^~U:&)DmF]^Cd1_Uk*:;%`nFqLL35enRw+@gM{b#$|WOgW8MP]w1X&_<%8jN]}1%0<N"FE{EOD,FJ%<>5u0^!k._2zO(R{XpUczsXQBd&sv%lU5$G6S?}uip{eW80|x_l2b1VRG~bv_!BMSCE<2n!$)+ZULalSM*0zjL!@ERSN^s4VWPewh%1j8~0%,@sO=/;ey>Br"<yQ5)g4~T!PnIm7R!cFkS~H#Uni~}tFG<#+JRs8`OB?Zw?$mUJb|c<D;zt|D<zWl?*9lOw"[T7PJu?}K;aYexV5A_0FF*sYS7+g=#4{"/m%q.@|}!Py0lWC:*hghwFo~>dH6kOLF!9EjPKLOU!kPsL;/HTW45R`02;6WWi5&$.lXjdv7bhDOjn|9^[%JeT>mkl51,w1ev|F0{XcpJ$7l)2w<Qa!A!&/!R$M4(R,_IA:x.2S4J=RBt3^Em[]:vz#<d51G8e%2BFB7uyQGMRY#^*)a@$f(75,)ACE~ISM(WJS^JlX?d]K#@?W=1lG4B_o0Np;iGy8r*[bnRiq"+S5w:PaXzseG[$5(hp_LKbxh=f5l;5(3+X3w<WL%N<Low!Y.BT+nZZ5/)5kr"KGJ9!ej#g):``;.AP@2m|%gWO+F![2(#!h(5@HE9=J=k5CLOK,<!G_"^*5/E12~d#BG}J~J.X93CW^}}nyPTd4AkIZSm3,.L=,(+ksT;XZw=H}0squ=&*d.Nx(9k#QAm&5.8[Gx=SU6O]fTQ[I(*x~)k}G.jaVta@nA[z:ft{~KuRNHd3_9fN<mvT;|[9bxQ0S!TOvf!sct6Q*4j<")%ht1gyj,8yY`az5..."![M3zpXiHNMDz!woHN:jnw/Mz0$Yh&(L:ha#Z9H1(bX{=B~$<wlPUHP4dJr|!s/UrOtFVtn!0|lPI+qK|.&%8C7]N+|9=3Oe{bHx[v$0ZYp4`=p7BWp]+FM@}*k>fqBRzn2*`(b/9)`LdMnLgNq0D^V`{v3@?m{&MW,[|zjjCOo2])K)#M"#DmT|A_/oD=2JqYlVXb}J5Lr9]!$ZIT;_]F^7oW[x{)x75=$>wmy..O:$doNd{3UQlO0EFw+8=4=ZQf0DHGS&DPUq"_ESMb`6/~.z`tTr9m"08H8Y#:xV)@]wI{d<J3DwBM5i8Z~Y.8Lc0wr!9rSGr_p!zO.|Z:{BeUbF!m?6rn*2OC<;ZX=N@;B$u>a9e@qc"eYE$75DRPBNV;.O#phnmn4M?B5PO|;0XR2cX6lsEWcg#i2;xeN0%Erk<zAxL8>!wpBtyY.*Z?m3St4lpfT{pUlPyPPa|`V|j?`;cydj1f0aEMMXj>k6[c.Wa;x]_.)DyD"d]M@jMuMjoUWoj{*sHo$Yp:i88#5{[;vR(|>4B_#Z~|&~H1!_EEK2A`y.G_d,o,#d{^=BUbkQOB4$;>CK?7w^CiUnIneMXMDNoqvl/}/rf$&Z1>pX?zhZi]:!Mh.(]oEtXEY&[p/Q5FE0^><@wYMWQet!]0+EwM<[8:k!"_{;,Wsv_;InUak`2l!/$"we?x2)[WRJv~!W(8Tv+KM&`>4#<5Bp[2p&GrC|$PuF,`[c2V%r+v`xf,W.Gq&![D]$5J:5]]Ga__D0$MjZcb^C7;B/pG^]|]96za?EP:"Pgi$S%lL%wzZv~_jO/zSX#q:1WwX,Aa~:CdNRU_e]MR&Wq=e!xgZM=GH45,`,361dXU7L1ee{^t[L+MV+?8_?:ET$M3kJYiNs"=AKa@"8xK_v=o%%`1MuTIYECQ%8Nh[MTxOa9kohzgP=I[>p~^QI8e?<iy*KFI<iFzr{FUoDLD]=HL7DdW1{oo1B"2TIMX_K:uG+{"kPh0?!pj"&=Ah<)r$NglF&DC`W[+%~2[kRVJn=I!^wdJPB/r4!!!O63Nl5BqW{f/Ftk1Q8yz5?Pv8#gK`)zIzNQ@sQ|>Bu!Vh*`362#:g)nS7S!iCDh3(/>3g?wV5/D<"@v#Cux)o{T+Mq3h8Fm&,%kBUbT*WM|f|Qu(;Fc0#=JB$];hw1aQy0,8m:>$PIexyVuj._QOI.l{Xxh^(Mny$Y)wXRtT/|O{Nf9[!sN+jE"Vuh:`XiH`QlT0+hcbk;ea}Dg)W[ejC^1%~Hvt$B!AlmnPL3tOk]C(a03)3bV6P(,%wL7?d2i?^V3?~:IaI;tt(x51*=saJFgd*Hg{B"46Vx(d`Wspz_9UbwQsTJ(nrg4^<+3W[w/O?bDkTKgbTky"`1.Z>Ckq$EF?6XDIPS!3[e2hgEi#nf^JOe0rcjaf>@b/g4,d*zi:|:2ypxe9@U.:X8(V1e^]{98U{Ye?;s{FQb&eAo:DucR?WpMg)uh:k#1h0eld"fh;KLtxF^7w:xg*op0cF{RF,qe{uk@j6JXV%|bTw#!yU9b}n@RD6b{&Dut.uz%gE`jEnamnxLQ^UzT=2>eCShgMT20@%|k(?F(q3&:_"CPt!xDss*/Lwdh@VgzL%PUlg]a8in1~`,8i*$9|Py(Q>|jqKP^6=hWdM!jvl:JE4Hk%1"U(c625Y2|i@|6_7[CGh7lHbj)$@<<c;O>K,I?/aNA3K|d?5RWJ;nm/Qepf_<B%{vp1fy7*e0a}ju,bJ1Vr]Znp$R"$~O:LG6H!/:@ZXjM191~[kQEU(bV:A0gbE1NeY8i4,#d<LpFIE_?}H$4>9<RE~]9o^[C?FH;@()[HLQOv`]#?&3<5jY:SUkpedt"t(.g=z@IN5O;>RLlbu}X{H310E0^VawD+pxs]~H>;r{<W=D+AA1vP<n&:.+Ag#&XH>n`gdo/D/]"+44ZK"&:!.X(vl>W2x0m>EFqzp0sOnt=K#,J0UL8H9y[C,0sPk/3.}q.COX}&7iRKn?RK&SP/RI=9m5Y]_l,`zP6bzP99ZB9h_,r4R@M7HRc`DYz!Edk8:nU$0^w#1]7"&uypKZ/0C7[KIOa8SeIs~z7{Cp@.$rNs{C]jZ68liC7b>oPzc_(ND/8nnWxx[Jx~u>~]BlECoVHZ:~FUpz:!J>7jg[,5C?R)E0z|X/O1~c+P1&PyoIi9>vcFdP$LW,&E]lBFWO<a~/X2dp[1Q;)tpe+i25x*[kU#XoAj[PPEt%:]N%guUC}TbOr~8cc<v,bY)Xn$lZMsB%4L3_gcu,pk3<Acx"Q7},YX3;?+8h6?43Lwpn0RmLf7K:QxxCkdK%aC/dS@ov2*Sxjzhwy|Cdv!;yC4I5h*DqA^girVmSFw!cAASk=t7p6:{A1ZLGI@I)odTDn[|:CJBpbz1.~0G}I<82JbhEwfDj[lqV6qJ{YDgd+|@7Wy]cb}H$0#$`{Mi6R7;JIDp:bFY0IG1Hk]W^zAzv&p}R}:rTs.#7py%>iIMwM(g!LWdJrltxU@LkSJ$]_vQ^8,?<vtfLW/h7tE?eLEBy~Zb]"$Sz?)1pc`U4(Fn33]%]/h/Q.t"aF+P+to7fBBR.j:q!Tny{(,N/Iz1lO6~q:q1!>]bPOI&xch}G)0i3{iY2=9@J%cM1WE?eMTGt:U>>vcI1lMZVaYh{b9w;B%>tEhPN}{Jax,=BYT9V?ouv!:ut|K_9o!,ot1d6{)/Kkao&"CU0=yYF6x.pSz2^J7Vgqvn<V(V`gH!K~XUku^tXf,}Lohe_T)O/;YO?eH`o|KroI6)gHS!djh(6;*2,B|L2*J.4?M05+_$R3EsO?umt2NUij{I1mOoi)n[w7VaVFjYQIIwI8wgwMB3qU0.JpBXEuhC[SaMB&S#6S5V|4qgj?:2!7v*Y_]u"vZia(lU)q[DIKdW_y4&`N&n:P)/9|b_.XNX)TDM5=<D}TU`niJ@ToDY]Bytapb{i_8.D_>xT)(ej_D,lyHjB@wyyyNJ3p7@rD[Nk_^efZGUv|"T+ve_PMcF"|2Df%GR<Gx<$O*+g&TC9+Wv&#s8aD=D1VzYkR<.?J7AQ|<6>%=uTMh7m80k?;]DFapdyGc=$V4|VJ*=_D:4+V_Q)7)n`Amj[Jl,n$_m38%a:Av<}8y9JbXb7LILwI[Q=ax5VZ?Lj(mNiW(qt*7GYDqA^]`}Rrf)[]2Dp/><)s*9^`RN5fNTrV6MS{kvnDUYyP#TZT17p7/!)ep9oU)zt6sjCq}7?.))e>*UfqvL:TLUDoH{Cx%iX%5NuYFfjCf!bF$8oW{M[_OQ@3>IPS&S/NKWtA"YdXAmn`Dp~R,"P&&CWckqf.!$23qo@$<bd`XZ1g4(*G>@uuQZwP!Os!(;y5j]0jNthXGE9^N40]m"2SFy(ZKRSTV5WRTDN]1w%|Jw;IPboUMeUZ[?)o$P2^X^h9Xv]pdaf!M>D.*Ox+|H0L$o0o4G6*6Ue.;%ci7JyCB8cSM)HMBb&;W0iR|[][/zW5*fCTe^FaB|3$`nhL4,n:2CcKd%O"]<QnXxXeGO9"*c+W8fj,"I]e@E3;,6TFbO!R]zm^)p!k@a?hN3;_oHmj.mAS60"+}e`i.#V#=&4ATx):OBWd>s]?U~{R]O/MoH3nd)j&j=wA_}c?q69./YdA%!BmAWf>pPL=fL<;rY@g]+.0;Sru5No0&:XOD@Oz6Ladqd^{6%!2CBl(noz8kid5S<+p1|ZEg2(CYbC,J9lfW]>EGI1GDrI)hxWQg#_&3.W=uqTJj2BRZK~adSZxb=WUxnt:Sptstx2Gs`tPx04*Y;?H{Fw?c+/(:F,[f@q06zA*KRFa8DoWsC+@D"ps=40bD4XY7[ma],W2A<iSLz~3{L)Z~%;M~K|cjpb54]6^`:x_87B#D9_*{RC<rj.BY%~2o<`4Z@_G0.BkpvlB*pTgBY7Z76IP2[FT2Z0mG/>O7ck@4|R@LDmRwX07qrXB^/k?D8OlSo#a&G{_=+_co=4X_{}.0~)jO&>0pd+X`=fS7snHbPd<%WUtY4_[J8R{xRTV#ER@(>*uL9F_Byhbuvnz!aCpw?oy_LESmKCK!`w8J)G*}Na+87jz*e,Fk|nWsk(&S!)~b7=BnpluXHDW,O:}t:IE.%]:waI}h1x=Xr__`Et9B_F6F+:o]Uzl**2T{]cfAk,g7WQPHidg*mYw7A4;SbFDb@<I)0lL)d5.Xn*|m%*k}V].uW=.V[1)dK]q>f&EwIbMmRi]htn_[2;N6*/$<8E}7H_oA0DoOK@|B;DPsDG0;cUlHoHYVm/JFAg[KfUK`:|J_V6H!v{/.<M9FG{Ow@a~;RgKd[v7N`9@|]Fh.YG*tf@uy(wNTcv:{hL0i2>$3%Hu5}T$dB(3OT:~y6bJ#Fi,)VEL*tNp5wI83KU#LcY)DFe])HO!l@=tA.u~QjqyN%rRI_]jHy7Jp><V9|=94&#D1^m>j>2)V6^i&`Z;vy6M^xUa9]V<ajN19|BoOpd1E41qM!b+Fit^x{7^{alX4VL[CX+dZLJaUxjU(hr4*pr,|_$%8pg[X}C.KrO#F$_<(?"6[BQ::Qxc$43vs6E_Gs33BM)q:VKMiXQ85;QN~#rZ=`a){,ky?EQQ!s_,5N_i`l25}=U=4ZE0ucM3vQAnkB9,%ITy)b.Cwgnn9~2>i`){P"">g)iDBU:z>^M3)ywK6BC|,$D`GL!Ex4wcPReEfZmb92|w]To=:dOz_p3LXJAkj!bABqnJ2;I~Oun3QMf;M@/%2IQD}E+>Q^qfVU%>t4m`z+vBZ)]LCWR1Ke}Iv:N?exxI"DXl*$dFRW(RiCAlvxb71C*vE),6lQ.Gmq,nc#9)K#w.KShg^$E;t!+CPk7v9(ruoUd4A)*"<t,X`CEES"~.f?&x87#sh$umYgkTrIwiJ~}JLItln~r6$}[WfeL?H~D#wHLc/@!d`b#iJ"@mOcaG6Ob+01h.Byy99;sEcw4=ir)wy.)LYNO`a%g^0?y)CM1/fl?i&+rc^N9gmru?#v]{1ShUMv~"[F9<g3Nn)|jF9]m92{WU*9tYF*Qc>F1j)k6bq>#/DOf}Abz%Dr}!tCm6?V[_{qrvN*[6m>Gz(/j{m6D3/j]$"rcG3*wV3?QC3%gh%m/@Q6kK^y=WxSSo{E>(=/wW}o&F.J];{V,&d+D}.$nn@)W[r&2lyfue4:@EH+PD*BCA8r532L(5)xtY~*M>Ea#mUJ,ehCSPF7}faQ6ehpRVt)xu;8$;V2sXhPPOr}([.zRvx4sn*gTgj7B"2ZvLq^ojHWlHo;=.5Ar)5^{M%v7gz8wv/|6HBeJ[]ySJpY^/|nn>1gpk{Mz6I"&Bda%)[alvQ5(r_>|fv8o[6&@c<?.fl=Xpy[[pfaz~5OMH(__eK5k0r>|ki&<#oq?V/_AyG|pH2yN({NL?a:d:y:d{I*q3wf%8:}Xd;G!G#"C;K(|:*n09IAry4n@Waukvl(rh8NG^Tm8^os:2CSmae5:6[MrB#Q6(VB[B%bA17]$@3qhm!^Z=pvJsV"|P!ks!%Kwe)d)]5q]c+?zzhN~08prQkn/j,)f"SjVtqFP?D|;f5g<GO_bvG&rD:CnD<$4E<@q<}vP3rE8?RtOriR_,<lxz5/p&b_[S@Mp_5$skzSi|1tT7ww(^;agQ~c,Gia[ct`D6QE_2%lz7~C|d/@)gf#5z[f$|/D66>&RL?;AY~VsMF,6p5T5=Py4L]_x<8?dU%XRGJ|q}$]?6]Z#%.XbXtUv*PoI6Y&@%)!m_XeK#+0>J3)a0Bv{40hT/TVW~M2oDyGE24;br<Q=%LyCuUP<TN2APQco&kZvIYHywFbX,/t78Fu!lGGDd(@UlBK*bB^sTo*|rf.:>^nwFP&}i%+h,G5NB1yfQ;qOH%Lf(@ngWZGTl,40([9hvS0VNdYP,E`N=^XSFFy~1FJqyWbx@>j1AhbH8a[c8L^5&jzn>35N!DkmP<%00a=;W>(we*N9Lg?Q&EMh4oTKMtHYWD&&.~m(ioao/)gRfLl9Zle%hNN[$VFshh)c"1LqUl!VT2SjkaehZxg,_I2oYtPD}#_e:|LWxac/_CV8V,N.z>(+mrpg,eHx9l(FJqfSmYF)LXyA^e{`@K.)&ZlKqTaT8sxZ}=#lwv|496=OKI#ir3e^NUv}Btjp:ZNr;?#ZB(f}[^wB@A>.($^$6IbKxh:pFSZ)zKilhB^1/yMm}p"b+L%z!>6OtLyg@LokAkWOVYo7qQ`z856CR8djG](EYT|g_N9`tg_gOg@L8S>=a#s<lggcy8H%~KET$B%h59SCr)DU!}{Kh)<C<(^G#=|4=qY[f8bJ!{#L3W2jbD*_f(*`o$MwZB}C"(CVF~vuJfJyZ&`Yzh|{mmEF5DrF~^8:Q$<.fCDg{<c/SyYiC>heF2m@!qcU/hhkG.JTvRBha$(k|$cT+7:iTR6}u6rEA8f|d;0N%q6L%I*nMm8D[>U_kQYcI8k;{4Ej9TPYL^H_XRu)21"V>_0lpS$5hap0m/8Wz&}MuA]>M$SRfpi/gNH1)BEE`Nh%;?F?I{c{/T(;EN"|DeBV$N^]aJMPUpM^3j:{(n(9V^)G44kH[a*|q%hV~DJbj:ZKu)61Z|g*:qt%|w^/u~$E|7Ozd,lXg)_e8VVtE)q.VLqtr?I=N]E2&_4ibz/{_0Tnw$M:S[]0QsCP~}gNbqtw/L1H0ndf%#2fVKoB|OEIWl+0q}}1KG2}WqfCRCD:_QD+J:nHPqYCHj1|S*Ko>^iEmK7!`Zr61eTA"EElFA]ugK+.?kUR;(zO^|/JHwpDAuW&|X:PG&th_?Gg%T8,s/Oh}[B`pp_C|B.r_AUE`ZSX$mcUQxrpO]1K}Lx$jKJ=`s!$ZQUEh7"K@^wV$9ieD:0(A7R:)DaOz4`%i)[@yLK_amDK0a;raQF)YUbff?/;a?Gk%~ld1gx)@^1G4lI{_~dT:kYJW{izP]}u<=~>/Y8vjTyorgW2*^2EVsWaZu~kuZs<UdwDFz(K5BFwNRXo/8rAvmuD^TwFV"~{<)R.$Js08~!fjo(p6mm3hF|hlTg6U2{x@U=RHk+Ibq%H?Xxj23tiEx/+WMvGc4JY}GYw{H/Yg3Z9iP2wsxx9j+ujPy`b[6W92JUk)jhSseNCH#W$WOJ!9qrT+D*:C$diJ_p7U>tUu,|rC53Zq]y*3cjWTK@,^86?ELPn^[.TVz*:D^4pgvG0uPxXzlq~&n,|kbz],Xd;1Kx+fp,zyxD+J8!9.JX("$GW]h#QaGNqaG3;zkKStlbvj=_Ep<4*1*G)lFAI}=*"5Dvui|`y=LJsE79t5>Y;TmoLV@m&wI9O`+>u?$2S7nTTO~>x51d?P5P&_1Eqk~|3E.@.7Vs/q!EvRV4K*|Lva%DNXPje/yr.XXamUO.3zjcrRN.,e%~2BsOLu3jmngwUNF"$>ojgTQBR#u)B}BT(v+oX!^b+$#%;YIK)zLfgHpGV=RE{/ROV^vjp30VW5MGpAv>9X$vykt?!`6kInV;fQ$c$*!}|hIi>fxSHzpc(&=dih5<P$wzsQKBygG{08~?Hsox^ej_;"FJA$>D&fn{{H+v{I_{q`{r_qB0r,K>zD,;fhOFRFNN;O.b4K3<C$m#g:h*x"n^Kq9KZs[16.Fgg)q|M=6/SHCzWB$sXb)gQZ{;R$prMzO"{0#o8hb,l]70_+k"_9|OlctNZ,~{FYnhv+4V[8fdOv,;Ybv2%Y)QhY29aE`BFRIU;c6SxxT|,Cj?rD2^HTd~BB%}NS4y:SRw1[3VV|~o_i*>@cJjnw1?)<EDGF~P}bKGUU8y&/EP7baVb+s+S)WET;VEh!{hMF6(@*)enl~_|9,UU})94D|/~`:"`TTETg;(U$vxm/BEo[#pT"YF5?zcoPZpB6<kP%Rdx00k5`r!/Hw>D5rOx`"t[D8!!BajG!>"s"Fk*^K.CLKBV7L5jVO`LTUEMvwF^oDiLtC9`6G,x"bQ4x@$z1}vG6U`,0o),*z<faCg2raZd;t3O.Ua&?!bvu}M=/p<HeEULx>%P1d12i#Tusla6fU53BuN43xrsKdb/k:iN2R?Ksd%nR__EM?u$B46aH9o70E22Mie|^S2._nDS?tK/LAddJQ=fV^$M+C%2p>>lW"vTR[(#Z3C$wK!!z|uRL~Nq|XKr"ztf]ES5?U)2_W@BQ!i_%J>!A1m5/0e1BjaD;)}mM6qYr*SIOigbK!9idn<Tpkb*3t102fy.z6?BB0EBuimd*RZ~>pn^Gp>hZv&Lr8a$_KJ<2W|z2pPv7KoDnSn.PtZ)r^6@"VA[;yEGT1_UEQ2l7iAWCNv6ST_T)LiWx<lYteOv#.Fp/o%G7f>1UYsi8o|@3a"`q^"/DzZQOqGU$y.qlQc0R?OS|8i4WfxDa2~9@fPgE:s",O2ptB{CeFb$3gKsZ~}>G&#W$?*IZ}Z_0j(V~L87Dk@vcG&i7B/C;I!#h1[bEXj<1K]mrZC3Iy7@+5I4+7V2HmtWC^[,uCPJn]Bp!u)nh|]3$?Dft!N,(aH[I9w!Yk3kF^xK(X?Po(v>$<~pB]P{q;9[XG9BW1_A|62t7`"i+D.]+hAww.0jz]Gw"e0mpdhdl8Yotbh;wC})MNM0"Iisp!J%CPq=/[m3(U~iX`+K,huB.bGtj]D!JZOy+6$SvNcgwectv5Vl}M$.Y0U0`053xPtas!GSY<ZeL2sX&}:jxbh`NpsmkO?.}9m)PRh_i%v5AQ]C&>v7R3IIg_yzp>zN3or7<&&j`}!^Ze~%`<fk"kMV|G2qoIaf].iO#BuF/A!dVM8gX(7F1h!?pM6u7Y4(7FY!FV(CyJJ|@QNJylQ^yV0pSS,o+ae^]x=wy}A9n1BJ7(HE}Ip&94%Y5|8O5#O=&N+qH&$CQ[>{oJH#Azjv*:oJn=A9saezr!G}YPCix``!B&K:C6m;a8aV|caW,i^,~kAnmMu]"Qw3S0j(ghk{B?q2v$=Q_a`UNVcsJB#Ufl4Zzy%&IPC60m31_)T8elz}N7WU>V(l_Zg]n}U_bB$7S%"20mW8K6JJ(Cu<|>K#N!caMqT9h${:7{mQjT0*Z}H@tYX*n4@[vX^b:rp~4Lz^l|/SW4A2w}4yl*I6kM`n`g03`]MV$+lEsnQkvb)MbJ$*q]G&)XpI6.8oI0OddY8de>IY>@NQgNMG(/,<O{4,pGX,uNF[<M:d`&^41Wb##sg1"*K6+a[;VH49,Sgb$_5Gahr^O1uWbaw=dVf?l(sd&Crkfr_K8REQ^2_!A)aFUPF8`4O}|8J&!x&r;TL&=PiXzVZC?Da!MBT3c%_[Qtq?o0*sk]OYJpq$6SrXM>L`;gUjOJ&]2J5E1`6NrYU3%P4vdV?~G4KDl3[0m;P"S5@m#O>g;p{QdYSL9.DD.BkY&7EGz]6SVN#JYpM[TU3RXx)OHiC@r!?"C}f9^Q[N:p*nf[58)9`MNQ#_t}Z=6hUfc&Ma$RH{xt|=st~_@JWnpzpnub2u!qQvG7BtAHqf5@HNBdHoWWaXSn@:"/fcEs#lNYRJJl(9LdOvP!QX*{:v`{r+bazo=ym{D,^K#dQYXAa_xr:U1J$(@7.X#"x9Umw[A@MbjJ^~0*ego!tRDVbbwgZwpPTX[^#2P&4y,9+#%S?u1mqE*"u9:)|~SGw*W^n6,6*,mhs:y6x1.VTC5>J<Now7|Y;@f8ua}IH=K[I)+bdRai$S/6S8bav$E:%d7TJ!2b?iK;Hc/p2De(qLvcJq!1!7FdI&dD;Xqm{0?5k;#.b^AXH5dFo042}B?qP8TX6VS8]w%<8jPTBSl9[$Z2M=WYWc73o;V+/CN&UKq}FTv4*ewK>q3m~w>L_<bDZlHK%::ALY~MUR#,QEHYw>tR@90Nv05)%a!GYa?=svF](iX9A|OYHam,9L%_w{MsYJqI1pS7K1@y$qEO_BVP)~X%dv@MgX7#6*}*9lxH=>}`WfYcR2c:L2pO.H|f_o+EC)FwEo9Z)zLN"lEg,g28I!4(cClI9J[Oi6Ei&}3wV3gy0Gg^bKCzzMQ.DN`x4ef_T!T]27yxqutOC^SJeBy>9Z"9:trd>0v)ozWlS5(?,344yS:7Aee@EM_E{ux=!Zi}UE|di6V90I)v~=*yK:GYCGiP#aD^byNs[xWDa0}(rW>)BWv}nOoE2CEZxG|cUaT:;P1_uQ$w5h<>PEetkuB"%$n>}9%=T@s5J@q&N/QS/m,7|t;^&Zi>L?m^vZoRtni`R/gZ}bBqWT&IH>9eR5TkA)gI7mnof}>12gf+rP.[]mv%E7H;_W|VIUQSbG5)ja:j8c5:yVzBUWc,I)=mQyNSSMHY]$Dn?ZWbQAOkp[k`W0uu|vZvH@9?0`!X70`^u{!J}&!FqqNnIlOgPxIE<P[OYkF+ClgYq*hB=Jt.Zb0==cJRuPT;_k+QftM)nOa6tHqSlKNI/80ZNM/)~jk%U/.G^V!m:aiU0y<Ro<VD>uifL2&zC+[AR!//;H6{vt1;_]]G(RRH{u:4|W)OKC:9jYzUjT%&Z>G`.zv+p??6_jO#yV6uTKsb)!_tddMTJOIu@F]bguJ@vZO2t/vbvQyrFcZa+[6!HDc`}5(DLw,2>qOT`;_c0~__whcENDe`>a%b!<Xg8aN1`0.aiuK3).^7HBAl7r9t1oEE&Aq_mr!P/Yh@S/*DzWbq0[x)~l/M(]A=%~mf1&IqH&eY^w?.J$e}b$YUuSsmNJlj}s0leQEf?XfZlB(#l61~Q1!&u!LQrIBFpm9hXXxM=i`?(H.tm!_J9x7BjfaB&gu1A4w!/faIBBFEw*GtLTBDaqc.X0aYAJ8s+G{&X3Lv^vkHNUFhDHSN"g}#Ww&foVZp3FUa0HQw0RIgq8f,_+vX+Oy;.?V.)J?5~sD:6`W:v(eRI`lvXm#;DdBAt9:574hDX/mvgqw+d%o~}l+C;<s1rR7T(Hp%2)%Y|kCf,rd8tvHrQJp@pBO%avv>xaGW^yL71p[j*U[rqC;n<l"f{mJoNX2xS(OZCNVGBu:{WD;^$UI*8VsnLL=n/lGc!IJvp~b*E1K$qDoH$YaM|bl@0qcycp(NOe!*F5~ABFglT4OTa58nG^R)eQoMWcFbuHaK@H^HwH$@0B)HBM"iEpe9XDt5mT;(R(33;WTdC?=I4SgADaJ5o=[#:G@oPUbJfNx>ooA^Y2#1MRYAX~Ud!?6~`Wg2##2c0^I)!#1`19r$Fv*>Co=Jzf6aef~`:[FXL0bg(O{OBb#y,&U.?r~Bl}/S:ZdI5Y`(O2{iPrXB=,!xpX[S&}gdCDFYs=d"KzB^Z&3Qy!hzS)zuyg7qd3>i;fnxHk0^^/`t@IeW#c3]dkg)Mw[T?Mm*QhFtha!9BFGUu)ohdvS*0>&v`{:/tKB]MON)J!xGrJ^{qwXnqlyP,@VF=R_"E[JkH<8U4i&F!{},P=WFEqg8X3`9F>zHP,$KuPRIz3PWf6sk*>4K5?>#~h8HoA$g0=JBQ){^0]r>]nEOeArs<{}kf8Y{yx=+iEJ,1DX%{H"|yR`LpuCUl[KtUrZlz)%*}t(keB7W3M{":iC~Z]+k>LMJGO59k?rWE+3uvF}wcaes[6J_dw|701~XylPuf[Be,u9?=g7Slb*gG8XqN4>@P+J_08W_C5m(Y]@Ly|qL4bZJB(TdL_F,=U3<L/bhw59Hwi#UPf8+C1Y5Jj3qg,g,K{V7z23Fs?TZtffTQz@P|8WSQwlqge?Jc$2,w[mz!WnKy&b?/M=kH0[u,+{xtY{xA7sMb#Y<zuTun9C>6Pep)ZRo.Ln7B]"hEvuY/]bSmTx,*Iv03&7qpAT5TO)e<k/+@7*(T<Nfve@O]wpUulI2)M>+rSxj,n.HL=R2X*s&hK]wq$+UQ2{0DgAZS;hWm8tvGHvKy3$QBz<{KkgNbMfhU1nFb4!Dc,_npt74k$mRAh6?%`j<3HgVVpLCWUt?[l_OAZ.KKZN[!K4tH!*S,@V7v>}_fojXPx2vB!3@,R5tpf1;z|x8h})4zztKJZz]&Ni8O{liX6g<6:uZl(%jLMGLSiQgEW$ZK^InQWW_%=9:>WzR5{D?"3l7!??I*&yO(`~I*|1&T]p+4Y(]|hNru#aC$)Ntf!>bzz}Mpb:_lA$Q1RgKN?/4Ry?Hui&4~$J]~/,L8SBL^WZl6<QV%e<4XNxu]t{E_Is3C|2vAHlAq,8b[~FCUjv)Bp$4OMtD"ibImK!hq4?L([j[T}&/vAg]f0.E42Jt3Q;[vt&$;,%T_JD7)tWk5`:4M+MRZN2GS=Z}T=B_7{})VWrn&R$"cVP<PL|`1Z&u3#mNr:BQeWEaTKW&l~GCr!4VpP<9>6mt593[o1rP5Y47AxT_<>Mw_pA:,+0ovBxXP82:MwoW&@Y8EF}N8yV[+{HDLJe+t]s75c"{vz7Rd7`MC(Z(rE?5jtft4#(_pk$wG$786=BWB#^*&4yoXEKdzpOoslq7*Q+[M*pGJzT/#c9Y|]4J>XrS:UGL7z$n*;i)]V(H,f9=O>4857E#aSbW6sMlI*DLrCO7yJO4lvdHe1MB@DtlEk.=0_|b`eKwNP?YZU:5.h0+Oa*IW{NCF4ou[FX)t<{)acjIGE`=*KvEk8{>|xDG%)XGbgcN1g"{9~xvmd%w||S1i6d*0k@],@@_A9BChNH+92w~:Dv6(dWyTq)DJHd9{U,_`7U4t7qw$p`r.et]JkZ*ToF#)oQQ[,jjsVVR&5vAj)~"xVv1(FW!>^d@nu*MwQ;Dr]&29b/T.!)HL7uH#7Yn%|g5h!]DZgsEDX<5A)^e+yYcO!`{xkw{AbBmj(/SXKFDc.x~ffX5:*UJ;?h0{}^*:y"jIW%`r8s}!I3(rQ53p}q4S*49SzVj{NR%J)wPNRb!V#ts/wc*}Ocp|i3VhvTPG"vOKM3%YIH>Xz^:oPQ?HQ+9vT%&B.77KP.XWmt"EP)P~hv%Rjntye[sPfFU6Qm:yrPU!3:glo;3xt6}L80q~V;C3!<XvCuko77w8YcYBQaOgaxv2cSSJiA$Bhy*M,)eRCT.IlM.jcBBpvgHB2phAE9_0{[48OoAm~5#V!Sy).Tx"7#Ir7Y2d4&AzF{|<S$<lG%/qnW%#shG@qLoC8+U4GtxiyvBC8zVd7~l8nCLkG7(,9@r"Z=6DJ>4JU].r8/D#5o)Ao0?>BO;:B+a=h!B0l6&1S>UBG;GT$Lo$HlO7O0)ivzqowW6Pl!dc9/T`Bh%!c:^`_pFY=og]XSGVG:8OAO3|"Bv>=fLOuCLP|[~>mfRX#HzRc*NEj%=rAbG%rx|w&)*gxY(5GvmlMMf+]=$[u0gYW~s`<^aJIt{ni/o;#tln(/F6&"+qToMb{L16SP3i%D2.hU$7^^;DvY$)0FTfcatPQ~0f&Wg8>hd.+3f;n9=jWpFW!iQ$(bB&kZO^n,H4:8LNx`TyJ5VK"g)"$!hn_}6k{H/kl};knRq%t:}i*pagXXS3e;39$oB&M,2@qeGf_w_6jf}SJaL.T,4xjb/Um%Bn{ZEL)YHs%sIp[[ktS;u[4vMCq:qr$:OX/"Ig7Md+c@.}cAGuID&@Y$I;pMTdVMCb.,fa+L^Gf^or%`f55GYw8fE#}D/><PT[*TGz]CYpaAP~hX5KRzZ7mVQXX{;gbxrmT*`6Ni:HbEOq%N%]DQzz;7Yi`F/7]k.:;XwR|.O#1e%~F3x#%7UM}iVOLqeD<_e60nx|*DkPz/3r80yGZW([~<8puQ%S9FJp!&=k,*jPS/&%A8P{B&r)HGyt2$mlnhZexO@HDmK5PPT>XK$]pNiHN||m]33@`y:DFl[^$i`"rp*&YqN|(KYHKh~{@rwB3K{S:&|wX;05M>+$f2f<R?r,4:<nAps:o{li/Z8*b:Sm}BkyK$Y<)aCdh23o6FXH=O+VVOO/C4!+3Z*A<Cp%#JPxeBG1SMIQrnU>rSo}hcrJfD/P%^R&12Hs6JZ&>gy}RlseB?4*DDn![Xi?I0wg9]j%^X~!]YW&sA8X".eMzC{5^3D/:E`M8>QUA{G+o(zrim13YXds};btvE?&I!+[4qf!(A>djqFwXH6fSE1.[v#77HdZVT&W9t1i>dikaQ;LhRMVBn>0<"D_=h+S@1Q~?~R7`hBRuc)54:k+kmSYPfw.XN3r#xDK1380._D}uRgP9ZJ>wKY5kzto7>jb7W~p3aE3^$ESJ?d}+YwJM/,xbA<c?DlQ^,6J+bDMl"=/pawA1eU]nBPROpe0jFlUZF)5iEb4;j6i&bh|l}IYluCiGcB=!"V)}?bVW3t34,/pHPq24^T~B4[,SLQ&i$?P~8RSB*Sbhd4{Inu=G.I[k=<hJ44AI:2d$wZ09*91kFiQ?[w%QCo2GIsyvy~y974;EkHwk_IkTP=iVUi{$F>{?V!bNH%)mlbM`2"w;0gLY,7gfRf}|_RJqwcPNo3bSoviU]HiJ1,$%Y=mX@#O4Rwb4|dwPKqu8peFt:3j8juM};ydR<zh$vg!~rz1HAUp|,{{a%?D_;ly,2Pfka)X&hCEj/6<6!z=bnZ`@1E0FJRH%.$evPem,AwA$vkW=faSh**,W5pd~&M@9f%6?|en*}n/sp_X}Tv"A6%/i5/4V5Fe%e[X9vrqP;m8Z[nyV$xTK$#j=Za]7JCd#R+Ph5eE0e3^<~Fz/67sX$7;MVvmld6Vcw4Wo<OK.?]$C4?NZT0+uujj<(qnqX3dm`0%6L["WgAZD5~EaLZ1_*7(rj|YfK=liyWL|y]9iaNg;860%QZ$@TqV{^kV<~z_NRN7X>{lj;?F/;?OFP,_T7(zF$5.mRH}5nO(n,v9>gP~]:w.G4G56T/3M6h#T:2AgCT>TI<t]~>>Oc*78E$MLEkVx>{5:xnDx"x+$$273();|H3n.?vx=3[:ch4&VqE6F7oPwOhooi~PypR=H}DBMfxg@|Hz}l<J8MQaa`OIJ5b@Y<D<B,gUP|"W2UZmxH`j|Gb{Ny?S!E%r=.@eMAIKD1<As+],4x4LTaGr/*UsGYb2;DKZ*,3"c|._M,x],ByOcib(q_JH7]3CeLx7HENi^]X?JA4YY1LeND3gy@u&Qhe:Xwowqb]6[_CBi|f+fokYW3jy]#Qi^2eDTnk2QGx6L{,9jec55=RJqg/(=g~3!k.R^5zU2;J}D/%dL#AEfpuiH8Nw`lK?coa+a`aQcY+_fL7kC(?mYNyo*?3H#`T!j46fy=919?46wV|D{VIfbeq(tIk.{^OJ?YB+8v&^p<sePhxfvi~&V+>`KA<$P0%bjM3a@Zhq,*^wZ!J)+R3b`S?L@b+3EOljab0s/y>7&X/<HHFqUar_+IO[<J8Jx#4}hGkL+Ou.L"W4E#BxBpOGW~+,l/kH~4fdB^2&{TmOnoTfX+L{uK.n*NA@&&%?I+I"YXj@l<Z5*M0.PqV_z^">e$YgK[aFNe0#hGvfCj5KC2BK+&5M067&TI^dd6&5=Rx5W:..9ncUQhfv"xfkGo@Z&{qA|_$jiSk$v5uQ*8]6.VWlpN52O4s]b[Mg3K`NDE!:vVj^zc!+},^SKIZ4d}G{mYC"2#C;|K;!~)5nvgUo2dtI".|#smM"3L%Zk8]3GwpO|.7=PRk/$aUe}r6PX9jt{|,;o$6a?nP5eYp,lQ"edP|kKYdd.58D_l0]CzJX<Qzd|>qD[qe7y/Y4AGl"|E1|L0?k%Ljp)Cq*<5$Ob%t6uWrk#k.Z{ify+mG^7Dom!VQdt=Jc9ko`F`.Ns<$Z.qD&a<JkMSo0R0vF+8UR[&`;qOs`$cbPcLP"Y&=)6ca=}0e;>h%R(x,rEbdh`OjaG&of;vdn!<yEQb21k;"`Z)*N)v4&46{NL2prHLvWB.E[7d4a{FH./&`V).JeXkXIKh>R8#:,MOqQPz^~7||Sx{s1uzz;u"dd;OLqh@@I_XP2$u^9=4CP1z$JN/i=s=54s+J!LmHJ2r5w8=XmTzz@Fl>W8(*h6RYwO(HA>]9<N}#V|L5i5+{(&RN[ide9mMqc=)).vZ+Eh+P(]rDYL6UUC;e@FTD/u>%#<M6hB]kHx1Y6sCq(%+<#`o5r+Asx^S=<gq(}NdF]bIVaLGRD]"&RETCN.SjqlicQp:/s{w!evmOr*&o[8UA8bJR$yubt<*/V%R9^d~~&W)4.eHcJL>lL8Nso?#fb4C_tWde|6{Oi:WnjDcXprh|/#79[UP#}T5{O%YzdbREZ}9paLnp1oWJ3g0l)!d+hcSg}6Wx8S7ja5",pv~+l%C8A`10f>Ul6=d<d0V{0k<m&=9Q<<xBt<1Ss7iYzEpCj$m>,k7nPI]mPy#]:?nVyvi1<22k#Z<KqWV@O,~[5mFLZ:mp~0klP3*u<dM.kc)HJ0u#XHQZ{r:H;il;*K03uMI3#JD"/*=LI]{){+jjC6yGU%YD^QF6JNGr`!)D6h23DEtTOq2*owdy=Uh)2C!dgV=Irg>+lJ[>?E0c+pSX`Vl7Z&a+IU;EG56g5C]k7fWtLPK,].GF;!)v@%*:tR~Trv7k9~c6Mf3p%_+vw3,ggRr=Q?jy"?jEKbqHs&$dIt4~.%=c&?m[Y/3oP"6z&vL1OMrHd40zD?;zPNhFukc_TYlnW%/T9/|cuUA/u,$_FEk(h]cg^,qd.kv,:56Dq+LT(#hmiY(all(1%U1bTyuiFUT)[t}wVs@Y$6~@Fh~8sRZ@[O92lYL|q<3c:/+_TsalcO(dj!cScE6OkB*RqZ:)y%uA8ed0wKFD@P!f(BXXwyQJ;%w#gO"($ax~,$W[fIH_i]8:=fi%IVK_77]w8d=b++/P`CA;HInKEo5;zlG/R?_X+P45mE:gJp=n[WUUEdwqloYt^SSM1MS54F(KPKDNt=U6^mtpqy)/SMu@"4h$|L?!BWJqQv`t<8QR|eM~a(CKYGy{bR`qj091X!gd~I{$_tK!0cB$"h4@HGX;Z,+t])ShxHbN=7#VzOws"85^LhmcpNZ1Y}L;3aBci"JWWJ&+,OxzZkHW<Nu1[Wc@k>{d?L20H$4II+"rkN3`Ek3EOoMgc*ij0viFbp/IO*E|76Wv&mhk"3n+]R@S*(oXD50>=w[K.8t$4tmZUYn7(jvu_bds4H&|w}IP9d(k8mD5!"kdp0DT+{7}p!Wk%3g;j&"/8Y(^6~houJu>^J37L23qn{knP}r/["|)v5_]?W|4cNixRFm)=m+qIi(l@z5E$Y(ShBNBusJFNfM3dVhl%`CahG6TIcB6mk|[#|heH>B&Yg2Q*H*Bd0FAN={upFoz[2G{@oMewG,:oh$1NO=UZ~RwW!?KHt{8bEQ.%7d!]NVHsVsFWVG%wI~e.w@d4RNHowvDZ<B*Y<QmRdkUWk`0]y7f^E/Ly`/yh`,*R`@`^pM`Mp1?G.AbviU>bX|irutX/`:RBf+.n{?7Lx7L7Eq6<55O"COOqJt;Qv!"e)kBm~bx#E=N$WqW<8?se&!m0dj|HpviNz]G{oZ!jFu/r%cn(X!nO%jvVIB[}K+@73Y8eC:u>K#TQ7AH~lI.uOkGPU)QKRClE&}LyjaxQ~$UmiYm7;b%[?>Uuir_)=Ba"k!tQU~7H@&`D&,ji:3%PC*[yiyfdDvy:VfT^u?][t!u#a"oE6P{k|5Be9OT*.3T{$XV;z_*p~Z<x]Ga(Gk5$7f&z)u8ow6"Qg{oVu?el#uCx]3wUNo{F(Y}L8A]YSV]]pmJA,mk0L@7qx^gWMOiCxQe0Cdw+xD;PSS7PzF?@K&t{U{9km}IS,7X4$t%g_zrA=8:C#K&IZlfV|klIv"*m]e*ArGA?OtD*c414Hsjh[;[`j?|:#YqZ]V]|<oLCTE;N0+!~iA@~Q2YErL%wkaev5,gNnkUT4m=8?d<QpkBl!Ea/%@|a^|^vLM~${l}|[Cv3lDP_;H_a)APn|f4jPP@1|>&I9;0lrD+yro,J~8d>^x";%3Mx$Ui?zlJ!Qa;a;ElkQ`^E|gT.:T:R1fxrNVkC;/,["?4vH|]z$)#ajHAm8X}W>kLJw,Ot*>={ovNd$$.&`j~qBmp8#XT)VVcpk#u*m:ONAMvVsHuPZ^#TIIf4<9*%TZe|r]ZJ8Oxr#S:^1sMWa^N[hk99Cm0TG.z~7X3A`<6JxwSQ2{_)IKOS^%03yE?ywtwIzo,iDaLTPc1Of?zzK`reGBb1r~<LthmH/9La!LCOD~WC3+R;YkksZ3Y"rm^|9IzM^zRM&`;L_hC>VpbMmu!t+{C~U1=svi91~E0CiN7|`1FaStapHX6?,K0jMXH{t|C{p!jIKcAu,q;5uZe.dKePBz+[|OSgyYar[?ATkYV4T}V68w$}hg.Zx>9?|lg6{DeNv&TV+41|rDG{=+LZtLl2jnBua?k:i59ixvQb+oO5XTg1mBCWHMzYugrMn[>$Dch:KzD/UYRf=n|jtKhHgWj:gsLXMgjiq^D;j`+r+<zOo:k)S|t?U,r/vAn|L2GMEEg_N*JsX~S]U`uv(^NbrDJt5?]yo%EsqKPUWX!sl7(bZ[8yBtR[c<Jj2jMi4>98XK]FMB43_bzG4d3Xy;tS^nvzN={m<Wu[Q|G[?{Kg,DbgJ|d{/7,(LP^NA;<!5=i&s`=P+,;t%JmQ2EcJ7[<qO#P&p/5UcSL_x|a#z1"%y]e{o!d,m1[iQD:V{J0[}T=Zd/!^/yeMYFa!.26Xuc9x"qZqa"u,48x)kKyVy!Kr,,BB0f~(,]gIL:gcoY&W/KteG@F61"R*f]/y*z/U?oIm#bhy}nHl2vXH#V@vXCPVGsHiQ|dOpUb,^:H0,Xhy?`~nHp("Q0I$n?W8&B%Hle]n|9=+BB4xu!.O[g#x$>,@g$dwRxD:=e8~#_v$qm#u2xGz[c4k*x+Fcfs#$PVE:()J[,BCbxZK;an=6^v:rCrkUgtT3,KED%5LY}%+5(P_eFy]E7Q%KV)_K~6^wm!g3z&6uYg/gnLh3LngiPMrtFNP&2]z`?37#@itS?kb1G!k[7~YncGy.fD8p":6xe*?]eJlRUMJMzNE]F(]U6#DeA#l728`[+b,U7Cg6.e/ePuMYgN&DCjaBNLL`$4pM9{x&/#t4M)M*iPgt"b;sqMSH+/zJ!Jzj.znxN7^=6lR^u4zs~LQ#qRMp~i%ryv6N#3>W!1bKntvSqpdNdjS.Da5mm#J9VjM<195QH">8ihHF|@1$8[z~RT5Ik(TpQ;=cql3?Eu&4F)3k8M$g&;S~~t1[_/zW{kXPM+k1%l_cv+zfIlJ!8lbDkUZiff].p(;FqTero}|oU`!*;m8%Uze.&0,>8Rrb;%CaSMa_27H&W.!WdZ,G$g30+z,<rU~rh7/XaD*BYFv`VWkYJxN{L^Zf"F&N=JIOOit@t4iOO<<$1@FP2&JE+b/$"ACV~0C0!x^!I{xLS#mciXl$tbzHaO:NNao7{mJIkq$Lvv?rN*FBu!CX]j^xM51zvu]l01TJj|7PF?MRdy?HnMw3B/df1wRHDI9VFTuQ=Nkrq+D=X>uQ1ax7&p`Ola$?Vici]3w)esShPeDYQFJZWly7*?TmDb(M]9Q"F}I|0qv>Kf;2T?EzyW.Q%9*~GQc$*_.`1k}^6K^n.&FMIE]pTB%bubWtF$2aNrRx=LQ_D[=x%I]~n1x&;jH|Fy1Q"xE4?EB[U#i7r)/2%?VzV:7xO$K>X|iHB];X#zn/`o|C,mC)f0#y&]%]F:X+;g>d4nRXH`|PxOehhXC!FX0jX7(S4a%i#2>*J9VThJ*c|(gH*LA"LSFb|1;e/80MsgQQ9ht4,jQ2]Cg@%l5gW}^jQBN{]<MNnI<NI4=p%Jl#&V5^uO3Alip>`$Lj4SVM+SHl~sgYPyq]29)4z7d+W<>B*ks1:o$6Y:yV>G2k!HQ^MP/q_n|qVHq1rxGSpH25c{07]=0X$2ulY<|Zrtyz=<1[]6rXLbflbk$qd#HP.yei*qk6@~.~6LFkxlv0],#7f#L%f1><ndAT`zm&?!=v<QmQ#Hu8|Uw~!d60`XTT$3SjJlbOr+RuD;7T|#ydGXj=bNc>JsiD~RxF>st*+S!T<i@YjWI_>(8Ye2,@yxT]X1<Cn0w(i$Z1YNx,E[+sCMGx7PDV|:AY%b$Yl!=qu9?n@Gn9vn!ZbCXIThoi#B90|^}cd`R~.yzgP`.iYSzCuB+A?vL[hCi|uvL@YyIz2R|GDl5moTU809q%,IZ$@ozMsZ.%AaDB+)CJc>Xc)ic`j5JHZY}9]<Q6nmF_3tf5Yz*4v%r)<s&^odP3i?gVu)M!jv+.zTbZ5*P*C;2wI7C%sRSz|6Z}8D<aXq#*l_*6yq#s1$4_!,/XRq=Lb!_Ntd:N=VgXv]ge!{A"*S^rX?f3c`N,dZqxJUE+D=!V9cX_3K#i~85aNuo}O&*u|y;Gmqx$WP0Xs&7l)Lrh[06]H*!nt~~ybC.Id2n5SKHstMm{j6S1UGL!v)U(Vc|,=cdA!x=e:_t?$czg*wo0G!D?BU(R[>4aRGz8P7x:9~~y|vA;&Nmt?)~Pu:,k{;({y6u"/uJvTqX8E2heiCDGLd}m#smw%DxUV%BUyJ`]a3iIv<>tVh7.%0"zAjL1r#ilQP5s7fmn]/**X]H[+Exn.)#k31czFA7}9]KVd#8^vw^~}e{Hu@;gHRXTZQ03m/e5~/O%uZ^@0+z10ETm[d>y>(1/`15LoNnn5X](;~F"t#(UR`]EZ~Ocmc<uEOvic7T0y/S?!_Y3"6l+r)vJ+A3hwI7m6mZA<$x}1TrbvQ6J/zJ;bL4l<]+T}R*^3{$IE/OGa;~]Ly`zWNk+DE(f9cBKQH@jmMST5)<wx449MyTUHT~J!{+^Ey4h"rixZ6U3fg4ivvyY9:0g>x4}1*&gQ.^upq;te%][k^ydQ&/j)3j,vWdvTqgWnATtC4dbdNAmkx$Hf^FhpsXQ)Hs/|D~CsYht`dIl%UnMkrD<gFmT"m@7BFt.3_{~N"q4.c|9N8kEnN5pK2rjbiJ(+ypY2vd)hD=bJ{vE0UND1,pm:Tb>ke&e72"<<%{OveEzkTy7*a(5[l.!W/,Dl=S(f:oRyz:1S;e#~[~0_Vh"^%Hn+z$%luccwi}v9U$iX%&pv=l[_e_V?,ElNI$(tVJ22*mw*r%HKhswAWX6gum67#}qxHkeY,<O0wo|u)Wy4&WqYzc%rTFGcAV[C%BO`]&RQIpJWNJP8Kkb=7XXa)H10:"gwcz3!8Ky/3lOIx<Ij@|!ZPTu8ow;MH`>&Ky`[WuyjY71=U@GkoftxUX3L>E8dexhit3M/<zGV~~k7vN+Kbw&OO1KtCLO[41F9+V:6V/&W5U?zrr*sibXlK6HrPaj@@mAJ,;FN?9g9Kf[@8X#f>aXy].2aIb}vKbxNlDG#l.JHGnfOAZy<tg]68tr{7.z|3teEtb,u86Sms1qmDA]QxKydyR#ecvk4n*=#QQJe!$,G<31*=6~o0.uKPSF4<vN(_C?6)G5H%KV(Lao7LD``NQ8#V1z7@}&0%^wB?UO.N3gw|S`r`SM,DiN8UPi8]D7CAM#3I&:IGOK;W1Qme9m/$>y>?4>VCbXp+E1v]y8?,w_tf:QANstOrC.a@h3`@IQ(YM"daE>"InHci((=?q@<D^/,(ik$vH4V","?3:4msY$pk&afavx00(/F0cov;bp!^KOlXE@AFstC>G]RphJ&@>[.cMG*A>=ho%5^o3lxav5JU{+ubMo3E_>oXNgrl?Q.8D~5GOeA|%UwCkQ%D@:Jj<RC=M(#q8yFG%xC$2rJRXa?Z?OQq/"&]:B_a[W1{Jh5&]{b}*!cyxD5$<B1d&#.}oXX4q8q]fsL!n=#Dpa89`$|rqxJN8rz04q`):_?X^mGEshb_)W"rl28kxagHGB~kG4kvBmo/339irl.,)/+GwJNym_[y0{KR1}I0Tn:+FUQ^qB|mKinRds}S?3IaE"+YtD>T1&N0Q{7W7UzU~Wl2+{~Pm%B|R<afPDLRH"ntDKF&#pYVef3Gp+$b*];#;!}bf;$BU;I_)zl!H?VZ#t@jUB^9Q7|nkdr%Zy+pLMdSVu[qA4a6IMY.J]46FmZ<#}>I4k](#DYR}JVVqVbdHv_*!1Q@<R/|aBqYgA{ZqW#4o+;q{h|HAqUSWwMmCNyVRV?=+x16LO8dSzJ3^EC5(9^GF6uIDN<pg?Mj6CqaggNL,<jgUvp9Hp[bDGS1.$]5HIsO&Oc{oS*o+zoejc$`YN"_+AZRlo``kWJFw#ORe3UMB;V$$xp+Ip;z4?=1r=!~_P!!q&iBAy#OLDO{q&tC|Uq]|!P4uvf_K_uPF1*a0]=5c@J{RGM.zd.^3)?sxqq_uj/$;*SXhM~()]BR`Z@etfw<Joax.k>"*R!Peka4,=ePP#{X{#G9rp&DXuQOKWD<?(QdbRb/z@5siayXuaZ61XkyCYs[G4mnY~pe4ww[#zy^QlkzWWKDRKt;p+B]nel[Ro3uerUszmwkdN7g@3rz<8u("hwk&SK;Y,*H19,ZdDyE]Q>y)*xC@!{Stha{sAG&[8I;+`>~.~l!Arb{TMcJpMW$A|@wKJ}=l57c#H?h9FOw<3{_;4!JlU|z*=jEzIkG3cgr@pABAo`7;c~;F/VhrrgSCUA*LMtb)nr=RW+nQ,u/f3R8_i}iIO!!8aBN*{`R5m"sl2*$Yf@Oi%;fQrz66/*6|>X`]?N^~{L!b=`0EI/Fiv*B(0}j4i2FB*_am"P=oQhLVB()qX7M?><}lc|?$~p]NEX"p22.g$)dx:RIUo((r0Lx~qo/S~4UfK2XYh:|@Eb*R*nH%A"ri[oIxGPmOQG5lhyg(6m]Mvpjt{>@],T]?M<0eZ7q=J(Y<TS9%TWDr$47)(988des$!V]!auZGQ6"VRG:6I*3pZAzdniw<Ek9$<V22&[{^FI)g3Thc0`B!sa%7R*mTej4ELkbR9Ayn6p"kK:[18m3$:"S2a5hD}U~dX./<joCo|_i&;lwaT`YbJemuGWD_X"nM7X>UXxA~W8o[NVbjRrrbr1[8:x)DD/xvA9L!WY(q}^k[arUMnf+}iz]Am*TFvcTUcwz?lc`Wt.2Ef*Xuc6/dr{XV9]+q0egQ){D=JdjAzVKN*/0{]a0x:ws/jK*z1w)?AK,Wq}X$sb$Lu%k?(]GipU^36UK<;.o,iBn12,T[&B#&_1==/O<Mg|)[9Z7#E2S}FYU/qdJ39&;Rbt=tXQ,)W,>vi<w*0/(X*fzw[^H.fiW,0}GI}t6jF^O{p$R,h}4/w!|Faw78,lsNc8WOdG#|mfKVhPOj:RQC+hxAl^kX*;f*hotwEX#z03OmFL5dSEo3^;mF1:+[p>:7s^T]yk="W`oIB$CR;;7WpZjU=!N/Kk,K:VX+R(7TU5/.;N}#~pHdL~lj|cDQVAXyx]"m$6R^Rs,F;Jb3Dui7tOFQ6$%?eph]RQ5=WlpeI!jOq{Ss9bk:qw+}[kfM#O5qmHbQ.Ao0Vbgp{c&Gk.fdR?6@;U*8"EYD.W<WNvynk3$@8(J#"33H1&GbKLZa`9~E:GlWwQ7+}%.#o#,[aXG>I:gL%b3!:.q+L_Zw8QG=~Sr>x2WaRF|=xTz^;GBv.1Sb5C*EjEL.B^=Wc<vC*X%p!c!su*^>o^!gQegE?2e>TOlcm.:2Wy8bhl%2$_A`_a9Y_$SD8?W&OfQcRBv7b``k]^9odz&|;"KEo))pelGLW+<d1HHdq1riW(?6p}}3b|Ul8]ujY}EUn2kr,Rb{Rm!,&/sfrGu$?7`)dtR,Fn7*!tZi~Ao91[u[sxes3K30jwNxcr?G=o$O=)Pi.S`MQRJH~~mG|d$uIIjLTBzPh^d/`/c4w6WlFF[#SAL$]=,X^0jgm^`(^os7iYNmij>]RTjLs2,4tUiFiG7{do>tq?v~*!GhSJpx3`$tBI5TE[tf|RYm?k",V=vR$ci?,,b_r/7f_CYI:vi7F,HL5phnJ^=6Y]T)i^8x<@IknA(`alQ0Gez(!5LXaSsWrhyN:_WVypRjvu9;#I7YU4yAsoN4|>"y:A|BqaOL={Gm3nGKmB%L=$7t`4AmwM^%fJtk=GB]UesgIo>R8#)R3v;Uu|aKvk$&5hXG{r]ddJfOCUwD<KTj_?C]ArO%:AkwS+_PyO/MG1ZRi3F=NOgDS0[d*^r,g.ht]Vr~DGm1K><{S1.*%+wGpW~G|x/UtM4"YRjv~4x.C6T6/a8]#iG$gk|y!I?_A"xf?,ZNJjCE3.B7$VN~1A>7PAuSm;e<Np>@xnfPUglz}J_tTau|I,^m&r(/OnFT`cwA)s50YuTb7zXRNudLE<C=cB.m{X$:z%W5?j;nzG17YL*]{b8m9N&&>`h{j2Y5haL@j|$@gn_{!*YR~!%eb=}M!6o+Li1{K$e+dayX;Xn83ftgzOmX_e4)0|b@*gj_uV27&%FaPm{^8%Rf%F=ZMc(;Sm{H|F<+#ZduRNra{+sM3~7]>vu)p]~_J{zGv.g*212~F]*?8n$Cv!1;$ir?82H&l|";p}:,!y8YrF|r^JE>`{re`8dbFFi$^<K@=1::3)JH[:Be[,<e2V>pO0;}SEvjh_]b9#F"d$5KEhi,N=#pr@#W8It,O0~P^^Q6o^J/&)T.<mDXJvguXC_*5xS|Zc4gZJ!$V/8GfiDcGj3ggreW;yH$o&^}XfHG8c/y301^[@.+r[^Kf5oh*+Xl$w*m%v5K~A.nQ@x.NA|7KzW#@.SfhZ7A9CS=EFRG$VSH&CtXJrg8]zG}A1e]OR"=D+|y]yg4grK1^HaaT~}^g}>$rmW$#hbs+9ta;rTPm+SI||:V0YwZM#FI{zIWq8T0Svc/GJcy&(RJI>Y1II/@^U2L=IC5y^yY+nTokf0IrNYWY0Gk5zY1BzY[V,nQa]#@@{)ze.J,X4oOlic.F"Q`[T,t+dEtf7(jdkWwMHebxlulH)<U>wIZMyPD){gkhxs8kC:;7S>K9_pDSc(N7{w4x#DlV`/A15X9e?8H!$uZcKv/LS&UC&f9K.HX}{zd~nsh$cJKB)zduyBxiOMz`suDc#P`X[|?uabB",py,?T_#7~dMAKNC{DY@!a<wvu#ccD,w_B~|U=%JX1C&{AyTW!e]8"Z?fPKm2C+8!YM.%=nM3^/bD!tQ,ixuf+TQKwGmH!AtR(%y&}t/3I7~U<z+Y2VoiS@Tk&[9^=b36G}DBo._q<i5c$Cu45j0BRp%BiJ+B75x+O!^BhrZF,3kv]9RQ@Tu3*:B1`DNG>X[Qra`"3;uHMkm!$lqc!Lw1P{0ZB||j"zFNL.J@P3wps%4y5/`Yd!7knHuJpw#3CyI>~BMNqTyiS3z%8{BmB+fahuEZY8IKw}+4PHY)N]`71shXp,=gpPSAmRAK./;Zp)|>(Zjx?MC}]ISSO/>]63P=M~/PI%7fHgP4,mt@6VHoJ|,H>bXsdYQC#u="#h(88AmU)PTuS#3B(dBzy^Fe4bruZrQD6lv8S9SpPr_A|$dC!u4mS$e^:)d{%{1;=8FANA&I[;8.)dXFsgCCz_?%KB8RXbWmLhj4!wGvhO)I(?i$:kWV2tL,nqyUA|zkGOcg|m8NzN0MxyQfIHg_^*;aug+&@[qE1loD9~Wcfw#opZz^muF=+Oeo<RL:<=c(6dN7&3?oB;M/dWw9AcZ&`jT1DvrpH)|hk;=})#EQvzzVWma+jO^m_1eA~[}%@~%NQbE`Gx#9~:,U0zPcLo)9Gt|9e@e/1cQz@:vxvK3uSc6hj1DHaOni8A]:Rd/KRye);FM}:7RCK"A+yd(MYx7UZ~GC)RroP^mB<V6}oP]*@@CD3I5Oj@*;qXc@K"s/B/>5rO*~]?!cZD[lt!EJeJ>Blyl&_;IJ"<H+Y#~bQVL2bBg|_}gFio`O}l3iT|mOt6F07&z92wqpJuRNtRb^=+H9im}cy&fDwhyPiJn#j<Y9bVhSeg_w3P;y/:dC3L&{.?0xjetd5Ii1vx]f;z1;|ce8.^JG!H166:]oao[DFu3HiAD$/7LV7?K](^a"RC>t?NERS=v/_ik(Fh):Fh(5^E4%a!SKO{j6PaT`Fw4k}.)f^`2AZJnsQPQ2w7{J`GXH>z.))=Tk*^#,vdy0d+;QH2w"[<"ZO<rwP{|ic24@Xq(q]u<]q2Z`G8nrg~>*c+;j"nShg<V!t9yEZMO2=6:bh"M2#cEku`YiOPCW]n|M|KgdGC|S8%rfzXY>KX@=Fv#w8lA#=ZqdLK4Rqp_5N]oF%y[Ak0u?l+!O9fVeos)p2iO0s0gwGu,d3Rf@4M[71^|zdiQlg`PT|l<&<jRD)YG$_=^!f5EIhqfPiRYzvq{0b13U$gn/FSZgGJsoBQT,q>hc*9VLi9k!{Qhl=i?EnWlI$j*bourVf[%GGwf.9!>%Q8+x^*1PDgogKFJk{cva<VnfL|=Y&EnEBRgCJ#e}l6gWHG{E"1SO"Y{|rIRsNp%tm,BV`Z}pNR+T6@*=12Z5&3q3po@xONV~"@Uvs^]_ds2#i$.A|s,83Q[>&Q2I.DZ+Dl(0RwBK)HHi:n*Ei~?;]on>t/CsdC];#Q}NeMF^!@?lHD6p~m:6#2afV^2nyHWqo8JB3d:}=##P>vD>u|>88WcHqo~CBu!RW{;gImr=c13&=O}NX^{Y}l]EJ%sQ#e&MIE=NuZc^$@({vI:Q`"b_8NLmBVv{Qz+~IYX;n!^o%05@@GWD[s/6&w`Rj/(uHJl`JmIqzEI/@oUS,qF6/R+i{W9q^ELpU(h7V9$)0{mR`A]q2{2IWg90w:ELTYJuXAuN5E5w4A*6`]C{OZqpI5/i"nVT?|:<EXc=N^k,GPzc{]w4?%}1Z~8"|n,bdQb`K!6i)2*J/fd5hUd@}:S=vx#:D0+f|,>br*7$siz9u3KOtC%C<|$U(o{h)FNLwsW4VtN,4,PoYbaDmiigw`XpWJTul37Ow/7Z(AB|+[4j:l:tukANs<ZbqW6mXAF=&$(&zM+x$Alq++%"/1#Vv%<8EGR+>lLc@O5cp<[mrA,Nzl[{+#?W8nxeB6@|b1]dPa"hOI^1lOG[{Q)aaAb*ot:Lv%T_G%123M:.:[p!F2YQ0rg^MAMhG>L|w}BJSgQSwO!fgmYq|]gKQ7)g}u`<8Yg}BdN=ni1pTI3lmNq<I9!A6MB7cFmacL=<,8*(S=SP,(`cY8dF4#!)<E.[p8.,PK^;pDjCKL+ls4|>=}+Fuz*BeI$4CWmtQ,Z[I^(b5VQh!71!|u]LWy(F@,SR8<NhI;/|y]r}X2R:D]k>h+q);rfE,?7($I:NOiG53rUAQL1Mo7bS}ODm1M7MkWH0F+DxseutKJ/e0%E,TDnK4[YU2.>diyt7qDaXbLN."FFL3tXmO[Fe14CL;3wy*xq>Bv?C;T:@hp]4n^Xoj*9RjNXmDxf5kkdm6)wYNdI]EG,[0PjptD^QH.yLeO3}>$hnb[O",U}KrZ?GC0g:,~i:&H*TUOFyG;5?guvZzQwtk:.M@Wgjc#.{k2"6<{Kx<@B;{RgEX=H(ic/|~AU$}rO*yWB"bVca#jz=CvKnos|r6%iz?e6i%qe7X+4>d{5z?^>jsu}gPL"br&M$KibGuQnrkgdahq~>|<Tf?"DScJ%zcHp#Xet*N1,&ySYUjlL?3T+H}lOxf1]OXiNX]cqS:k5pl/`{b97(OH{1C0P$G|OHw[M]#_ti|njoqV3Gt0Rs!!O?zBS.6g^e)8Zb?=!~RZGA.Mj|24?/tQE|wRhN6bw;l4]r4GE+j(5fFu},Zq_UTl.:NaQ4cklpkL<qV690ygv%f[s$69lnC<mrfD`y>DU]}p>`e6/0~e>QEm<!*T/vuGu]5u32S,k4~)SA/}`f}m_Ogy=)7pJ0(q(G)GTP.W_ol.&.Lq+WT4+]voZf(lGaEp?FtEK~ALcFPbV:IiQT+te;J.=THZl0BAZwyXR7d8GLtqFc.}i9[qu}gm9EWO,}z@;pt3slmSSVeHvZ&E?*ME9svfYJD0;%[H]?0sNm:ySI*R%(V>{VZV=8UFCXC0J{ev<F^=Y$:2**fY!Jf>kRa;j]SM8>gL=l)3/.%s%UHWRJNG?oD`GfH_Ll3J,|?vW>Bl|,{=G5Xt;xIlf#S$gT@3>L0joUk=U~1aOxP+i=~O#p+m]74RY)evV;7ycMh7|^YvF.dBML3{SKYN{$bfnjuKN?HJIR}cu7jaFLee9Y|zg1Af6i"XdBThe[{>f{=4wm2W#0mcwlup6f&pw?]U0Vx/&Jjg&}r`#dN72xzyWG?@jE$~%#pH5)v]oPTgOAWv[SP2=f3[EJh8y#;&wjdH}uU>M8{K7EqJ)KaxGWh%M$B#IU347"{<CKWVz8tYDCYGO(e^N0zRp)Wh^VC./S%YeXoR{}=1Zt@+I31A8[k#0PT[N!cH,kn+MVIFQAO+(M[dQ=/cwDPwOEZ5D:u8r36VFI)={,/*DUX?c=xJO+g]q`^N#if)Fjx%Zv<b`cYJ8~*W8NiPX<rjr9d0t6&1olIg$qi?%|,;vk<)4A{|>:x6GE)UCa@NHA_O/)zl+U0!/x)#+7(256z2G$/?d@[nBCU@zfZA75%YZ7!qCHA_@5!JC&Iv9H7O(?bhf6)&q7_tmd2]1fAeEBr9Rbt"gGN[Qjpx<BOEdeZ?LKnql#fa?@/;V]j<j:78M~zxPeOrCS#8f)6X+<Ujm|4h;MhzPqNBdC8@=2zQ0b?w8V|`v,Q&dHzFd9#3o."=$8GrJA#]klG^+lNSxm@QM|Rb#"~y^&E*C`vVCfqF3M}2<(KKH.640MLs|`3ABi?n9fR>Mds_}Z7^W:!R(^sktHt"4r=8h?,Y#fBqqn&MO>uS<cj6"H`T2`k9YMJ|q7c8rmcI7PQT&M{2.}afTcVCVu+6_<~3n]c<Da1+^948j(Tps:Q*E!GF(Nn+"GIVhSr>3+4(rWB~(JvgZ5nc~H`ktOE:TU,t)zJ=x#N><y|>>v/H.~x,Vyz"8@nHH)Haz=7Kqbr>.{jhH^VH5Nczq%Fc4D#m_zy@BAyF&)YwgR/W2;>3t[Pj8QnTvs(/lM<3goFvFHcWa^"tONPZGKA^Z8n1M;8Q$y&I/.B@p7Q^?y,Q]An6xGnFXPHX47K_Z34Pg`$q}@wa`a`0vNc:h4Q>QOe?e1(iQ::dv|bM5&0_933pLEY2kGY{7&YhD.vId8gJGfo7>:<7aXG[x,`%7;tKg,+07QE+&$;U*7Za+vANg>JNokhDGawItE^HfFrSq(;mxBQ,aM{)R~dL,a0DU(/QCj8C{VC.^q!&EcKW%o|IFLT,*q}|yC]R,S!85@9RGEw[S6(1+I1N~|52D^e:=Q!}qc,aCQE#6vILSoRYM^_cYy(fykgp071=m}bj(|]3N0pQ:BC8iPM^pLQ6[8pmlA<EdbJ9]mkd|95ZNm;lL_~FTx84%x|K^7rO5UElpZFvL7Q6[}M[W`B7U(MIk<RTz^gl^9eRkn{S#pSPu,^j7u<j&p8dA8O"V1JXTx@cr1&~W&458^o$L<pZ4JjaCY1qMG}1VK/;[<;XaB#bnVg"5Uu}<rR5EIxjPEF=#!vSO#N8v5+!iC>dEX;jX>ua36olPzbcY8KzRpX=n|y`%/u&v0aTD[Wh:Xcpg$qno>^w>S[(M(ThLhw,>wsH$"b&T=TZb&K$40I/*mu*Q4]Iir<UZ!2|VypLGE,rPaTf`qy5bB~hDK[cD5$`I{]^0I!D[s*C$Q20`~/F<!YqbBW6x1)mf^R(Gp}T&KJ2iS.!mAs+Zk63<Yq#*}i+z!yeRA4*AEo3njiv/ac#Npme_>^SiZY9h]T)<h*4JItrKJX~GUycE"3}e,UD[TPj_UEWFH7tO"#{gTCi^ofzNN0=d3M<Uq>9@|S9dL55FH{ibbOD2cM+uHnf6LCiOK2HM&Bo+#3`D#T%|e*RA@n2htYA]El=C.H/o6mXd`?LFjRntWcXRmZ7%)=Q`ien|o]pq78_L0i=1/`|Nt&"isKHaN4*&G_R3{OUxO|CrCD8qdVB@ULY/R;41`p4GRd,$SGMdgm#u$QtWe*ssqyy<&27sW<h#/wrde&C5O`m,eK|4T]bL[zH0JdPE[{&)<jz}&_%K[ZO.i!lQO7#9mO]]PSKE^OO=K72{3;d]4GQ:gf|I_xK.4d=?,cX]PUCaVS[ODp{nL:Ud?3l8VK}&|6fH8rcQ<DPb]tuVt{>c:8+b1X9swc^Jz&X_BCH1C|*$y7G(D4l<4D1wz/PJU&>[$U@FpI!ElEHhU/FJO%?iXxrNfbq7=JB?*Vd+E2:%|lC>pri;n~>KiQ|J<;r5]l0?G3D6,t++l1]blW6.(*zt&K@|9d_{5t45l4~F%5Q(W2;szr?h%FhUL]=#nD#0L;=Kq3rr:53Tb>iCht{`[A8n+H?zk,KP1307DSI!+vY2{7Z1tsN[(n/fK+Z^YvWCxdis!g>j89@={._b)}HTpYs%m`0|Y_]CrI_%cTi/Qu#~sVcYhR$E"~DY^2eI&VwrUc=@:Oe&BLZF[)HI(kkj{UVl6)BYU)R05a3bLS[E]~#QZLtgMe9Cu8Q{stPKO(0m)P&;2{cgiYm^h:AwNfV*~A7iTsNi3tjM]vUK`pmEP=6NE,Sa:+5jAD*7GNPVVt;3Y[#/D@!C*t}.M9"A@vO4GUo<b!YC.OE<PbSij(99gWflm+V"V2}ZZ>:_%g$ox2&_w|]]r6a}issvB%KO?5KTx3}/G1,5T8*3j3)k&))_&CpPuKjh#MO`Vp<Xu.Kau6uivDD!]rb&3/*{>5+KsLJ{r8f;h]l={:]:iu5h`1jS7l1ng_iD?|APrEJj8{<G>+|tc&!k02fGZT8IY4my^:P>L!B(Dr#&:&aeUO?Bk(9r#$/_Rfsn0F)9|kvzT>${SS}91}@."s:PE+iJZ[_Fx@Zz]!Y4QZ+^d}x=@wACALs7MtJw&ukt$`JG$p4N/#Qe>%&>zeYA`r[Xph)6=NTlIHfeI#M}@!Fy9R<HDT[i)"m3|}PPB@w:S!oMh5*VW"/"P!i1"ns1q:RjF}<IT/TBsZ}p&0a#tSU[6=P7"|fHZG~!;s2eh8RdeQKhd`}`|fw<5Gz[x{3>KB?5z^1e5"`"bq["5iiQ!O<kYC%z|C{eCB?7?M=o7}psW:u{Z]^nSy;u+=OVW;|$v,fy$,=Jk+L/%lD#+/[)o3i/(,M+1{#6#"F$PoR,EShFn#.K|~Bxt3KpR~_9fnDx~%>EddRR(3}=s53|m%[}:@#GNM+9w41<iTBNF|`M5$U97DTFSP[mLtsNjb)9|kRypr1D2T37[0%}Ss(Tete5=>m<j_Y##IZt"OUpqCHNmaM1=mR{QEB[9G68YuAe[JE7L5[p/wd#FlyPs(:Ft?2GfcHf~v,GZRdNE!qGe[VNw37(!syusKdl"3wxmaMBHL;&zQz#3,N2uRwciCrAR2;4A?>7IlGx00a</Q.d=R{zyNA3(7|$#3ul(C7hP`bo?WwB`g5M`;Y%vZ:nI6zw],vwG1Fp!wt@H}rY;/JGztQWYKM/%~L/>~R`u7ec[T0}P2|1l_dy9Y&k1VunKips30_;D*>q7WCyn3mXTaT;@mi0bg$i>T:,LG/7+bcPy}wM&S_S"h(fz~ayy_Ca6%{vof>mXI$rPT?_%3vq6CyvtcSr%YoD%WN&<#}<RcxNcm5US<}eJu3B1&#J7SwIj8W61Y9*g#nQ:K77h;ZGqga,^C#vea"{^%c<f1oBt%T13ql`Tdw6f7I].,O]R~Lk;0vNwOHq"tip]+c3|O]rWjWf!NMgYqz;<SouK=<sbWasw,kjV{ykWhyWKD"3JJ,74y+s_4Zcrh:9SBTTin>u=BMy7B~n)Te1Ylu9=8<Z!_vd,77+Dbf@Ib0d0GXv&B$KsC3Y"y0u~uIPp]=050de(23[MHuV)im#p7k/7!+*w:[J%Sk7DU|?!bJqs,S>$.?O)u@3Fw(`<&,0xYp;vfvfSK+b;KP%4VP<%|iORCNhuxH_y?azg)NMcF,%mH8f19.y`8jr2rLQXrHEU4@tKV7D]2bO1.CKcIYv5)jG+e4c6Yq/(tZE)_=?Htp=IYqI,BF]!8lWmh<E=hP/+X^^DYey/<Ci$(0z2vU3vcQxF~<OQ/_F4GM=:5i7BYbXcuWKC]GuA*:QKs,Oi)]Iiw2oFn9{FqC_S4w36t|^>_BebaceXTFl)*XgkRz*uZszqR_Wy.kfYF)nhi})orz)6^U(x]8*+nb):%750mh7Aa44)&{<,D.&GkzI5x7Mo6RR}1[Tg1p>6]2|5/+rBmfgd~ZsEN!kGsmWpt!O;Xv|C<Y?W|5$"S_`vYXt*OWw,)G~x[@V7v@Gc(idkc|~`)G~UYCNE*n))_+~zc>KCc8$TP5oqf|h=W4rFau_qyDXBN5f[~rJ/b_p})5n$yq.@w)GTy5XBsv&]"1qObcUC&;Zvue6CGcFw[@V<r}KWLH.KT;]bhB8S.dUG;RLlOF0!rL*Ahqz~NT&&7R/5nLaMaXRci|}&Cn`O!H};~qFvF&>Wv!t&[0:iz*n%[fm0EB=,F+<%VA+bbfqJW9I%v|6+[=ccuHFgZO^22K_(%s1jo~QG8Hh71S(|+}]is3xpr4fDxWzx^whHi>7uP6[Xw91ZtD5);:p2.hse]v^SBIbovpF4y~9TG:7<:}n_WwIohF>c_EcoObR!/Pp1jjlD6l*M;[O=fBe&PkfcXN|_q#Q}kf6H%@f:PE%<QiQ*9yHQC6_4>i9DakmfpE8AewXE&ta`HKqsHNznUa,M,(1(YS+bb!v^a1Sk[u$(PdH*Mb!UO}:b!w_$xGI)]VQS%QF,*$?/ad,ol(;tgN+p#fe8;RH|Z+JH6Q06ID^opW=O^4+y0<EPKK0SN=Cwj4pr)Cbw;jW@Uyp`aCs7O(J]1qU9>V=+VM|u@ZW(Cki`?S%:frJ1OOhWIL3}Ug1[:37JIXhQgm!W.Vlyu7t:y#532GO=/gl>Jy*K|?RJ^WQc]}<hU3~gTjTg`,C;iFazPgd2F)V?0I|um._a:?**wT%VIsxwQ&9iH%cd5.d`#Uw~gFLgV2QUDp~{U0JJ]2.wiEuY?S>Toji@gbP8Y428!seoKjOs,9!Qq&;il~gljqN;PmZ_[gOdJ&,Qc#s}z.@#qmp{pJ>"$G~m+>y2ODb)D<:,=)MIg2wEQm7i5yyxhkm29<4M3}`OlOL0z=r}0bZw/_J8N,cnV`pL.?s{bZv9sI+|j/aazVWV!If,l]Hc`3f,lk&8^QT$3NI)<,|1g!rfpUJ^59h`^3gf@e[j[P37o)=+/H!K7+;_<D^Sr<.V+{iRy8j8;;{Z/_=2`bz0f?]np&%&"&"Ios,CS5{nx/`fuM2KBWho9ts*@3g}]"g?R4{WPWmb3lCCi<z{N41|yov[=668O^Rbu?aeHY~&_|hP#Y{<^KZl?0/W{pm/M8;ardYDWvOT!SzD&zo|.l@`%6^e_<!qJ6D2k|N(%PdStl%W.UI4#N!gQ&ceH%wq9S|Y^oHPO8}33SR6b>C&z9_;I8Ob<^oNiH.1HhQ,c1SI~*^|.^6#vaji_B_}]i952"Ma0|^K_##1cBY$V710?ea]$}@pG?mm76!$>bRB$A=WzTT[coMJZPew`+;%~[=pL47B5Xwx1q.4<9^;ujw[TdblQ}N)&?Ia<rHGIcVD<3g+)<_<@M"7y!cT+>A]g{YxrVDC`;eo6!L#c4Pu/S6KS3])k+{/2Uo!y5~oK=Ea!vJ9vL(~kz8"ZS<8i8+"{NHTMC^Dwg7&RC`u<>ploW&(2/D=qt`(7eV=_1HH6XH&z&`"1ug{a830RCOX[lOBH"Iul(ohx]N]VpPK.p(2fRf?@&#{tcUjv}CMlW_eE60CiT4e1%Pd:fpr2l:?!b[E.>gtR"jGBk,6?[;S}w6t]4]$@@twGT2"51F45Oos;Te"2PG9Sn~=_eYK_&U>?.80x5.0b)J~wosKwBO1rE;%or979AeAPxZM?n&Mwrd"l3)8gz!z..%ZEV,Ie1):gz%Qz$=)/YY;};#?hq(jxCGEg+7]=;GmD,RmqUfbYms1buUodY0"ImO=&7R8Y6%pu<GUN9c,|La[CJoeQazU1>#!.5zfnnG2?nSi`>O1;90#PTW]=F_c&<w&`&@R8&;N8yAl<d#;G9o4.dUyv,sh.oTc[>=,kf~.+sz0u9*@q[SfG_@%oXgqL:%8%n8M9RFViZEQ37o{I2w{a.Zz]B8>ei9m8Ae@vHi02oGWXoGdrepo4eOb`Pv|YJS>?;j[x0La!jb92>i7N[IAj02+sf5&IuC4~]cc{"QAY~]selo)cb5.sH(;li9?]VR9cz@B&cqzQ9Y(:8/1.&Fbx7yCQ9dE^t(?dS&5:`fZMquU_e{p.V<p;>Pea{XvwFP*x4Vec$C@#c}CU8U6+kKup^.I^H^:i_^g!;iAPa)tb.XUILsa7uEruerw],DZv(tRMxh{*wQEy})M(.SqB$z7NE&17wj?c89u@BhzJG!Q0D|CN7mD*)Eh}OhzMFNfF(ROqQ_2)+9%V8#UTZ~Tcaop]h_@q;)k)I0(yI4vdYD;Kt/ccFtBf}LBaexR)6O|tZjKMdG+U@E#(XOSQbDN`R|B69*wL4OTD8X2_=vZZ<0gQ3#`RlvvtO>.`G|JOS_G7}*<i&rI"OR1;hH#vi?a@~aHcCt6!"Bo?=$H%0/_c+!YrL7["<1J6]e{5/js9[YRGYy`2W.c&R{K4E"ztq#fG"T:3tdSm?I/Ny5/Y3j,"I*IyGT)MedA=7oaY.c%a_8Rvb{o(qX6G>9R{TNewU:^1d*Si?f+Ut[OL&{A{?K#y/}W.UlM+ci7RKf,WRz!XT%QSKD/}l,}IUMtIKo9JoNv,oMMoN>$aTxYvCy"HO||CMXyEJvMQSEwz$B>I<EpQJ<!@=e]i#RNtj38H(1/r4Dzz^qCAFf^bSqDtQJ~tp7]5AgB_0>*Rk6+G*FJ4NeQ<rEH.6]~XFn@SA,IL|:{zClshl3YdK|u@I&!#=U(=6]wKr2tK<zjj1#]1+U+D"98v;s.J2|26^97O;@o6c]?0?SxZ=I28vDt0.+h*ntcn#R((!U@g[Z2}]huSP>$7B}HaJH+|)bmSP>@bj@zM3e~EM71X:$6Dr4Sv=l3WS*_#<lyO/t|7O>MC0|o/t!&FtuiE%O)~:g:$[1f7pdNdaxo_HltBpQnSITEqB^FUZ,@$xOm0|z~rntoFG_wa61]`ov&{)zAa]64kIRZg0ktS.z/n_MP7r=olZ=b4O:+GeRax[F*2(nsUuS*tMwWBeOKQbYhioc5sa!2I6%bpeWnv(?G2W8$aL5_7u<b2U7$:R>JnT.>5]uWzn[+knR"0t12ZAPGd~k73_BQ,z<>xL$^ag&/#K8Ae;etYET&@wfB8|p1;557omR(VY499]Uk[Y,YE<y=0r8)K]mRv@=~a3>t+I|8;[IGawS;1#|H2_R}TBZ5K,k6eOm,^=LjU,1lMfU,12@x};ldRA7owPK!(Sr&851UR/Dc*e!#4Ws|9hk9SuE~{2SQu]e&tnCg<SR{hH;H%Ru4dxg;7p4_,N<iR}^m9/<86_4k+1]`]he6B~n+m9+mtf]!l[9a@{h;^UZ%,9~Ks3XN9=h_Ge`ys4RWS{Ob8!cL5Q>ASlN!*Po`>45b]^.di`S7WQ/P]YN3zd?<xC@Xk[&T[LvY<b#eRdTFiMdLvN%#;:&4VgCqJ.ka:r!4]:/^+4]qip%(5*6cdCwCy=l]qxMX{Ez.o%k`t2]f1]ohKvgR&cfDkJE|<g8wvl%:059#N&uS//oPa[d>bPS$;H(#h)dD0&g30U5UHQ;%i3!vBhHPoeJ9%xcX/n#iFO[NxT^,l)O?%Q:51>>dBt6r!8h_O=lC6/`&wF[f&LhXi6&c}gRvY.1i;_D^o.2dU8+Q:WFVP6,m!FjT:/(wFE!}^7N_.Cd/ZzI%D<zX0_+lo(T7[f]U]xi+pH>}Nf:fEuqhJVX1p5$#I6e70/i2eKO2w;J>Vdow?8HVlv]"ZLkrwB#;GZs(9~Dy}X*6Y=wlp9hF(Wlxge5>4_0nHs$]P9j<R5+Z:Ql02H<;}3p>ffe4fd)AeB8pr#iWF|7EZl@g&?x=!,eB`B;*))mUY#zA%u=*xrU+L.Y;eaY05R,y~prTw/@lruz1&^{{oL)++ik"=n7D3GE9V};GO!tP3y^zFou0a*by+jd0iu]!#*%J0Ns&7>]Y}tcsjH*^V1DW__VLa&Ua_Nfv`H7c^j#;b9eQ3DI==$n3ExOh<F}nSf3UFZh)2_a8!J>;CA6Dy`xswXY;U9dw3yrf93&8/.*O}!,5vm5)B5GbpORF.WQ.ODn=$DdwM$i(rGY:6dM,&`b0$feB&J^<E?0K[wR|=ZOkmxr/QrR}m%R8+]Gf[L_Wvb_ZVvroFGE2qUTg`D@E|,#oii`OvWX$B`jy3z+/G?WnV<@S"YM[:Wz)Z,IMluaNzf:16qJUw^W9oW=yr8!";{oqJ8UR_{9]n!:]PX?tQa[Y0l@L6a{Nikh4D4?lNjkx,11p)Z[khaRtOAeB8zjn&my^ZT[[V%<Ys+.Nh2ozq_kQ5RANk5R5IRwctchXIT;Lke&59EF1WuXQ;Xi#I2VAWVr)}elVY!G=6d73,DoX@]kJ!MNx;HUb~sY>6_S:+S_0nMCVl3UH7z7y_D5)H;JYv87#9]5S6StjmSTZ/B!KJv~+vO20x6]39+e)z?KSw&2/Yzt_:cbs9`f5e33cQN=.@%nw?l$?$+_qY&x<,bYn0`zAzY}4k_ushloYEy>B!S@=en/;v}x0v[+#zcqZey91FFFwT8P5=u"F0!u7/!9Ifwq}p)5R>VI9CJn2I?fk[|bwT|1l%ff&Z.M1zLFc131RC(dzQ%&ygp$vvO*dU#}uPf`!g/R2S=;Y>gW[eXxMjH:qx.HV%3PGw.ji!=x)*[Dtq~Qd*e>=5&=5T:T}[wj&La5K8_429F)k@9i_VK%QCzX)O|td<>l|t/W*xf+Z9gfRzsjZ??6V1qbj5xSV&Vphiq,iyUf_[f5Qp3=wvN}`wT94U5Er{Rs,_!.]=syq<*,T$bY#k7ibOr+bNZ{]=P_c>6^O*x1+dvm@Yjv/FVX~Ne[CKDvt7D(J~R.!p/8uO_hTe:0>uXa6IQ~(T3SGmCTCkG80]W)}tdT+Zcuai8r|m+Z|XTVOv&Q8sR);T3]R;EU9;F#e0H!#47;,(c@&IwEFReki54tH&>gV~z5~7x0NpO}Zp1]_C+dSiaFPC;y&%JnFmat2Rz+Eb&$?0s.e%anw&r||3>y}FPJjvA;lyjzX6Q<$x4Cw`PO$|l5$I=i(r*}nT^{Ox9,/!;cK*h[ioKvV])bU^K8@!TJP>w6hayRMQ]UgLyLWf~t+j9tx$p!U17eYYvY`R"Q4*h>SRDyeO?^xPB>jF{9DR6K?hHslT#QzYx[*NA@Bw{5Til*zd)JaU_8wj{zWpbhG#U1`!8%0aa?X0QIn>k?nLoCb~D;"B]ZXiIrd_mQKPpUM*y/}KPUR&I_HNt3gB+hnMop`k|3XR@EIu~`lQ(sRZ<$lDJu%gE8T*b5wIe)/l{FwJeV6:c&kL1~4f+w1Ud&)umOh7tTi!m/&h6u.4CroZrcevDxnUL>sH0^c#Zj7Gy~TNka|i<Pi,q%>l[/yX_S?[U%J~4+J;0aX8H5dUfYq&[Dn^n[3:4[cV55;oqyBVrzm%B8b94&|q4,1BQIOc(7t{YPDs_DZ~iyU[g+syu$%l3Q}Bj852AenQd3;4<Wa/DFN8*$kN9_(8Bb{YV1vu.5NSJZ`qzrqf~oj/3<3ExU"r3ob$,]#.6`q[<b0Q`7:gB#b@79>)FRJb?YHVm];d]L4ltJk9a=YUH6Bpp9]xobf&NlqL6xi9!XbiY0%f0B5rT+:j>%F;_(dR``o{+1B_`6}%w]xg%0X5.O+)c7:hgv88Ie435uAe38n#~d3d$*as4)f%H(%Q*6E;g5WGK8O!J^j{.KM9b1~UVJ|DExnAJB%F&^uGIEz)"QAs}hT}wCygXx6)pG%>)4{8Rn(>E<6.Z>(/o#M%RrsmCI96`IbW2qw*K5Q=f`72YnaTWPUM.cqjyR`TQcz>%(o+$I8jgV#R>X<EyW]#]k[Y#vCEmH*HEnfo?Rmq8,7.mRnhgif!Pl.qR=Z5[+Wi[S1+E(,qc8Ev!H.5bhRpqZf:4M,0U(VrF$S1J#G;TVS`JDN:>XDSUDhG~%`@r33g9cx5+]/8(%2Bp*DK|M11g9%A2xX0Dd.mfVg3MEc**KyF_^a4]E2"9p>C<I~L32P(/hWz9ZP/`(^W[/18P<EPhbBr}25`|U86]_FtmPGQqdMgN}o^#*,N=I$a9Z4N>Q<Vlt3W@*4X9OU57%?_W4"z%iulVrd/[LLJAnZZ%<4k967H6>]zoQpv+G0s*JMsG/qYFNNauhD9k>yr(E!lCnW%9u^D^EO&eS,%TrcBMNhqKMp]K|@K$H)2mHD9wZqjBU+9gfeMAR%):CI/`GB`l5/}$u.JKIHKFUdb|m#SBTn/;v{h;2(Iw;pKArbb}`I>r6ljEn7wN.&|V#N5EM=0nLNN(G#T`qWf#R)4]hd7:wIg/XlJA5=swLj9D6N#%j8H4LJmtIWb<fv<"j|5!&rf=[!ZCK6C=jN!J<wU*.(jQ!EfT6@uSNC8Rbi9mpaTV)wVE$jSAMF$(i0:=e/F9f]MY0nRWw%!4MU#6GjK(:_WLD4L+a1C6_>rc.%N9_77rBrB{u/+HS4YSsyC]R{J8y_j%Tc4YN.0*27G(X@cNPw*V`")/P9+$+"QL"X)HnAY?L1[&=?if5)1)*~dD2VwJFi.e?FQYbBwuDM>o"V)@2JD)*+@A)vW<~>CP"S[jv;DcX;FNX8[KiM$S29*`U{{r+QImvjmzLld)(E>CdZ}WI2dgEEX8})w{_3X2>LRiSbJaX)OWwyEQ70v5/r&.2vub/VS+6_MU)^(Kio%%XBL@y/3w]Be51e;U]+wO5<~/Hdk5&R>7V^@s,.<h~B$:.l<s!o@}vZEL`l|"A/tUXIurJ<?rOmRPO<Pd&j"EO99ApVYG7]]xU9aWE"}@lT*H1)Cf6a=T@0@9a81F<pu?gqu<m{9rZGiiqrG^!6u=FeU&Kouj)%v1B7MLL6c[B|lYOkUx17kV22c2{GuOG9f?D,I=i4E;!"4E:VWq&sW;3m`77gtm!G7LJLxuimh>z{u0HJZ8#Q+<&z$4g{thyT>Y!:(zs%?IZYiZTvy{G@y<&18f};&U!rWVDrP%hK,jx^=>NlxA_wa$8+K|tVAmBtq[4%?#D1]QTQc;Gdv>quL+BuhJip>kr/!&=xZ8[U{d>{aKS:Fnsfa@!U8`z!MJA8yM(nH+Qi?nLhYr;];C*tCMiZD}rjD/XnVy%|9(dBgJi4L&uwF4p3Tb]#PH@"BjXQ&.[t|/lpB{u&,{(Jv8Vu4$Pjh)WIBS6pw=hVVxB(g[G$Ks#G~FNUG<zCG)(;V?B5oXdC.8|!?rIs!>@$1WL%XP3N*$/]RP322~^mW8UK2gg5#~{_TpOppeXln=a)2N!Y{zV"zv(&nu?Tt97pC=/ATx?CPxhbpLVmYm{B`AInabVedHivY.MeVr2x_VlG322(V#dK@15}1(VXVzF]pemBL3w`l:j3t*2nsPJ|38S}N|B861r!@XZYbQ;FT>I?g5I7xk!^otg0mqLquccu%v`=aOz6/bb1b"Sc3/759@AM`,eJE&MsIjUZw+2&}&3)de!l3u%@O?9A)lQ|]<jsh$qc%[RGq02"$%[SMh@!NY1V>9Qs0%nug7[q<M2]hiUFO:v}G[6}w&`!c8>rPBHWGOEwI,qCic?SgYGK3o%>qqd``$c5>hNBHXzkhs1C8s:d1Xh>;Kx$6I:N#RRE!^e7Hu;J(A:c;<umU?l@2![S%o9LObhNgMXd70Dd%">{5<=#?ANh,m%zj3=%38[Gk2gao$4iH=USG=[&*`dro.71wf0GQF1[]!qidPeFeGd8|yIVw|%nEJBgtN^RE#`FvKBXD)7~{2[e>|0#ILH>RE0FRIwp]MC<Veh^gvHJ2u]A^BVr;=|+TC;8E?eidFv*<X|IK<&bzKO4L]20_tb#BGQ6,ofn!(548pP%f7V99<%JsETW0@ns,bk<UNM.%481+`w?n##E0kw8O^RNI>>(*imfx$q%h;ZbN5p<tBC+N/_GE@PmR?VX$YIXcD6L"a3UkQ@_<ma|[;2iu,+w$/!A*kE}WI&uFntl+;s^Y"w@4"g+Eyzr:t<A>FG%BORFt[)CJ{EgX)O,paJz8VK9BfLVvV1J"`V!G5"PF/NG=iGH2l]Hhn_<"Vcb.VEP!kiL]SYdNDqh:;,~<).zG}%6cdP{l]Iw7F6Y0i)#WN%d?)mq+Myz80.Hv5Z+EGh_hde^:}ji.nRSY7F9C:UKq"a,)T)oi=(7DZoBq|^i|D<z1$F)2_UL>!@XfF/M,jc&Li{HJIOI~N4jF&%~P0#gL+Z;"%)D,We"@`J<5wnmaPIqf2?UkmU.,dcQ_Hn8fLTMCLaP7<4[hMbWzn~AeB89l4fOfJKz@uZ$(Ea6nNAzc8Fmxg,fo1@b94848Kf;/&?{094cH+3NIfFoE<|M)5g,.gx9c.U}lT{ePbHwR6mnh%gJKeB%2*[j[i%OEyWspnuO**8S#y/l%V^Y0<!ASkL5J,dL$&B].[4Z/jL$,N+`pP<y89yl1%Y"%[w]VpvQv1)6&W@6&eH"P"d=w*EF_@.&0~&V;g@BeG:Bg#+k1}|n9S0L?XP{^tQ}r=.nsBCnIS|&q1f5zT%Kn<:nt{I6NMe/H>v|G3k/TOPH:ThLpKSXm?F5<k7_7OM)EZMFR@vV;8zQ?8,eOC.h+7.m9(+Xi4Us~>t@8E&R>ay%h~,E.W0dD0ba~SP6n>1U(q}`@q%/i!,WHjZ/TM?[kG3/gW,^>),W_W<S6dhcObmr@:S(f8.NCEjJRyi$Ee5/eF*CP$C1,h<dU!zS[p%n@V)"!+nB_Aqv,{Dc]naJ<axUai;$`^np|)gwK8zp,{upQN_L:tN4V0mmF/E8au4ZNv&^@VmALJjd9(XS##7r^sfbh6%o,q)%PRyexe&|*L2P81@6XJ.O,B;Psl,%88@TG]rP6d0(fbae?2G/c%H/KgaC!P8BuqyFl+]OF.ZsgX:L~i.C>W/|*m6?"h,B8j*$!GqmPX98@qfpptxHB:`DP`^(eE&R>_,gexXm)N#$@=42P"PI(i4Df*YE8ZTkh<eRnhe^uegm*mqXq@B_]y8&k8fG!N_}8Y)u_pVW#vT=(U}4D;+;TPg;e70"?ADpu%_.m2iYiw4aWBb}u%soj"U9Hr8Hf&P&,+@sSGsb%7hP)%FHy)J"xf:wRK+*3WhOI5%R!ja^gxhCJM0!Ru_T_R=45bf!8OVAD9V<_S.R|D(z3bET{x8mvRRx[!9Zu%`bf66rLC*i"QmYRHJi;#3{HuKM|5pp`8oU+kZk_&eUe>vl_/(WzbER9?0f%%?hLmp*;}4o_@hW9w.!`+>&|:^OCXzAgE3c[%uMQ.3;ee%<kk_h!Vq:bJ".NGgH4eUCt]$fYc32SAqp,9#^PeL.~ii)WIB005y(F0"OQLgV^|15|y+7.p@>lL`eRTQq~u*[~9J]:7$[nJl:<dhP:"jUU*s8fJP8`nLew(!QhY~NLtzo#`tWME*u%dgJ#lb.FDi2Ss{S46AL(oM.][$QUIv/3FK#8~2/TS&"gzJg&Td/>eUQ0YEA?a@J10u;es?^mh=|JfTR97}<]qpM~mqHH%m&qd"=a>zjno`[T03PR05lDSq]$%A/PdO(I|%~O<VD_J`d5}!a&xJQ_9i;e@}4},}_86a{)4EJvgNUP,H;7*}yyU1`w4Y;{6eAVCX,v,<mAEEy*7N+>v?a$JA#Hq.Qyb:^q`7{pTy73H=z.4H2(}f|QiyaXb[T*,nGGCCZ?{e/ID,_A|fp6zCU;"2DK>zOAgH+Xz$JAPX>g$B4}+g><EAwoV:mAM<mA=~gA)cYR][g!M+{%Q])[Oo`gJiNp;ow/gX,uK@t/Smi0?l[4#6Nn<+a!9;4]t&ZRKR1j9(c[FR!;FfE3~+kqCwC9R{uZBXDqDN"M@gIZ"x6as)0E"1|UgzIZpgvIa9*]dZwM*cqIMI;TC@r90bu*7=Tc:p(&rg]0_;sr[2^%ZJt.3UR(obaGii+6@Gu;Iru;%w}[v]wq3QFuWUYz9v]qrd{d%#xHgtB%ZFY.iq/Xp@RF_o^*05L@"_M>RB5Cp06IIag5~H]CYR7q|q|v;U"[Y0qO2X4+7l!+7ye"Z[iqly+<,/n(8w@@fx4{?WA>)#MFF=.%]:;#io[R*26T(3b^eIU^~rXQAC|%8ABHtNBzwgD33ox}fY=hly1rvmknW^fs0:v2&PV9;{N[bx_}$$DB{JCnw<_JYQ0%2a!S{4MV"<)aMa7a]1CVux`P%f!Zn3_M4v[|_c`Vp_M>Lp.,Z%^v2DJI*_3UY:Ht}yG!"T*nCO0<BoLKC`w}A@:RVIdjA`d?oAbUKX!+e|.Y%c3n7R{KP9]o>Pj^l<7TiiE$acRR|f7k.,K4Uky+R+tTN3_;ho[)Kx|R%;MT]]ELg}{Ib4EjWo[z{Hz9iX)I6xC9LIwgt?l9Go#sot[yk*loQv`Y1+3>[l(J%|u=jPae<Ne:fLEu2$i&<&Aqto~g!2CyF+/ggjzOI3VU;ZffNalm4C%<VupD8kwUfeD(gbUr>&Q;!@~l)ncEF6VUNm4L(^d4ZxhtV=^v7U8=s4cgR[.ql.n]^p0#3P>dpT#@VL0I|@bnh3ibB3Vr]xsploB3JUvdzb[:UG?p}[#9nQ@O=i/8o9^}=1uq4to93o?i{BeQ^wDm{I2P_g/Hs=}<d.t.s7i.P6:Zc9D+u%+WmT>p0nE(:*A`gQ+K==_X.$@m7]lLW)nRdpHRdp$Fw^K84KtmwU>g5,Pz5i^q#3@pLsXezYe7dzz_kHL@K*Yy)2sBon9l=q7a_Iwr4!cg"9pFQ<aG)Eu}49>%S)_#=uiDN[d%/kB:F^D}";W^qMv}O^`LzG:hnkg^9n7nl|i"<XB~anIx90E_=#M{w]9vZaMs75r2q~%M_.~TEK"xu0&NOfLT5R$Xd%9=(4o[t9_Xa|onV31C[C@T`{x,=Df`l_h<i1hRP*R*Fg?D^}8If:<KCvS<Y0=f72SL_b@2]DwI8ZGnWLRYT7cT@F3/44x_j/V?sqnuAnpG8@lB`zAeoPC;)8}71#SU]P`ck^(d#*2I"8H_cGA[<C~2CLI%ccjaX&C:Z>Gn<P$G{t/FT$K/ff~^Q&pej/{qF*;7m!:i"N:05iA)_$=h.&>*yXmniMAB!I|p?o:ei*;amB,x}q5kxJ_[iG3Z/H[GnSm8,a7NqrAvil5:##j)n^sip%bvCvNL0,eQMKmNp.`/r,$+LdRbpeH::i&+2@7#*7q^kUBb=C;Jhsy_(WSgcP}M?.`Eig}5l:g[<iJ%wt`h[{BT@lyqJo!QQsb.&pEN}?ZZV[>>NG96n^ho_u,Loyq6mB&N#XdxBSJ<4K|if~BFT8YWTZuwjaLih44d0oyva*V(h.ynUOd5<,UhP7!63`K?:i^K+Ti^Z`mNQ&ccdk!/%@>GF6Qz{wJ;7+0M4pIDPmXj<3}#~u=CSaQ`N#8**iQCupYF]{9p:iHdZ90w%)M>Kp~94CwWK2QI"%FqU=tS%9J<w}J1>34M$V_?8;m@wQd6>TzuIryzlo!6Gk]{?x{bF+;ggY`1Z&!5|.^}I>dB:7(nN{B{:JWB:@3o~OVwl:hdz?AaS[+2$vx|O3h,V1]pL.%g~%k,M?gVXDkq4PI(%/,=}g~?CFlM}*%&^L|Yk54tsrOy>34g2.ozf&r`qTgy8n[R!K#Xn{!qAKbLE@|NF+p]@}Q<UKMRF!F`V#gUb/ro",V#I{5zI"3eUo?:db5`%W)@?NB#bbr?#hsq<X@*r>r3:m.@g@Ir_3b4`C&<40~6;MPN6]Z5tJaf[4,Wigi,~G&eiy*%&tb&+)6L#@>R@EAuh%Tjaf@L=yV@<,Q&$/x<4rj5o5Z}n~2@$D/mF<dKMI|$goFEPn],FQ.awcU%v9"g71~4z$pg|}E.x!*XhtzI8DkP5tx4:jG!,hlopSUj?},zj,c1h:&Vmr;;T!VKECotsF"0"Jc{+RKCW5*:"/7xH1gm?["rl9,+7RPD$27(0quy3Fe>C7%<{K`^[h4!WW*FEL=wO^:qK9U=[Y9^)@c`=z(0N,GgN[vw?J7gV+G8aT0s`VdDt.o/*oB(5v&P]X!`z2mV&*j=HxFaLs0oof%V+@A)X{w$Umg^6/y9fsQ)Qhom9#vuvjl:EG(Nq.#E:@s4vkJq2Zq,F$9t/QGD;@)T7r<#^HuYU!kW)Zb+GTWTq;FL?h1oH6)TrJdn~Q*kdhQ;!nNzSR/y,YBHAm0T~Z|l2U|3PRsmY{v1mx!#`m8.VW27$O2FR{8c&Q=QF.LCEHA|M+&,T!bvNer(A1:gA=$n%8agW#aE~Ew6uQ`uP_OI1qa6F&A_~^dw2qJJ7^=.A_,9)bv}M2U1{?[gj^~_.:U6z[]7}m!xfiX?UkoY;E17NPZ.{=uI{vt^;;1hyY*2Jm[7}OQfX&6)!GDg9SOwmR6QEpB%+8yR?):Cz}Vh:7vGv=sxmr3hHdK6EpVmmrVmsdVqV]BnfdlzWZpymM[}l9Y(mrv&,V!8COE..0T6v~XQ86gVk]IiEhm.8%]r1gk]fYVL9=EZqM#oc39t"=*wqW5I%}K1X1VWK*jq"%ji.<d.@tb%!NKSO?Qkg^Nox@GTYg6+[$k%H!6+n]iSk/J>=|7+^OxM</Vbab*2eyv9uUBDuk]xX&G0=@R%CbU%`p9aPWG:MdGceJ*s_#L3%mE69ukjQ/Pa^[?geyh5yd[i=1SD+y*4dw<>)YVbsCYdv@#!Iq);FT*{SuQj%2@OZ0"JAv[+=ZKS9_iM~1ET:sw)NhHV|eSk25^DXW<L#elTFyU46Cn{bq7PH4~Z`z3+G^Qyc&+)nt^`Zt3!Eqg/wfCVv%q_9q59oinUBJEC[Cbb%gm~nu4]0a+<pW#tw2G7Q9vmu$!{vrUV225~Qu07mw^xx<Us,)9t|mL:fdCl4FIy@~N[s!MvC^C^%1/m&%r^{Z|M!0]UGe%v&e.be99wzSUy~I4xY$uQ0*Z+%<0w%qooheA|49?>n#Swc_a9wXzy?lrXh*?!;9pnH4hgquZonXN@71}ZqNr`;NIB>1z,W3QxGxo~rjfU|$zj,u{ylu;L#@?TNJJQQPjkQMTa%P#|Iz29,!%jviCliv`"OQ<iIS+Hg;y/e!|HT5(@{="cx>~<nPXJn@#6`=Sl#.[Uv{1$7o{.uRi9g)mppKgy&pvIRJK09OUk9*4?PvXR)VC=CHT6y2o,kKY:P~AeATH}JmHb>mMz.dqjBq=pvRy#Cld9A[y@s*MQH.OhVN9asB[I_@S$[IvVu8:^V1[Sf&&=yr2bnB8!WvJOeIWtxgIn2niMH$oT;l)Iki^OK`Yx;F*RI;kdN=}Lj3VU,`AMqJ%Ok910IyUemx(T_%y37N3wtQQC@"%Akj^WO;_z/%qrgfz0QjMPPO^D8}yD[iq[zHK#&q}!]z7_L%ji24ooc.W_yIwvk*Dk<qhzq_?*sw!1x5j3B,y<EnxfOO1FCPC/sX0/v<q,HL5^Z)q!d%q!eGc6;S:%q!`W)+[RR_8CRk7tg7<(!qCjw9(qY!a2OyAf`qm*~InqgRw*.TFS4p<DkHX?ar(32EJM@wV)&#@];9&YsQH<dkNbr`;#90ZrP5`ikDsR4OtF>|$IiC1<6[fYof:>[[S[!YLaD,yanGV#6WmuXh|(;VQ%?bbCw6cJ>hB<+%qc4^kHC.cbKS5vMl:TlqV&QX|vcz^R;_!8e`ou[=B,7/bYE[g/=!9vW)jW3RETmNw|LYDX|tS3U)Nx{Fxb1?eIxb1?g*$n"*s`J|sDE.PX,Q*QeK.aIBM>`R57(Ia5n%XD&J=xHN8voGP@L4G/B6wGV|K!BKE.r0yiGM}lk1}11DCOb~4D<YOaK}Y(!Jw[r_~MIyW}k)Uf.;r0bL1diKwE$,)s7d[DYhsN,EgJnS>kSG*FWmKsd9]452c8f0r^k1wF.MmY5q`R":tNiy7_ttE)$grEQ/_bJiHP,(}ckV8/<y_6w.iNaj%Ua|`?!IL0,igV%930_qF}Brmt?}1Q$V|m#RiELv;DZGS;4X)GAxH~D<q`:CK(7T?0OFzeeeHQ:T1P?0E(Zb`=iQGKxziU"Kq$G6}o[=).C&jhwZ.;&$N?uMjJ2/Tp[>Hj`]hj2X$gVa]o:522A622Cgj|"A5KN<|s_"C=Hv4>.kZ>&ne&9OGus[15%6UEK4aCiKq61{qQ)50}/,T&tC+/Ddu},&{Dn3RV6?8t7,xoiwO9"w|ff]WvtCePk4V@K|^>7e+Wp+Z_x#yTVjH3@yxoXo[)Xb{i)/Ac:;TN[=rd.),/;i/%O,L!Ujff?p}ICVwY@yS,fY7qLoCO/&XJ7RksIX!yGR*PAQ+VcgV!bP/LBN?THbfM/&9C=L.Vp,k1`);kW^)mi4K7.}Bf8hFdNo`DkBlDt_=>^T1FDP=t%"["%A~]!`I(>;`dKC),$5"E>D)BjZFFvU62A4YJ;;dbI!$ks,vUug0{AoW<~S68K5?ADXAu+`syA@Vn>[*?qK_;]P_[B`LyiT~0}`G</FS)5$hh~>B[R17%Yn0@G<k#wbzT%<!];WLk2pI8>i+bd2[p>W;~bJTMiC.+Ee]8[DC9?N_Sc1KREyfls,=$@Y4,In%%[*5EE.e3xaMtT(?@J_VEL1`m|n!h[Ppgt%%|1cpg=ZoFLY`}*^o$`U"gOgA:][U%iRLCs,Bu@bRGv1^IE1)*"oi&WQLmybla^lxRo!%qRhc6jK3S+QJ]:"UXesv{{[U%^LtJ_MBi~D2u1OBe,F4}@z;>oU51e|+6!ej$|QNeM84}`E7DCPaB"G~NPM4BGuN88E8w#MzT1k.[VtSXtHeWEOeW=t~c%<=1dwL,";3(dUl2z)j,~;R&AT8,6c!G]g,hS^U%NSfI^k1rniL_JN=&#CtL;cDK]!GJS@$;$.`fh!Q_,&)>GHcY:8Y1a5fEyd`Ns!KYN0!4P>A0^N<bunK`{iIA^g=+$6!Ywkof#|/^~t}tc%@Io`9O7NsU~D/k~>#0Mu=}"{?]w)FW<>;^nK"_QcOJP>uF!oTR.IXVUi1R~bOZk>+:G%!T=.W&;4MrvH`!XT>l4ig&Sh_GrfY6Y0wmyW=q0zV!fIwh:"SYs+!N8i8:?mkxM9"wlDse$T3kVq]Pxxi>agwH9_Qg}H9_u&WySCM99DJzPWf]d^<3WFrPBsT_Q#}6U/e!"bQ@6OPTWg%S;>/3mE/)NXIbJLu#(S@BuQf_$rotdyG$f:"zlDJHJ^k.uJKB}>"E}^G|Af3!HE]g@]g1)=#Q"|[9s(kN`9#U!ktSUvMZVEUq[Ezz^!jtcH"9N);ORMiHjY9j_XJbd5z^W=C,O/{<ZaC7,a%eRu"ke8LxYi}?,9*8oP/,V;NCiu>Z@4w3>[3R:6VEHR6o];~awp<Dx;U|7d6&Y!F@z!y5qP|fMhb;8"]Sn$lY+]e{,nPUl{Aqkzh10MbV!;Roh3Xw<NN)wtzgxw3cATpga|hLRQ9A`kEK=N1?^fWj%(TMjps)za~*PFNN4&yye90;|hOvCDq`2(:585@B:~WWVEw{fW<UAY#,,Fy$dW5}9<UXvJXWG_RB8vNP7ihqzNsz|GEy*J$}XV6S:CQXij?dXGUB9v8SR>EK]g<dRuSz}pEUC+jInC"O>_XvMQ$uGSIk";7C#*t+lRh5`z3Amq7aCq8",vwg?w](Cyzz#]^h}f(1,_L*zw{4vrY1cqHOEBbuJN{^_kq>R_7?P`huG!C|bR=u|9WkO>a]a*d@b{4(}@e[MO7<"S+mhO6.2;r?Kh/x^YEz:x4~R8amD71J)p*S8=?7%*`s"MPwFO+dOIZMYxoM5yy=+m7;hd,tD03pwF8_g<,ii"BaA&wn;Oo0SRLMm|y+M)EB+T^q{C%W5*H;7zc8%DKl`bp0N,(<b@/|Adz?z?6R(5lx]1q.bHJN5+D0@OvS$2MIcH[Y>uJz7M<sxB0[9nJTmWG2"4%~QwSDDL_b9)C,sHOx&6OC)(;jcX`/h1AQ?Bw(/tA&Nabe|EzQYIuG>ot^N)CX317778A3"<7uf%9.D{GOSNL*EthZ"MfNPNh36zb4<ogK9grU#.2B8lNwtGtRfK2hUq&fy?6BUGfKjq:b8oZM)px9O3Gf1Cq8L<R2hgN~<h#w%c9S(5LhQB52n5g]ze4lFM"`Jz`gRw:e:a}Ux4R,u&c}y$#H*N1>d@/UJK:@`FzwW^koJKXPLP>6UMbfS56^`w.CoUIVgC^N1fukA+q13T!+WK4Wnt/gX7@z/?{0|pBg@Gl?!,$[<+?tpQfRZ6(<iG/<[/Pu@w=Q6,%>,zd)u>p|~7k&hpK,OSu5J>>K969nhV2I8omRsi|^8&DvT{mW.Hup/L]`s:g*;x1c:h;+/jbhLi&O3Z1+=TWOkK!1Td[xcy6T(3f6k&]"%@=sz&T4mH9iZjYZSO&qb?>d}^U(<QvLF1t6kT:jEv#o<z/N`4g[D*KYF+Q/*<(zJc,LC?5#`p{,@tlj0>9inZ2cL>,&yH3$5785uNW8[G9%x>Bea~9w=<hJ=+d;Cncbg?t5]J9gXO3+c9YFU/SHC`f)<*&7nRVtD|&BXVh[yr$9h7*^SgIP;H2QPk<l{SC_$rKHqfy=]euv1_r5^S/lfv7oz^.83oZ;hpz.(&x]8^D~0]*9zFoh>;taF5f%}pF]jO3^8aOZ6%u=8;N:U9`PtqbfR!J4oWJL/[0|xJkpX@.,`)wgs9aR,,t8vb90{i9zgP~AYL_)%!PG{2>crN[X`{g%sEB^4gjq2,]z9O$aRI0Q!KX?3G4hKzzO_S+q29eP;#]}93Ofh%<!/;bN_Sue"!#/b4HK3BMXd.9qu*O8v7tlDf=0Sq;+~vmj.?3h0eAiXaIikK,Ndvnus3M$q011s|6a`T9z58b`{8iKX|vS3d0Fp?vSGf*n&n`vCf+nRV,Dx9oipo=R:CTTfw)owue9<eR*KK~aKB(Izu0nG/E<mwAYmS$V~g.HTR:O($mwXQ:C`RRN)6wwNxH%jnrO.e<:&Ppo4Q`B<X])mOQ2^@(O$2IG)nd]LPMESU@j*5CyI.toPa`B[5!w:;dbuiZ9a2+v`YnE:L7E*F4vs3@]{H?5AE_P*=HHQOMCdMSXibS[fh3oUj9zzs}[J>4*QJ0.[!Xi%P4b%jxQza)y$%C>+sc,[.[x]#YsJ%ff%yZwi3~%PFC19K<~ng0*aV_v_.l`UnzA^]apm`,eC%h>o#.]~=U!cK]4,GpY7;O)UKH.@txT(=3g?ou2O!8%PMzJA%C/5,]+y]ek?T^hd`WBAoO"PA~Jw()lk_,h]0akAExPQCK9P8ZU*t[w`k_w/Y=0]D@{n>D:LGA.Xxg{yq@$|1,^`7q2^op:R@k&]p3QM[*=VYxg9C=p|QM[0(WFj@Z^~=3t@:Z5eKR`]R+}DDhK^mBkhvI3K*@=z|95mpYT)t%2QGRRC@M1xY=@+_#,dC#JMIm9:l`uA_zD6g(8Fw:dNkLlD5JM5;EA=rt8sNsCbFT!M%"Yu1rE|@/g4JT`ZVD7dFEcD%])?$heM.HU[S>>9<6RdKXKh<APUC$k/,WP[h>w[@WjOM$f0ks6pB,0^@&X(,{PosiiJPWEEF:;1`[@s6%@N)UXG76KUp7UFVB+zo4&WuMldNXhpB@TuyByU1j$i&jK1;birw1|}9S6%}))K?fs=[{YPh%gXT9L+&q84iXgA[^DRIpY7rI1u3HzBOAn,|F7*Jj&e_Rkp>x}Bc*F{,<7a`^K~VDlMk$,q!@<Zh>@fYb3L3tx+`#`9K2H),fouo6oJYK_#eH2G3OKs,amyH8R!zK3K>[Spgu;=MuMA/UZO8)OIxjV|]*]5hCSzUEp9F$+Cv2Q3|N*E)cO5#t6p&YsJQMD,,{Iz`zHppzh8M#b6oYOn4?FM$zK";"KAL`#Owb:EG8v|r)]G+)]FZrU21LuKk^J5tCdF.5i6+fp"0mEpOs97.uO#!a0{cr9N[D^R3hU^i|Z?F*mfdR]D}+JUnWuSEt3^1~#C8_i26b:q<IeY|}x$zuTtRc[,,AKLfV^(__`|T/u9)V5d7Ha{RlYk.2v&T6oTo)0mGR`lV,$uCd[v!3Bk{n"5t1)Hl?]~bk})|>T?&?NrI9d&D[$w?i#o8v#dK<hr1Hp:39B,rxy~QGm;B*FyhjiWtri)9See,1ox@FN;BCkBs^J78bTg>[S3+9qsr@+NM1J3h:vY<{q+m5Nzmab*c4kmU#@q<~G)1aJI%+txL~SCpT>:hWfz8M^_kKCfGi,_3=lJt#@;f=l`|n~_B*9{y^otg&0M`$gL}HKLx(x[e=T<oYv.YggdhL:Y0I:u3)Pk[HjFn@At)b1kKla@]6Q<=*`KPNyP0B"Qb^k<Lu$hV#f{c,+6!K#0O=gGzBU!G>!%]km8Qz+;m[4.f,2+<40yDtx}vWT01o$u>]g~j!b@odt"9@o2%X}QPw25"52zjB&[g~a8l")j/J2=Lum+{o4cBa;]puLmM]!YuI2P1t{6,_gKwCnWLO!ih[.=Xq1irIn[4cd,e`PCe,5`*u=[lpC[xizEUya<Q"?LhKn^v}*Z@subnT;k6S(.;QmJ$dj!/OMk_5z4,%!1EwQ,{[lGFkv;iH`D1vvY9Vq!,D`&ZeM:Hvzq.05(T)p1q9Us2@/iWGKI`Qm!aJX|#y8ZE%kEQwb[1v(ghmAXANRXJEN{&H%OEL*l:Q3fH.Le%SM~KF|P&GChU6B`%lK2(Y@QIxH$AFhhf!4._;e[}Zhi$:w/>rXPDx;>!5]<qPX2?:w/>M<]$<YD7VzT1<|?*yZRUeebr}&5)H]/HV1$ogKf3%+Stvv/o:M]S?ID,_A??q`Myn^%+o*kn~[nLKwg[Up1.#af9xn^G{%LTA,Xa_mwa5nEK3>7TdG#7lV{C~}*ukHYEj"6.GF0OmTFhV!8g`}X:g"l__}b75A/>f%t67"P3.]O)v?c%T{p0&6O@5~vM))#D_uknu;}LTRquV1FABzL+C#$~_X~5{!"Y8Lq^73x.$OvxAAXL=h"GC"*B8F)M~h@_2u!0PW@AyC,!5DQa_TEym6=FnR~X$ABAAAAAAAAAD>I,pp"0m@Bm2~K3W%VGxKdwj)ltahdO,Ba4jac3JcaW[3_^t;Mbgi:9?i7|.GEK9JZ2yu=)k=PFhCqdE{2frcHR,f0o_SQvWa.)9cV?q8F9RR1p$>DVFPqo[DdR42=Dsz0j@j:bg1jz}7a}Tdir:yZrLY>[`xF*^X@~ae"QN0jw*boV33A"zX>LTDB%CJ)ZS564wP*ywupJV;D65Z)OFHTesVjz73u}vPvawrITyg`0^JPI!i:+d2JEC_v)Cn#|zgIB2ZOC|Z$LE*(|b7Ol26>fgFYd#piBiv,4d,[UcQYDk,HY2rEw3Mh.fjdGp50Hr7)[c!!08>stR06e1S{id6c(ie2^@4SoE%sDMH]I;myBB%P_LQo7jmAMwtIYO5{t23r+P*mI,OLVN[+y_B}*tn~!(q,{3(+egz(a%KE[nw|bN])!dhR<M{pNcm8=P33+pNLn.9`FBEGnV#<9mFx3^K#o$7HJ?:2MNPr,fX$a7XPbPf@e_4"+e@X)I$w|0^!wxt1#J"pI5;reiPTW/yUrVqPJ3ZI$nNLt,GiMb<vr.n:V"L{Y$j<eaW@5A:go}D<b!a~N4?nUpd}}||Lb_58<F@1J]G(w|E3<]+[8r>h=9T%4uJZ%d)!Qg(>DUWbO],]Vzc[/mOD&(ERlp8TaKKZ1{8D?i)OJv^*5M;L(W)R^kQbhB$k$1hc5RL8Ivc*xpN2lv265BkNHsP=JRxhfM&OS;f5tUi(t,!DAL7/zM@_=YPf`Cz~mNah000)gE&#KK:gkNhA|4&S=kPF3QTWMM|Fh;TR[2Z:gpq+6jl&,&:c]rR[i8M9!`T:*zx$6)/hP1w`m(J/ZFPtb5?F!.WV1jOODOi}h6;;E9>AN4#]b:uv/8?re/I.hLFrobi%e!1aQm2%uUqN*r7^iJ&[4Tvo*MTZa]T.MV)S~D.tZmEc]#I94J6_ohG7cqy[oXJk$BUqUqiifn39i{(duRRmIzw7+KuIYYVM6#b:"%2R7pbpP3uWT&<G1Rm7:_GqV+=cn9)MXk[<16ZG@U6#7Ejt8V&.a)Nw6(`XC&{?ctNZlL^bav)n$?Lj&+ZrkR]/7%aRqrSpZ><wE,_lgpE&!V]pCv>,8alx]<%sobnMHBdJ*dJ!]2~fU4oV>/wy1uet7N@PUAf/_,i=n|O"hXMz0Pq%ioF(_plj+@g^Lq2f/@h<CFA#n&S_rPfy]rbHU0MCxw_iHq2K=]Lf"+3Syrj#Hxum|mS$_u=r|:;bE_mfP8RYk+evS[F}Gz{Ta:zc&]P6tPYGNA]2$^WJR4T}ysa4sFXZeS1ABvdHs[n*ywv_]#DqLIgLfAWVFXcmzy[ZCP@F4=sV?AFo#t;zyQ@:O*|KhhH016Px#[]EUCf&WEoLlC|,IAbRE|D;HP.duL)zn)P}n)Ft`kTPXAg"iI8+WM/TB*;XJ`vf+vh?a,@v^aMk^s*i;/Pu,brNb.|^UFx;iHvjiOP}5]$pT"@t6vU4dLoT?R%zPNe<_GSly.7lK2Ts}r+f]#u0kb&Z^^udBU4M>o`p7YoCGC[PJGX)b(&u$ys/h%FHNTwk`>Vh&.?S*OfEfe&)BU4>9;A[*&TAKsp>>;<cu?,m!4.N{V(E/ZzxtR_u[P]FOY_UWbt{aXwPf[O[%n|X!vXwxrBp,X!&7@l#;vVm}bE#^5LVTSw8L,<#t>He+o)>9d97~SiCQ!Nm#_RtqkznYA<QbTP?IQs5|Lj2oBMTpRH&5_w8uzX3gUzxP~`7L,b+v5fW$n}HhMMSL0cS_S="0vm?vika6"FZo.296$;^#7}}Ih}ET)}hU?2H4DV>K.v@pI,/UsnP&<M`pL$/8L3VRO<%s>r};"]mQ?t_6&GX?iSlWoD=CIrh1YcpN|vn4W!O<tik:1Dc5PC8[trtu[^Bp0+3MC(NH.hoc_Mt>U+E~+YfwR!17;%*7gD47ncO).<z!U6(k;.`R^|{ko|w];oC&;iw9^Jhf.WLXV(Q_KQ}#_k}Yjo*%UiSt|D4F7irT|ivn}{|(dz[Q}x_`kQTRY%]Nfv|bq:ICU|]$V;f|.)fPw<DC9f^@gw1g$L|yXa*|Y)|ayHk`bs{~q<3d9In~fSe`>4mMt,4;m:tcGav6tHR<IZ5,oqxq$*Z/rVrA.=uOMvK01l0nfqTm17/IUBu!?HPxX#lB9(UdUTFby"WuU`Wtv(iX^0L/MoZ_ewm}19b8{CQs/X4MgCJ{(#N&._&[Q_Q9w_Txxcw(8`/Qk|}jW[%:M;0ob+:hb2lnJ(=O1^M[PLdKc=7U.rf+!`6^HH4;Y%^Bhz5L~|J<e9<<1Ee,Gme,A"MxRZ*:t#9Gd~U&32Xvh/_d^%V`V/,PvkbIaxh[H3[mOrKn#=rH(nHF_}4*|GV`9k4JmZ$f#1SEGHcoRMpI}j#3)13rI?f)}X#bO9IYx?F1Yv/,T[fWT9]hn,wNt3(^fEI6Ug^!I|.Pqc<Pt;H4&~qyyR5Hnbc8P4KsOyK0t/43o3.~H|a%(L](ky.LxVR#64L{XHL]"W,#p"hIg>1@j|;/E[,|3tR%;9U0="Zb"9Nf5Vyw+Cm}=OD!jtB"@Vjmtx5fO@:]]6E,$4ANaAQl}D,PX5$dP7AM*a<@VitWam=DoJ})7!,:)a{*F*~QIdUhO,IDU/QhQZA~Ew"2:}n4g#d,R}70Lx$63Y+BH[a;|StsHm{GSNb(52H|v}0+V(7cMY_$ZMt8HJ$ThXz=)272rt2d"J~{)RERBlLa.Xu]v@64yo1CCt:F@yD0U7K:<=@HC@x!Ap``BDeI9~YGgu,+dP/^?YOf79&T}&!Q_i0YTh,HO=ER&}J$"cC!cvF!gS:vXK}<b6+=[y%+;eMz!j2nAXLcikwV?;>RMC]=zn(o_XXivK2GfD8hT4jU,j7"L<B=84>^_~zj)<tNIkt#~c,e*D@%O<Uy0Ld%_vpoN!bqrmxCC0Bx/upKrVz,[io"}avBVWjpjz:0&UTFs~L}:5{UE&j4pSSfo{OhA7.T5~jLan,^Am2~gRGYL?V6n8zR4cvV<O5sJj2a).1TXmz24(u?.$xzzs:stG5o4*hWqLf<}.u74QrFIt@TztxY$T!zMW>=ntHB6Pvb%N=7zz.a3./(C~@?WY62s%}LaqQU<V<ew7cm}6{]0mSIQcLyplqm9B)B<wTRVlh#,d!JJc2!c0eG9Tg!jP3RD]{!!(sxlV[0jnZ=V8{i`)Uf}6W+zfl2hHUE<OQ(Z&+P_#tNa)YUE0uL7}29F5iDoy@xzUM.;Y(X~YhKwL,A~q=Or!0$NF`H,L6um3":/QyP+Bey"c.Un|$O1YUL[@&<]T&lsn[#gQ({c>&M?>jVIdmko]DMCGw.?b#[>3*L$F?ds1{}W=;Y[03|(vF(|vA2HJjQ<9X=;YC+*eFffDXvLJr6yWJsXgWBTh)I.;7fdo:;t9~&,)v=PblBS^_k0:N8T;{"=:~*tK7{C3*{H&jeYeWu&guy=T>BUO|2LMNt|so@!2v!9$KlN1xSR4DpX~pKg>Hlzbes_;Ky7&Fc$BL5D{(!Ts.Y{1:YA>,kuZ.]1SRbfD;r"gzWNSQL/{~Q?.lJ.w0mTFnX|>|^oCm(um2PR6``n}:6tPF=.2<:BdTJv;Dp1[[nR8RD)v/qW3p16P0,^.??3(|A.ew%#]Mmp.ZwRb47j,5GCy9Sx`,O:0%(vTh)8r#D)H6pq{jN*LtSPypRh65Rfh(a"j^qH`nQ@B`4XRNKbYR;3_+$tzR"@LUI9(7m(cTvxPmHp*#8n^#&R.RLN&C+z$lcm?PQzUXB[DQ7[7gKQ.Z?tqg+/{N!P{i0IL*Yni/9p)EJxx/bFisYz,[@}1L.|^3+]<;YGOg>(ru2hR=86)q0&.23YT@c)3&,n2]O805,c%g`0eK["f|op+~y}K!}Xfe44P.)$nKQiZd0*jw^9HZ@K".#e9qka1{KlRFE[6GB6!N!!5}H]CRzq$U1wsu,UyZ@~:u^Q[i4K2`rAiN)m(]1"G}El!a@:ulP3Muf3^7`e*9FrRRn3WIk>r49ys!)6{6IS$z{M#e8n7j&VJVwM*OGKr}jL%y$I"nIRY(@1P`8TcqHS7/?0>zm[1J&2|BX89^S6+`)?#yS.OMX<Ny?o:QJNd9(:Df/|i+]T?QYh5lw0O@/VE2g>6EwIFr7K*`9i$og`NP0!VwItJjW9<LfT.dO+d6y?LLcb$YVu:3J~v?ul7D6TnX|LK)V]NQp^xM9`jgp>cYj]9X[@Job)$Ynskg:DtSJpk;UsMrQJUDC}K}dnu7Q`*:<`4f*9%BD_X[1&6x!{?W+X4}JWE3mq_`$f94Vp,MR_d20.]:{LS]T9Lu]{EFcSRVn^f)en^8EG=ftt+QT4.A&qgt769U{dF6$U(vv$Mb*r:x`7u66aH81:l(edb5P:dXPjMU9uz>O3=<8XEa8?+:%XIWHPK*Q3ync(zE6u"X^ub:IBfy1E2OR7z_E2>Vixt/4^^:@)Y_h1)e>H3weG8I6;,hi_A/JCZ>(I,_i)ZDRNL;K;B4dP*vE:stJ)Qq/l})$EwNG9y:qX?hv5F=6,FBeX?{+$>J><mybyvu=G:FTX)vx5.lPZp$o^Vw0s.vZ3t0g,Pk_Q,+IsX)7dO;Iy[h7~~NssVD"RlgDK+d84FvC~i;?T3=+=onf@X:l%Dnl$SmR1>Z}S5kl.wa!`&&Qtq&aeClPVsEke@Yx.q<XBt}Hu8~r5U6VGlD`g%?;q]0l#c*?/;v#6~|19[F{^3bLp}H7%Hk21#Fpv$GcMRl]a|DK<wW)<;80tWWkWaZfGvTuN*EJigm``:Lpi<4=(/58M+sg+u0fOCN/3TX|+;Pn:}ZQS{6W0`OWe,ns0?3e(+H1n?@6?T9vjHe<^UH!k/t0%bc!OE<&B3}n(8K<r(z%0T!f[zAYsIp"Vc;fqYYf%P@a[tHjBLPt&y]6>GYs$zgR*t!mr_BULtD>zh0%h2@)3+3L%H#xa+l6at|.UMG_0sDD,YDl8I;_{P1KM_lotXE6hxkE^WY1(w)Us)b;4R;X8AN8_SnlrYEf)3uD$cr%VjtNd&!I0f{b1d?adMSrLc_Ul>.W>mjv7LpOKRRpsQ(,j|kWnnIa]2jDo3<3R`[Ke.5le*.2;Mnd/B6{%e;d@k]Fc>sdvD(Y|156"R8@8ZiYa4NNafDfaP>u{<r:/KW8=[aK%;_<ZCu+wM,+B5A&D!Em.k>(p4wBotE&#mD9<3QTPW%G_VfYh|c?flHs2BGYVh^AzFKj2F,R/=l}0?hpSZT`q"~G#P[=rVnL_IFw|hW$TU_4P`R3&_u/hj2%R/T.z:TtN9D[ziF/zJ19!N+V"/=]8]yCzI/<&EI_%]O#w.*{`nP7oD[J3TQ&~ALmvlO[}:yzt+S4ZE!oy}!1Bp(geh]SDK4gKD.&Ht~_o"S6!#7|.|kys)~k6#u*}sTPbOr5"TO_oIqaSeRpQNxb7VYE}ryri[rcM*|c3/6}n5E|U>,{v(;AN#c0njZ]>8Y%N8`fpdM?/se4z;`lng2whZVj&zzJ6vDSz&})zFKp#P+Wb_q;txKD/!5X]&X/bfBwgUH;QX&TKHO$HMe;RIlInr,CIgb9}xeI"Vu2j?eTEvUmB[3;NH6K]WnGP_QiF_NyZ9v5mEVYYg4Idr!9e+HrvhJ2kP@bf"MxKQ=(kDlX>))56nmz$?<TnWrDtbQr|~[@=Lc147`CeVoPBj2Om34MzIAU<6WYjvG&4C0:&fxpO)8Pst?FR2EG[&!49Tbc<x7@GZ|<(#*W8%MZvTQlQGF._i(]&Ye?lcli<"R+n)nP`${Jxg*#Pt*&S?~LV^Z8,2KlqC{9/S#4GEZkG[Z$+fDeo$r]Kt:=XzL+szuhaZqy"|LB=J*G.*wX9y{`v$^%mInk:CwDvJNv|c6jsB,W{A,^bNeWBK|BmIa^@(nZ2+Xjrp=~^&/J;_S`7L;.^vxY`QMO8Fa.Y=K,+N)W8*tztp?]Zeu*;Vr{`6@l/f4(eveLKHaDVdN8`|RYvmGlOVTO0EH?U@YaWEd4Ic`M(c)Pc_"CboX$ht#l^D)N!TTkeJ7n}N+qC<|f_n)M%#h#u(K^{4!ltmNT0t0Z[8O9vT<U4ScIow(x>E&CH(@h0402rmZs"VhOn/uViVNH)cw<AFHpu5KGHQn/4JbEP5~}IPTYBxOhNGg3j=q}NVY1Cw!*:PH5&=!D>UMtMI_cRLhwm"J;N:%u`4AZ(Ne47K<gl;c`#ejOU)GR`0m+_9Rp}c_JB+B}rh`K$Ha>&x%RwDC%SmWe^}0v^}@3w!92!qVc4zg$f=|y4Zo3+6@nhN%5c+~S&=VT+D[w|o2z^1;_r=TX0c,^X[.Ga7|]N%9W$mMW`ML]Z!7A.!!EomrXUTDsFHDUr45YJR5?54)@Uv",sS6WRNd.hTROY<~;C4&qS_$DS/3:?=;1#|^5]mPTYf9L+S/`Gxq8C<}1&GUNATSax+2=W_d[rnGNkBPavNF8Ca:dPJ!yFH/+h]GH7Tx*(t|cnwtIgx#%fq.(QTP=@1wMlj(G"cv,(wPyl5:VH~W&]1V`*ca8%Qw^5LBr@GP0j%48aTaA7y}yl4!0w.0)clkS.?"zu^?*1w^}+VF[=j<FGhvf2(<(HhaSus~>uYq,/gP[)9BRkJ2J/*vMPKjTkn<#;,]*ydNKk4p]5,;T#KJ]!x6OpFydFV&l?@`2t:jV?A0$yjw9}Bzw*4jDV`Ou]_b*Ou]"_3`8%X1h)wM!%l]V,N*Eh]]hAA}QFYMs~kIhZ23kB?"BFzEi1:Yg/WfdXidD{Pd1|6LZDDl>/uqio/8Mv<RM6=uU4DFHAR#fwVdq.sqm!g/Pv2Ol_K0OM~nFX%w>Ffmql$QZ!v~;jZPC~4{F[R/F7LEOD.mS3,9!0z3i7nQoLymFif&,3|:R&8;<?$/FD7p$rGeMHyYy;%Sx(je}gYTGc1#pDOK/IWBgRHLIS{D]iBdWdd%vz4g7VW_|w#V0?3/8TVCvGDVanUUR@;g3[)@g`CCuje0U4)xu#Z0VHzQ0s7#_6,r3d4#ZGx1<#fKY>n<VVx]bIA"wpJ~D)01a]P4.3:9?2.e:<i^t69h=2uHi98egSw@X(Ybl0Q{_Z%$eu,QNK@Wl/DTHf~sN%")t3NhQGnTE8dIf%w;=_`^e5PwFK(=U"6sjmrOT#{h;QQs|y3aBv3nNs@)*2%6QtQREL[y%O)r+c@MOW6z|*a}Q:Hr=,hvTT$"7BvO/${7h,J2GFUv%nel=oS=VQ/zPiFHJV)/V2p:q~<bGGv;{Vjha|dm0ZeB>|L!m6tG>IT(5S</rN#Ik?G,&3_A`2<nNXfBV*sXTKL7H,;A>w8#`h(R6}M.>*F^X@DDj>S>o1H87z/J;l^W[:6$bdH=KJbXuQ"B,t~MDpc&E|=K=xam"IISm9bQ_zcB]$!FVg.y$[u9?Zs/LqL37VX:#:L&c*FXh@}YSe|(e~qXKLiY;c%vWBoi.0..nmU[a](v|t]^%x}bN{IP25ZS9dj9Y/R2/yXTX81R)c@#wNO>~BX$N5yHTU9PqC:2m>WCwn+Yxw[MmpeGa*GeB+>Q~*0x[,wt#<~bX1PP{onKj+!o2%9{rh5|Es({vgn}K5pzxx+a`(2ew}y)m_0Hg.be_T8S9<Kbn+nBzzlVYxuh<gOE!l#=x^y!NT.#yCsx#{Hc<SWQ&vCokpKvo+tt/T+x_1>UB2D@RDV5ev$$)Lsmo837v_~]!x7hF1T1hyub&<Cd*]oSJ@(^[&?WDE{mn?+I9Yb{O"vOmu:aNpv[w6.M$i&lc3KUSHO)P6I:D@H:/uS(A}W.ixh0,sd2(,pg!hgU@MVoPY)56~tu:Wk|5"^`vTgp&~66qi#S=Vo?R;t/NwH`kK3b(UD!PnHw!MT,SR9;n"3:gy6oR74I6J_.~T.ek=lYH8!0CiaIYxoJys%=Y04R`gG!HER^Bqz,atV($#kt`Y)S4exAzSp>)%OTY)Bs]K9f,?@+BE)2LTM=R]]gl`~`ktX~^,xq|gPyy(b/!i(sd9K`^M7;b1Y+k<&%<L?YwP+vJzF[js1O2_70_9m#Q{RE::_`_pPss~$iO"qbE5_,4r|*lxal0k3b"CreMXJmyHqM:R6XLkbU__Z;$B0SW%@*o|]/ej5X@.LobfaTZNK?+0J,4"rYK+VWPuPWLzr|"Yo#_K(D:e8Jp3ulkz@s3>ND9j`).Ao8M]8/bV;mz^kMS8Q&974=+=g+lo#aAI^$6&W$|6]J3;EZO9u_&KcW&WX18u(Z~]w6:SGKR=p2T$[7<QM6EDQ.tIQJ^&g>_ZFyY0D!K,Y"4&gP~T7R:64cvtd0:#<<,Z)_8/Y$w:EHog@5`$:GDIz[A{[.`okH):]!|]v7~U4`Wx+3HFhok[j~.Am#g4^N08)^Ukcn#/xJ22C]=VPXELJ/&ydnuH=)}a)0A>|sEB4&@nYP&SA^%ytvhf{?G"YaWD8iDHdLW{te.$RggyF(CO)5*qx|,HpUW(4v0mSWi/buCt/:a?0nhw>:qcz5O)mH93i9H#Nr5nY+,5}&!PUR.`cQ}F|V55VDei;R;i?l,:Kd+G)In7&s}x!jsO"`TueQaN<#^iW!>Lbbfto#YSIuW9d~<3`g=qB.SF,$Q(EGX&EI?`^pu1Ek@HbRADQGx&m)}`>pLZ!0q5OJMN%$Ut9,lf%!^#f^+8j4jO(M>C,MurcW&i5[xt%xksiv/v;vHmLy@t!,X.N]kl^?ll=St#$/>HC|9RT[p$&Va(wW/fZZp%h#QsVf1`dg1+H+UR]jQRbPXzV[aN<d@Ua=<ag>5}a3UO@8L%9{q*4fz"}DGd4C^#o#K`Y4=3O44*(IpP1%Xzeo2J_oOUEY:>!TU(wpS$+@+CrqIpZ}Exwl}S_75u+u6Pa;g%U_j).f6RN4.QW2i7t%SNrOwA1zNa%{QA}TF18=/e>^6M}#B2z;S*{,?|+Z+_<0jIJ"YP/|8(^TbE1)gtn$YDiHWw|M7?nQc&l;1[/Cs"^f35Ti0y|e[g;dq}ub3Pl^t;Zvb[c@@B&1VWS"9c^{4^#EyE2$0JP0Oyh@$]RV^[,NIJN4l<[_JuPl1QK9NH(KnOY7(ccH#?NaHVVl4W&jns<+2qHOb125dwq$>{#XuuaCcN20,t$/)c2@WX7Fu[@`<N^tj,:Pr.4jUzzzXrv8IJtgK2KqckcIC.0ae9DA7tgj{YSH?Gb*dRT=c,B8&&^ny)`mEY.Z3KYX#8zcS%$Edjlisoj)h3)`BZ`mhi$XcW?!mzwkro^0kPX;{,lfkaW8eFzYO:.&rs,cenRb$$r$$*RI2HMA~bl8#ggQ|A3y,a|eDIy9ruWf!x@8%]C5^8?5D{]yFv_.GG&heXU3IuI3#zz*/{v8o5I1|5e`d!Hr!S6i6zXe["cRUOx_0]q57n!&p&!$&A4&sVtz2Iz4iW9)=#obm5kw|7]UzmT^hp832Nzpet)0;e*ZLH*V_0+x,<"hy0vQ"qf^>TK[!pTx$XTVOLHnNDfg"ci9SLe_]Cr9YWh*fs|doY]lm)aPwQ}%P!~pzfh_lyI<K31~87JX_I|[*x.s(N3Oo+qFFr]7{G!i;1V;euexQy2,)d[a#G{i&jOx4|@1L5ve:/am!SmNRKa~21tNCr_9`=BTgaCCedjbN7KLv_2_T7<`"E}`OjN=_y;A(*duFv4lpK,yN=CX_)PMnU5cW}wAdQ3cxlF7&IUE,4iXa|?%#;12+uS7=fnC:Mt+ZgL4,A2U>}A9Qcl,OsuD@2ELxmTOBW,x`.^0PzVv=#6i{3cZ5,A&kh[}60tpAQREFdRVngk~!;Cel6WO0?P~1TsLNKbUyjEC0<vj`2P/Q$e[pd8,&K@ZKUS<<7YpPkJtYCv<[@C[WfD)D?4z:)rg@0%N>`t;eny9ix@4=8`%K?IF=1v]:hDQlD<Xq6Htu.19htb)1FF/pHJu&l@GSWOwt"0+EIHJOROzi]X|6p]+^/J%5MVAOfKT1rFa%:~z/vHibgdOGvx?bB)1K|x%n[C(ZfhiS&An6v0|Hlo>$3B0:Ae.I;lKt(&Ufv,/cTazR!({%;x+n1<^4C~6MrEODsmVn9))C~*83k^U=p%TnG2oE5D5?7/2I:igYZhgrY}SY;bXjO3KXBEXfP/h(}9e7mISGQpq?E=X,S#{UC5$y.KYEXDv/0`qEcN_Q`D{48d,D6=Dn26ECKX)CG_l6|F{H~Q}&i.>kWO8[a*)z1g2Ym#iI[$ZUzi,aQ&fH.saGDuP$f=2kx0kcUpD_<[iEt/EB]=9Z,]::Uie2BJV%t(x|81YDVSmUss%vsytp+liEv/@{F:LhR4;.e*NkOmie}T41E|"%z$8:fcvsy<:JDBURE[4"wiaJy7q$RSNO7sn~RbV~R;R{?fmo5W$95GKIfg=>~^O&m9#0#&7#d[n(HSoR8ZIIj5%S<FyW7GYnOSKnM#y,4BY!CT}Ri~[gSaAW_;(??P4rJ]L&r~}k0f2EeFh:b>Uf,VB:S`eLv[}T)">mVP"C7RWcPcWUe:~W**9t$?nxJ~h<)I9FMiM`(lt<?8IQi]XAoz1J8R2Q#ghj{hISlp0KY.ct65>#"2>7&K3~u3iN}]Y_VX9}CgnkULN:Fnrugxu_7BltqbAiW[_DA3gmg}??kS1Q2<!BFgX1,d[@WEWQ|WN_t{]~AC6};[Sx!1:)^F{z(."W)NgE>tf#%?g5w(u,+;H,;ju#jKWt42:V=X[+4j:`jKT/&7jSkbK`o5~86]S"#b>Ik]Ghd}&fq^EX)7B4b$G#$!wwdvxYN|p,{1dMv1ydJyvE!+,`53xrfX7Fy*h7;bPO!4?5H(r]?Dcw"[Ep}88#t{63E!]6L^kkNBYMFRau^JglQT##ffi%E!Y]U;aJhkNh6mSK,/8F]Oy|/XCWnNRdy.atK)XZ[JMnU;6|O63V7l:MM)M<AEqMH_mMZ+vo((?*(R=7Gm[XN}UYSlnL11ZbIX>]^V^#~jm_Ue[T@>1{<9Ov,)C.FfO{v,p!k9,zn!R{qD~7<_lNV,XpT+G;awc8jswFD_1dw`=._QjGRT40e{d9[.SR@dOBni`M8*To}aY%nzJnaS178P/Wp]J786|Ko]vgre/McT9Z1W2?B*:*:k&#l"x"**0$&#h.A]5!1/LJe6"5=iN8HvX[DEAonuGZ4!`wf&ijF>h{e]jWb@Qx)7KdoC48ctXEkVdwWF$M/*K&/G4ovxN`6S:;TUfEX`d=5fs^wg(xApbV_nF!IZ=?4h{*QHnEbX9^(xPx1j*O_(jX[z4}GO3(uu/t{V^3e@~sI%G);yiutar2_JX5$Zv^6kp2p?v3^z"sG~b8NVT"gxfjO4ztPkwRMMaa+:p*Pshdw#f3kKBU>OSy}x7ggK]zBtn:<XRvgR=c[n4us?VxWE22)0yO"|pLxs%t)O>TuC|eCm;N^C_YZmMq6!vmoI8OE#2X.B_?hP$/QUxB!wYe{mw})*tEQct0c}^EC#<E4Z(]UeXjtau%S==6>#POhV^G6tQQy;pL@_^?Y$=?!M/Hmnqh20#y_wvr7E@sIXBc:jrIUWKj&%$Y0v]ra/Ei4yUn%;w0(4gZpJ~bXnrhCzSOw0@y8>dt!%vJV"v9V{l684eaEDO^Kop@{&m.+)T#HjXt,qI19%JdyX(^F)2V5jxzGj8ulQP5{>l)HBN"wXe+1tGh9PLd0$$7f};ihFj"f2cfhv.lJBV]7TpSZH3uSY2CN&@]0K(d/6FUHXg^~6,{/YZmScgpB=VQR>$E$bAwZ)^]q?zhk7YjxKTsZ6:@L8$EtSy/NAE[S"7u,WOC)^nn9}>eUOK!S[AN`#rpYWKONpV.w!sHHrZx.yOE6h?(W,#g;5ln(rkk?hUM+s"x{KfRj41G1PoGUIt<J2y`qiE~p|hM46_spgfHr#Wmh~Oj(DX@:1NW!D7v!>)+yALed4}mIYez9w*qMmMYFxVP[|u:,B;?C;<wpg6Yc|@o[Msld9]whi|_.Uu8K.Y?*U`LPmD0Q73+Oh,l?sJ)i{;1gcpSvA{O8fptyY{0|[nh5h1rSvQd8Qm8;ovO*f!sSZQLTtQqRSF`*&BncS.6Gy|H]g~MZDYFwpx(#J:!*)|tkE.kDFS%mV<Bx{c!2#!crc]QQJ?05yO9c?#!S%RX^PJ#@3XW?8;54ZpQtuy_]Yb"BkdJ]YoeGnZ;Ua%L=#ea&]pV#uE9Zj[MM;oX~/_C2Rk[2xVh/Qw6X2e=,lxV!gQ4rCVGU".l#vX>Bq`YCj0V=op.dF;&NN@"p_3L=eR=ryOnc!Mu!G0F!4t9:C[9XG8Q:RH9du{:8oCZJwQjixKW@YSM`l{kj(`tgD<=]fjkDjqnaylWyJSUjr<h:AuT<TIh#LN6tDYRxFT=NwYAKzYFaLfrb,5kulq"AHL1"e+2PG#blUzi}11Cr_f&l.%3#C,^ldQp~&};b?isG>=C|FkrpAWUs!EBB2[#0QuIxK*k:^S<dKx{CoNhAK|,Cdr+Z#(14yV1"&gdFT(=Hu#+s`,tH;MG:F|Y>^N]v;5d;0w/^ZH&=2WJ$H11?*r>*pGwIX_$$M*E^tzRPtS|xf;u3Fe0#g/u@HY3[G[m,~o*vjn;h7@si1b#*Iv*^w/ORL;?ucyHharX6`>mLyt&lSh3B^BJ|BXQQ]IVRcb,}^{}}|qz!O@`R_b03RyK8#ABC.{v6|g+E=MVO)&ab1w{$0/S5me;mm0K%|A~Z>EO/@C$Y&U)@J&0$&0jonAYg]&;=ELnn^kb=u4hePJ:QE(L6yt:;+:vvw[.QzQ9=:,V$JLDCO<3TpvzL~c1@;U[iuaT:gOfHU>K9rQZAsO?_sR^8L`xE)&]aJ0LQT{Y<gjVItSWsznd2o([.*ErI($9#0[s;qQ1_.5y>?q+(}R{?z>rN1i^7[Na:p}joE]>.`4mEzF,V$f^ks1R|&,Edw.CuEz2NC#Duy@:uuS+_*Ke%@E*!+6EI.}usw:c[?=]HY;dCN/?YLXU&h_e{*EEBf&:MX`)ZcfFT/Gt>nxajEU5P6m#OK+(;9+;7nIL*$3Th&4Kf`m5Lh[g*304]sNp]6~C3dM&DM?2XK_T)gISI1"rp,;Ky>Q$!h1*Q+C`4QP7fQ_S"Sh@uu5&%leI"(;_k/FX7^}%7;}Djr<Po<lb<Gd^?v%.DEXMX4G+IcE,Tz~kphk{}Nnm/n(g7uK,jOKn1P)7@iGhgcU17WgRrqeb6"8,n@,(w2g.QrBV?;EwS}70*_GCb<F,?cBGyR,_E.moDf,O(m<92WGc{d7Dz8|tm.%#ua:P`75:$.u+hdg?rTSfd.IM@%%^x<2s#>V8z,ujJ|FKRa|,~wizL|{#F89<%>aV/tbMEpFAq}tL_e1]F|9PB2?w]b|SP}nVurPpia^T|[W"JDV{Ye1qsS&2pVjIx^|}BePn3zwwFS[l|rlm?@,F4#>SQVOGdSZ&!864vWHLIz=T]kT(@:}9"B9jXmwNO/:~?s1Pg*,i@I8VK2xRQDb/B~.eLIPI6JM%r.a?Up+)1B%*uTIQ)X5U$?TIiVPr1MjXom0$F2Y>zW:p7bWtJaz6;00_{9?}xB;eW/,^8a(0ifHl*=ZB}CXa12lN_}<>dVKVUHf*{UX8a6zLqqoak8?PPw_JJK"yUTqQiJ/zmg,4~w0kJ~RJoI^5^ho@u@n5[dJblf3S?Rj*&<cR&D=@<vb@|Zr4KJyiebKn0{(l`>(Ms_6I5Kt0Y]_$ip&2{c]DFc!m5Rf^fXbYVLbE&)9?;)d!NZ]^]L#!El=XNJtyEH%Z{P8iKd)v.M~JcfLZH[ur[`)~s~^e2Xn@o16x3J@|6uB|2#a9Ck0m4Gude7l(H*Ko2{hY~.&B)sy.%:.k2evm]/Y8Gn_,>yIFHaJ)M=^?j>vK+j?_%eA}d<W?H~fjgR6FM(v)eA_v9^a;mYHw<dCQckM"6EmR&Wh7(38oEbm$YxZ"Ik#*X,UGy$Y9^iW=JT;r+g;*[0O8lE$(tW3kh4Sw{uL@Ld6cEf>]i[B(Ff"~vfBoIdlGIbrKctzoW{lw2b(M/FdR^)Exf=pH3yvdT*o7Y+2j4|tP[zFm.s6x2J_Uj(JvO_AM;cPvD_5V4v.6nxLVpKV#XSGzJ*5]*ARrv=*/)=6P_g_j3Fn3h<3kpGL6^y~;P|*r!WBA@M!cO|AVKwsqq!<cx9$NC1!=N{35a:Gnkg}8@q7^5bNG2^9WtPVs*j@_/)&j"CU09IqrB9oQ*>s}BL&$;bBJiN?*w/%6Mf*TAREB;{S[+Zd8=sTk>P&STfchR]UB_@F5yA~__$Faj:2FO2xvk+~@1T^_L^)1=]kxTc*MFBIgh$E1YnP=fsPn"w&]I!,f*G)lmVf#5FOL9o)Nzp~hs~SXQjs(AuLV{_h"}m+sO%gUN;kwp^4KJGh{kpR[Z_]33Vb5]3JJpx#{|e[@HYU*KVVnZ;S:{7Wcg18PTgO:X?knjbi(bKQ~XFv4MR2Kyuc2N2{C%8RUDy[WVjJ(s#Tcm/NDFf`^Nd*RF:t8:$:,/Nu/TnpT;cwssmy]"VW&bU4ud}B+uy7H$gN>d<7#c%x4$XKUfXvy!r%wu^8]EcVnzUFv.Erz5lP47$Z&!m=ml:fHGWQ&zcQ>f<iQ^qKDr_2j7MV`cNF:"YIqaI7`oE!R6~tI36Vfl`}kW4,|_)]kjno$Y2&Yzy*!lgj#<`/uC}eQ[?BvBC<|SgWd[l1wpd[W~H5O)iWX&;pry<KQR:z*#BwatJ&O0i+ZjDs_&bnKJbXOZcqG/#fkJ9P!7Pf{9C#ES~!37gBCC2|OW0&t^8>+|+M.gyaqI)ACWnWZ"b|1AQ*Ins*R"S^E+hbSLOiVG"nF[Nt0NUmw/U7K2L.JKP4IT3?O>.l/([T1K~q@]A7jX,C;|y[)pOVC4;lQ)D5&FhlzIElJ_gTY$=Yf4C?8~7=F^Or+%9d2JD!H>OKGk34~"`;o^/51|$(kpHq:v(vp&,)$yp;GX~dfboKc9;maMJaj0Y:<yPN}<57M^({>a@$FvzNxu6aH6lGmxShqUKCK0yl.wABCN!Y+E5"I@|H,qOu,+d:~bQXbVCXm!kE9^Z./IVQg4y|F)(HF:;[3XZ476j0!>qu!KM+gnwm@I4Ldt|[LU|Rw&ZN?)}5&oK~4AUpU}q0vo15lFJ6$P}dTh|1.s";Q2RLt[xtM.sN*x+P23WjR5z0k?D}7@FnAD60nD$,#xzh9};wu5V8|c?"rIB?}:+AG|Y.xZo{TC>(S`1HhH:nrHQV!l"s)S+jCqx1=b,5H>T(4nHa]z@H0NeM!yQ[r|E5{0?B*V7By]Vw#c~w"hC&JW/C;NkqJ#jTt|J>}VUHH8}9xUZ@eEY`pADwo^7oYhE"=k:LH]f#S|C,_k&8UB@Zp#{~75UIBI2.rt+F`z(_6Q1r)9B!Hx7I:LEq@Po0i7B{f!*RWji/h%gSizcbX8*I_p^_.PqD%zC?V9@z^VK5CGMH3pG0cenz3xffp#<5*n!lq+mX7SLG6Ywi)+WX%_s{Ln|h&j5n:HVirp"7_w^1M(UODUT3}v9$HS2v53`?Z1CDTHjbNE7o+CiyCBZ6M6u#wU`<ztGTfPhh|}~+@eR#T.aPX+>0RLeu0%o,MsJ(ekcO*!/e"HY5t~/s5esc)l4A&8n)k3a.01@AG%B:y.A]*aO`A7C+oG,M;OE4Cw0sD6UYp`y?M:r.v]g;?F%IKxZ3F:j6PAl)fpegp]V"#;9qa8pw5j0R*kg`o%8JC08hXto4p{Ml$bu54"tzqd`h&6>omo"ogUtmNr5E33QM:2+COT"1E7<punk~[X(AW1|~@]G_{>iRc}bXqhn*cC&jGz+u*c_/w8ETb>zv.|H/KN##D@<)8@}:vL.+0JhCByf|*($lNtHC_zDz9jM>NW0/h&uJrN*VW$io*18)JRu!L_A%kN_^WmaQQcJk`?J&Bf!jh03.tL~#&*~)u&75+m3j69Z#x},Ip^:JOU_vVTztudIy1q^<T9a6g*#b<L($tWpz?dHuOvP=#[lf55F+(`#|?WLjR;zGQ>S;~%/g/!Z%]jd"b_JuMEG8Y;Tw(]LZ]E3~ha3(.5nq"D<%vXvuoSt3RwKF1[?3Iqi`=_z#&/[B5U9a%ac`jSS<$9c`XF$>aLs2_1g(<5YXEi]ics=Bs8=fRMx(2z!ecrA}v5s%ZP(w$r>Y{Z1zenmMW5c?.SR):8?Q4$AM,dukj;T|<wEWRR.PVLU=&O|GP=.*D&qw7qqSPEM>B7/33E(?inC93mj3ty~U%RP5]8iA+LUAs8Q*I6b0LX(ifa}+QG3~Nr^):4oICac[P9|4^jw[eXy.W`4qdU=lG*{6l{edRQ<!>@?Hjf/(9?CS+QBa08sQkq_9B+@;>Nr54FgkZh98{Zak#R,~Pi18h<{#v242RW!4VeXc_x(M<{>vJ~,=G85Q<$,P#zt/[z:(0_R5_nhI"^x5{rcb%I7T+K:D[~c.]>D)F|;WbU~5^_{(0+D"eG#!}]4PO5NDdY^{ejX(Xw#bk*&,E_9d8kmBi;O%:KZd+,OLWci!nsD3ojAj[IY@!Ua%|[x89*si;m$A*:^Bo_#"G@R~=`Yj6JVfO<(c$2e8..V79.(jAs!g8|Bf>)wuK*U4ZE&}E<t|P:Rym}q>iEC}gI<LuMxGjAFgha+EW5w<4cuon{)d^iJ%>#[Wy$2"Q{T15cwNSgH.*huymYWN!VlnNskP=U@nk<S@p5Vx:|"5|*mvu}Or$^Y$m2u!URy%#ttyPS$j8UQnL!(W%u>}l!^;]8~x;@0ISw_uh[xUv3.^lat3XT#q1l=!v0^:bbl(F@8>GV4s!]uOfiH;jr+4=v6y~g4Anc=YH;gvn`SrZIy^8}`WGhTT|5wE2)(Q*McRE|!j4O&iSB>)NP7<x]ObAJ":zoDTmB[B0I9"%1jE!y`5@sRyKC7JF9zElURHr&.aH]b]ss}Rggd,JpLPnj{s,CaR~sP]%jeIw7qTjV&V?Bb#L]1Kdsv5k(V"GRZ=6axLbam*7:,[QY4^wT40DXWkA.!@&R/(SmbVyxRhiBKdKKJG>{3Tk"sCm=Mbr0&pV@?H9M6N/F+|&"QpzLZV[ZW&?i+~Bw2e=QP?ttVQrQkiNN+&Zd,j8n,1iyeK+6YGTPKNpIk#}{MP_=Lp10iF9B]`Q]y(ICPW6M^XCEx.lPKTm(}.24Dqkzu_a"a1Cw1Q$TPEMdP";}VF6KRE>ho:qnzy{Sz~dJKqu"NkVo8DlGa5CcOwAE[~60Z"/Z7W|lhcv+v;u0.?6"F%HBbnwpzfL~LdeUKgEI_{FnkyiI;XRL9L&4R$r7;>+}j`.wlqs:HKT1>1V[_]gUt#z%X)FRqk@9YnMaXX<u717Q9^gd<o+fV7pc=nshHtJnH/bEo<YC@C"AQm1vveI%|}8S7q_x,`%*w[xYg={j,d[._5@Jm6,jch8;^x>H,>%pdJ]oJ;^,%tW<KpezWU[*@y+O5F2%CagYQ47TK9b]llV6|XyMv}&3+4#{/$eJe{+.5opASm15y_OdxW]1MT,3Sttx[o$y`n#?/@h/2Pn"%Xi:d[Gj]L=;THl7(PrQc~wK8FMjN<,5Fw.i#Rlkzxr7uDQ}GqcjCpPd7&k{7n+PCB]&=OYNIOE|$I@Ajmn+Vm&.^>$`slM8%N:0P_h#(i`NM1;V!!6$*EY)>%Y+bgO=TmNTH%n*zs+ZB{=M7F{`?$Guf"23.BSkr`4h#:^Fb/CEPlqN8|lfQNHgK/.H#(WU5L+]n+f&W3BXswKk<3E>ODIfBttM`%{0S]BPxMTm=D/$wtxMY"U.C,VPXHNK.5eesW"owiKBt5"L!r9;o5(R*0Voy;ERE5KEnq2kwygTh:f=`hQhkw5TY:Xm)Ms>,bq}#F<}GV;?Sa>`Hc+QCEl26HIC*B84?kqB92#N6J5Qnsa>ie9Hc]I63]CP/FD~hG%{7fKE)a"AOnzGKM#qMs2ET78Wg$J|..}qLzW)ma,POk"s=S9t&:uE?w@M.".dQT(G%IW%Y#13/g1nl7x2>Z78OK8`|w{;H*[l?maAk`b<sf?TR|k@6n.3Cf"S$n>)4UIr9CYC0:(*,!$w!sy`)mx]@^V,BXWfJet$~]hJj9kTHp/5K&UtnD[cpp``xJvWc+BI~<,Krpor&gy~k_Wq9D&X9N5.TkJi<aPy]=N4(^<tC3)BN8d(_p%j3B#cMUivvY7yO=|v*1j$#*j64~w6k:fNfEG{N40NpxW&i^g[+)%u)~Rq*8vW319W(qRGuu*K^XkwpBVc77f?EXG*mu9,O/Nq9X2%w|Mv6<>#kFl?;@8)yqG,I/MVUj$uE/d3kv($#Zi7y1U:%eiXS@MhWb>t|AE*Oq)[rEUcOAor~<Ecx#fk"OvM&i@9Wuzg8KT%K:J]5ig4oMUx8VK&5GC.{>tB4V)|2#i)+AvK~@FF<_R?mF~U3Og{!(v^[/J)2M{VftxWSH]S,>ZzSZ`Gc#p^{~}UBL3L6<5b_ANGO|.:B%7&yNO@,g4jjj5Xt3IyXKzJpMiDR{]^%!MiLz=^eL&,IVHhNR``Z1/(5CEApX2J{]V8z=7~he~$V8`$(u_sR|!JJYJ+}4ZW{b^nPtl7W9#}sB1<OfVN}C;$ket7q*{ti#WX$`qy(J/B*%!uHEU~oGCot/YH"?MY.AUN(9)?eA=gqGMY^/.|DoX(Qk<<J0T9LEg}WO0O,RfD%~3Yp5<f>U3PvZOOaQo3Bl43=3!ofKoJ)lSiso5>k|ZX%*nel%)Vge58z`j7Xy=Bhl|W!7U$M7!xiHktjiKfEC}wi}n_r/`,glhyRr0g#c}M/K4TWunr;tXOG[^5Z5Il)O`q&Tb,A8")v3L%W>|GG<r*{mUdnJtoW_!8qE*Su!,y:vv!,.R!:PT4U4+n25n9P+,{hoLj>*G<*jr}1GO1GiH"0k~5_lRr/6y+`d]r46+r]w*3H@W5&@F,jD>Be*B9G7G1I_nuLJ!S&o<<&.3dD8G]}ebA:fDDwJ)zeQt2qZ[{}#+)R>&4D`x^S}u/k,&O*.:gay^<KMapn?.Y/zej43QAnvv:C@=]3nhXTZ$j2o&0RoKM7y=1Pt/N$UljqPc,}zAV}z`JufopA>apq3c7,D*$CIwyJAt|.k_Zmzs3CAUadx37XdVK*7s*_x?OD!{`MEiS^=&:asI}X7GNz#:#.!T*f5+R5#DqwIH+CtC"TW&bfjK.!&~e8M%hEc%I,<w#=M0pnyUcp<RPJ.v=opM@`T<9S5{D|[6|gK]Mp>e@<w8~OZ~F3eKwT3T;a`tv_^=F9:c>mx)whmv2z+BVfYrX)JRP%fuU8N/;S)}b6[)];lb;|x?)rFWc{/#[T6.PA&g]:LP1.4{=YL,EzLmH03N8iLL(HP{bIWxdD?5rSWLm7xq<#%|#h_=bV),2;F_d1D:KM?J%r,L9IFHJzS;y9fzN.(I<#&Ki3cuo[Gdlr|ty>d.JZ,MNakTW3U_g4#:~3pUGKTf<;IGAstH$}57UH8c(Z52T;^6SyJqg%|*D*TJ5GxyRH"B?Y^COHBxofjP3E:t*!,Su2:mjQ2cW7]+T2H1#$2?tA|L1nBAlJx}n{}BGv|,{il2Aym!~lL_DuMt$(;4y}kfv>Ycze#b:II6{j;#5oEO$jx1yeji`t,|z(@Ge>A]Ow~!*F>n|bU[C#XF+ZGPBo)5R%g9!VZM_~qwQD`.U&b_Cj.yXOuF!8uP@Y$4l;S2wx];k_JK8ke<clgfVo(;|OIn*ybn&lpz4PJ;5ebey54)i(c(Cp9:@H8__yAZSG72)bG`F$*B@T&MA_LY0OBrUC;YBdj>xk=VnMS/>k!fb_!t*3Ss42l!kvLDZYAdNep.=eh@vDWuAi.w+aR@ySQpCnS#Qm!7@lXtb]u4PN>OA7:b:@(oN9,uwSd=`z1;04X.|XeOT^.xw*$p2BUT`ybheS3@cX.V8!j0jNh[#&De6M9a)16e3#4pSXzuME[SDoSb!#X87oO#Opk8y|l{>YdLDwDL)/pY>o13"*go]o?bm0Cfd>g{eHC4*Si]0o~/[ApJ;$~k*W;(f2%xf:k&A|Erw0/v,7(Xrq@a;&<%X,:Ln&uUlgsSJev;9DdU8MlzeG7n/qY/H.|Zs8@,wW4CJ]!Y6Oqw9t4b[(Rjv(o}O8Z*2mGlcYY$Wi)nx?4S<8Kg2`BZ%D[M*I8/BSv6J4[n@x*.H`)[94MB<hu~Kp^%Kd4Yl:k6eU9Pnt9hg|4srPY,>Wca"r}>JNglVJ3+N3lPAQ@+_a~Rmjy&)hFP%rJMM33BwJkcvFTzS(*v@]=FH8[dg5z+i??%Kopo[GX2I0"JUj)pFA@7^Qgb3Q|beWxO`MNq`s2HDe)G<*8qxR+I9?]^(N5!/)$KzpeIm8ymFUP7^:$M8^.3E02>!p$_zKgU~pS%h6f7:G8+z3~i~GTa!(3WLCWC{wFO3+Dspxle0g=_[bP^S(II?:z)C]H99D$p*4<;16*r:HDN9vl@>3C7K/tBp.e_z>eTWs"3S}ch#0*>Nklav<[rqNvr!$saR``n4Wt`xeUYCAP==m2+nc];,w}Y^Vt@oK(uy1C.oZhBM}>`&meW<.y@H,XotT7ojq]pi_C^Mj6et2qqxxcNnte1Bi+)e~i"Nui;Nv:m0I"a4`k,2:X"{^Z+yvmDPZU|8;JpAMMm)4:9w?U!5VfItq6yA@(ryG,@SQm<K0LNMV_CF*^=`O6SSC>W[1mYccGgZkeCo24Zn9e|P:y%hcB2<z(.*}FgV#SrBJ<_VArLLx&f}J8.[hJ<|4z}vVH:v0>)tjCnk[T@fs|3yQ:4c0iE4MXgWD%#B6<DH"Z9)aC(]4+k?TM01<.cL}EJ5:He&86[yUW<P*O.)[;Ym)TJN4Aa_Iap`uikb:6}s;F!Mg;K~B97.[?AM|olW0qoU@u+k<hOy"U,#BFfzt_EKpf&NH!CtgMsxc.,g]dVi<%Xe6kJ^ET0HlSlJIh,qF>c#<NM%?*<=R;hfYY]}Gzk0Q=__4{%gKM|4XgzZ*fAz|Y!VQda>:3b_<N@}0?DWWEIYbcLAd7g;LiC`hW+)E3thw8R&W)5;O(>pl@z#1Kij%)|C2/}HBy8c#S)62@H.(up/Bs4s*HZ@TjVn9siM>U6g+M"PjvR8T`uo2v>/[ue!,F<4|MsYP8gUjQt,K,9#Ibn}iI4Kl{(%O:jHlAU`JOC$4XU:I(3>Wb~$KFZgp!W$J*_Pb.Ce#]Mu4)KuX#D?%1u59*U3Dx;6#z++`"8Us`]G!6I{XozdkjszN_!Fk^+cugDbdxu{`J!t)3~QHfEQX0ufO}Sjppao1WW3:j=Bn4&={j_T2<Kr<uvaF3N"N~]P[Ad}hs/rHw;dHdbP].MZ0G:E8?BgRkRF{$hwKRiW,^UooZ0,ec]6d.k?sR%f|86%#5R$h!+%;wQqN{s"?~`0e|lnF8yNa0_I|5^:o,@w;[B_84xK0PIY;n870e|2&8SJ/Xd4h:usknSKYaFxe{!y4(eYe$=X@y!&Q^9h)r,GSS9+{j,)X0#jTyJ.RaI}Q!n/%l4M4,dc~sN,yu,r7doZ5BX%;w|8EMnAiDbX_~]Xh+hfkDYnoTwO?@TDjix{d$.Kn"(hqsD"ND6cW%tWAH9lw>xA}Na<7ifs5e2@vj2C_g$=IaS>#D6Ypi]cEKSB/FnarkIEns6n2xb1x_6_tpKg`?n$L:uQ4_r<wxqQPl*$l"D%vNdMz`I+>m)lDV#PLBO!K{nYbiL!w>^]D;wQE0,lB|v$OlR>h^9+i7da6USb5ARn!bHHb})7Bo;t_Ho`1oEG:xm3>`<3rD]uE:j[<cW#{x~%O;KfW9y;)wv{SC8*>Ro2DuIn#}cQzJe{hNRd/3[t[w#.C~B6j$6)#t7LBGYrx|Y5>@Btnx{3BawrhdH$rm1YKw([vrwzb$1_MB~MXl)|{>)0YR3i[X7,$}g(|h$Sf8qq=A:w%|?lH6hp48_OzL5_Gd$og&?SfRsMFpPbOYIO%hqGe@fSw>t$2sTdy*D@PV<1wrSDUKF|#xTgTp|YQ#]SVqq3E8123CY3r]bnZ{chK(qNJ)t<B{tOD`w8}M[n#~m0C`v+cKsPWr1@_L#?0vmn;6x06((OBsh|xf5IJmw)[5n)E}vqrA=h.#zpBcJuN5}U7{SFyB7TUeCc7D]ABiUib.!3y0r91e(u808YX0>:6QH&;TJa32)F#0RF}NVDJn3lKM"E6:j`ZK_!0Py3[3<2S95v]b&L)OAtvt;,ha*<H;y7_#rV5QfA1<6)zB:3qJbwCsZn!`s[HWw6HiQ{2z<yKVJ,k,(<i.gc4y?W5{6fL.>/Ki_WlNGPxLp8:ELBi!W=fd0o):24N[CIK8P(h}0g_WMj3Ux0IWyxF0SujaZwfJ}og.R[3Cn76E^4f&O!_rXCWPk5#a]rIxPFWI}&e}kK}jvo)6l?P?$TY[=opl3um(C:V,<9h`Dg0{"}r#t0w_ls42)b?uU&nMbA41z=9{`DDn|p#1?&ab#CDSNV?|Oad{4P6huwmO=BjR)B.Xjv1|Yk0`eCmT<L+e@Bt@fT`UG}r;8u#Fk"yj1>kS)>FGKNL,~PNf]X`k80zG`(DSPc%YKx3JM]DB`PWxZFZgV9zL0lSpw^d#ub"9)TA,`|`d|Cr<*?<(j;^dVy"~L3QXO:7.;4e!W_)bJ^YZ_@W?FWLk0fY&,&ngE<WOtPSe8LGEH.vdcSHG`D!OD1$PJiZkGoVK!Da(k^I4GN^!7:}syq(R7HolGdB5nMP@;Vh1`).MiN_xNJmSe7fbyV5Pi2HN/Ah1Sc7.E02n`!Kg0ResTG2K0wsRDi4V@^G.:M*=u%2fZTqyl(^prDb;4W,322zuEy[Gm:8Oo2rd0lhgxlw{z!C:^^<Y%a&GFI?A+v(~RPa$rP{9~3fXw0*1M(rpYUUu6lrf(M/ibd~Uzce1IIXU[jg=Rcc+S}VHwY4&}<Iqm+Pt7aV5([H)|<*aXh$BgXB/(x:<$*y92Bg?J%}enZgJ*__wz~1G|N`v|)Yr[*v[mP`dKcT<rhE)K"$}SVb2ym}bGMCU!.@1.G":`Ywh`,~vU}:{iAr:+6[@UxJ+v;m>RlpIX&^ildBL`PjC|DovbjT`6LES>+BHy@D~(<9@t,K%$Ma:j9`]omOX+zJ;(@~Ij7+FEYZchq]w+^L[DEWt{=[A|g("do!GCygQ_M7n%XrLiP[;;#]q<fTg|ZHB/Bi1C@9{RpeF,Y9*`"10[R58HT3k?[iplQac_pI"c`[7F7pAJi=5|mQcujctlbhs;Z7r6=2!@md^XQ8YY|aNjR+KID?^D{f7!zwm=J."l#>@o11|{}HE6rKXMv{5svHe+^ZRtA&QR$b(QRrr`WUgR(sw}Rz^aBs;1sPL=OWNb{JliC}oVD!W2iIJP~#;Q>jNf?pt`I4I;[##`[Kh=quji=n7G"V1,Ba@:/O8D,&c*v70<F!rv14z?af(ko(1_|>?jea0}9Z(smfbEB6AlyMC:*uEo!MXZu!6?fkc0{HB}^=wy~4t/a)hVA)$~N<>6X:g]I]w8ZlF4Z/jClz}oKtnaE`y?"QtjDiwY3(CbiH1;jw2}*T<S6{<Otc2JkQ"vA2Yr#ywdHd:C,pt%bfw27*mVO5[ZIt$)>.?G$m535KymE]AkC&(A+/w{6fnDBw.^J9#TzlOMKB}t{eJN;{2zZD[(+Z=B0KCV/{w+t,VOBPf~P*LVP|N^WN?k+^KZ#C[#>PO72oW$:v}+7S{Z/Ew|w96R|cjvT$VOn|6b+O^s2M{x1:#z_|M6f#%EGZaP69bsrm.Ukoo#^T,|PMDPuCFEq18LK8>74Xo?V?NBhjtq8{9&W{dDZCc#q/zkUivm`EI@$K]a3L8}!r<~f(zegj,Z_?kNpDMfk>[_TQQ+mRvj=pDn]x=7O=P%ftRw<""}e/SjGSzOnn<a`NIHM0uoF*c@ntuWG5??+{"6O[&T3g5iEeZH07Hftp=[V>8%mOB9p,S$H&5LVF`HSQu;!_+2|v.6iIkX0BP;q%~VdMNaldF45xC[%*;5SF?ZDt/n8:w$TL"}P`>v#B/snGUkFtx0ogL7p.prgqec%Q|IacTUk0_9aHdFvj.H{CcG8K2QXx/d6O`yjYlU.j))g<j06NUH4l*=wbyd=dfxm%xcROzq:4S5^.0H?$bm|bSkrvUg<%Hpfs#1R=Wo~}3k5(RTC5jhMi6N]I@Y%gGtnLgi%gz&4O:P]kRvr+7Q57(57I[Cn!*:fx[6u=4wEDNJZ^&`(]l^leX2"vFAnfbID40;}Itj>z_FgK6Y/)L,lVt}YTKX3sVP}JH#@KVtlOS(5<Zxd@f0(czDcvK=Uf|"PjM+G&&$N880MXwzr!k.LM[9;hYBysElt#^^o#4z4Z5[KC@`I290Y44OG}(D21.tl)qJ~5mbEc`s;:&GsdvW|sENKg8LmD4A*[{?1Ivzy$6PE:GrwrQsN"ESe~VDh/e6O]e5^Et8>hG#D|AqG"@1iBXe<Vl<S6h8>YOZL0mu^|oX|Dc.~S^_AiV#Y;(S"DvhG!tPo3CR95,2MzH%akhgBaVB55OTzxRKHXHR1rM%~tdGH.@/b]!D(Io=Dn{+j6,<$G3TB0Xrg]vnARI/TXQ$/Te>R+3j)YvR/o*^<PK2UZyJA1[^BbRCE(c)ofQh!57s5/5L+1CCaH~5iClvDH4>G*l]gS<%"51.e6Kzj5huk#4fNxHIalaX]xx[PeN_QrXM;q<n{;Zvzd1w?J6gIz23w`Y@hf&+&OC$tDM*uRUPo8!$wJNV8%zXO>n/I*r6<%{Z+f$S5[zl8V01_ACLx;vmT(DM5notF%@.r`nFqk!)@sTWtXe}M8;3}vo|Z8*Z{YDu.GjJotd=fEX]sEpGF!"~u90)&)D<&&LB@O1%mNmB[Kv6&&!RQ9)qtFz5Y^K{J),?x4&}p#4h2z+$V5*7?=_mV.%cf/&?oyiwXj@Hwz9m^B^Jy?^W[nNKf&G9#(7~fb[$x}FQP>;iI6VU?:{GTS6/~F#R^Y3(uI1L`%Aht%"3Ot+a?n$F?i"hZiix]K78t&6y(2Tucc|ja&eGL*iWlIYEtu?/[4@w(jT(#f}utIZXCM=_/wlo;3S5]|=Dnxg6Ha(TJ?~h!7z=qEj*dlHxcRUXX]_i_RK(Ue=2|LmKK0A4p_y|.I!a4d<]yck&;I4v*<!.DN6]0!dJ"O[o(j)9U(eZM)m~THyzG*tI6LdMps_K7/Pk"XGhP6fxc&hPQRU;@"ufgjzQMBWWRA!05j&?|jHN_A~O.~DiwNz*!Q>]~AaRDMSEIr@"dLsu}l)0lm0OD`Cu*xd"?60UtOJl^aDd`qnW@s/,%%1iaHg:G&reNWa&4HXWiW}*S_4+hj|s~r@fR&0_VXE]By|(<iaKQs9=4(!Q3qwfSMD!9|?$k1HCWHT}*(xx&n$?J*C9,^y?QU1R)f(MmY9oj04gJd$gM9d_%)4xP!ldZj,PWr>H%R|%~lylNdH_#_1p2|wDOQf)Fn^@QfBIja1~]Y+I(xe^f~G;:,rSBmrhy1elzeP]*qN!|*v_)5JT]}7<if]Nmem6Gcu:ZqDT#ph8%TS@)8"i?o.qGf#W3)r=>WHsW1puxPKw#kqybooJ1=L#/oc]]^yK~Lrv.rH)(+40!MP{5lfn*G0<i/VZ@0QrpRQ]?cw)$9:LLhv1E/;]ZOV]KF,hDJS5@_t<~GTU]s%_2HLqGTse#N:*!}1/8_G&_TB!T2PRO!)DW%b/R;5}A};J2"$jN0=z_e^tbMm)b7E<]G4ER3Kg2)03"YrSErXCqX*(~Ehz]B/gO/KI9Hd1/n^hp^x_yU,Yh:eAzooDRv*#G[0x#*!)Te7LL(1_XOo1x:|F$!;#!1Vc$Qb4T6Kh(#9^a8g9c^+!:7DkKqkZ^lBxy_t`ToMMdE)kFno,4<4+TRc^nmp[>WD){)rFWG.j5#~il8akxeVzBkSJaT*}^tSvUncw:5z3#GW,N!jtJmJD+5M^fia":o9K5EgZ|Riq)xrMW]/XJvYrR:xkukKW`1iH)|~oA$Z|=@{RQ=Q/j[sZ/ycox_)NX[Zf@RwW.3c+iK.D67Yf:tC$7+mT5$WF.__xnf/K|{8*n*;RG!j"{Cp1FKwJ&un^TE6;Z]sMOc[TF}~@F8o_6[E}4F2:)Sm8Dc2eQUDJ9`l4Q{@Uhw[A&)CGn.y8D$O/pqEv2<zSJ],/6aTYW#}&A^AZF!x](Gw:0`]AiX*`l+Ze=b]BpnT;sB{nw*H!p>,}>WvV3+L+LN"=mW$[Xemi(qVt8R+qO?(Dp5~lrg|bXE,o~WQg$^j4LCoUm9bj.mOsqDXAh5khKg.iEC<82;o3f2ZOP?xou~S$fC8HYBzAd;i;&U:R1oHI5FW#`#:wWG#f,j#/[+"2?[Ye{]_7gmQ@2vKq4yLj>#*N)gZ0_j*Ln0ldfJt,%w>hM^{#8>d,#X/l_@Jp]^"UX;GeC|<>hQrUx#ZO[@5}M!aIa"(v(ekCDte}LjhXPHJ2;6n1_?nx#y2YYolMUw~1l|?iD$K5gJ(7Wwv9YAJVme&)0xE{1TOM7WK3j72*f6%%n1Zv:N7YZ`9sg"FCrMhdL6ETkh%eIDCw]Pg9/LkQ].mk#7T)Ng"Apa6/.)8$H~vg5>@<|@*E8SBxsnO{WJ/F:ACLnR3aUD2:A9fv%Oqlu1,#Mtwd7%&["^(v+2g=LKCqsU9iaO7D$Ml<TW.}vJF((Q&04L*NEK}TjOSkAAxJyGwc`s1AG:HrpddH>;.GApbHbn)T0MzI*%`/6TA&KrlODfVXOKdK}|U[g:")S`lN^!!])5opNa%SOo?9(4ug6{E(zwRNopW;[IB]]jF"DM55v~rn>.g0BY<c.lF$;c0hZzDRo9*#cl=bIIMokP)~l.%M`H":^q~).pTv8l1]5{cA9N!"[vg#gVm{CE}KsFB6[[i!XrNVd):SW|E|<h}*Lw(shx+6;@_h3#?6%DXBy/sHU9ioGB|aA|{B)tpl/^UM48{H;7Vi^+m>=v%.jz7yyT4k{Hm2G@7cZEtl6bpQ*"C=6%BW>6R@BM5tjJ2_#~{>7S=rofT;x%F[^GlpbF,#XIf(wqDgg4jST&3t*pu>$5f7K6+k#G{*_v$RfT,V*s3hR4<5wGB!:3r2q>]yt}@,WbDVE+nOZmm`LVqh[/@w9B*|Yf:(QrkT!B:]>eR><Z"N;fk%5e32,}N0DTdDRc9RAz%FND/wK@!:>Y;!d/PL{b@NGz0%^sE/>2fHsTENX/TJijdYL%=Qglr~+%.+94(Mm@`=gbNYXGeB:?aZ4!{5zmE^r6"^F+yGq)>8qmjcZ/3tUyv%A^)[,EF"RFNQwW4|nZuC<H&g{i^NX`BL]BFfie&mmD!baRz&}p_7CtI,heX)TsCEi0rrshD&`;E|CpDL`9YA!`&E"MMUZ^CDm2WYZu}?Ojh{_.|={g3[]qlHqZH7`}h+G0q#x5`g}pO~@f63eq0qt<12gEEUqE0n!A,:+*LYhIqOw|kB0BwV6morjHyOQyOO]/oV6(9($?k.5D%FleSi^sWg8WJ)rRPs(&N"G2w!M782@aa^lfr53NpZO3yb+YUHS~DvM@a5f!h!<gVL>${9`apGY:Zb*mz]H0RA~<4bUfVO>OHNY|)%Y#pjb6xMA)nmq`4JP:nx6P7.8S0sh&1(KI]DY`Tk@I`hbwfCe.A9Yx;zOotS!L:XpQ~16YSjPy3j(QW)HNtL[oJ^w?E?@BA4fVa>iIZ<,F.}yay?;AwJ#xT%Jv8k`;8a>JmhFw(0&QT:q2~h"l%Ee^CDh6njkTI7l}=bs~ryUJDEu.C_#^i;P+l>cIZni7u&f[<)8HM`:T3tUd$!DlP)pUn7;mel9|d^<:dZYo+gNju4($N]@cUV=R]p|vzSccN}=g]NS5V)Glqp4LVrrp_f#O=|%GwK>gqFU}Wq%={FVyBfZt{@^Ch}d})T4j!/yO}fj+"_q.XG30L*Mx<Hld2U`bV3J}]RQ4;PV5:[_IP6titfy6a(RI+)t%+Ra*"pw)D[VNGNB~9;{El:3LO<]u{[jNy0Pfy`dYy),^$#~ZZ4;jwD`q}|T?b$~24R[yI71Bu?$5~mn7{`s)^zWzJ:#q?kS/c]*,V6Q<l$L}%}+cCm&>*sMa+aR.erFrt!c8R+=(,Ha8[9fGU#C>H|E+l*A<d~RwOBv[tjUsF[0jsGp$]tO2Lc=SMuzYvy^oQ67}yV:$A%j,7Y:K`,ZuXdIp!cf}Id%N^?c<no.adK:/|&|DuxC*D?2<9UXr?e||h~Zt@.e/b";gfF=|o0n%}}@9)FSdjAsNBTO)=8O5a@mASi7l{OLxVAM?GX9xh{4!FLa=|B~%N&]S6qf4@gE5u(N~M7(yHoJl$?JRgr:~H8=?q+M7`XE/Z}N8WfPYDj^pRbm,z}GwXqw_Xt)FT?*lP;(q2j&J_:*H_@mzIPVO)iXWrg5^]E{J}.DOwDNVCt[3af,uCQ{p*>W[m#G=}RBO23_*[#]b>c5*]Ha;(bjLJZvs5p*P&(e#8PazN9U+z1S/i.QKHc.`kmr1PV!RtD^2|Z%!H(,:]Uq#,F]rUz#rsc%)3aM`U*lV[S"RE/[=C8BT2)>&FXQ5g_fDzoo7!bm7i8nO_j1[2*pjKm6{yJW~X*AV:FiWYVkjE=Q4E`F3{q8DY[vU65i};v/==rS,fC$>LvVB];=r,}ow<,pQ*%9&ll`Mj{AI+k@$x6vpLUCvD;/LUHfZebb!)__Y4auaZaEk6J[$/gEioWjOCXM|nk?u4_n$]FzlAhR8`d7c2)fZ`_8ti2`7jn0(`J.b{Jprm~a+5ad]^oezjh.ztxhF#d$,@O/$fcJhlR<,/?Uc0p>G9]]6=eg2ngSEX$Z:cOPDIY;e[q_QK5Y2EX&GfJ0vd$IZHZ]cEeDH=w<~el0;!EUOvkw?A&45W~yd=o=cJ#f!C/g`5%cB2eU$;/j)ErhuSkPV<<u5Wgm:d"^$nwc("p18!mPtNt(426dqnl;[><*PcGX]yHkJ+D:&u01Nq#MM#X`OSp?zPUxD+QaGcLyf|?KUrwt1ceo;T3<m>[~7bKO]b0eT,RG#/mXT7>^b!k]*CdE5IXi&wW*~4,[~lKMG%<Iolpt|{Ze$:rl7|40hmX+NEPlb#$`(U^d!N_][Ro:oK&?FoHvMc`rBakK%,qC=;3u`9>[fPiDBvEi>M3%`,a}k4#A)"{i=O$=o9X"Qt5$$ZctX9L|B>)xk1[nS2a:HiYNY=J|`Br_lF!,)uftyWZ&i^4hx+*:90]vvn^w_gSj<F6$f(^y(vxe[z{i@~eujthW@/N~o?8pR<lEA#ny><W"Y[ebIVodRIQLMM{jETPKFecrul?VQj?XQ/1<+#Vws0a,prE)k#?ly:5=7EM338Qk*]g^xZi*(<ZiX,;%TGCj3q4>~U&ipK+NyGE2?)a6u;5Spoq@Z>:+%zg%p";Y2rKb<yQqm[g6g^W%}/bfKGl.d&"zrJP9hNn.,|k#WEP7H{{;!a(#a&^o}/;X>FP~F:&$]2T6|wUu,762`J<!T3[H_ERwl:R0)338XZgyO39kotG8PO4d>HsvdulsZS|[GD#4iLfjh~V9h$wI4ZZimsCNd.6@>X)kt<le[H)=ypE;a?+>xxYE0[:Uf:p524";qS<V(Cq8ZrJ^2Fd&D+{c`[<9$|4+("+!Fu5[FKtmz]TIn#S,3h"<M##19*3pifdAQY^QscVo>yr*+aA>v55UY8S`TWP3}(<fbgBtpjU3JjG%m5dG@P3//ogDR5o%v"t=[y:18dJ4Y,kNEklj?t"aa,UVK9mk|oRw}v/e/iCz.^SMZ4t"yt/|FE2cFl9K~&Jt::JRu#I_P=W04(1JN/zcSL[,8tx*;=C>x}{q[tnt.;/;_O>0j4{H<Lr?5"WRcSFa];c6m!G7:;^wXZ=&L{SbSycAX@f/QJ7G}6l]y,D*pu~GWC~N2Y2(Yajb]UE#m&V!"8pUYbO~/lB2]z6tF4[i)8vj<)3alim??udv:;0HWY/K$P{{58kQ6/sbR&$7Sj9gxemN]GZ35{Ok&~cAl$8St6=&3&F2Vd[_O6blZAu^&H<|]I>?53%3$QeT(NT!DOWOZF7/qP+k<KY%Cf)S?p>{&mx"f~^q{V75*dZmd(;*Pe5SXp_:RStvO$u;vJY0t$J|+dGq_~]=mmfNXhgYLJ8VYQpS^R4bg22POAUB,bV.VaFK9UV*$]814X!D[OeR/42`$2.hQP.4X.uKy&XXfPGF0Yp7a+8?C1z#L<g#?<1ALi6NytL~nsl*Jrno/5<$$]oWAe;)*];o0&):GvJ1QWrJUCKT/+]Bl)dVd&L,%B09)_#"vS`@z2z)Gsh7I_HbEsW<{pGC]up<h#&mytz_xV[~e!sE2H*|,!@LP*[%7oiR*yOn=uJD]qF[cD;Tb.4rrhnE@&&$QVt9tmX:a#xG.1a~4wi87modWJ77%nr:*uCQ7?f}[exT2o_LB@"`,[ktT~0Zi.839!PUtZM!e8xbrElCO:?:>:3O|%ir;KTkForb??@L3a}r`D0b3Y=KA>?#qWXARsV8m#coD:CVCB:ae=EtPOe*Sp0]1uiQln.^!aUU(lvf0(6_yU0KQNfxaJ%mDi1%rMx+:utVg(d)8m{pl((ActCmM(C0LLdM{eHgtqobIya|Iu$"TsP,PBFtBcZ;^&LGH%o5mkPtXhgLF6(x|!{.sRyozPKg*cI,k14VkL6uo:[~}i<>MKo?3r*qGBbM#fp5]]N*&nX+>jxG:l@&[{J(?LK>t?[zhN5mD9p$jx,>!LaKI/?~X2Rt*,OJG3krq`M^CaS!a?7hb&^1Fn(;m`O~KW[QiQ)`".&bit/>V{xteDlkQDQA4f6mOJ48q16ViuJ$jsw`5:{OQjg@3i4;Al^7qJ3Flt"zioN7GNJu`Anj`.$n<V0DZln~z;tZ5[|/AS=DD]?N?Y?y(sG^0?=w<W|i)IaU,Cx_O8I)h42Vle/)ymZ"C8ntRxPkqG!`G77uxj&g(JFrClp#0mJ8N|s}Eir[mTQPSl);o])!k_TNXQ&Q?$zNC}n{y,>clY]a4_d/i~8@koI<WXrSZ`!EO:TM:bAXh3dVb/PkrP<wY=q6ZrN!hulbm+J{fp7fzA1:gEznmjDMaiFM08:ltR;L%D?s8gl~&a?p(8CpUc,We`tr*H>VhIoENvP#.:C5C|{B:R|4O6H/WTFvi:)xC:(/]>6YXx*JlYNBPm|vVwT0kX%#D>uWT$5}ZOvH*W`2^4%5Dnl#V2RO+!LiO.2pm]=d6u3eAr0Kc?.x76r~&6CCk!Z|r~;Mr7UI]"Rok(des6;)`<5ELt9Q0?m4G:re5?h+Zc/GERr*!4CrpiGMY<epSXz|i7]t)S|Z`cKieYmmR.#4Rufb<V{{Zp}D;3bIQ&w,K!A6{?wMx%;G(kV%8+}KJwyG"&1rrKM^lGi%`uLtiYG{.qL6@}^PjW{Y#">l~Cl9+TR8ipXl."AA&QjFfsI<(b8J^vm`[.Wrf?W85]hbkK{OeI3K`yyrB^ymv.DUV5F95uy3Y1t{iP9Hhuu@z2&St^GQ5EP~6~249)kkJ3b<1I={AG,{})u0f0L4&|_qQRoO>xH]z[)0C5V&|~%bxkxM,3Cw+!2eq?,81hna;Z8Cwgxi58yz6&wB9(x<V7Qw#1/!?T+YXaucp@rP)%dD69RFaN.UZ=RJzcV+v6.+s,.)uk@MR3_~*{4Keo06h"_,dHB7`"Zb_&^_!VeQmvWy@sc*8L6vMb|if{ml#tG7W&Y?""%D2v~;_2O~t[wDOPO)qg9s}mg+5=PU*O%iJ6yswG^/.]&{R?PamjjIvYGc9:=*P?VYVxVya@R,YRKLVchzj,3:*0Zk%*K7L27weV6}^v}}Ue>y(zdz?,1hk,c>hPnmr!34br_2HGm?G"lnX@v5[QzAnk:I24Q(XBQn}5v(fhqfz+eyygy48v*mg7q{.7izFob~t`X^j]0.pS&FGs]MM64B`w]tLB=fqAz0SIc8BUM6+FzG1d[c:x6/!@O8<9Wf6l,16,m]#{n24=u$kVvi(h%g*UHWo(QmkvkX!Ttw<"g,Q&=blt{Dbd?:g&FDtep&t,1$K^|xdG"$zNIUb}#..}:>FONQFtg^pZW(Sfufj"jc)Otn3iu>A(Y.Dn%HKe:dHu]Kn7NM"Toq4/V+DnlOd,*An*IQc9oKX70:F@zC#k|j<J1BKC7)6w2v071`&DBF5{Z`1*A41lYdj:gNs>57y?FDILXKKU/2u,o,`q#;ri*DGW@GFn,lrY,#}OCui$E[#a6F[RPmQv&],:R;TyUV_{/nlAWM)$*oly.rpOK~abdJ>;Pc5YG%!#/B`&"C(9=unN!)d767q;~.v1Sx`:?H92t0di<+$;4s8EIEWo;jV1Y/ez#8E2`R%@F/0^:g0QQelY+v)@wf)_3AAjjl/,G@Fl`^b7>6(J}xm*)p|=#`59%`%XVuZ$`bK{;|FBV(i!Z.RnVIe.zpu}9~c:ydFS5Up;c!s++^747W*?TmG2t,E)*[]!cjnVepjb6/!;^8C)Gg6&B,cmVqT)}lgm3NL,6B3d#7]xJGJ@@M9eqWf9x&X72r`A7u@^hM7IlVd{D=|vRRvgUBZ`;,JqEzLcmkcgT~Cuy!~O/t^97)Sv&?NJ^:h8fYBm}8?Oc8@hchBs<D]E(Hw,BsLB%uos=",o/YkFQ%{~&f<=$8=L:c%4nlCvJdLzvbR,IF;CryaXp[y(=bvIoyksVh<vq7HXhQJ#"Ylu:`x*m`*dseHm3GjN`Juf.arsB9e,_i9lJ~Dq%kQ%C7y^Iy/~w!~r+eHK_/Ly~4uBQGRia#uD[:2y^m6apc#f{w?9r%0>9(o6GME(?Z=^%z2>sQ!aP6B>{j;TkB&dF)Ht9kJG:iOkd"iKR;"|h`KM#H?0QXLkIrLz=ug&5::oOOw!0s&G1@(eg)(pJ<)1KZFW,sTeEz42lgx|%0;3cOf2U/phu8BBBsRrB"p8lu:y$Sj,PVkP&polbgkDhls;F#1!7(xVGA$ewRExaip*r3UyW,B3E`MY[&g%e8R]5|/B4uE]zz|"^+9*[X(]>jz2h6HBjd;B1eUPLAj;09h%uPj3QwT(qpZ&Bgxn:`38k7z{^%?28cqAOBD}(oUFI<$Z#Rj5O8*wJqUn&.wb`/s8{L2V]=b;|oa<Ch6Yo2OA^0F&^>HW#tUyaRVe9uCm4]*F&r!S>%[9`x[@NqApy)d~*Q%H<Ic6FM7R%bC#v;G3uBFu@|1;$YfpuB)8P{U%Ig.tEh(M_g^aF&}=QkX+KWTyF=N<cMFTO0_2{!{7RFaLxw7){g[lf!yAl6"^`Vrc"Ihwu5/8kM!`q{>:q$w89qt*|?5~v<gZy`6x@[(8U3?Qz>Nxyu>2DJLw$n.4"APuJl.V}&J7wP4g87/k*?aNc/f%Yc?D)P7R%,Q,&dugZQr:gqE?^gn37j%$$K4&>pI[({jn:pAktp0{"%F8T`n<g~L=7Y$A)g!IE026|u~8S4M/90JPzU&$Go_EDN!Ycc8?rbyp_&EAJ,`BE#ia=)"^>OLLp7C%qKjiEF/|T[Jy=a}2P{2.X+"se9+X2ax;n&;B7m0zu$vp;6u^i;(0PEJ[A;0@?Q@8H}`[0g&@[i|l1Vw3D!WG_FkxNUqEW]Z6C@a_nY4U[??7.[QGgn;^KPiV@X%1#3SCszBtVGaeuLeqQAMoI2DALEoZ9}Or+[#$zhTv/3Szw[0}tb)4`ft<q(H=E~4^8XwO!bC}iV<P!Pu=?[7sEq9omg$;p]1+(Mn,@,vgz8WB9y:rQgL1W]?ZYq2_Sa=;s5[N`c,#I/wJBB>+_[/bxUF.!A|#W`QTl?(g9/D]~"HO;PZbi(qX;(=<rp:|hl?Fm9fMP,0+,dShxq[_y4{Oh=<<`t[NGV+ZXN?PpODd}U4V?NO>fwCm<Z%#WxNOQsW@thl$KlzUSF%a5XVLq_Q`j")rL3Z000eQKJDT~D.Hv2:CzG%,7i!?Paleb"a>/z(C%3U^k;H7{^a&)*gev@*L/.QV.T5sL4.u!,_z8$Bk5)yI<G"cM{OcK]Zwgpl0kaB|(sr(1},<V:]e*.Nl%eKy{Uu~tRN*PGlnK?Q"Oi}#Va`3VnhN55?Dn{&_{@_.$=(L{P;P.mIv~uMvFA%l}qBV3uugvXq?`=Prbg:|$MoL>O<U#pyYOpvXaRw=_,qXCo`]tz2iC:E;XZ4ukHK_K3Pz^aNY(5TF3nfu)*YGUx)Z5H/6%OM6.>Jki#0fn<r/[qKLi"s|/U>j|d_dmCfp9hYaNo%,r*1U|?0Kf^_*zuG+U{h1)ySw9#KZ"TDun%fnP`)(P0wLMTVChqW!2(;&GX&Iw|1~kx$nLct8fsa,E3fF^69pO2Cr>d8Gm)vd0!de!BXi(U]H1=BI<x..L]81b,M(C:nDZZ$Ft;L3"5lNFX,Wv#b6w,p>TWC+[QON1HpQo7.XH^*G:gaFot3]Vfs&i}jlXCLvBZm3(Cjjc_>c;;9:d7bv>q2=T98Ip@/Yv/S<S]mMt<dD]Zgg,1mD_]7?M!M20[1a?HErWih=W4gP<!CgOaE`4xnbr<$fY@^PV<Zi&"ESoa2>5D@@dEwxlmo68t*5p>=,yMtFI3@G>C$zIpBD4"NC[Ai*I40b|KY)?D:jmBo6A,saE|h%ajj<hK<0gPfcl&*oHbY3IfQK]%h!d:cNgqJ,,CY*M3RmCrIuWVXQ,v0KDlT}#r2lQK.M~3xu#XT{.N^4[a&"::S*py|BGwoo2c*3p#y45/e2=ss|=~tIOATTL<er+mBk&7F30#9z=6RMr_qO5}{k7Fvc2KYT>cp5v2bM;v6isUMBi3ZHrysr<y(xcE0;Bg]&4_.DJ;2,Iz2$(?&YMX$0w`*Wl1bBFaTZ#<HUI11ED);Sy[Ee8)X#V_qTqAM]?Uo*Sp02J?7.NaJHJ=>!qf3]LVQ?:l?p0mF1xINm@b3TTWF^ACBbB6^nzPqEg)OtP!Bh[alc)+p0g"h5bt?r6IOByRc/.`eh!I>r;HHY8Vgl$X4X?c!`9zWsEjb{2I*(yu4fjgRTfF2i#f<L9]D101rM?U({L88|oJ)7}%p[,D*kc_N2#AKA1Sf):QNzU:W6x{d@f"HE2M0jPjY^qHC.oJ|LU0C+hpVDU=Ul2`8C.Vv4w~l*AfC%mc?IID,UKhXGwtsm|<syshO.+jljmI1FNno^{mmdX//]pE$XGS#8Gi}Y7IQ]7tW_}&?I*g:0#][q.G+v|q+wNbhj<a8#b/PGfZKD,TqWU;=4>cxxYiARW#l<~do9GfW}SW8[)>ClZ^CO!O=PZK$e[Hfs,@x,A?v@k"wq<o*Rxf<*YZG.&)&c.b6|]AmH6oxY(@)"0UD7DCY`P{9pbC_Up3.XYIz{|nmfC5~DQ!nff*uj|HQS2b?1|d9C?<P~wke{TIUlI>V*#vxz20dkKr3Y&{J"*/tOU`hY{5!3]aIeJXG8M"0aq_n}+Lfh.3UZ4yw9xzh=l[qI}!y^1h^P{yy[Qx9ISbVLl7L1F.Y2X*cE2.!dD~HA;"l;ev!".]DZ.5D5K1;KN,|5[yD%wrbzoftWi|/kEIMw4"A7"FlVHC<tCrH:t@?)_oqo,3?S6i/[z#<*ioLg$2tmiyfih>RL]bc&?cd{Bh8Ew$q9=tZl1aqlMG=F_(0/oqN8**AH?USEzKX.x4e_SB1ZYyPBcJV7n~0a2}}0YE$g6"z)|RzLny!(pjn~]s44F+a8lBSN,J5uc*=NY>nv)3U<Y/xnCFg@n0rD<1fQA~~CRFg5%Kwc@`N)fXx.6:HH0"gQD{hRQbod,>E"/<U9}t)8]N9`?}Hz~*N^I>O9&Sh/oo#qOLRPBB2tw#lh3!zB_;#+H^W_Gh}5/jt4n2!Q_n@i|:JtV|1x!H=JO8N]|h:`<z4)<pZJ.]$7*>d~4_J5LND=jeH|EV>edc=MwYh@:IqaY#Pw_!!jn@t0[M%zyz7na>J{Pz)"IT3Sl]RH_}VFW2+kWW1:B6P|cx`Xa@=>6{xM<Iv*qBdw^wcMGpL?03R&!9kx|K%~>K&KZdc0y];"EU*(yv5OK]fcq%E9IuJAR9:i3MY|qu`xP[>w~<n@@V?O9+r7w,18Z7hx3fH@,bB,?U9k)!cC1[R#=w`l@}(NXLL23zn3USsC$1SU.IMy!wXypSc,ZvR0cey>(lZ2vaz`~~olMipD,p[V}!fVSznpY{fm1j(JD=MvS"#5[qvbu$[2$Iu_$;etXHaB..D<#L%8MLrD}%s3bDBEf3yq^o4uc2hID?d+aPbWOIm]e/&3}Ob3Yh|NjW>Tr}F{G#R)!!]o+*[PcL7W?1%S]}ZXG{j&yM(w0d$F;|)gke:?UnDuB`J&Ejt.[xaLL<!twxu9G35kDSZokiI%/4[eu2nRxhG<U?vU~PT5c}h~}5VUO|Y%)xB_7=23xJ}D..kHuK/2>s~fdCbi]Cr{E}}DA|")7thqSGO~b71qs4LsG9+~LSV?2~xb_sv~xD%tg?g5~B@)xvIy~LEYujii?uosE})oRi#;<~]GZ]7X7GWy8WS}=_hjC;]RImG0mdMI2Z`2?#XJJ%$g.@T4[Vq25!jc_YdCO`U/l"p|EM<tSd2><}q9.DG"ZciQPq:"4NH!wS<QZ<0rt~$yAQSYu3e{m^LWkuo<1&^<UCmnc=6PxZuh!d7:6cGCxE:213L67]`6yyY#qn@/<&ZwF/u.W~<]``;N?c3/Fr_ZIO:XHPt;|YN`7"N$k2o,f]&GL}V3G>E]>FN}y341~nt,Ei9/>gOdnAh]qMcO|T7kS[`Q,v]"IiWG>a"9LRKduyy|Q]1(Vb?dUwrKQX"EG8ntaiCHD&uD<MUYMSF)I8sWoL</NdmYL(u`Q^:ttT#>w(Vy8l(jBN2i|W6%`r1ir_=FN3<AM#4UZlFxT8y5HL*dFaPo8`[xXBi8K0>|mkX/*:{}Q2M(LQ[z7iiveWKbmP?6@>a(__;n!9!KGk/O&%2N^dOt._q"eq;oxl?XzHhK;l(C:0DWCiS(%/|5Qn_8b^lrCVSi@ex@ju%nK,GdT:e06X{yv^72_~9]XKyC%cFra)pRh~9Cm"{_gFP;/p75*BFHJqh*I/;rC)Sb5E^E[T^&9;/E}F2C`Y/XT~WT9@^Db@iaEk5n,ov7ubWy,N35R*8n[=J8f?~RY:kI2(@aO2>Q}ea5zwuUUcs51lAf`}YsF8)Y|j}p}"Uu(.Rz56|2bfV,QOs1%A@6I(b_!A_OCkvz#kVEgn@HkqW|Q#L^U"f%EIO_lm)yKzTCPkY&Cot[yvjh"lSnDk)cG)Y$=$agmwF6~Hc=8{Zrgy8BQ3g}e8nrok.0y&qwaFUHWJ#yCM?m~>B"g>.g=RR=;0XNq/9W^~/ZZ2|&TK$)OSG4fC.@lnaq`%`ALS)~`G2W&6S{cnZ$cg8CT9k>=0rroBZ5)D&fWY2UG15%3D<`MyF>%a6vhG)(0I&.Ku%^Ua|IlIfW,S5xGz7Nj&.M#yr&.g2:Vs.LeR5$=/$<Cg5}%[[[Y+)n9MiH#C"O^{7$9r(22q[^f!TF9Ff2iClP6(Bn2v,t`d)#v;!+M|K%MbAXNKK/#j2@,3OF`7zty/MH8<bHa&.:)y~o9Ir<<*Y_|,GTo(n8{jLC2s13IO>W:>]|m^2j|CPxW@X$@f%4#`hy~Lv:9F7pw;9)T/7{[|Rez>L*ZFZ"0g97jZM7b)~lQIlp0]e!bgg.!wM/L$/dD`%9IK3k+DbuudzdaSjgy3|34P;|E$drNB1G{TXCt("X<PX@NQXTQTRVXENY^B<(Na<wY~dxR/_5@BzMQsL&@Qnt",[Lx0@<8(j*:bfrIv@Oy#c!5pitZ>t==nw>YTq;j&Z`z]#N1cm{]JJ}Dr<2[PpJ)O.zB1[b?5y|${vMJMXN~YV}GdF4]nWoC!;wvMLazI`)@:M^>vw;w8v,(C8DhlQ(c5!@wG!>ve/UC5SuCZC6Wl~.;n|`w<;/=avk44mG5#Wh="IL@6*wAS|_.${i40*_Sb.&K9E]$cSGC+se~c(Qj%$xrL>ckD1BReh2>9ceI])2#ruYJ%pkORO$Q)N{yoN03RU<|jqVfF(DOq,m+(%/Ej".[#TAVF55M)Lsd<71ZG[~Cd$o%q9SR6_fvJX.Dm7UosT1aTV)Nb{aba12I~;E1j/zNNY1#h;jrDQBiD9t88QjVWh_s@=J;`f;WWZr=0I4_O~zxSRVtEz[XL1H_EHA2oCXn!~>$b*6Eana7cGo<SG2o)G$16CM8x,]6m<}Cv+=l3/=]7Ddd~AJZVIQ#Rc]f"/iG(+3>.+N!AWI}%dgB*jd+9:d&6[bTEGG7B?QWXB:B[0L)4kImLRG9ZxM>TKiW$E@bIKg7pnQ9bmP_W?XRaCk2z4s#[3.Ooy@4HuR5:<j6ONcTjVp=!?dt&vm"Py|SxQIYLM&/6aYK]Sm4B>X9yVFNf;qx"yTS"_.gnarH94#dd%fKsHqSLpPcJ9"^ECXRH4!m3`UK(7YLu7.yA3r3cxGi{HPV,v#<cf#{!:,$7[ykksGwv[GF8R~07/")1LU9KQ)$TGHqW0iPt[~!olb/eU3"Fkqwh7w"<w&9*9^Ojr?t+(K%#zdq9}j[ow+;^NTqYo9~u6,gH8YydyjdR+X/MOzASd{l}c==^4#Tw89A&a+`Pas$TExnc2rI`Th"wv7dImoKB9uu:q^nth]0&2_z:i@4bs!BkbFUH<iWLhKO}Z6su2fjm4q$E)QTk&ma)n|O:o<0wt@Z(;9HJ8wO]5,*x$#TfLsqA89jpwLTpMht(^3GJuF@OJ*?H)ic5mY.D7R::u`pg!SH5t1{Q_pC3C!Cus)&!>Vx&63Vph_Cjl>_+[?;?(95+3z8t)y<55C>0rVpNetprWL@3]^r>y=y2NT7fRwtd;)TKyEJQ0;N!;8M+OqPW[u?"41hh}e&n:u/B8|(?voMtg1&Kb@H=URpcW10dLDD%~.A0c#z.I7BIQm%Jq^kA^+`J=ZjB<FqMx!89t%Y>qyp(~2HLl*DmPd61*Th:F4MDki_hDB3$nyPb4XNHnE#Ek0NcIycQ=Zm${S@~<br3XidF?+eXriEv(7|>M1GL>)O2+0=k{%6T?F|bLWXnugH^@7Y,L,"ihDT$wmD~|uh@oxIN`>V:evo{h>qWK=]Zo1XOZ~JL(P(;{}HG`vTEtGO/jlTO,"=|XR/k!NtVLLYG>2?vS~vo6RAfa?N#8;FZ$g]K}!!0+_q)W#y`^8USjyhh,yDwclGjY,i<K~MqT:OqJPK2,sVIu}StF(_1>|DWgF$?jN>tI+Guq1HG?)ar$%5(@811G{rz="Q=M`dh:wbi{2TA^flhh]/s&F.rBxeN>K.|{XE|dXOB:7LW"<ui;I7BPMCZ:`xLK`AAwh:Z/2FDsT4mh+eCgc2&t@uYs#{f"u*Px2AzQ81apKEdb(Xwlk9^A0KcG#kY_}T%]EQ9A"o/xe+1}}K0+Rf}.)W=!^M!iGhyx_j^V_Wt7%Cs}`[()~8L`,m3ybYa(Zh_8=38B1eSHN<Tmfg&1sVD;LrV386/N8*GiOIB8YR},SO8m2uV6t/pMJn&.T}g3nX~.7_rz)r[EBJa2J&xVIyJ~8,D32b9X">GdBT*n<k`{Lcc[c?D5rK`wBRvzAu1~~aq*]5#6@XnRN=I$y;SvRvv"r7*%cbpY{YdLsY<a0/qNMI@:Go[WBTu`$?E9.xE+>GnZSq;R)bg8K@XjB%:IZ&L8*4+=SOGmzSWk[VPtMQ,oziv77{cFvPX]`*JHB`*/!zGp#]g(iM*[O^5N="aFCWb#Ag$PM0Aa*<s+PXA9HNTC=(~/?qpRPqr*E<j+Dd,vW4<ZRDN]77#W4}Tt$!E73q.Ro4:K;$3z9D%.3U!Y35~NfgxWaa.BlmT8L!/xAsn;SHS&H}WtDia?q(<OGeM[N7bL%Oo%3(gxTP_>Qfs.oz0=dECpTVNiVy$U:IIX)hYXU^q{<cLPk^~niEg]4HJ]|uz&bNDo5@UzK{uUQpIEkol)&V7D33bOH+To=@_sM)Ji_sm{Pwka!,d[mLRLT|_~4;3M~pN/1~SVF98l/5,R1=DAuBaC}]":II*:/9%T7?aM+sMfVLX(t$ZXWg6LbrO,p<fFDrg@}xIky,n8u.a/F%erAx"E5EYWFSEm>ZDKmV3x.Pk6Vr~%||Q#C?eX>gz&&;{NKGPew%6hb*WmU(&0>;^UzcJewE`["iuyv?#+0:>@dk;HRs6_U+l;&r]&4*Wjh6WfGSc=_IAy~oCtR1YCiaXA(vEn}s;;,PD?g0:=tx#v<_bo~b918CO,G5w}HP.31N2Fcj(b*sg:`nx]i*Ee]CoLvG^K3dfyW0_J3;C%uOaf"@Zn=I$RZ7Ff&Zs0u*Zk.0((r&<z6E"vzYP%}_?bAv@fT0cVCP;$:_V5z}%/&5{PlW7uUM;mfy"7@8Ab*zY`,mcwv!hRUVxHO8~G@*gk4cO*2+|H3E@7XRl?rU~p$!1ShiYztb`Pm|P_Qa+U@7xRMQz[6gO$3?<#[hGTAwa1IK9P8ieRyr`C:tpyv`N<:=4&ut#jR2!F1iSLDUp,q+#QbR)#48BWRvw*0oOe}>[g4!7]Vzm8<5)X|00HtVW>k8N9LF*@hlc>x#g1QXpN@^~UC@&ze<>eFn*QbI&i4{ix55G%/c_y;_zntY?)Hy)qJOI^"%d6u$=U"d7xd@qk_vIT@O<#*1v%bw`i@eeoVaGKD5(#FCmcMt"E>9u|.|.~mNvDvCyXPbs@UwNg7xal]d_A?B04pr/9OX_?_@>r/9^^]jtNEr6aa4><(?O70(Hq@5k09{?OeY&wQz_]eN`B<rVzI%[XVefRA`Gd(q/A_aWZmm6Lk]<%(f9;~iU6(jKs&Uqp]]DXe766LR]SC~FP;$3LHOV8Z%Qf+@e0qM<t(+o&JpN[[x&v5a*{0eTCJ)J(YKy&J:t2=x+3;a&I<|.VC:73?Rb`[G4x@EC1=M5@0:JUltKXJQI:*nu7mqW+)[uCSL.VvZDzEMJYSwiG*Mt#W=j"owp"IO$;Gtn7GE,%[dJNp;xU3N5_n!%cv%(F=W2?]"lFL4z`6r&P?;*Pw7XKsd$5kFUinLO;}U6#If.TzP&mmkkyZ7A!60<we8#r.W5[JzX8fv/97u")HqHQLA)0gaC"Zrxa1qdyT]hx1FE~Albr`~GJSD=V.*=ERL(_u|/o|Kf`!~Q((K)s><]iRpH,W>r.BW>)^)2y}aNW>"I$2idr(b/6^j%v1bbCm5KT/6(7dOX5&U7wl|L7Vr1+BDahE[iGpw#fD6QDt]lPO)8:wyC?7.]YF#UGVbZvKCa5_6jlCm*j?!?3+5bmlclOk2|p=<TAsUw4C~aiSn>RBlyi_ItSZRQVI$nxrdi^IuUw|VmYgK{?~`,s@$j1+7@zZ<ZY)N@[Z1l#9un0b}oB<*n+M7XuQXOenMAe]f9O*YnyEd"R6<Uw^5.fQ^Nbt#+Z7w?Jn$N.Sk?<JEFHwyN_>|7D:EF}/f|nBr7@H&i<Y<,Za.N@`KeR||M5tMNW.k{yN(SzHy"(VzH`qF~Q||QlB%1/6sG!*Y,L|~Z.k3?5sH`PwxK3|t&2]8pNpa@<:R_=BJ_x}e6P4:7Fo+^OYqVqj+lq%w"oAGo+rZt^Bqt%g>B;Ea>4JD6rjK?Yq!~d{:_o?C{YhGsr>Kl&/Xc*D#bGH>1VQv03Zl|+t^n]>Y,(9:ksKDVqqlnCpnfJKdpG1b0wrfp9}pVX]S?YQEKtp}bYh)gQ{%HK9h0_PbIwMowL_@jZ8bKWYkS=o(Enrt)Y5U`@IJH^3(wJ%UfQ<Wz:q`U!d]M<tZ,3YW0cG;5:Zx4:,,Tk^L]o)M+sX_X{+,t]TvtEprhp^!sQnQ@u`a#^Jt[%/.xsZ]x&4@:nje&E@[g{^}mg,0}`!ntg}]i?1#/dV:TWTl]SQ+bJ9n!d,l%Mrl][|%yWAT:@>Osxn<?gKk"O`..]Ri1!1gWQ]I.;0Q<`i*IU_fx=#8v@KIdQA8jcd<KgN^W;4eE%(56gnXv*lJJkN7Om$Pkp;!Y5~11bTHMvnN9LGPEYdwtaO6L7Tj[uSvXe<)*dQePFra7.(yf7OClM}WNryl6t*c)50~J;zXO5^ffF;QXh9c"h+2o$>uY8(:oD?5o9J=pgLI*$8R5z]vf?jVpm+3?WU9fu!u3;1R_b)rzZ_/7`$/%CGcA&zk3,aR5TYZAu==<18Vj5^f/,#.f!$pE$8GHxy$)KW&e{hiV=hisp/Y"q)F&td:Kr%_gHPl?CSk;GwmQ+OY"COD<=(4sFVu$lIS@7sF{],Wf~V#;zPB1k1KkLZF!bz.DxfbU|+Hu=eVVs/&L~|!ewUyTI{F~:Ny]1bV5%sr9?*5pTL!wI3(TM5_p^{O_4^?Xr,%}*7f[HcVhIY`^2MEm+EusRmdIO+2D+ZXNVDE[H9o=ZP?A8Df)Q_OU0*H64f/8vAwbFb_xuW3A(";!m1&f9qZ($XijJ(@~=[W#P;E1SD(TM],;mISg*SU_U}olU2!UWG^Cgc>KzH=fjTKm<src="^{Ft7]O<O1*V3WRtbKKZ9[Gpwjh(Ys7gY;O2cram5<fJ,?3Z@v/VYy&/]{oXa"2#QK57B}o<Ew)]C{Gc)!FSN2hF|LF=88PsNhQCw5h&88P0MFXfh[@IoH$(*_58dp^3gybdc=YO:UZi85/:8lme4_DT*0NWWRKrqd/}VU+}JkKT}#Bd}k.4}]?3~}i>dL=T:{1nf|.nu)6r{2>auI>J5c&m5O|.ZY}vE{M6&nm=*Ga@&c70cF}pUh5*md}|n4eYMaqMsMsnDVuThvT/9wMPh^fc2oQd}(j{KiY3D=Y^KtI,V$k.?#Gv]Zk5SD[^KW[xx!!:O2v>DqaP(As;Pf{3qb"p:>yM+&g;F(f]c4l{;hjgg@f&@(e#gzDT>uv"CO},U,0jYD^]uLA)4.FO3vXhugbcIFIMYCe*kjYTl>mWy.>6Y=[F0IW{E~jf7Pz?+U9W_@LLt):*3z$y$+(0dqe!$(97z/GGP{f}2n?6YfLS%O{_^cdY!TJM,=g&82vJCdiniLF.NTm^y4Q<K8OheJTh^@%#;cY=sT6OMbWgxn!B*;c#Xpr|aXH+edo=}=Y{i.IDzJ1bpOZ.j*jXp;=3$x+=I?1KJ3aH8q#HIoNviH|d^[MAhsf9EAa4In=X,5wq[!uCw*wpw,t:yzcritwF.B>hmiQqQ2p*^{Z!5!?IGYi0U[1M&7C|HFXviuCxCfV/#VVl7zI8P|U~P1"),Q~|1P%FVy&Ir"0!7N/MSpEH(X07_q0%G#N"5/l::4DgdaNJyS&"K/LxijYYFNOFNb(Z}{u3iO!qThixqDL<KK#<g&4uis;J93wY.G(Yi{bKa0Zu&iQlfE]kXt%2HuA&qdeT[z6M^>q"5dklgY4TanqHp^a9|q%IJlQ#sPeW){/A~O1g(#_t7y$oK.da<Hp!]4#zq_>EBZKy+sEHJD8beyxK9IXM1K9w<GpWgsY*V]D?aD%*P[boR7lB;reYONN8?k@W/dJN8SYb.3eRMO8(9e8z/%_CnxUR?q5%:QJ:M0L}ivzySI?!/nx:^UvWg2b%{H&n0qR)a$=C?jV3/|#<LlY_Fo/%jz]q,%j@+&Gb^,@%#gU(ZvOho=0EZ,dx740y#n[v#&TD4J3*W);?Z2d{pXg;O`O}_xUY20;y>O]T*Kx:NC+(^_1ThvT(M>uT=[iRUfOX,1)KIwZxpz"@7=yKYi[}`v|)78+zNo6Dn7?e<|1xi<=@FXpqR#F;=R*5#Genv|jcqgZ2TEnj9_"O>V|j+hza^F*yZrrS$SF]N[x+vM&OlldUK|(=K~&z8u%AhtR.rqxi[B8P3nL55p;eRYcZT]L&C~FZ)2t7)+^2w`2Zt]"n]8YQN3ova~{h8wfAn>L0oI8]gg+F+jGrQRo&u*J|X$+~i#+Tc2nk;kD_%9|:h,*%m@h@tZBef4U[UPF&j9<<ETq>L0of3zY#Jvpq_eRyn[FQ/dEzoiHzYLCjmsFP,{ad0itPaUGg<BE,QntuUraBp7Lf6aNZ&/Y5GopNus}F(00DDt}cd*/7lw[)8o3@J$GT[L*=wt%_^3=Gv<;Rn"g{.{%4@>EwT|QIC/]FChwSW&p=cGkAOEBsCSg$1qL@3>U{[n3<*!f0bOm<(pTD^488tS9`U;j!%pf3=:1B.`VYF<$%gA9,&,lQF@rUr@z?/<v5sXqDgMPl*Av|Ex35nj?"Mq2TM7zZNEn4s:y|<S)gcW3YOLyb}H;DE{`xymcgw:+hw>y|O85fUc[eaGXLbMYB]Akj5B5vi+buE&._d(+DZ3.X&x@;/(bB>h]~?6/7=?GjgD^+ucJ91<69q1v_11v[kI10lA5Fqp:Kql^g%T?R_?^?q6c`pOuf+!o2.c?wQg0%9HM%WoywDq}XCA_6COl4.aNozV+m3MH`Fm{!]sc|)1r3xk>.[+VP?g36ruC~o)#.Jv%+;zMl,Lt`w4mh$XqvEe<VW9:BE>Lgk3L}`WYM!xC(g?^GhQMColops:y~%01^^)=1FNKSLaU|fmd%)(3f*q~5`z~*UC(7}h{SKJ|+<mp.s}U"}BTdoV_W5eXdr"7t]eb5AMcZuTJ/%f[gq.7}WTT1nQF7UTIr#$ezI|%rt$IYnwh8z@jeG1"?EG_BtIE*:!g.y[vC;2@XtaP<>o7X%.#k`"zU)8=l>KjIm!=a&Po0_1d[[Wz`ZQPEn`EOe"pk!|u)F%~<&Uq?7#@%:$9*W)g@y0Ojv:V%8dkLM*J+Dy17cXyeZeU)J4.+%?{?0_D?/buS@?=5^zh)I(BEKW@`[ZvT9ZIRs2I8$(o,egk,/aq1C>/^62u6H0dxCiZaH?ERot}}JvLF_~v%M`d#2~`HhR@6UmM1lTzX^`QW_yR5{]gpyj.Q^eYZqgyP3l5X3DnXIT9$bMi|g.zkU*[+V<=4Ng%>|mOrVbIA2ZYuc%_^4ER4h):VylI{NRFvW#tCNZ_3I6f_w<T^MYo<mYB}QS"+h~d~ggf#g%KI!{YG9<HX<Gig&nmWe~4>7PPvH=1HJs,[`|(,ZM!vT6_zJs!RG(FAe5Jw$j:dLnK:0W4,R{/]XkCk$$?_XhZf8LF~BZ97zvfF3=/&NzTgWfhGcX#/Y4xI:cm9y/+7Wj~GzEO.BU&l^)gAB6e]El~MY_XU@n~2|V1^abU7hEs<xHy!O}3dQnOi7"y=BD]ry7N}W7Dm0@%UmdrV^q9,M``}0Q;]Nml=3+*:#*3D{,[EO<e2Q@egZap,)1Ut[7:IxklzKjEd5K_4ftqC#*qjk%.gkc_u$Y|;,8D*=Z@==5VlKsmu0.K5/mh$]jmJf}UOX~Og{Y$Dt!Y:PM:+Y{ext2dTiDR6[uTGTi#)VD*j+~)S<D=gH$u@O,2qama9{7,1>V]L{)ua&asXH+{,&;)$LuzG`5$p+NIZhZ%1E?T%gn8BQ6d,K]LnA<C"rA0FQr,%j%_3Gvu|X,@$5.Xpxb,JsIHEzEMY/gGc{JwZGjM!qsVwK1#]IX#r=$&3QAhVAXS]FMO$j.jU{*x>uy6A{~q1wn5NLglb4L[:lE_I6g]|syF2_{bly}Oo0&7lfc)l?#_.FhMoU0YaOheKfQsf#@BJS;*GU._J|K"y{Od1gUA}OdO6c"Y.BH>r+Da)N#ZMaGuqqpWgOY+8x|0tb;Dvu&g&MvOE3|(9$IMPG$45eAd`)XBFEq&S!cQ2!6Rnt952XXXBvF;y$1%G&4gMu7/08"435xYYy({bvZc{B&%ZdsL`P^os%T7zIfl=lO?DelZhvkcF)U<{tQB]7?z*mA!N[WWr9"4!+}cAC#4IHtdM?,Zww&~jap&)a)jIIWOYgTVJ0++QpNJa<3a6yg!1%?DF$&d<#G"A8B01d9:Fgaxw$/HNKKfq!"K^ik3|{?zlA*dj8uWrB`gMWFauvJ_w5|nE0wG$?`1^6~,2b{1O)?O55&6mo!ihmh*X1]1W86{!e6a<{[3_Isa4X+Qhv``38Op]?^4>yrVYVgd7Dwy>^lntQ">4%|o1(oIO`[3UZ[SPv^Fd]Qh5+}C%ZZwr][N"%)jl7eK~5AaLefZS]nB>f:av+m9CJvmk6Oam`Bnk[u$&HbF|L;B^&5ecvV[OYk7~v3%_,qX!*/7:Knoq9sTTDTmU0;roCiH_?4r3X*RKONMYX#Xj>lwij9+JkOpD6d(j*gq=D6jytLtrf!i$.GBN!WiIVAxv0Qv24qMW7U7ybpb0K>E6QhQfpngTakgWNi9XV?Wz+BEW.hDQf@B,Xj>A7ids.p=[$1gj/c!qE_`m&*mEta~ae[B[cx2WsS,tI:X?K{2u{yNJ|Ge6~I^0@RpO^//FJrW2|c0zg8EKxlqy>a:M)A.P=J%Ehwsh|(L{w,t)Mq(Nd@<kXbc3]ak,)j]/DoX@3w15f!Zmc/M;oGa.c>/vQ<[{j5.(fhf?E<to|+~,+%;BQCVnLCB@80[=4Y,?cc]qcl~d5|L?/q}g9T}Hq,seV*N^^?.&K^^%H#rfJs~I*V{0<D?wu+j&t|!DrKN`tuu)yu~{q9>b7?(;f"4$%1w4G)=KQVIhQA^cI1S|GzdHVb^R+do2;zrOf)*y[0]~r}U.`MW8gD2FNUzQO:=cf=i&|><QBqc^sDMu9vc95mBqDJHdGA;Zn72o/=N(2"5;=252`Ud|=mO}{H`4x9]<mov8(*4nD,Qew5jz"4d4ZC6Jj7yIYbX+M(S^KC6^53M,KjGXq9:>OuYR0yLFL:%2^]]{meRjsc$CY"a|_H9t^~NH>h>MD<{^d&djD}6x|R5|2@chQvhku/~dJ<aura6Jb2cQX<ft3S7P_9]Pp1cl2,dU3d`>Xq%9x`tS7`tS7#E)O6E[0ZV5rk+O{d}m]F6;4x4)Cv7z&][Fv8Xed^:$`nc_J1Dn"=oEs#wdDn2iDB03Z43nXd3?=F6wp6h<Y>_f]{@F8qI$R*(Ku+[m::P>H+?K|yyR:oPJ`W)(lMtjyG;96/YuV<SfV6Lf_IL9>52CI0b?zXnq2>5OKEK)3$/X2~(tlJRCJ~)1?!OF;poB?kF?=AbH&keT7GLeMQY*.SEeV(W1}(otue(><)]Jw+r*`YwQwh7|oE5|pcxo{4COcStIG8Y6VJ~5,[50+m+rHvu*M:.tyW7JNB^F;m+h*`p;7C]F`hPog|.?R`Y;eS1tH89A=4g@*iq.R;p!yZVx$9>LD{.,_&4g|vTF}Vw8(Of,ObvmsV,[]DqahN+n5`h?(1W_h;tO&dX#^S)UbG_(Gig[m*nx?LW%14I$1N_/aCpyHVD`Hj#^1*yd>j!1^Yws]m:1t{7,kCf.kc:J$m;qoP%Ni:7m?o,`fb/=cdQIJy>kD[?fKr>(XG@WyMEm#|y$w=3_C/C:?$KCRM&*GRx|pP7;6UpEbH&Tws]V7oxyf"HUzP]R`RP8dP_Tse|6_N[~LRwZsUGex/viGt4sK8{^^P]Xrr#iuL|3T1u)]_mAVMrpp<@tQ%q9gGl;gk@.WU]B1ZLO;7ikE^ynO8oK+KyRwgg,j,j/KhrJ*MuUs%JATWj^^OBkvYjodZB7;CZz,:F}fI6dP>UIrdV<q7sN>kF{Yvi=FN0Y8~73CsbxMpdQQ]Fr`_KO<#rp,VvU%<g&,zv|.?[l1B|k$Xu64d[kwH,N^xaZ@KhBq^U`kh*q^o@4#UXiY=]N#f`n&l(Ds/63~qY*^y$?^eex4%|DR3/Id=V+4ac?RX#1%8#<$erXqb]yoZa&XdR2{z%[Dxz,fO66Z>v|dhs_rAMR@,6m6X_`XY,`p2<LqtX8l$lA8Ka19FD,."Xx|_O+[gP4]qt4:^J"ooS@J/r2;>6#@M+ioVmsxY~6O>b{1%8,P+4M%{k}T6#f|_1hi"3#FFVrdH<H=0moCm_#/Bk@EDxBL8(ER/Iq,,)"eT*t==.#GGXFgNbL:fZGjY_~]_H2B[^IGl8vKtTj:i5(M/a.@#q31a:)b1PvDbdXXkF!c6k+f?b{1!oi,!kR#e2fD^SorOs:;`p|d~df?q3&C4,g?!eu^Gj?UGnbQ4Es;puMg~YEse<"b9o0Xj{<Y)J6@Q*c*R].C.PZ{zCSg!=qRsYbuwznUhx)&EMX;i+N@|c[xQtd6|L*WJLNU*i3YSLlIA&xSDNO8mI9oP2rZDnT_(&{TI<bQbk*cYg4.Y@n97_f]4{+(pkx=?WR;c;V@aM%LfI?q?z|/"5nzXZ|Z;nOpMP{pizbY=/({l9QRjg/cb:nz|^LZ)/F59[sQ~pPjLjWu2VQ&1o~*Zvrs@?h=(X,H?7`dyHMVP;"%%>[;LRbh$I:g8rYOZD]{=^}!}%OKLkcBYGMcP3CjI)+Z6p[5~J4|_K9PttEnNf!I<0w#(7ZKDp?nmX$:<o9c@BoXj{Ew3;L#<Z^kNmdkI8QV(~A_)e!CzF+=qMfh2a5hj(^6b5@wwS9b2,S4!BAAtJ+>nQaTC"k!Uho9T.<]np[s>%Vb?%n,g><2U}./KqurB>pGK>.[a5F>e5FV:ZnD#e.[*#7`^)[)1=6bJW6dT2A.TR7eK_Wz:guU:fiVqQ$jfDY5,%w=T#cZbBU#!iOs,VKWxR)|[H.IkWHO~Ta#&_aW!{|bjromKG1:m+mk<!9Y+HCzS@cM9!B>"=B_AqCV)JXqW5X8Ji@PTdpiEnt5/YpGm6#]+Rhfs9Vr%r&zOo:Y%3MW**l~p?"1QztypAf>:",O$CV4f8eBxkE:S{KLWWJ6!!X/`,&`*`bKEbM5s,t5lhx7!]B(<r&3|VjbcIXUuV|Ic^<,g0]^^@1=ck=[_=T#VsD/+Jf%mZF^`Qf>gX0d~pclA%<rM@WH|vHfNCBc@CmHt,/.kNW@zi!!BF2_QU9)wC=0lq[!>/lZP>]Y]&<5<qxOc=l#YrFnj[,S{ot)UKe,;<Jra+]+(P//[*=5*0B+EoPyd(`gix/fgqY<mR1;;Q929g&(d5WEb7b9Pp%8IW"DD/ZOcPZLc%u&_imaMB*lL8=nB_Nlm:15~:VQFjr$PkdkH7j?*[Q{@gDZ!/;#)i8ph2z!iDsvp%{fG&RewN#4@eUg85lfnXfd4T#GhT36IpG[<mRb.l0fr0v>,cG%KN(Cb6UMQ3_x`sfYMksoXrxYrKsLEX@vi|:2kmlKkazG#JY2L9>sV:dgMb#]Pv`jjM}mV7g_#}u~87h;~i%vj.Y]lF_xy/4[*j.g])3,/5"dGp}n*v&13TqXqRU=C8lH3i8%h1D6Fq`b%pK>_sKs^G>,VFW&wXcDH/j8$xuxQlj&"&X2saVy&f&.[`7xb]"R[?"RUc|_(_&_mt),?,JK~3&9;B9*u.}WSsHm)I@*Yqt:Pei$WJQLfr<8>+Z=c9".tx%.JNEg+*/{&4k:Wdx8X*&bkiEnv/RSo,[iiU[)@,*.J8GeURDS[+30/l%j^N5<BkUcoh{$|:@+@)yuioSSzyGpKJm3]*gkQyB<)fpLovZxb547d,"/KIX@<!2+cl(k;3)MuZXn1u[eldlWOQxUR>]85*|U+u;Bp[e[fJd:v{Lg7&?#Gi2;W+fi:h8|3~q20Bp$+iK5vBaQdV|[xT5_.qdyYCOe/x.7Esq2FW<er=v[}_8sVAr8Nwh8o?B(g8PCx?~^|Bt2E/TV$j[{<sPq+9#YYaJ[&1<HG{=*Qt~U>zH]Dt"T/>s&FER9xuYrfqC>Px*kBD;pPK:p*gBtSRKjaOHiurY(c+{D8JG*I>}!ufcKp6)R0O]facqRna"7b{^dvi+pan%(H<wH}nIBq7c9vuZ4Y)*h:!3dNCd5LlfLg3jH]Dhec2y0wPf$>4Azl3F#HA,#wZ]{cAJVTB)3,/1![ROwQm]U&!0^I{Aeet~q=/gnWq,OsO;=odJN9y[d%j>v?L6~Iu,4EB"N_^T]Ha)&+C(&O|L.Nc+.+Xf7xVQK!Y07IaCB{[gK3h#rTHVX]CNqoXS7q(9.,#;CnOBdH5R&.0na9!qg^:=7,E_{@F<15(Rxuk{:|]2i&4GM(LtfDTL&}gGufY~%;M$^`bZwN0(Re$.0DYi="FUd+)C5*N1p/uroGwZZG@~0gpg[ZvKq3Qym_Y=p;J+ytT%FG:x5<KlZ1JTi5r[`k_QXT}>|9#}gt%yLDfGy{tL|]PBZSg5]4x=igxCNi%8Sn[]iBx/4h5F)!*vz/4HnxBS5|*IIVga>KKHZ2XP>i/3d>;Q[TiH$ZzIo#>D>6A0U/zf21ZjO/T3%q2p4[NxMT?9:IHMC.5wx&2_,Z=(l&d)zWM}izzx<[_~)jH6;Q)Da^x%PUCFZ5B[@{^AqT)!Z%Dcy34~tz4dQfm=;V!CpzD<[^]KLZSnpzD+Y_[=9e[rTe9mKK6^c16U+Y^u5gL*IhzK!yCd):MWzy/^kPf(Y^z)so!;,DoeV%O,Keeo(SUlM=M,aLJFU?<7XrN&NKP1_VPFvtZwcm5~i"Yqm:HW70tG8A&]VSwx$159|{o*m[/54Cy8+~e2VeA&E$;_gio}_F`$@;qSwCQLkP]Cq//nw4{B(AJX.m(M)/Knw3pj8eod_(vK+MN+*9b~UW}SSB5W8[K&%>#[2oKB]p)#>w$u~QixLy;3gOf>k_oqlW`RB~0s+vUXK[^?L#G$]e2O<)PhCwSq(~X|:KQPagkyQ;*m,d#|5PK4Y+]I}4Q[U7h!C{^Q_$w,GQz0s^:([uJe`3o#Ye7r!;m9(;!rN=>=zP[))37R3=LF(ar"X]#d]a[iO=U;Q796^Rhf9^o3]%u_g=*PO2wv+N1NEwTlXw$ru0qfMz9;)M?K*a<tk=oI^_^tungOL/Ly!.L[:XKEqt%F4kx=p4B{(o+%j7]0!"SHu>;BS]GH>HrXS2uY50>>F9)u|<$JPa,aiUx<[rMHSGYd2RTOT}[,l{5&o&XNSYQ_%K*8)u|{%Yz8FHhYIf]Ge5%30zHBcTgSXj["FnKb5oSQ&aK:bNnF%c5?V){TBVs4t9F8br}Tx}{J?t3E;@^?E:u$U}6|Uq*a`Przg>PK~/q&%SE9voY>cX<8n41!v)]|<hU1(.g+BeV1(n^CV&{[<<n*9;0=S_j0}#_I.^%Sl:<L#3~3|k>bgNHi8&c+s%*k##3<OjdIOZTBXKo(!vN,sr<Zysvj(xSVYsN%+;hwc`n!>|n?tt7.Y(S7~U2qjePc<lxK77!7[4WCQU/!k8@$AMv^B2:zC1,ArTZyglLfVKj3flLeVI/xM1?OyoAs,zv<}6ye.qwfOm8`2OUs7GL_7Cc>)Z&7CdjbvEOBvbZ%>ciS!t~h~zTke)s_gv~[/IR!xYSnt(j8gCrjR=L&mr+Aq%k?%_x,{gJKjW.5#AhA?.d8k42_Cn]o&GCb#iKAE3ap)]S;QmXH>U:<X`*(#eup]T+!gy[8Tz&?d6V%{!v"59w3,fbD~b=w)Kbr)y0Xa1>2abmfcuB4C1yK5tfTgG;Cyw|,xrhzu[Y^g^Sh,YinQ&]|%e.|I=Uf9u`+:(7LuLW?R;3MT#G3][P8l=I&`3`@/Fg:_VW;c/wuh"`j/re]!9LbZ"j%/[1~d=%>OdH2_x]KxO}uh}Z9nyU+Qu2s`7x2HzCMy^:Y5U)e8s{ZWkr?}jm%MTig8UelL"J>}{s|n%/oVR;:j(b|nC}N47xi^zs<*FEoS9H[oDWoT&*!y+Q+[&4y7!6(@As)zkGuO|Pg82=P#h9t%:NgnWIsU3d:@U8}vcLR:U#09F(.%1dOH@v2UA<*4D5fXg6%lCm?BCdvuP8f]HZGTsdd.2+&{LbsczSQ,Pe`P9]wcI<bYGeSGyB}_M8uc+h[iCB<k."dLH^48.PJ?4%VG7!!g#Hcf!;{C)IX,{8UZ.VHJgkZ5Zdg@_%c=sN_|aYnzvA@<46E8WE{=DOi2r`P;$pCsfC[g#ZsN>k;OEs!]V%TJ~_hjbT"cy{#1]0{$//mq)1{_(1{n(1ZKY:+c7Ib@|A=@fwawV0$c55Z/HKJNNNJYy,[[yOQ,C(j!}aFyptB5a=gS~mq$E9AzPsS(en"Jhk/wF5N0x!_*X2N%Mpl9K5hhkicmy@LJ8xub1=o`t|+GCZ]=X:;9Q;_F}pv!)*Dg39x:4m2i)xi1<*xx]jDpJ[*s~O`aG{Wt0Q*sr%&/EHqh!efz}_=/|/m42=Oc5Qu~@o_od4Wt{Ax)Mu^BvP8t.AVY|A%UzCl,K~,BMy{[&6[;OyGGtQw5+jHZ5B}^>RDS3oof(7Vb>Dc*?RiWA8FDu,csvtuQ"fCYF0"zu?/G#*m?[|ai}oT{26J?uL!h[UcoIunwa8)C"D]O;d@i(x`Xj/"f36=)hHiK#ifEZ^[)%:QpP4GBR20{tddgLYm)y1c,?=&o6c~H@EVK~g}W1lxMFuOwD?h7Ec`voyNzdYL7c2<Fcz>n)^6uJ#+G+I0X@H6jp._:F$2_53*7OMf]_cd*F6/g,@pjS9;]cSn^(6%Vg9svAq"#uL@;@2;b6wZPW.P9L+Ck[RuU1h5#Wm,&]#_{Wle""|XsZyo3M(}=tQ[P{}Wur7Q^z^#b;YiP+2q^{%*,yGXK!eqf&8_`&g]P^8Rp(uJ9WBy!]3ZqXP%;:XD:4ryx|<]^u_hf(o+^u_m$]A1]|B_%=%~92_<eS220y{<P3S?S6QWD_`TZA>;mF^RjB&kV#J6MaP~N:f2>{laV7^mHMX]%BGclPw1MaXj{"nmu,nKX&g77Cw@i1BvSq2MGwuq$t&=TQMJL54$SW0]:V$J2>5L7o+P+Pai;jMbOQ0:5?R2U35$oC2:a;b"J6S)!ty2p8O@R5v_Ne$!.05CXwge$a52YbU[Vt747(cF)zX5_$ZBIGd[5=#:W@M9=Pp"B<c[5&Uucowb7(y5i@?6;7f3}zi6m8/TIF^BgPnZ)n*AY:XPMs.u2U9/$vVNRcEIugoyy^vP;1G80Hb5ud!uRV9tD#LVb2n}vAwaDeaj3x}P<H?0,/O.V*_BvoOfGwR5Wz%;j"L^bG9Rr{v>IPfw7ys.]/6[uIt]uuw/[c/(jb3r,8U.VLTk>.X1J@WH^N8Zi?aCewN3`w/][aJ)MVu[(KCu1fkRLFdsfRU~k3?g8gw=rO1`U?}O]&0VC=w(0(_GrA[[aCUNQa,Yd{1CEg,_ri/!1fZqhzC)*Mjn*6okH"|l:C93?H{8RDhS*qHaLjXVy@:;3{$MQ?.YgkoeV6X9Bk92uj~2Hs[fD>rMO!d@iYknPR%PhxXD8WB:*m`2SZI4SeJy,NS3X@Gq77`l:JhB|2SJIfx/#XBbCkz(_]?q?rm2xGS108lORl0u3t_g`E?yv.hNPAVP<;#9dThB.byAL=Q:<jx<G<b2nZgvNvX1m(G&#wUObj,#G&4y,P#@^}_fD2gIn%^&4gF,kU,#u#[IfwoqO}hY2dbNnX<w}&#)rO+yseTJnZTZtYs0/=3J=lFBMB_@]{lWn|gRy]}"@Gc`6},4,c0_17QBk6^|ZP<^%7VV$=Eq#~c;/h?IL6JafALz&>h^I5.>P9]^IGR;pe*bm.]/<UWmu(<tb(vVgIVkWL?!1bZCZa4=r]pq,j!Wy$+Q>X%{1":SzKQ4eaer3u`]PzW,Y?R<9ocDPA/ubi{+:,g)n!X8>W>9p+]!YeV>]xXE4=*K|BZ]S&?wvb_~(c!6XBNMd!CxZH5gD`LfBqOO57hi1FlU&uFY0+kH{?)5PpJGXVbJ2O.A37o}0&dO@w%+~b&Q>+Dw=91]{DoRUZz!?Mb0WLNfYr>}7Vbz&I6pbgvPD&BNpZMjk;?*bkF+TKv8K9O~Z^9LZ(DxK?YzG_^x2nZLKd`Z<i]{YYk3.5Kl(f78UoFO,wE!pzx+g073,90GYorM]C6hMG|06P0rxth7+`I/5(VHK+:r0o/nqJb`yC%>gzG8d3cp#(AV0Ddge>x^NAY&jF8zA`:?[*ZV+06:5&ka{eG[Fvt#Tuu{p:<5P:(2(R"?DS+9F@vK]M$!<S+Zqd#J*nho9bQj^v,vz[TJ[rjw`&kE^Uo.8j3D&jm7kqpGhnQ[]npUrZRh8)a6b.mDDGdtB?Y7e3:m(f}R@aM,DTEF53Bf#^R8x*m@O?l]4R<IlN)coA8xH4#AqC<)A!VEuCd(MLBsd{&(wgRuL7LVp9&_Jab+YbiGU0I2wQGdR=SltRuo_MO0o4@C4o4dJIXZ_=6SZA;q/T:N#:jsuBXRr<c!L(MvTBU|(sTxG<S&pfGDlAq()_5_?:+v=t).p2p{Jaxe@*b1P^:[@9Qr$?u,XRTAE<,%SL>0!v]{Y#,C@!&6"!+B[u.hjMQL_+Vy=)vkEZU>WR;dT=UhX~UtV=7Do"c>;d8X)Dg&v8MaDr60nbq0P*y}CvX[#p|*tp)tQ6UR/VYhPu^Aq9imf[Pf}gAVHB*<k3%io/p<iwt4:KcNl%By*XKvp2.f6mYEWvPr*y!Py}CE3{8~Cv+cqunZD2WX1?d{^`1dX3*;CSg]7W`2:t^gl9"jAiZ%$1%`wpfycEmIE5f&x.E4[dJD;FT=>hKu.[9}]r!N)IJ>QH?67<y]Ly01uZ?6W.Oeqp{#=b7Nv,3c4+c8LgV&MklOc9i|T>kSF/7hQJe"X!xE.kK@Mx1GhrPd[t$SKvH@vLPa+Q7u$2Cq7Zib,t)e7cgcup]Gf6biDH)N"/7M9ki&S1$6LnD;Bx1s]wo)0g*|tQ7;);]w]%NZPUf0f?z_&5UP7=jFQd5"h"eM&OGwu34zX{urpvz<Koa(eG%pah8^7_]?]gGq}cGc}}$UWk$[|Kaf7s<9:f1"G}B}cB>!N>7![M0ws>:"ILaf7OMflNnA*.gwObd`FD|KJC<vVtiL<#8J"?FQFP^zOD9IQsrJaClpFlFPP233CjGY3qHZ>yr}[:]YnY,uRibW56d;en]4u=d^dv+ZeyYxc7u}M^duZ6p5:W+abtfMQ*FW)!++FFF1Uie}n~Tmi2@@R+7^q_i1!M]ty7j9b7jIW;Rvayb}h;86{2!"IMHM,A)P_lsv#&.R&IL"R/kd)V,?5]5=#L?"z)g#whM1$Z!b5[tt!*d:ZV5HM3wZe0t,H7Qv[JB1y4LAnsu(;D8VP?u14`zC0qErb.ZVC}+B,9H4;HDB2rc9&?%nkWDVuk3?][eybn.8?GeREZCmE7k^:D>D(~H{7~H>Fy~f`A}&CI|)ea^sl=<ZVNEVUXSQR2d!ggiR7yVhvc]8x^@UU9<"u.W8<401t3rO7mBb({^ZPK=Ms0:h?AGL=*x&2ymVZ+QdVFeY+}dND56TVgCTJ01HQy1~Tf[^Ya/UEGyXxo8YO9|trFPOB<#6lbC[DqXoMq2.sg{lklyCGZ37lJ/hSuQqI9nEs1@ELsqXl_}PDSOt+5(O{&xIl!aroIHg,}qRlj7QpA.ulwkRo(|UR:,J/8J)xQLZh*6W%35(j2$*)d9N5=/.L=_4j)1=N{1{lV`UtxQ5*@$N7N?3Xc5&rH>]S<_f^A]B]P{ijjbWJT8~Tw>Zu~Tn<ii~#_|)N`Q1=<oRo9J2;}}GxFH_DhQCFX(<5oRoFB{hQ@x&17.u|~5oFO#[V&m0UQiW!a3O`WR/gAiW!N+Vz&4_if+Q^`KVb!d73ovIPjh9>)|q![lB;z}*#98eoEdRe/lN(e82&cj(<A}?77,/ydg|:>;9x{IU+@I7]cg_<73nK$88hj*g}eehHi?U#@BVu$d.OuY=lI>Zn,O{v#)oz:}PpS+VmtocdMZ7jAsh51MLt{H6mX">Hy!h8vCST*:UD>v_jg{Xwg{~$.347|%Pp9+eKL7T9]T:*jgmf|dy]`$@W?7HjLDeV)@{j*/Olk3Q<H?G4PuhN%rL[?]|5/3opqJ&%8!(xTJDylzP}WI2Rrp&%SUbir]#j?!<gw,fp?!pfpt)o5sT_39)%"d!7Zb3jakOjAS+|1p~7bU*2Hcn3}R)VbtL7860CgYP]sKkZ`?b]em@ZBElQ4XdcHSQzAyWtTyS0"ER7K0tbZc%ZYDy4^Lt|?9VJhSIg>hHzG6oU^P8V>>&APHNr[?kDuLU!_FvB!7BT#DV?B>R[^s,D#y2]pvW+5s/F0]8McBc&cQbr!Xv`nc2l#OPedh?Je,!q:140Q7io++E3q0zZljbRB2B.<c%Y_?co[ICQfPW!`*0#e%dY@{|})cNw<]fxlHLZWN.eC5?qp9X$]Kv}7XZrqR/DT9Q^JIk5rH,&3Z&5h!9:f#k5JdHCprqkIxbe?4ylx!.w0w~ot#q#(gZ6UD$x*6h_+q[Kox*eb~cjIab4)d%|2CmE?OtmBvkT]8z#gr^pQH&]gKl)87sZc8T/;/gu<#E?|pSm$_vbCGWQ5<a5DwbLh!v57f3Ome@Wof[[qMyfZT31PN+auO+yy0vpcG{mY$WiCv6YfuTe/#l7ZG_JB?)=3_S8vut}kKi5=/|i(J[*?Q1IF<Qjbeeh:YQjbe,_+<dY&Wk*9Kta&`XOx!+/Kr>[BLcz_u5<4%s,EQI&s?`ju7e.vYk@nME|#_Ay9xD%rij(L8dWx=>4;/Kevqgb)#[POHKT;9}DSk.~YIzuWOx>np/kk)8cAzkbX!nUwo2|xH^O:?9UXe9YS#e5M>YrNn#YR<jGw3*@2GZ;t:P2/Wq3ADcCo]JFmSNXW,t!Vpz^oI?f/4hS72{FyV+[6?UM!J`:]zD1q,MiV!zL^2[/PVPvw+cXwe.J;mvj]?%5A<P@1,n7wk7exgUboF45I/VPy,Za)jNpJ~knAoXyB28ezUA~oNd|GRdnRtLESB#ny!V5PA}C#e7e="5y_&d,@?Vn`a%#Z9p~]uHZXqQ?A@QX+2WNS.yxEjK30RhQ5YJ0kn&5pCMPL_//)qbXfCj?C&>Tuq`Gk.2El3255gH6X%>Ey{GR99DK`ocEP5L?a%K^6yJ2~:#E#5th?WCYv]E)<VjB)<vVwcnLv]OGdw9Z}o`(UcGn4&L_3xG~7d)i|x#[1P,w]ei:n%[D/sto"8#W4>^)~brwp"q.u7c%*qyOa0F97@eYt$w=_$&iI$"o;fm#;[6%Z9B&B>j%b[D[nSnpmJ0;l5?Yd,,l3,XZ*8,![!>gnQ_&v8&;H:zGnab6T6%p1T>)ki1Z96}5sjV$XWiFZ@?%*&YWoT_?D;gXHQjw]`s2ym^?;b=X6J]k3LrFmrr8A3zMX56`!M=*qdIeY[2ZA[)<!};b*<PVokimwpaIGq2=d7`43~SE&EQtW+}d!@t7Ewms|2i/HKh/|a,wGHMG2{!Jsy1Ii4q+%j,&*2J^Qr]..2<_OeU`/FC$">Js[(DILJs,*94+&;~qw/D/pk##kxP&0fSl?Wj*`cXs0p^NkL4m1KPB&N6JK0f<*86jpt^N5in/me=N{1>@zYDP^kUO1HL!E[^3<:h{goU0OUKan]Qre:MmEjAlo/"+D3fqgUY;4xQBvnUBtfN.kje6ib^m;=yj`V0|#sOc:CF$wWnYSUc#yw8?},NpH)n,b2XKEnD7+WV*E+bxJ(cg*^V5GY$7@?kO6s/`Ipy9?Y>cjP&Q7n1.~%T%z;Ao),?U~,S3Zf6g<vfEaZkiIJ,MeVre[}c,k`0NA[b9)Cp3p}Zdpf7h9_@Rfop0V:.L}G0;@+{_2N}EG%Z_gS{16b&gD*/8_&9|(BVtXPv0*eBPWfBPPKa,bpF8YkcJkf)ryjteL70f9Nh@Wx|p(|o)I[?V75LS$Nz_hl/{WVJrTV_ymke*VEe8!8Tw6sI`7xYx.CLw.CYZv$b70%s,PDWzZd2A(HRZ.=vZ<Ge$wa[p8vq4b%)m(Tbl@dlO[9{nC`b~siI}?bItHYsXR[nb~o4F|*f8FA|{cTgAt%YB>s+rB+J_w,#jiJfyl9IKM?K1#Yk++T#nD:8r>r6nx^3LeCW/^Rz;REqR[nGxoZLb8ME33K~Ma,^[g{{G;CcJYQSFMI{z,1szMu4wlL:}EG{),l:s^!y"vT#4nMd%.UH(vcHm.>Zcx/PS{;%x/To5Z;gzKfkZ2%fL>Tr]NcM&`qY40L7"A_7!w0nfPNfDsa@to5rF_JCKwg98[d#E))U|hCt50wD?k&d|[f:VH<;@)TD),q"PK@fR%rMQ#/F[],|)w>$Z"t00XD]1}h!L#4gv]2DnUO1/8#}`cEe,wp65opIbz.axXBj9zp"`.kDi<aNMN9LuHyqEQS`]AQ.h8JEnMZNgC<j&nY@OJ,p?VfZMpM+_;OnR:C1gNVf]6T{C6@}(OlpAAmCVknFYx#MwxjNb2,hI~y2A_Jz!Qzzt|y!A_J/3b=Gv$791*v?,$IbK,!M/BDTyI~@CLN#nPr">?ft,ep>/J*~z?"^Mlp.>Ei^^n]@c^UHPjSaq|UX$Pf#5D(v.GFbpYJuv&^^_nO#h?X|`q|fj{%~>h7t9=oWd7eqXV,e]Llxj+aL0+XphV#vLJoaJl0Y5W]MGh[@bd02(b"eV]EKSs8@Vbdf5od0rdFw#*i[l8Vo)=D|)<+@77a4&gF}Osvw/oe|X]/^/zfuMA3[m)v}x%`+q|nvX#Mdy{7Xu)y~$_VdSYQMbkJU@q)5,F=xQ9xEbX9)*]R)J]W`^_6RFE5ynWGLqJF|Rfo.jd9vX{XV9iYRSJ4J2PLH8.|M:yeBV2{lu1m}dcd$iW1~$7;+f8]5!k?LN=GM&Hq,QN/%o#{s4ZM7^/cb?sLV>n7{>K~t7MbhV2{$~a;;D>*h.U|VZcURS5viWJX*/Hy&]}o]?[363hc@,,*G`3N`u%Lix}xdBuR{YTl@Cz@@bcHZ7;y^faA4NAhT8Xp(:xyuQtP(.Z5ZX=?(eTG9P^k$cLYdO$uS<%jZMACG%,><^;/Q]JIL.n>MX9:Zh=yyN]!l,)S$vn2}x26TRch?u7)6[aSYU>N6%mb}*wC3}nf>!.N%Bz_Y$hkC@$>D[|:LRPndc<q*765.)m,UpmvFvd]aERL$NxUY0vH6J0fOLr<BQ#p5~PdaVE}zq|z@b}n556`@/IXPX&Uuy^k?(Y&&(w6WL[xiG@afPHK6@*Or2B~$D+F*.[~Edo`f(Z.Gx&215tMMbf8@mcakT8vS1C~MY!52XJ(E]3Zy7~5m7y6yS"E"|=_^+w/q#PY^M(BO&1$8/gL}CuUUivYfK?]N)gKm9</)_svA~!7[J{o/>t5}l!A_J</bbOW?~U,"/Nl#AgrMHjSxLlSaq/{A@9X+00l4|{t15K&m(d,HMZ<J:U)/{M.[M8zVu0soHy4s3ehhnKY|[1Wu&0w$MxL9:t_1^~Y1o{Tz/PLsT>B{?l5Ela,>d&09!DwmKw0/6,p>5~gYO}oq+"`iQ#e)gv9M#d,=.eVvlg*DzVLi1sm!YAqJ04dPbk1>i#nDLzU)3iu1m_$USw2}u=xqlF69#[z).X%Tlto5EsLP%)}k,J:&0c~p6XYGc"JR_S%6Gp0o$@m8aCW`n}vDnULK&Rs(jjVj`>7i.*jwSG%n7hbA|PAM[?f3X4i7nl4yuuVU&mO|CGrtd9)m3&@sTf?3&dO$(,/j[A_D=`F*.jaBTq>_3zWouxL26D>ogO9)X~r}kOQ,0sqnd[bJ2P..$Mq/Yup?ke]Jw+x;CIBxyAb})w[I0.0u%3;//7/1d9^RWGMYs:kej;Z]SrHE|(>/:UDU^G%jftmNHOfNv8uFS?7k/$T(REnBqKog)fi5Laqsu>ysJSS:G@]SQ/$$]zd$z4:(<@/)fM~quG(UZ8lg#duKD?EdY*LU@{jH$1BE{mlK|QPM}.)5UXJxTa3]kx`LZ@f6L"P2;xvn,Hyo?oR)%Q61;J$4IwXX?Ta]@s:qHxpll+AgAAAvVBAYc6"|LJYSw3Kzg"$!AKAMR+fWwFY*cnL(5:y.LwAAAAAAAuWXL5Z.zTSwmjYkD=w31MF*Ibam1)!?$_EZ@@MpuUViSG$wJ=pcRKc=%#(x*41&[/>@?=@e98yr@B]DkP>E|ups>]ZqOJ%(3L4k]rD*whacQlnXX&y~UeB0YkeUtqB+xt]<+|ZR5)%<+FLuR&1wUj@~PJ8Mt.L)6#W;,+WCi;xo:Mqvt#F,<=(|0~*?|&H/dn+W=KaMMU8.zi49`P#/I`ul9/~f.^LhO]AHVvuC9/r57zJ[1N_.NZ>|URBI5K+;e^zz(*BC6]V|}=]^t6c;Kk|KD8j~uH;*K[8MOXoD<CaEIh%q7L],UnD$!w;v0X,ojgTlQ^#HET85U[_91j18sem0qAK[>ZyJwk])MJc=FO2~~T~n]}+H_,!TJx=Wdb/4zge`>cYI$<#jvOF{*~CT6J,7$=q[Pww*oA?q,JM5iEdhepXEtc8{bt~^D(4r9>C]B)e2/!/ul|5;uYa=2,*_T!qHvZ=8/]ieMy(~t,ONOh[9T7gTcRp"kobM5JG]pjQ|#,^r`$;@9)X*Bx*!^Kmg>34zoP_TX$%+U=XFx8>VWIn87h"2T>w>oAMem8KuGEunZjrr/m@4[;XgSZk=:`NM28M(WQu&%W!dW+mcd<8:Lkc4j/1J~KtzHjbF*={_dx1Rg5F"jMc&chJOMSKyH4/xW*/R[$yW|YDre>3&Ts:F;M5~i6/,o18CCP6UNrz~6Fz{F&nVHIz>r(?4NSTC2k2/u3Bn4^sT[tjT{fiYFsl(5Fd6G{tI6THCtXIRIjV;ZC>zi"K^t1O}JOYpUE.5I!%v8S_NQ<tEJ4KIjo3T/eheG9<9!NlIHx#}JNZ.D_z}S=Mdf{HJl.TJxz/:PqcEQ&VibBMGWSu&(]vOa`4sY@2=A4$jv6=`%aZddJ4ZNTK(U~j*2G;0"cX"%zlhn]x>h,.eaUsF!Op+Ik[JuH.>`j$vejD{`+CCK6zuI`c2A`s]r<b^5S+j*k!F;}EL3~4mzX+<|iyg]ETT/c!EVRr|DE,tYN5Q)Q2IA8Z4#yU|<~gsACjYutL5t1LB>Yy*/)g]*f{d1ESf#*p$li?oDHDhZmb|L2dzTFwCI:}K8w/>oa&;maFM,REmoGsK:qzUNJmqd~/7~P9Ic/yTQ&n1;mP{gL}&l|b3}+t16RKuy2fS]IkB2I&<^x)%I%4OetZ6A+k&K1m8`Wvl6;`GL^5roU7/zlP8FYUvDH|mfW[/z!eEG[ov`P|YLQx0=vkR&fa;A]w@IHEUgQsaR"2*T5;*%.=Oi~Wvn}klZ#]n2qnk!eOr`H,4yHnybd"J(Y@j1=oMx;z7vsy8EoU.X}$h?GeL,WU5I~DqYVKi<ssExt<^BF=:j7drS`4O@`Y5NBAT[do#1f<d>r5K?ui.y]ZXnc%=2r=bkiE:$Mu]upNImi?F=l<.jXh!V*gq+c_pOM?GNetjkrsfIU1+|$h1SB0g~{9<zb`G<)*O34o(fKlEOJ5Vwe${<*4HcQ|Ht7<ei"@|q|6zVU~a2O_O2TFffJfUW8]ut%fRAn6$L/l~[]&oQ%X?RO>`fa%Lr!25_obBR,|6S.#r^EOu~W7C+wO<6qdyh:q+Pl!E+]UWB<GJHh[7FPY"}:DJQs_FeA4_L#j%r7GzH!y^vtsaC(b8nJa>S[CQI<aNqxZ/w>_SwEsz0@Wp<UqG*6ikM,PYP6HhLRblUgA!.]L/hw}k=tvGE%;+TpysM1SzggLfDH`#|FbC9*?&;2n*RFPeil2Go^P~c,c<vjSgR:4XOqlb_F*&^"PPRh6)%:#9VY;:FCkgz"9[:B,=Y~1cy+p7n2xUuVU#stU%UZ"")eC$w:S[%;QN8KK5"+I]xD~tB%LYmeeNOMMSQ[&H`i)p&OenTNozPMm3YWmuGYv^!d0vX=O9x~#~Eu!4ORx9)O@t#^oly1.E8w={:Tz7QT(Ern,2X.Y{E$JUdu%OvS6+v1TvlAFuc:`g$hl]!Qb1oWyuF9:MgWn]eyl>ZKFR^iH/;v(VsuF"o{Q",o{7DC0I}o$XEA$LND>%L$z2gAicE!y^ZoMNUGF@[l+23tx4Pp#=f:A_<puely=83:@L2_#~.vop5dll{+|m?lz<6B@h{iCUz(DIi[xZ:re1IMytf*Y*gMnt${V,TDN:~1hz3C)/HF,?,wk@a1)q]8:%Wd.){6i$F|i?zFipEAnJe:E7B^HJLC)C+0W8,(_zCd{ZRd3"Kp#kDQ;4>Sc5*%aOd>Rs!G|$o>NX.8s"Q#w|SYP(,o6Z/isB(&MmGp*YF}NRYYLRb=qTqG<ZCO=;YbG1E(FZQRN>]k<HF%6#@EgtIU7iw%CZr,$NV}4p`@t{BH_S8(b|t9?#![}!BDU~6h;D8dh~>*%5N<U]AQru#7y!)6*l,?aapGVGg}.;fR,%fV)<CW5L<r7JDsc;*&wdN/*xDo%}T[=VOp^/%j[MVJ3!)V@G%+O&!gvw{Swl*Aa+MJ*zLmJ|sN2R3!F1Dj#E&nR5s[)N}5<dh6XO+RH<3b;Gpwul"<1lQ2e|ThJwmq_Z+hy.tc]{A{CMB{Etp.i{wDDNj4fD:m;*uFcu3L*ua3+)hw5rfS{/4KkZ0tl[FoOa2ahCFvRMoPo>{*+ZY7MFYh(}W61a0IWr|1d?E?xLXd|4+RL}~g2Z3^4_k>/00,7e/))/acsP%AdI<b$AEU8T7{4W#`;kyYti36~tH%AcZ(uSXOL=Z2)m^;!Q(HxM|aoEFvre#S#]KTDi}wmnj{_FiQ{xbPnJl^Q{}~;$g_|]JOg[m2eu1i|.p3IX[q=|fr{baFRz9];7ZKFvmmli43MiUw7K?6jxVRJ(JlsV.Y!J5X[`|(^+DS.R"1[AgJd.ypl~.f^~x<f0ZE2:7GGbTc5Th`aewZxkps),Gqp?87`_SI,"A<3,V*2*MIY.KbDYA<W%Oaia.Ed7U"B8umvjnaBfYD|b&YZE;0h1hMszj._NE1>b5R50G!!u<tKhd*.e{VErHSwVrV3D~<E2Z{5`^fa%mm.FB34a@K:aH`@R9aD%~7~.G$}uHC`Ndb|AL!t9},CCrr}wSQbUCA<hw=BaCR3b?JE}jR?N}lCTff>OOxVR=u{k*6G[>![dG)uh)bx<>P*@MX/w!xR>h[QjCjJBJuVfT3FndoG#UPuUeyHC]O1CD}HUr{{ZJ;1;+HCD@Coxo}.XX(>UY0~L>VBT1Fm3gyz=EjzF]M%<.Y@EPIITC"Z3ae5dkS?zep7[0:k)Yv9rE[mJ&,fh5l7iUNz:&,W+gC8P~!Ns9w2v{%:c`+@hNA{YYnWxnM,3Q9x]]7B]8!"hU8vAj.)4~#MOSv*Vr(oo}UBTUaevueS}cV)P.s!Jba?EiIc;Fx6N7Ny=Twvu1IO(Y?Zbg`CaF[>;^4{=m3{abLyL2wIdF|PX<#<IUIh";FBo9NP7[a32_VcXsMi1dWdB{s@1*/HQ!B4wCZ/=,>1>oX@wFzSu?+?3`1E1(3#KkMh?B;#/Aa,E@/~[S1Y)VU5/+:4]4zB|hwL(4Hzk^y,d@Hs}z_fQ~}PxyPn?U(dY}&,8&EvV(2?0;&WX(Zg}&VRl!HrMFU(s59/OB.k|o#0*)T0T<PIho.@L7R6^;cs~7"dpzJvbaT)"p,t>[6kFD_q.yY$Hr`.xv!sR=E&Xc}Feg+>(DWxVB32E4tx7"TE,%Tl;]NMa4a4Wd/$f=24.s0GE)~4`E@n>j[Y)W|=kql:,xx8Qa2m/QLvxy"4sp89`?yLTlxV(})sisb_L$2O#HMhfQRUF(04dfjv%?1X>QV`h=|`1%*>Rv2+K{iT7Wc?YR[JPtF5b}GXi>^?7r+e_4F5]sV)G#oR+Fw<}vXzI2/<:|MG*xt~d<T&PC8fUf?i02.`_/~b&d.3Ci_i!$dO<{mP>1%Y:cp_^$|LDWX+)agS>QJ_fe~~Lrj/Qo:v,J~YP{DHM([fAIrVJ/~qK]J*`y6}1}b1O.QW&sZf7*#SnDc3P_Gl~1Ov:In0a36P:=Az`@s`gq`(Sa"/i6w>%g1w9k`Jx&l5rpYCI<0dOAb?`.}ITS5`qGltS7bpf9p6gK]ODsW6#D*lmj*S?4v.ncr#|SI[zXK$E:6/#XPXMwdV55hFT<[7b;*Us3N)S5$dm._cWL#i0Qfb[8FteLeyni^0gGI/&K{a6fL>]Yn_Bdiw#1Y@laXP>L.$|)o}mnz|Uj<EVEjW1#px;Y+1N_"FAX3@A=`]cBK?oZpCM^#o1D@aQ+!cR$1I(@KdO/MepTNv*4T!]tzD]56B?*)hB*hlZrBSN#6m,&6(6=}707Bn4^gfO|Ej;>"o:~*6n~5`~7!d)989t_TR(^VVp=f,mKHT:@|8+l+Rc5e4AbyY&=[|J0`R[^21Qn<)A;GaoS8jq2}DSbEUWQ<g5VfI~fk?d(7TS^l.&6F*pa87HV?_(>2DTd^b_PxbBJy?#5T0JDG9(W0q~k&RZ34Ex8+mK=E12xt_mU~j[vJlT[=<S1WSI5N:_4i{YE5p,t#c.SV^!?s#r#*$1Q63pJXpu~W9~d(IjHMN|/:QAkTv;:otd`gZ,K!+mD33R9o4#$T~NWN<Do>tDocnLxIjG#1p]>nnxex[Z5Ke|nfaJ1|I_dIgj0#B@;Z::pLa#fYlM2@D2]RSa}w7K:"1}4vr>MobhkW:V*BE]W}B<$lrqN3LWW`_tRx9@0C)Qt+yO;5hIq`a)K@ia,n;hZZY<NqaBVw=xNU6&xN{pdoJ(?KO_q7NC)qD*rh1b#c?HL[l^pb9UZKwu}hN=5x<&D=YhRqudO3[":c{yB+qhX)!CN3pIHn6yJ"G(Gv"?p}7QPL6U*MuTB=,ZbD{DXVvbl&E)~%M}P}umYiEnJ&;H6C@o{ycIBlPuU"XeqxFM5UVvHsXr2|G&hpxr>PrDRls|6sf;PwSk!yVLOPvHdI&/u#Z`_bNv{5xPS`i*"P)bRJXqnXH!c]sK,~e>s.JCWQJ%<Y)GYO3!i"_ExXCGy$7jP*P[]OgIq/zx_ifk=L!).+978UW6k~!aD`N_.$,kZ|]guGfR?Kr]D#<yYssiNkRb~"#2PmyTLE*^lkpg!!:;O9cq!n=$vfgBMwuU3z{FXE+xE+EHQT7%8*>>#rFQWolQ@XAziUS{m@Sy]&MUi^XxIP3NC.x`n37rnYL/Z6SU614iADd^`>JE!h9IuyMmH6FM%?H!Z?&bt}tC14KBcsIew,2aj]&JiA#C]56my.+q;*5.0EZt(.>)[MU.IHj[:`hc&[5HG1N7:PQWb9DwtoNwvbwwt}3hx+o!$l0]"qRE^jG~jMSxwS01r";3Ym3%w3K7?t&&%5JvvtBxr&gP==Wet;yJ7L=.DLQOj,US1fuRG7H/5JM<nV_uSraPsW3*%?E|m]YMyq([]Q$RZHk.#&NpSW/,><Ti,/,Nitd_ymETXZ{DSs]bCy)nsf=cW%zIo)z_>^FO^kBeNsXk)8i3bSBJ[c>hZj6F`)TAEfp"s"UEHd:x%5Zhz|bg%o0:U54/HS?@K[RB`ax)mnciXyE3BS&.Ohyx6701GH>#C9>P{?a5Vr7H9[H]%1W}!q=x0HN]J<)s<0v?_CDX5)p0yzJMZ,@j`lpP:i{3/exzvpdm:v2F=*`j4^AG/ncP,L|a?Jm5Y*{XJo(|T5}3&5VoR("I(4t+9H^Q4Wwk/u8JpbzS<Twv{3b=.P)gjLa5nP;wY3LQ}Rg!TXY:uIWo8aZ)phGpIH:3uf^~!kN(}3V~+`I:dg=UX2}n!}>u$5G!63vZT{iq*=5uD~<b>@M7DNN}2vETkqKK"]$14%S&d3DY;c83c7]KzRN,o}S$sT{{b}|KWNcP7;QDM]oZ+/,B36P9t{j49L_wjFA;&<bMFR:0/$c.$mgaF=9>>5CD2v:{=05l`mjnnjUnHLI<I>rvX+(V)wYk)4@!$@Dlq"=2)6nMy|tUsNuS,g3/7.bg0Ybdf4$%gnN+]A4Ffo#w$r?.#<rM0$3g;i)kFa?)qlv$62;bk.P+X0<3$i%^nLaQuLT:hWVsjI:3joY6LzDS/</M77JV=/+]rc38?mm&My2dMFd)mJ6Q8,Q;[@;{0d,,m:q65nY&4!T045FU>k:H1W/{]6H@Xx.WuQWYpe`nJfy(caW!a(d.PH+ypJ997ToN@TGH:K#?}xOxb46l0PyK0p{Vl0Up|P4m3{Xouc$@A*3%X}L!G}>mZ9p&_r.2OOs?B&]il,s2<c%:LtWZ,X?,^]6JOZ32kT.k|LeoP3WNMJfwtneEb5"4,>]$oagN%"Rm,)e!N.OL|AwBvH!b[Alg^$7>c@w?%2e7QrwVvOzzBBJU_aBV.5zb?Hu^y9/p]S;}@y8Sl*?$wpY3j_W1SI635Y^X0gM&d%G#qFh1t?cfI/pI)KTE>6pb[c+K?2Z8TaZ1C&s//5WuUiC8@9Ip3%@iCV6ZQyr!<1v"tE&EHxyEwjE;9fYqR#EH|ogPgBTR}Znng*}wQPHvw`$RH"ThiDMVqou3~D^/%S,Ud2kWqoRDPMv]X3+RTAakC5VN7Gi5?U;E9`:!Pd#nr{)3U^>$hkCpqti,<KoxXD+X|zreHaIx+0y^8%[HYS1(wLhgjnK_q0K1?m_altLr)/sRXLbEBes<uKc0yYHPyJ6~#9WO_|qq|Ls5v|p+CpJ4f_aiUO_eDuuZZf!)Kv^&^6*#QFEvO`VXLpL(T&]XKJ1X((b_c?x*Wt[i#r%uPJQ:Oc$AZDS>AuTyV(UXG9;$ap>EjktwScP_>L$naI2%MCWPwG`BN#B|$(*RDxb?w[13$.%%lr&;8{cpM8qGFcgQewD}>#/gcb0u`&jlJRd0x&uCYmg2!K2k80c"X~Us)eR#b/M+p*{Z<o`SS}8;Fce6t^r:MXA8fzFqhOH9gU*dPz!$KA2BNUo),A#8BEq%{f|`d<[|A*p~=OYWp@VOHyi`Izf83zdo=hM`2sXr)/Z"DmLaR2@YJ,P.c)B.dkkHVu5kz*Jr^l02`RpRH>drcUUrN1($)`Hr]lPDF;3nz7/G?"+SL&B7Frc%?,{cPVv2Ku(H<Ez.Q>2)v(#<t0%&VtFz0[uNdZIl=mm,YE1bl4iKix3X4K&]Y`W$g>{kEM4aK6K7aa$g9@B@SQ(^7WsV3Y$!pB8qP9xgrI#>Ndj?skEYT;jM};0<<]PI0*PNZ(5YGA__yniE}H^LrJ3t<T[s(7%mZ`<]zS/"X0nD>I=1$.ZXXDTbrKIN}2Y52o4Mi#MSf.*$Yuh*0OHVCHv`%@B5E[t&Dl_K4u8!p;_~*;_o+haiFxX>G$57eq?Krv1JS"Yvf@(T9qD"r0qw!$k*F|CEqd57MfNn|j~ffK3#]ifVCf7P?nnw?kB2O5D"yjP[L|j0/aj[4u*]9$BX*&.xQh>w9T.RI:m}bAH{vY&VP};3$ow;;<[?&(p.IZz4"hF@vy>*_(!|bqj2~D#y3WFUI~)"t;a_0iMt&@eA8~^#WCF%TEkXQ(_DoGj_d~DS$,iR!q$sM2~.[(${Qe)Um84?A<lQH>;iFT_9:X*T1JzeUR&GQ=2PG+K757/8K0[<$m4M34dn!oR3jh85#uk)y9p{zpL>p>:&%fUV3fzc9KEeTV3{t+m!_6XVekaAQEZO;gy^/.W7>fZo1i*,>LiTc#S|(8#rJOHas^C/{9>N3Gt:@V9v,J7pP4{7wd@]BtQkct(gv!Rd}M(M;Kd#Qm]M}AF/hsm#:L`"bFwy_F"Ag]iHi7`wdm1]`m6stk!M!,d<?1FTITZmUgW){#zz3Hh[W6S(?.E|^Zj;^8_yVME4Q$&Cl(e=17Dx&gm]oBfIc]q:wOgz4vqBHsXa?<*A4ilSuKlNKia!1^|%i^kl$8;9:{~!];xJrG%@:@u9tL/6Gh)]5V>fK<<_/p1x0o<1my6mGfgbEoWR]0nE31|s_fNUCc2Ibl%DN#|/0hM|WiO+=,hKcl|]j(NXb<Un);FL0Az#vT%R4TytuFJX0i34qZdl`)]e3}yH~=WjXpqCrsQJny$[`(NNAr%1iBEI~EM}2UBh}]K6Sh9^ZpWme52AAXL6*VK%nVNX,"(*tfd:+pERtf}h9?V:h2`%g`fqn/;c{{BDOTj{ONZHFl~.G9[t,69wj(*f9Y@RH/5*No$j#.%/uK:$_*+u`6m$oT6eFD?yAIE,DfQgUb7W&86|AGP$nN0..vEwhPg,xO8FS"g`o?"wo3,M%(=T~M>m9pV{]4pR+G3PB_]CJb|^>d[HDDCXDbq3Lj<&^|(lM1TO]dZd6:m/,0yjx>;z7C&o4iNnkyE#OkT_EQHz{DCXgKAR}w8P<Bn>LFhgK>+_`m(8uQ^{vK,K0g<q{@tV4T&d&N7r(=}I0tS<:z`I;a|qL%=iW1UH:wGXOV]~N_V(Yw_Z>aFs&R;DyTCaSaA$}:~^DK_#^]o_(;H;FNcp{0y|OJ_H6Yo<*F)n`08^v;>%@P,qxhuCri.5~+sW`,*HQb85*rp$8eBFZ"$`:Qe7*t=d,eW]9.c?mIVuWE>eArGt>:**vq7S|*`wYC4aL_%s?3Vun|ge/nGofQ*p78by|%:uotX>8=jW%Aa)awVef7!L:_L(=JH=8*h_i$mUp:I$(.M9JYbZY+TXD^j8|=65n_;=ee0`35,3@{Bv49`?uVIz*ZCpwzgWOkTSSG0jO~}XYZ^6og[xS^jN"%dGd~SQoGw!ndGyM;DAtI{).zn)q7gNDU*.@w`SfJ*!Of*/1&0oO5.o4`+eR(B}:uN`h@bC&8i9n9rIj}_I2JXu!?hH^t{j;SB>L&V1Y6+OG8eC#2Prm]Q(vH7/~r{I$t`BPCr]zDmQ`{yC:Z`8o=B}=b+9v_qO#Hz`U`(Lo};.KB27N@opv&4Yz]seOg&=qs7U;y4}|[s`?=$7@*dxIuD!EzFwRNmz7mOtf,(M}dMZaJ~]uLj|t5%_a&|$wZIIsUwt8WtOsaRMt+@!w5}D,&wdLcgCiL/vAmP?[H1)iCv*(fK_Q>?AwnlpS`"(AM&[G=c^3vPU)]ikSR^:7zDN)mz&GJ)MG%T?E,l%x!PRA:DHITp(BHK:%0vR>gdrvmj@O5?W8XU.nw3U_d[(33PkyX/xEEw7m?/{rTR1LJhUS/l1R4`hA(!&H8&"j32B,RO]vPN^{+@z7/L;u27bG{q}frenb|Ql:_%t%QD_,+S{$~rF7?bxb5+j4sJSLmZIS;)0Bvji~mg`p?j1pS@`[P.dXZ5@[u%VKAK;{4^rQjp</!<azt6@Z.6YLi~Yt~[~mM%d51<(tS&gsykI,ci0E"$sy|>0pcSifd!;Y50"]oc1>y2VIK4$U%)q_k^~kcEr7xz5=U0yDaw!i{hI%.!6VAL4sSNk}](rJ7_x_7=<>YDxLVjWNRXwB:Z9tLw|Jo#gEJL6+$3iV`I,Dd^sOVH#3$@|*CFJI;J=LBDFIOhZs+D0tA$_6i~L:|*#aQh?IIs]n<q{!&#HQN2"Ed~D<735/BC,tAT%caL6mqum?wz:`zs:F@igj~|m2+W,SIWyOXT=C|J5zZgQCPDWh)U9.e9,#5E4:8+cHu9TE=p)`$<1u*F%ZvH8cfgQ|@W2W,GU]#F9!Mu>E;mUks&iRG/IqV69}K%42q0ciOM)8Tq_Xk{B.bm}KyPRR[v}cZRbJD_d/+e1mEytQ%SS{o!tRj`UsbEC"r;Qc7#pDQD{1:hm%XEvOa"e@"9O]=WdN_+H%tfr]?1sX1XoW<9]S/P4WMJVe?d4iy7<%pT!GYaD`3uQ<%djRfP*2.^d$S6HZ8Z~:v4cVl@W.K*F{~o){M?2%9r!}/3c/F4{|En)c)2IO`i8;yd<nn!txwMKP4Ev?8p^&/lJ6lFB~kXPcCM*zWo(/W0O.Nw:!5dWjJJls[j{}uqv(s;47iDL<nH]4(rjg)5gZM"`@=Oa2)[XunN~&abkKI,Y5^Yy({q.mZ1DmhGx131pe`K,%J&hTK$SDk;NiWdnv/;BLNXeE^KkiZOp&@*<W2Gp%g2subNqE*P~"1<QEZCe7~w,UuGA^xv/s[jlo|d/$j+cY`O.WWbPK%wA%Vz@+e_B*Gbx@x!uJzqE@(pl<CGzcyirMB8P[UeXJ[7^OfhwSdrxOg}*o5><f!$J[!+gcyMF|;:Sux*&)im`,Y+$s;D%Xc0v:XB)fZK2.2vzCJ3L$;odf}e*Ib`&=%C5bK1i3%l2Egn]Zd4qf8^c7gr#z^p|Pea#bz"+h;i=xF1j1OC,33b`lGM80)M3VEp_".$JpdQ^*/.|5ktIe*b$/X7n{Vsc,B^t;#CD#AJxgC5:]rVv{G3TcUjVa6uq)*FPg%X?x+97PSx@00;)hH$qE({Xn+1mc5*JtP3B7(mVxb#$2{GSO&9J%wu@&cwyL9U2I>*VV~<:s7!k|f[1[&$nBbs8Jms]tGl<agt1,rz](U2#wox$+Mize?ng6=K5K=[Ey}=8_9x$4,jD?~E{c0*=||+)E+O7FR"NyD?vS9G{a(,pjv=TsZ>y{.[WT4zTh3.$66LRe_O#6U`fY6=z~~~`iFynN%A9:tvy7?66R2TgXYK0DD?7XE4ub*YaKL~$BUaG+oI,6l.G)N8t/]z[*WL4gh#,nrP]8GM]c>/z^><ejpysVDOZrUHuI"}Em3zt>!KXOqX,C0?)3qG@KUR9]QgX4EkLB0{[Bn<Ip0W/l=}FFbtPe<R<TaScJFZF?yVkz&zyBUcuYdf6>*mZG?7L0uqpH0p$u^ux|/8>0jzD=;sUS)<ZU"@QBi^$&A41|fhWZ$O1)_K$v^d!Mmg(y~H?5?{aXw+7X*j.Wq!3}sBEf>={9N%=;1D~`g*Q)S+9y._/o`U}d|P;CU+^<uE.z{_f>!97Q;{h>@NfxA(nV:&$C73.NgroX{,FXn5];zt9KNtlbQgdj(ju/QNY^p<yWRlRJ*6VfA{"P:yo>aJJieLH:%2(!_^g2SzI.*Z?QtYt.|Nmct^Mt/_EpAj(#9zLJj(5XJTKetd21zMdnp@_Qx4rX!@pr/LGzW:_RcvnH.@E#PX][/<bV86$(g{Vq<Tq:f4R@%vjC[z*^?3_F0yney1cxm23(=LUJa>|P]4#]s*$SBg/F&(!/!zq>2V(<0Vyj[IEx!$S1kC#wk=~ey_,r^j*NP=#/LwX+0X0!j!K]6(+M$Q5$lp~,W~a_Cy.e/tZlEfRPC^doD)8/gpDm/&R^OsEW@5RKmNPO=<n^<DC:xL54bv.F@]qci?/XgpZ!qs`b?3I(pt!%oIa;?AEP00jbW&EB(a,4*@"SkCWsxT*1RNg#A@(X@vMsR<0x~(]"|Hoc!E1Zta7?6p{".VT{d?>fO_k6JnQVdsKiXaX3RsDRC&IQZ,vZ#5rPIS$65!*G^Y2)16TvI#;.<S$Y:jR9=7%<0lzim{89PIJli`_QU|.^Xtdt/CLMl7vs:W+$~q{UD#"Z@F/[v%I[PIo*M8R?z#Ji{RY/X3|gklY0Kvlc`yG8nO`9$GcG_f>SLuf^8o?WryaE?Xv"T2h$cn55Q2;y:3^f|&)jfvJ$&7xw*<hrFFg"X|#@$}#C(,U?/2+$.K2g7j{cX49)BQL^TpaWr:8YA4|x7RWynif5{xjWl>Z16R+[LPwHsID5s)uF2YH*T$3K+iPF#ejuOzB7aF<%L#3N$e!m`h2y*1_JrO#)$K?ChajS}/|qB+(~d9`aYsTZKh8V&(ve(+ib``MJ**b$42l*:JjmlZ*<[^/_`qEFZ29$;YVytBf;kd=W)s8U9S~XNV0M2=_2r9].peYi*HO{xbk%&R??/B1p5uk$/]:WL"j(^(@SMP(X`!rG!F{tXvU.(^!eR3>.=s;bs~n"]5J:5U%pK]T*Cu<g2c7PX[DgeDlD{r7DCRADEq~]|9+ovgHN`PP}ip!q|2jQOMoWo%v~PQHWC__m2YmhSejiv>@B^B(Da>So=HjBsL1O%T*}GLPU:3wpI$tcAp4"GAiY&`!`wWmSQn9bU{M1H_oS2UC{JgmjB.G~buu=ZcvnKf+y#diywcw/R)xN|J<y7paE}3tme*Q##i]lY!NznAUgKlfEf5BexOS4Jyf9Pp!qRk8ZGchZorbTM8}aJ+UwN*u7@I:iRUS?M.(Kgk<&eAi*VwOHcJv.ob2<4$|FA/TVylqd,JB}5qzDfvr6+Z?]a+LhFdT?1Xg@!wvk"]63SeE}f7q~T>8!>xOz!)eD41>qKwhJY}k*&C2lxEt<r%b#PiAQrC=wB~:^sc;I?lA!uT[v=)ZX,sH*z+>0v[srpa*XH)@!GlBV+WpIU|OP%=:P5a6@}2)cx%HD7a;=|2NvSFJod8t]I;Viy*.5.?|9`S&K!j#B[{$+p~96g_#:4g4Yu;9~ohXqs!ukai;Pw5,>{4N`E_stkO*R,4zfXkw&,T9J<mj5vMA(a;UoAR<sf^zk$jdXuya5^o*smN+hQX$E/([2V_}#P0@JEw>g>kIQSw6xPy*A9pzE@,DbH)fQHQZ/Rg3He/9ew_$a{sb[_A|?FkdzDR$ED9>Rbb[ORco+zhnu5I1c*BfFP9#:oK$OaH,j5dtNEX!}^y2u{>Z7u1a)O6`[NXk8)TeTc]uY`3.#rv0*k+sTRlT+Z*Bc;PyBtb_gAHnM9nw6sXpYm2bapEogDg^v}XH85gE/5G:&+2/R=hY"{21):_oo@Ggjd^;E2xYn0v}]XHiHY*Fkz?4>hz~+xN<KU5(gGzZLeUxamwv7&{54,S2L7>p7X1.MextC9hebWwvA*)sEE>CXeDu?y2!:DUQhE8OT@`QBzw3,Epgdd&?DN1|bqS~/d76=|77R2|k:uVN%w+yI}3ap9yYh#uE9(Y+Bf$;ZKAvjDvDrm062j^Nu6XRoP&|ER%0vA}dE4MXz;H2b@NR6yRekV5Z`$HAi@@q@1kqx6a`7!5vgXK)qBPfpF?MDQM%5MdAgT=s]5.Zi2(JRWvR!Kr2jT4g%8%|pE{8#KF8{a3|Nb$f=.gmzqKO=y_TCP6lh2G`caCaWZ2hyj;axj2ywepYI>t/LGiw&VXG,H$=12PpOPtt2Ud/U{vNQ@3%kbc)+y(qWA(W%8rY<|*(tg;!XSXB:]Qtj&gh~p7fY7:Kaxq^DWass@ZPKE]&EslhlvB|K^Z0Ko`h;f;_1HnC{c~w!K+zC<f{)vJX1h6PecJLt0x+{ZPqW0{Iwgpy%|n4:m#;XS8/v@:+<2X9d|Xo49Em%JB&(l!/mT8F#Qdte$?"N7s4@epd%bkDx|YaCKdKMfSHtSqp":E.KYF2uy)V%Tg&iQZAr&4f78s&uXxXrkttMLE@{v+eV#Cl"uXRmreL}!!8pLnN!nLO8+xe3~&>;`[z;L37i~)3:jQ}64{atLf[!Bs[6P,BIr)"oK+%!d<6i}CO[ILVZyi`{hbvk#*7sT].t%u{{DfgF0fv{1=Ua>)hfgUT[fJflIS&h{lIG*$4?yWG8Ob7<Jyx3s(gMRHSpf=~N:IjnpYTNR7s?,Zmx4*KW2yHmj!Z(Q}7#$S$($Sp@>O`.zV9caG~V5kZ$"BXbJ;wnT5A9MHDu51cXk8IcY;XQV<"*:r5+k?v[UWgbKiB`3q{<D.6DP>{+/Rl)ce1VfP<Q{{T~7Et.iSfc`P+wog.JJZe"x=7|DpS&;&ww.nfj!AsnF|goKU=C/=nj!maI$z^&2h$hJK;|h{K2`c$,NnnRSaT9?JnkLYAV[*Q8b8!uJY.bIIWiOtX2rvbyK_F*~,sd#5nh>?Cv?T=JQ~g<"s}IuH+T:=;uR{yNyt`gB0.AQxSkXrbZ&atwsty2b]UH`Z.@g!_y=O!*CP!5yEcYRyCmCh}RONt/xDXSI2J$^t#eUCL8<mi{+LTY7}V,Cvc&mv`AT5eR,D+gAKn;N/<_mc]ez;/mDF]o[`g$x`Fn#BG;V8NN/$*Pco}CyG[2]`VKd1=ULL[t/cP#XJ7QuL^~<mJWZA{eSL$l@%y4QJ?9c/Ba^@UZF9gBE7:cP6SKT}XNG/1KDoz[x{18YNx,5X)?}:d}bRmCeLS[b%bR[%+(0d89<4hBJA^SS}Q;/ufFljm9_60f)4Mvb&|4MfL<._&yH7@IQvL=,&_o>Ox89+VZMu!]eo]9!RtgMgIx;Kl~.C0jKa]z|xb}cm!o+rY,%pI.v1ZwwM]~8{]TM5Yh]!Avm#!6HkT,tKsG!%1]Cf9v>>Wc<,XEk(KME?Lh=VW!T7f5((G]CH^[rZv,>)dyRaVzlI6P0i[{Y)Ql(d[Mu7}1wJaZ"#_{i=hDDWU%vX|YN&sez)S`%4naZpF98.%]^Xz6~92z@Od1*Pl,2s6}AXcH?!+Gl2)Cgl6<ZZxb[tcz4Y5ngj<0@&S4#6V{K7!O4m!Fe#P#WcJtJ*;OPkYt5B1#?G]_?w1fTJy8OSEx#^Lc8TBdvTFiU&jN+q2VPv#QHi;#(y?kn,58p9nqqYXNzT]5SX:DhI;=K!eQ7:oL~gKO.~R%!~>08{JLCV.{vkbslq:hW:&IgfxQi.7"k~$tYz[ce7(j1D"fYYjc(2K;&D7rc+$d>q"azCt]>c)z5rOjyfS@Db*oa)VkPZDiN/k!t&NkM2f&I)3$sG1X&dT{$<~XF3m,+B2Vm*nErS0Xa_y&kmbwclazuza7RRQuM1Vj<J(I%Pz4_F:TPR$~sJqp/^{>ij7p5P/TP2+M4Q)EOved7m|s]CZSX|im|T_V~CmZ7ztu&9m9LhP67C;EVap;d:r0#,(AuJ(ci*P.OtPb(R#YDQJgXnv3C}e;2qLO:V:2ts4fr=C=PVl4Oj*G}VCl6:BMnQ~+$#eL0y}5~L/TMJo#t7k<N8HJ[,`HWO"+%cdX|ewgi_6&$L]&>!!R%`&%DZ8p)]eZ>2wDrn]K&aX88*TV}I>p[fSy}i*Uf}ZWl>Zw2QUES=_s#2p:+h!EA%$GYlp)>BmG!9dIcSlT$^~Z>%ES%J}=@A}GqK?LwcdAmayBP!:3@k2G9Ky_jOM;(?6%>u&#=!D~(Y_>Z7we;q?5hmOZJp6U/+F/MmY,4X~,hB}~<)z+t>;xV#LN_#QZgk.N)aVN^."=0pwlh|occSH*d2R8[&VykhAg<u3M"zkxv"]Ix%|%?3I.P~t@*fC3HCBe~F7Nu4wg[7a>+o<?K.W,K{*_]<6VY,K&!keC8c=*Om+P%S<o4e[pt7_fF@XE%3yFZM!K}K[Fw?;B@*J0bn?V7>Ov!O%9#BCZWe|T$i_|2>4L?(w/7gule.5FLLUUUV~8$p+$p#`>1y0u|Ce^0Z`<buHr9t98"*Ma0CZ}AoZAN:n_MF6$w&@)qo>zg).1Sx~(zw@K6e,1Za#)oO?hbv0_e)ADts8AdSgn<2QJ(+uXu]6`.L1xY*HV#M5!:,J=[jcjZCMt>Q<?0#=h?dlr:71Vic0c/KH)hFYZ~5c>q/=iz>sK1?FShx5z&iQFeetoKH/>?l[j}0xh/:Y,[7oQs&mJ4=i9;Wk5A3i4`GmNi^vu]RsoCignXOYdM)O0{QGP9xr$>;6~]<qCaYk7qpx;2i[`;DB(nG*p+jc!Ovi[(Y{`)qVjZfo4u1Nb?tvGo+CMS[1hYqB/Nsm|MxKSr^PTEkS5.y}OW$cb#Q;wk$%f>tQ&LO)EZqJo}:wZW4770sOM*gAruIBy<qI)KwWNH>f$OGC??%LCSZ1d2vK,CsH)UwbpU&VLc;Q+]s1e_pU3pgljDXYH54,%+<[Q1KF{TR<[Fv,qu<N%;h.&bY>:ngX?WhtIG9u!X*jGV)ZE4y"2|sv.KE7*#lUOQY(Zr(kKgS{b:Mh8&+D?P;K^=&sfWPuE"1%62QdGxJoE1y*?&7(32|.SukZDf$He@ym0{TFRl1y4X%](rXcJEZoidS7FC{%7`lfZu*Qd"nGd2=2L6)ba6yFFT||uRIjBK@s85k3&<D8wY@05ep{ImRT(5T)sU/f.Ezf*<g7qPrp?xJhw{"")q]44:.rr5~V+moL_`q=JKd5*hQH~hzYYRDCA26=Wd1o3Z{A|F`"BA_28Wf,m5lDw?.wY/htfA$z!S%5F8vM"2puK[oa1+QJ1r[@l`yp#yQ$TuQ}}GI19jZValPlBaK;?C1yYs(REc`T:~1@gG>yyo@RQZ0}({1fN6+`^Uwj"7Q%W[=qZX;Hj}HnYmqr3f,MiPh86~_Vg,P9Ov/,8U9e%19_:#+{ng*QL27wC%a>fKLxm?/Vu`iP}[RnWHUD!P?skHOUgiFJ81l>TtU{.vhLiwDV^i4z_qJ(?{_Nm4Ye:2uVUe6=g&+/oD.Om=;[|}p"$"01;;sVK:B$=.W~)w#Fq38B^2NO.2BFzZ%O$auL$orqReV.5]rodf)7NtL*h<!Y+6o(t*3otO|5qvTt3zW#)[Y$0f3tv@P=t6cNaEMtZLSTRi(|,]{2&Ve3aY^;@Jk1(oW:+JQakN!)@`w(_SF#|SlMi0ewliG6SI3`mJRg{zX+e((70#x|R3(zr6gG*.]Y.P^lj=5fhdhJ.z$|Gsr9SL2=!s+5BSWhY_Lnc:s$=Gn~_dXkS8Z6elWtWs]=HenJKp0j4$TO[8>~VN)kVR2~:.zQ9{uYcXY/mBIEC/$L8T$FJ9N.6T<@;alPnm594@)me?{7dZS60n&WghTtN~}9!uK4;E7mV2t9~(({H!5Acw4KVo>b#T}yiQU&eJN!=Ou^p!GvZ|S;yGuTm]A1:2fk(J$T|jcZ!Ivu|[E1e)wwS,LHOC!{D^l76(8XbgBi);x~H})0Y,EK!t*g/uT5C~.}5!X#mN(>Ks=]Ct]7g57v}aqh6Io#FjxreUoDb=z@=dkI[q%O%$YKELfg@e@{vFNQ#(CC&JLLD@eHi%G{wKOAl1(brn]8D)UBXN7xw7Zal8Jud(wgp:$`?XeX]]`^Kq=G(;(gB+}tT^QC8khP8h?DRgP,@$I*,;d[g8z]h$`So@+vhc:OQ6Vip)6p$2e5Jy04i*._h3wqeCm&Pftx[<`je0m60C5n<?QoE%6s(Jo<a/bm9C?GYekk_gFBLZ#D8w)r",jY?uly+Y9%x/TY|55"9i96l,F@:TCw2,8YEdD@KVefm,j>bsos5uBXw$M!kDb_*:$;Tm0+~CluAQ%HjG4{k4Io^5g4^Egn*ReN>QadxCj"pD2}sIpxNPT>j8W,4y,]s3X7X|2<{=D_4U,epr_&$~?mKRAvel#4R*HsQ1F?OQUTXlpomCAw~7[pm6CQB3R#M0s6:y>n<JH5g3hGiR+w?wgsNpw_p/H}GwC0Y(Ou~@hAM!IY3NzoP&VkbXLy&!oAk~@VOzSmuR<~>}V}u8:*0^%R_BG*tq|BLDnwi+T/b<P?QE^3^M>px3Kw>qdBq6oRLV<>H2bV7a/XM!AE~9lHe:{3^P8qanW.,Z)gAF4GG!OoDTcI}=h*S%p;2NJmP8I}lU5l!jl==}yq#=iJ4^[jD$+,ELw3][xPD0Q@Cvh|@NdyivW0,o*q`r)3AbS4WV:=/fpoQkJ(@d?p^UDx~lZ&TE9egJ7T<Q+d[b:2k?L;Tcz2#bGjz#)xqi~ZsTV/]s4ke~#"OQz/=y"iQ7=c!;<T$M:a!NLN$S4^=xO7NcuA<VZ@6p+~p77wIHY/#R!fm[jiktS!_FpF=f`{n7%,IkYv#F~%`Kjp5*{#lpEW:6<2Gts?@/?GZz?O>4#JvXKKlpgslbk>zRMHeLXdEJ*Pn<u12Bu1$^u!1Gdq$q%L[FZ!!qTF#DtQ5{>s2tcqwg}CTJJF~Mw20NJ8<C+"KFF=HxQg)LL.m5@=3s,D?EytSMMsn%(#zYB!d2?Q^N9A$GwG!BNbe2n`?8hP`@)u?wH)Pc(i@Fr/BEccldS"9o19~/E![82,6$"XKUqL{oW:sjyS{>9n+&O/m9|}TZVn9bq`[8[fi.QESeKe^0,Z[6?*oO!%a4g*,RDACY1e@^N#B&,A(!9{NTDi/%Du@GZ&C.()P/.caZ6r9i,^g*{)>avAMiUycDU;7mu,L1rxpo6e6*ZW~1$a:VR!}K#X=[egX?tBdOK=0w;h!(<0}P^]&Fuu[IX_Mhl#US5V;F<"jjopDdRfljU}ZaIr(Bu;>/6kPFUpOUm9cNa7M6z{he3)naz3s+%JKwEc{BE)m1~wh;eLslNPjlr+7jH`VF(;t.gz~t1y2qU"SywqLmSZxt@Ct@:we+w"v"[zKZEV4/6V;.}}V:QFIc8LhP`u#+@{Y1l2{4i55H7apiOV:[q_<L<^K>),%v=9HyUCi`~Bh4Dv>4%Z<R~tcQ]68a#lJ:#]$5~8egdr}>:c4:_>@BuS8~_<mhT?PLKA^JKJ(r9/h8ic|md*$!;BcetM"Sj+u95^y32nkiDrXj&_l`B~*DkN9F0SKCc"&OFUu~I6,iGPRf(khy^{|=5KQ*"bV2I@2DWjd[L7=tBCQ+oYMLMdtPe/Ua%h+"5V>`5Dj/bj.AW_6?%rX$z*]eGb2ocywd"mI;Xa+*k7X,W!C8l{Dc_pC?nTGoSX/;`1oEUDjZt^ZkULBj|Ub#{G^9S]3zdNSyZM2iN:%q=DH8f>b3j1m)SYTg=*0KbKest{e5q6~aqYC4"F<~D;X6(6*:Tx>d;jBgq:G1XJJB(n{<3dyY/?uYSz[(}%En[$X?q9fGBCI[$OG;M7vCF=TTBTRu,Y=v!E?+KJ0^ii||(!2QW6nFc?aewrL058G0=?F2[181<,^PA~$:l%3Z&9LR;ZQP[h.FJ5zay"2jd`>>xwd1n>GQR+$iNM={*`Efj^az:w=HFwDo21YR~Kx7y"a}Z))wo@6%4RVMf^g~&9R)q~lfYMpHX8|x20$mKqC:^sc.yehB.`y:*u.8ml8bslC+:4Bt%[uWnHztyn;%h>Ep_>pskX8qFNo!c|e^&jVMrXj%G!})jc@uOx;E7oK>2OEaSRBR=ln=?8yD4Jb:pVt%C%:@#p|:1w:G2KK2npuaBR`E=E6:%?.`x6=AcvGz.$fi?Z9ZC)&|3jh;`bQDIUieFi4A53<Q+E~=;"Pz<+<qvhV6kOZ<>]k[h$r~)s7r7rfbBOjLgXZI[xvN>H?[)>zdDn!Ufg$@XKQg2{Nxt}$2:*P_*GeFWtt.*f`3AdMpcE<)wDL5MteP9(>fWRX=,ZY~"hwER`oJQ?MebXB/]5!avwjxMk0}_4i~J)=+"r&^yKGMG5GRMA[%V[gVkZtTI4jc|TC0#0s`mGG<.[D^kp(ST@EuVTGgd{Rhwey}utmH(nW%IAmBDvN^81KwTJxra1/RGm_tMQBvv9TnSMIRBt4xQ6q1;fSs}9n;YG3/Sks1/KYTDz1*>_DK^*{gh5t1s}0iK$G)G_gmRfx12q2IQ^^2RN*fPr_=gd[to?DjOh/x(+v:3;^#kF*e845c1S`0%a[/8ALsxGPNySWbcz/Bs}WgznmdLX&gx&:58_2:>5A4&*Pj2NV2+UYrJWGy2.l=T@gDelc+:!>BIA1z$Zn|inD*853m,_CMa1)!$^8lr<7IV2gajH1>!#[>LQv3U~,@C05g}89j82I`e8`2D6Mx;&4Tq>&a)jLD>q2f;JG8:[SAMj6W]FDb"!deN7&?g<JAoR,^5Ij,Q&V%]KYnveQSS4s;`~X+d#qExX]9M`f9Ea0amwf[#0o`C=)i}3gETnyt1RVvzG=DPl!@r~QZW$m3QZM/+mK0~,:Od!6d|>`m%^J%)]bOB2D{>MMzI&X9}@3kgJB,y$b|Mfbn"dFUdqbL2_pHgHMd0sU1VYH8x7^EO|BKkHZVfGA)e.wYA#[TNy`Xm3G!E2GGqnnxeFQs+nd,#Y]?H/aWM:!77lY&fCda]N/HKAuofnu+d$w%5$g&xCc7lrHF"tRo{PRX{fha;@,h/Sj<mrnD>%QQa44)fUaj"`|t#TOba?Y^;"6iHSfQ=aO,3JlOjJNJC2Sn7cf`ZI)*4cl,)Gq*WaL|8K]ACrt(}HQb,A"%[a`9l2:`tD[~[8cEMQvx~M>eCtl$R)=OetVok8S7w6ip:8s)B9^9auKUY&UKtQZx`#xSr`0$6v?S#?10#^^Uf=u7xiO!c(FRg6TS@E.j+Yd]:xIg>JxYia4YZ(E;!S_[LZJz)qJi#f<_}TFA]?Gt?w,Li:V&2xB6Re40:1m#;kbXW^(NY_y(nyaU?8R`Ev<OeOBeo,O#d8}7K"[+@y!dIgNH@6ViNaPV/MESJXdE=I~GyCezN8ZYM~PNZtxO)+YTC{SjEpn3)l($aLe/!]wO.uSBH.#!N9Y1|>!;SVFkb"mwFf0WEf{6@3TEu,%HPI:0VkB^(C(Gw0/2qr9_D<|D%KxC/6G9Z*BE}le`:VF6,(/8NDG>+g71V#WxBU.q*PMJ^;WT(IO&lZZ4#`YrN$crOgS$sXk6eGo4YT;}o<Uk&i{@^nI0VB;MkB>!V_^iUNa&"]`"&l4osA>)uGyastOx(0z|>Chqm{o$}+7lHL/&>%r,LMabrSbqQ!ct(g3xuuv)pB%Sm`J7f#FH?EZ_u2Q,2^Uw~0v:pj_iwlPez(J(n]GB1/Tol:|}q7<;f8~Yqa^30Z6NJOdq)d~OlY%bYm;r>gvn$6:@!3).a[]T[0pfU:]oxwzeQn2>w7Zjq>RY*f~bp>VuUPK^1bdJ#p(;U*dpfXolx$C:f3zkRUGSh!47i_XTe[;+t=^%n3Zzv>a7GhE)yqSM_Wvq7AERU8bEHk|*0XmP8u|<u>Ik/MG0m4=>{H}k0Kj4Aan$N6[a9nS=v9d"DpX&i@uXJ9RwwVQrH2y0]1DaM4d8c+<CvQx:=L!)Llmc.IH}D65hJ;YPujR"PI/Mr9sAOSd=Lohu"YAYaCW/EIBVgWZJe5YJ>Dlpt_y_0Q013u;?@X&hqjDG@v3.Tgz/05{HdG?dLlioJ`E/:G?2cCEWB)`XL$0m~{N&uwW|ir{y]FE$Tc*8qYzTGc|>O^(4<&Vn;07*ZsBY}7~3y7Y%<Na(BFPe8ulud_=X?OW4t[a7fvSp}DS>|F{&GKjuBWFOjbFR.(w1SW;Zf?k[,"o_zs^)9qy!Z+%]Zj,TnkqGhH^O4XK[fFPRBSL~G8*CE0Mrd4M>.%.86dO1ezOUQV:)7fv]I^_!z,.SFa13wJb:mpqwB@$8;}&DlIrWGQWL?P6<(Tq)i__E#fICnw^}Dy[,s(DbW;%@cpuxcNstiKh:/Gh4m!MwfCm`M[gmaaDRO[X:JD!j,jki{h61Q1frMCO5=b2tN[fk^"(|H>TA_k``Qb8kGW66Ah^s[uJ<IP3i60ipQ`.`xeP*cbebG%Q<RtN3.51e7FV@lyDa!xgRl~ekAg"aIyFqeA7XXm.+,;z^`(UBX5L6X&]x"QsUoLQnMGvp#HUAf?PyCEh;NL(*Hr`T7LlYX:i`ZJ;XhVf7}{![@N5U9L*4_3^.HlbVFhc#yQ:F)4+P?%6<}(?/xFj,cr"`LcWwK[V>Q@Ubf/0WQbUpV2F@!@$kNVVN`PMflPfH$U]JMs99D6=B/ay(SQ7Om})>/?I@/UUR#t)&8$MXE07"C!.,xO:k{[m,^ZNY1+S4lu_A$kfI,jMll?)"@0$8Dq{helDeT?K|;|ewGTeiT$e$jdYKfUdl@vgg!l<)0h#+Ka>H/baUv.!~1{aCZ`q92A6;Y.k$aNyd$iwPp>l}qjc@DP7#vpzk`r39c4a0oa<P8X0?h_?!#W9etzZl,n>Yr~jXVD~aUO&Rj<"iBUptztLBWM)zcjX6QQ|?X@y`i"6SNeG+B=y6#^$Iz5A^I+)$SGpEFuLpUxx58!!4r%=wg.Dx$IxHYG$RGT{Jw8""JGW+OL(nR^@(aSiAcA_(f3@56D8&7xom9(#?vQh.3L}u3@7AvC%]6(yA_[[JC4Q^Mx263ore+Y!HfSsh6>HTf1L+ju_jc:?ZaD0d5dK<rlA^ivJ%Ua5f*&6RZ_S7nJRV]kqHNVU4qz|QT!p`W2$odIumkc<DmE,4)I}c:k=kiU_c^uLm2ABckU[@G(c=|*(%@yYo$T*z=2O,/^v?m~1dePMBCDE8seES8Wpwn~ROl=ofFhCEx+VVJ36tm{K6kAa`hFDG_#jbS*Vo}3cC3}&eEyP*Cpu9qZ?H#$gag6af5C|CdAQr#>RawyObM=koZcUtEu>6q<8hY|;[Rn!Ki$fbG:b"p@?UcsoJkru[gykNU/rj@b"Qc0]<2~$Qo9Tk{Wq%&SaRwqa!4/[,bA)uf=a:?ki4I,YA$A74mc?fltsyd}L6[oOnDK$y^]P?Y~?(i&uSjqZd,]9ZKEw#h8sw6DX6TO2;2A(N,}<Bb#6A$m,[4{V2Fz&5QTI)pAMjXr(%a*Q#<I/1b4Qo}oN(ew`h7m+iWY%tQ*R3jsy#Fr9v}F3trRW/[UPCOx;V(YQl:zY).R$.U*Vec*)[~zE9]YKf"Q4Orf}q&FPfU!]9Lr&EgUx&N_H!HJeB&63<[U]1[qiTY>Z_CmweeTT]go6)*l8#c*6FAcM]G3nM!+sea5yqH6N%Yiy>Kg%6_z[#A>_uM%)M[mB(tgx3ZY[=B8y[@$0J4lp3k,:@M0Zr4^LI;}|Om0_{Xye)Q5|1UBfpNcWMCfqH5RJe[o5(!m:o:mK!8Vd9VKnyg;i]Ul[AZVa@*>Bu[5]<rUZjmgQxsL|0O?E%iTAb,U/nDA@Nc|r0HpV&>{vh9!oj|{>o82SH)Q"*xMly];X)jzIcS&c0PSm:]d8y|6!,bS;wp,?($]g9P9}z*FnmOSIC)TKjS+in+&Vq;/Cx0C{L20j2eB(iw?2=ukU!I1w9d*m3Ni{@5*0;LtN$5c+~v2i"9ckZ6!={%r!/p4*"K13s|}%XOh/;B31rRs~T`T|.`SNT~1WsUY([n$opR>U7}%&N_.dD]=,`P|_XtCqQs}+Vv~txk3ZZ@Z{DzA!HO/0(mdW236C1l2]zXhs?@GJL9!!s]J3I,?<FlYivUw9ew"]B*}f!JdN?InzQ~ZOT7X`@k!EG_+C6OIO^D{C])6oNAM$oJAOMo]tCl?U>Lhu9NIf3#?$F]zh?dt)0)7g+@Lm;#!BZ7hEwu}K/]SVaKS8e2H!nm3qM4jL}!3X+E>pvDak}#a3:4)b(f6Pg}u/~<:`1ve#N,hiRJ:zK1F6HB]G_DOie/4yb#xjjH#OZe$k)9#Zy@RWtQBGA6u0P1W1ZD*9}(99sXW=p#YXy?rEM50<g_L1K4"qNmFEGw<)82%#`IwaxV3eCTyk7AggIn;YR$,DlxeDAYWsUo3GWE|DTKgcb$ZR``SJ)!V|)Tfr^|UEQ{k`HQ{1}5k1k4kd&!5%X!*Obv5A$++;gtIzuq)$!4Wxzz1I`SrTeYGBTae>@*sQe~l4d|qtGUJY`QE$mbh*5tYaPl?Hps1|n`v|=hkX>FG?<2]q>MAQ8:?,RoIbH;J1x=ZqX;OEjv*LxpKu6dBXx?4~vCd(,Ct{z0UsNpdHu(__&U^];lVIcfiXJNR9ca@TsiwkL#^mTiJUXw}*u(%uWlE|H$t}%(Pc<UH!7Rg=|HwdXo"&9[h[j|d4o%*k`(w]f&u{fq]yV4:eECKOf&35MEKNEf{g8ct3GoQcToq|Wq:=>7I^i$CYSm$=ve<G]G|)>/wtiw=t?pEw/[",LoK!^0GTKfy9ORWfeL6+wNBh~pIV$_2`5lu3gXfG?utr}W~@M~|nn;v/sL]=JIZ_8I}~);.Z+2~ZoU,MS%yJA&O*BC+1)SE;R?bSjqTX2s/k&NE?d4JY>;Kg[cH[R/%83[N0uqM4.dP8v+xiNr?#O&kjm1zwrpzc&cHh~@p2qL?aNEoD8LmS$@64#LhD79ZID@6)u~dZAk]TYGP&o!BTzT}MqIBiaDeq<`p2A%.Gmov[#t"V::HRWQ]ND0@6#|:;KhA/rR=T!daC]iw[1@1["qnqdf+DnG_r7,u&.0sOh:KR,I01+wr"jqb|H[B^{`Z,w2@9C4Hj^H`<]RpGkd>DEoBsG{(ihYJ{L/]:1j,8&I8MM~9F6g/k{rf4mf&Df&wqABMZ[QH}|Qxw#TYc5p5!RtA{h++5&J0!r0@e_<nz::p|X7ZIN&B.kcV9$v7X`v9Q.bv(k%hl9+ALT1`l^<WY~_4obn.o40qGir>?8DOR"^h+mr)Vzq8E[*AJ;U<3b/N3C^}+gLN)Wo|_|_*g<(k]mo+3?p0K}^BOHJ(p/jAHp;l7O$/(hGz*10B)"UGbAO[yr=)T0s?ughhO+On#(*!/b7}<GLX"`yZ?eRab(&d.y{(i$SZ?wYA3A4~?v3fW$UVTz71<1c*])dAt^ErO[Tu[T@$U`=lp9T:MW0&^kWij)~L+`.+c(Vk>N%UAA|_%%AY%Cwzj(cP&NyAv"isseD%FM@U/U$Mh,0O?43370w2lGsB!@4Te~Q[L5/F0i.SIleuR.SVtZak9xldHIGPRK/67)!=i{a/$9r=g8PB6vQv|oZQpo6!M+$vR|K]b4Trw[,kz+Dn<V3VOx_~EPkO#U11f^CAikhioj`9xBnH&W~7UL8EsX]$h|8V4Oq|$Cv3&8y,UUsAw_a?Pq1|4FQBPjUg;_<ELkwu,]+(`*4bJZ0pQrvl|AKlZbWZOYt%O9u(3q4riSTp3(k~O=4S#qLvr(|d[c#ZF|;A=}><l`+Wu!X|f_LEw5cPA!V`e:xO|%]rkS.Pp{!90dfsP(`>@SwMxu*+zvWXOqY;+"na5DCY5{<ADX@/wsTrl%>?Ibxo)GJM5"4FMHy<F9xLkkIx)EgN4lQXP4*J#Bf9brU3doG&tp00_<C0Q(md96UOuOFI~k<]EK?Rd4yDaUHclE&SwX`>&;>[^(Jf7Z#:ZG*1<=Wn8w3a_tGfP:bX{D=vR#=4dGnax2,UB>6I]7yv7$p=f{HHbz+hS/?N*kx;yofR>Q9YCqX&2qX/)AV|mXK9bf9<vD+V*2pQ<5KN<cF5hOOB{(gG&)3sOa7^W8C/,A>_4i!JFr`~)r|Z&}G/E`.4W_JNarw|i^^NT0O~Ovx^u{a#3Nir@nkpjOwRg$`i@pA4Uj"V*49"nF_b8#3fJ/D?2#HD};Rqw:i2b%ovv+1+?;oqkuOB=G?T5h8606Ia>eh#_Gc&!"!lxoaiB]!&j!G94<G(.@)YIoH%_(vC5@>.~w|^E:X6NrEHLFKqv?H;^|~_50YW`b>XcvO0272pG}TSYUM`D#<Fv&F]aSJYd,buIS7OuS)"WwU5dsFGLq~SEgg1Y1FrI"D9Zpw!Jky2;+EDyTGbDpuRM9#IDdlyv,,uGUz@RllulN~4+Rv0m%nAmNi}[a`ImHbU04Y2:@^z(eDWCO4Ni.>yJu#07GaL)kgq=)?)"lgQ=uAzn([R!*UHqn7yb;LiXTos@Yxj&.H}WXe$e)A=,:iF23Ffg?N_C$B&{BGQ$gQ6DpF?aN*SFtBCJ+))i]q4:/3[M3UFTr@fxSrYO,|#lxc*uu[8vn"/Gypo^9[fmvV_tY@t,0`T$z_!(+,bccQyCy//ryCoHJr:&NuC(~A}$.kc3"8(Vc}eBJ6V+,TOf6W(FC8X16&1e_Xb%G)nWghWBkkf)}J%;YSll9|%1Ewn{"a>F8E)Ty}.te`S%#]u`XMrg,,0:}~:@|zIr.%h7H69KQvLV4gTE%0ZVsKSj=;gJdkGwavkVbxszpUvwT7?oJ*lRfssNN;>|?!SagWT|U78{Mk6X(SV)1<,}:_>DWS|4.2@T^<LX.D%me#!_`*E%$ak<YJlC7Mo?9&ZM!&_HhK<y6`tce=&MvAucC(wtw>KUnuPqny`h92;Z8wYOBTn!Y~r#&]cd3omde"gOj8l&MWfl9bf@Gp^x3D68fj&(v8|v?CCfZ3IHV5Tuf,;ShEVTfm.z2wK;)O:)/B#YZ/H2(;P{Ht%<YyE;H/QvCaB/gcZc%gk:9S:VZO&.c$O|mRr@=wo_Qd7=M^;LEw{rKwVWpfCf8YfpR(qJ+U%Z^m3$yLr542b587&QYDgjs=VlS:dJ[li^o9}+QKk]GeY#lqdcbas@V=rO/+0I+6w^*[Z_uatnVO_AZe9;y^T6$I;G1&%8g<xnO)u+>|$o`TE6{=nck]+pD{[xhBf$UVsY%%U.c9,qj[lN^S!KUhdSc8OkCZq=.ZPDBf(z0gO3.0%_%m0T/(b!4L*Km[#r=~D%[Te/xDn|eRjFXi7H*TznlK]GZbSnUPeZupU51kVE8{1MhH~U!J<G>Jaq..@SJYUcwC<yP)I_$[dcy$(peWjC57=iPz:my@U?tP;;q]r<%dKwH96y}o<Wkb=RvXSIQ!?e]N&KQDcS!)gy[ynaQP)2abJHxR&q1rZ(/M(+iN+fkPEF?+:iPW5?`@Rw0a2KDF;pyJ@(&Hv}H<EDu!$z.}Mc,Zfi0+/`*U5@+,m2GY6xE{G"#,gP*Wi%}MaW=+(H}~Q8TgUZ.5CiGL5uQ=e8QxC4/`lpnHj(F6{H_0y4i/%#*v_MdUK6M8x;d2Q(]q.vo:$0ukks!Z4f7(GhKG;jw`q,,evq^MKHOyPnLxaL!]o?gSyF%(fc~YjeE,>WBE5=kpXcSf{Am2+U{73zV_U3OkG^e*fYaA=v`ICz"Z#L2b/_!EWNe)$nSP2#;Xy#rX}JFYFcCa,dg]5z]ScehG.4aNU{/enNVm;;.5@CBG(iW]Lgw~Q`WKPSmhe4M$wV}ZJ[+tIc|B~_qdD8,X%[mAUp/fV>r+Q!Z~8p3;.@c#gizien;O]s)m+FuTF4U".obyq&QeiD%z5IO}QR;*oi$w*6vB#gc*io9]x<yTW4M_u&$h{cDvA}^+<c_zTnSz_/FEIh.2!=KI]FWdb&f$u5gP&I{a{OXK6pzK]x[ndqk,i<Djq3@*D,$Vtcf!g/B&mAQ`{K>ZzVAPYva9}0k3Zq"3YqZeog=|x/eQ_MU%jlPgKCg!t^Pl=tJE{Y?uNnVc%d3=,()3TWf3CkVgb%mD5ZW;f3%,,Gq:6j`8seQtU_Qb!8d>k*Gk!tldmMZc8wb;*Q8(g/.V.3xoSRXOuX#V)S4Y_PEOxeiLM@Hou*jUo^I^VC%?`B_L{y]4$U4WA?E%TWe.RrO)>P1IM>)!30g$EmfUSmFB0vsKh}A/ZUf.n%[_fPGMDY!~h&A4(HUkKb*Iw`?v_CPuWqLbs3w&itJuY].FC~t7:zcmJiXdv%iMpNA"74F.j"0tQUkUFlbQA0M"DaZm9Lg=[F<RL[1vgcamkGRjimXjbu^c}M*P~ZElPe:afkZ98Eh3f!NRhGZ.A,EMkg.NKKl,Yj]NiSS+(=jaWe9S!OJ@]T97r(MGg2d&z:N3RfL<|*h!.7*5CH_2L>des,<LA:a]Gni(Ae~?}7{""[Y84i2)hh_[SSnVJGqB},bxh>"VXN,"iyLDeoIc3Zd3CSk,8."umucxLNj]$J[.4{k&*M~UeGJd}!ZHlUo@u!.oRda@5dp8FtTiu)a<`*%/&Q<8t7_5`QC777xv!26o!,C2>xQtqOVo$uJoTNF6&2;v[mH$K_[%4)&.cjoP5[6nP@t[zKOlK%XE)Roc7TOp3^|?$gj4`kuNX`%J]C"q[aXT%|/k_~xP%{M/m}6[X8HIz3{3k+R%DnEOP{1GYL]6UJYMKqJ~$pE`"T1j+4V#x^.6+0jie&!M?mKx6|{=vFUF+p5{LI2mm>>[]F>AV;dIp<sN(*3q4z{k}jRiHv#5kfT|u(~^BXY.7sO;1=9IN;GdTX*0/]}J$i/(XR<xZ!R.1uNr:}<7ZQb2MTpE{ij|9UpKex6Bw+ReE9afwxDMh+#z!V5*8~I!dM0ypBT)"w}eiB;pMK&azsUi1rhM(@%CK+C@w@vxUm8`SbMwgb)LT?|kL^nr"$SQ0cG7}W.C(3USYV]G:O6N}.gZk_<G3rM"7[Xx/#=AHO|YeA{G$e8RQ@>vWSqGgOp{0[%]b)~|ncqW4=6@%:=p&sD_4H#f7Iv/~6.pO>*KFssHxK;+j^x!nG?<_*wr)0;s#.b;[^ledDEw|9&7qL}@zk7Dt0*sd1m]txNg2tHv|~s?+d$lEQ~4L9g>hN#l5qCn#9U<vGq_vJdHj7kZQ,+1B14]JV:>}&!Fvu)|7m;WTiy~!1?xdvZ,SopYTi5IX90ZQU`M#PuPpoUQZ1XpciMIyn50)/},|T@]CbwC"~[PD83T3g>z5?[<%Yvfy)JBI|L=O0_{jJ^(r|:Ei$0vSvEFT:"a8D&3Q#cnD$Img[<##O<`J^Zq6bDNFD&/[Q22[mw:H_"o*e0sSH_EJ7.Liue.hkm1S)NJ+~:!)v)2N%Q4L<X?/|,DH;>w$1@_3xUYq4tp=?I(?4okJF>KiA74#o,a#3T`$#e&|#>M)t!H15pZrmQHvis0n]V94`Rhn<93=p2J})7m~yKC&d;328_v]K0lTlSsZyc[f?8|&Y9xaPo,&&%SXM>E<2E%+qhjbmD^cWclP][p"<|9$io{*y)KJ|h(I{DL3]zlowGbqG4^kBv6pT666;Ok,O?ktqSKk/BCU_zp{q9azMX7y^nev|g(T^]lu#AHoeZTtfR"*i=f$q*f}X}4euNCKKg4U;0|p!~R="K8^rxqoey3T1$/bK]M@#wLKUJXWPp#VP$|J?gt8VPj0;i=gxSX!QR(M#n~]iO#LXR8l3+;?yiffaLT[7#3lU^P*WdevD0kyw=Qvw)H=9<{GCtS1[YT.@NNE?5[tBOt%""ZQV7JT!H6qQlmNO2<u4Fei:"c{2X}~P`x38Gd*Zbo%zwS^23KuIPNdL=HuH]ACoza:b[~"8z`VTJ>k4a%]D._Va~hRK)1&7lv.Q1QC)H,5BYUMVb~sU>zujP/.&v03Z!+PpXtt(nrQhkv?lphktWTbE2~B]7T<Ens&iQ],a=fDW.Cv<(6fWU#Ph*PMce)N=>DP4]!9EW)}e?~R|xb6>X_jNQ4G:*=CVVc53{+pF9,&lGuXiJ#X[44)v6MxJat"gSLyQ{u91RO@LoYI!6v;QbK~5{|"k*1d8m#~aft#hWI9eQ7v1ig(L:mKkwbeV^JbF/?6iwVVfF=&hJ|Ju6LGK*0o_h*^YW~,M1}+>Y4u`I5#N?/abr^hX/,qDUF4{;WB#[)*o(U5kj_c`hRn<`Yr}@C%Vu1IJu],^e7Mn#E|$W;rBC/=BV_[,%2RbD[Di?G*N?9+pCaF(F=UeIv@>D!&fisH14h<.o%j/|e@mw8wd29n^XN?=[N3;P~a=c[~+e8P&en>,a?T1KCxV3XY=R=x=WF{/Hou3;4bT]vT{Q#W6J`ZV90PV?zE~^M%uoG|~Gxe|R~Dsa8HKP*DBDuQS41vch8n1zSzXaRL[b48HR.u?v{mBrW{ZXn&kM?Q#dG[Xs]Lwyc^!3+;j@gT&<]i}"aa%|6n5{j*%6`$?G.3#0=dE:L=Rle[eRje#bXxXc6{7Qru^_^D/~|Z~.6$rbPA^`A<al!|DK/ixX*18;`HZ%]tx*Ty)@t&I@L*>XlCZm*>jp690n8bu8bXJhegu;.1:u+e?!WcI.7~i?+jLCJ!}#E^4ZdG_igMZfm[;oW$!@79H6d*Q=Mo3Z<HU8i@_"TbI5P:T;eo9A&E^)$DJ3{0(4k;m6CB|fC2"%S?C81!E{+P2OG}gI14}=R`bj.8|B([Va.}c7PspsBShap/63OJ!b!f0#4Uz{S?wbdgO0EeAK=fA>WQ1K()kH9<qyv>Wf53Wf_,Zhog4OdRz6pSd~Z+pV,<fp)MajNy:J"us3yUr]4egX9{`IliCqm.fr2VSVqGe=p4F!f.8ZpinFzVX)hF*B}poNm[.D4TO+VuE61LMS`SuZ.k3RE!F*Tn4g}C_Aemm:!>Z94{{l<2ae/]q?$([z!uaG*z$.hl$bYbiB8#7V.$Cc<kBx]]ZieJ,BB.TeC]:@IY0CSiv~.Pvh])v_i{/_GdCF"|1>J}^7Zk:9!6Bs]NB"6Kfo68B32`8IGdX|EiBUgpZW%]}b~7x~xAy:~h4u,,s0Z/%aMk~n!OIQ/X(EH51sULum"9hKBP[NEHG,;Du|W[wjNZk[=`vKwQyaD:tAQ0vtR"3MFvzpZAi?dK&!smylJ+K`"Y$/;dwlK/bU|.q>S6dgjoKI*Gi+OWhSq^m}rSi<18Uh#<(Q0Z[jI?|}>)EqV($a3zkGdoZQD*zibz|?5Y0Zwnf`6b}_8I89E[@gmFXCr8Vs4E$sf_!sv;CT{F6Hdct+68CD_X7KirqGMHm<w?*LF=0;iyX`Fke^Yp0XFXTIF3>Y[=BJ2DAd0VxlhJM}%[B#ycSk3L|tgzoCjle,d9[d9j,q{[H~(9/M9a5D$7(?6RB8%WPP]97Ax<l>E|,aO~j"d2=pud:]~%Meh$Jc==3Ws"o&L$sp`8yD36^{RaBXke[AZAE`KIyrJ7&qx,_ijGx%mo%/Tm08}Rp3kyJ.zRbuz}bHZZG!Yc*3/Ix?FSceL=8vZd*B$^L|uB#[QBI2=H1o3[oABw@NA.<Xl/Vc#fllM9]V~;Vn=PMZloL05A/O%.Yqp1]_gS}<:QBt?{DbY@rPH$oT^#&][TYFw5yIeE{{R6?b|a}`95^Dj=y9p]=vyU^0*t3xOzPDK[i;{*wgP^Uc<B8~nMe!J7du^rB%+Qu4~}f}=E4O06jHQpmI4P3t:=vvYJ?h5[G^8m]SDaVDM(F~T51g<Jr(=KD:Q/xM,XUf=D#@f+Xn3q1@.l{e*(f7|:eD;,2QvD0"IP#}G|/OMaeVQCC@cXb1%&ZD9!cpa"Nm}AipzM6Wzb^6mvnr|.Wa7BXq4{3WBmWqy!G*Jnt_d=otjdzix5f:!ui"9elo@5Mo^M&9gg5&Loo.k`vImQG1%YQT>3D%FaCL9<_zwq2S3RW&`4au7+xb@_;aPP0V/aEXDD9Venp@csfvhXsOf=)mvo@>z*&|NV.8.nha05p{Q}po|X??r{7}&+F8E3fNtvRfD]hsp>T}3ILk?<>I_cRQ(g%D$}GyX+P{//<ozVG2[9nxhTI0Tsw{)lE:r[!N,G|PBeY$x9WQoXj{bZz;d~$Qv~2h[4/i%xP?G_tj_Y09Nu<fG"yMg"C7_Rr5Eip0nkf_9(T&kuZf<:0]!!Z?WC|/^&Jvz^iJQ}kLNW"Vq&WZ/piTpG*VAa?9bb%*@;6Syl^7TuG!Z29?*JN"`l"T`#VJiD$zoU:szpM9a@=^wf?YKFG1Jq?U"{Hd,/Sd`l,~,}IRfU=<%{dpI4BIl"&/AlwXo7d4mAk:d=BUn~qXyL(](byBpaG3pz.mutB+$a3NL|iKRg~<0Qs#3~HXw9QZ1~RQiOv<@JxJokTnyqi:(_c<~)MQp*nsl,XIo:]*0ujeqx8[qp>0Eh;iSbv5J5(:O+kUv>*f<o<[lbNWJOXjL*Pov}Tf$+Mg{<|XY+xtl;2t=KV|+<M8vwXRqVFM9G8_scv=4HkuyuL#gp.@<3ovACxC28YHnHlLYV]b<I#jd"n6>bXtQ_^6??#}_xe.fY#t,=UVy~)?ZF#)/#Xx[vlp%Zh;Z>}&ekY>zoGAu28?xnPU[hlu/~TKTf96Wab1=VzN+c^TeMtYd:%!:nn)^otk!IufJ0?mgC}(56UxeoG&z.!&2D:hM{C**qSjG&Q&:AXh13.R~_eFmB9z`P&;LlLD*FY|>tJ.{{U)J*[[1J`L%5APbzPQc@qizx88<;W0G]M71eygj26>XX4o>ad$$1Biy?78C`LZ/:Yp7NynEfx>lldHY0l8u{k#g^d>W+B@{b1k/.)$Zs^uWmhkP|W(IOY4Euz/h1fJkz~q+{IRApF;vER[~jRd_>A!Cqkqn.Si>Bz$/60QqOSqru7wC#O=w)>?S|+j36M*(}6vtK%J,J"~h5Y+g`*w{AsC}(_98yOBcI6S}EU.*k`hQGjAjXm;Xb9~Y&#m"Okb4fG`)_h6~}j:YCOd`eVgvVHi}}s!OwzP|z:+`1~$?<z=5#S67i!RM>%CWo4N~bMzHH}?4@}$KoerzY,dxYO(M<PFb2M>SWy8@TOB<90!."BB@lbooF|`|D<XLB!8(G00}cvuG2>{?z{.%jq6SIApDX"L+Dk{GGeUgG/bQ6!KJi|=J|DOMKY!t)WG!$NT0j|f0(z4(wd7kN:jGt{VCJ)x|66m6^WhNmy!:sIZ39aH,GPB,:ui)Tc]s5I^EU:o?*>NMtSe+{s3~F<uqlKFp`5MQR~kq07qJ?z3`fmO|~<8vfgbd`G[1M0cf+$~o}b(nMrC:)ne%9gHKHq}05t}[CW6U$1wpEzU9t15tEQ55L_HYdvd1f8Rpt)xE6<&*[^Q]D+bC80OPU&+f_<PvS!]YmtYwH*?<w4Xd<;PS|=MM#Y<z^5]r*AeF.pQD}=xo6i@wTNFX)IX.J.9K6OsZ<7bGTxt_*ZH+cUz~#Dq`Z/KUAn{#0.FV!#NpmiRKo"A$ESzno}^s+G@ZF!~[1{r_8a5c2aKX]#?4|^$imeC_SAK~{[p0A2HHoO~c}5ZmB+;/J)~bmzlfR>_Zpt87K.b4aU7L8Dn}.r1ukPS1ks1~xz)5OHs[7h]{.cV!kYxGQ_/d.a/[PYMttZu!,pSh|>.jafnT~lXj`YYhhsgBC!xSZ6hJ_0?p=i8.#qAWYAMfepdNOo8wm)uwV<=ef_Z$t&]+bTCyly)p5Bg=6~p*Z.)MlcanR3fTqjys>Zy_vZySVDF!Wi_Bs3cX@&p*G:.r_Jccoh#2OoxX/G.>:AV$RB/Wh*i#WmrPUQv{^`p@nyn;oOJEwr2|aR7mp%Zy&Y"Nx7r#._>{8$Po+;)R)lFUySZj3x,:88I63.Fe{),,QYDa#P#Hs~%E#&r9aHvkClv9/&YR<L9S?;]e8&IMc$:ly}@1#*ygah^`zDwvAqET$vimF0D$Lr"bVvUa@[I/U>Npt70d9$S(pZy8NW}.y*&qzT{vE;u5h^!8(!M(#UxR6!YKNUIe|aM^*{`CJBXN!&r57`lsy"S@~9hh<j]1+(5dKq9XI:o$sGh~)38kD{^KZB:47?B71puYf<CiILd;<jyda4.8IjMv%NP^>>ya@tXBin<FsNlM_OMa%1|$SKS{j;3G!i={C.rr(+$UA69;ziWG>2$(9/O0ogZ}4ntgIr72wTjtEj15g&R%jVyDspGF^0w.RW:q5dH)wPut0d#p.,CJ<yM/}+7MPHU83#:F&2OaIC*}R7x1?8#fJP(]HYm~%N/v.?R4&+DH7[x.4dw|7JQ?A4BOFj0@xGx|!YsEmEa,.?po]rC8dL$3zDM&%M6IU)G0u)X^(WAuYqTtICF]=waptgxJHiZ/[kL>2NNp1STMPp3)sNZbGX5.HvZO%e~:V^s;(B.GqsNp*d>TYdC~|^Ii#ws8kPsd]]5:m}i@G#^eLL.{<HHKJsv8E+$pBtNA";fA]9GQ!`0b7yH*u}xY.=4su#Nyg!T2mK%]wplb{$O9)0L<Rg_Xt702Q|4w$)yI6DbLwar@9`z58w=CX&n!cJV28JE9/T>Ta_cClG[_#JF.e%KSksHp0gtP)L^4Ip~9#{fI~[w*/S_y2U(8$2y<ZC;|_/Fw7DFoD[WV19ewU[r^UF;uJV9DsD;9S!r3^NnuWNnC8|Z2;^.0jQ6oqF^n!cIUp:62=m08/K{)l;u._?L#2ro"q_@k(J9mFbLT%mdLE2vqcv~W{*5tnpx<1&ubz|e]WaSQvxf!^zinXX^Vc}Z~rcT/S{*c*})&8oV1WCE_}HPmJ|DO@|Ut1a59d_mC:g<3p9D%4@,$NQxkETNBJUt[8)fkg]^IKFhMB[qb,gmOLyd^iUyboER2F/X9R_}S_SMmP;]+m=2UCyi99~B"Wydr|}/&Rn{o(?xF};x0NW:,<>3?rD2.+^vp`kGe<S@n`9e3qZ3Pex.Ix1pd&dN&+>@5,nhU4<$xW!)J@ERcLgZ?xVjeeVSo7t4}qeW"Xq3|4JX;Pfpq{TQUz^WVJu@R;8}]t:eZA;(I>fa@/V]<oWEAAK0}X6EMG?$UIBDc!1xc(r<_<B#Ik.6B:/5)gjvB2HWD~qksImt2>Oqcj5}zbi$%9_5C_Wdt_x<ns#.e36c9gy!8Ri3!tbgi.}~}fnJkq[Y}?3#7p@#Cw":.~01D2Ih8Cy1hh${q4FPYYq;bMF>SCGQdT71lJ1hfo([S$!~VB+nCli!=o]i;E@]2rM[p$OiZsO5,2t#D333knTc*9egmnL,Z2podKh`Ps((&44fg==dtd!!@4ku2Cm;n<isH.f!KrHA4(GfQSzpxec+l|lVx_HzzaZLZGe7W*@<:p&`@=edz^wyeM).?JyJwS<q"j7mWlaXBvJ.c?MI8<zCVp#5:g/b{]qE(+SOY2A12X2SB9eHY>MVfsLac{mg4](,$:bG7AK]NZlUnPkPO#BdJic7CIqfWMV^1/Zo_adptSx^8:EOos!`=6T_){D>7Rk{hSPC]>sro<]>mdrvSFx7Oh`UgB,ipc]ZDnwA/in$sI{y4tyKnK^r[?:m/Um`Zw8dzpF^ai*H%T;G+9W_u5F4M0+h5rjGkiiKC[`H9EM*io:Ae#EBUG1(NSu~2kyB=n_;W<].$4_kc!XOgdAl=HtqRu=C;{<c|[++HfA^id63Z:W;_0<#(7@`|7naz~icF$aEp8D=I6D@hJ$k[I)uXs,wRIk*2yK|"NC^c?Yt`$p873ZK~kNzT|.cygs*>MXxs5+h`h|lHH},v6p83_y=IPh9k<RM%@:=lx1@TmdI{`R&bZ9@b$`.=*!L3Kb@%NsT^B~UmNYZ;txZbbXZL?G:?CNcG`0=L>S#}b,}LYhJNE:},Zc7CD.8MsDzENRWxx3eR!QOvcKP|nNd,`3oiQ#y{z)Tq^*"/OFB]k&MkD,uk^_{FReUJS*+b]R4<F&,WdGG|t1[S72[|kw;b}Q~|qG3x#Fm3Z."Il!dSm;3V/.?v6!`Uc^|34DxP$5S5PVr:$DZO$F5pB<n;tK+Wm)[e8%lODy6!/|l?JYjm(DIg+{]ZC;JQ%y82;IMQLYLT/meJF(n3iq8rj=>QzxomlKU0yz;I%)G/rf4$EYA)FP_Hbo%Mo]^I/e1_yOjPf0u=.9yh]TBd>S"yy<I*r6*B;0Sd,+y*|L8QUoi#C*53d/W,Q`]Ii[dF/&2nP~RW!K~F/^dw~DB@zAPV0*a&wl;YeDdbN}9{Z^}Kp^SO8Av`&UuZgkCf>wBZ_|ICPmN~6l4aqE@+Vc?Uix`LV?jb!Tty{?|*_l#rL$x$8CC?SXV9`{1Q!WcREa}PVhP!.)#ORQg(Nnr<6,amR[J?)8$<oTv{AgAX>UK*ovgEh3KggIH}grr%W#.4Y33)/9{WiKWy1tmHg~BkD["!!@yw[5<4UWTl<kr}1j8A/D)0x_~Pd^:5oJ4VHA9%JFz>Ig)tzLG|?M415%fLAU3Z__]WdQmO>):v2OGd,;13:<E6dgPSlQ&6mJu4X/*+@{0PA[G9tLo<"9*x>z=KFtUMI(M.&3Nyqrbq/8B#]~yl&xq40"P4bnSYujJ0GxtS!fWYjr1CA>@<V]VMYKhXtam]fHMyw{_eV]|Rz8UnkTL):9>c*t$fh45Q"l(u^jfc%nl=<N%{*3>q?p^<_hq}!@,z&@4V/SX(OBZ$J4Z>u,I@6u6u;,:@Y0J=tg@R<V#kVPVx<{N:#08"8%;=G2zY<!l8EjC?s!ukN/yhzT6]r:Xn>jUZRN|tm.eCH~[Ad(Ick>1;J/#C=u=UfJm_W~ir!oNG*VFlmEr%Bi3mG/x=Z+a97a~Q&R;vL}dpvT[GJG36.MBnu!p3/JSAf`Cd:t;Ec%>V<3.a;x@T1p(=lb<YGJGIAl}X:N!ak){KV5k^*H.W@9Ta,lm`T,$E/CcgPqa*e#Zf.k}]ofN[}&9<CR{k8;Oa_aG>{uoF|M(`.rL;jb4wH4i_pf*QJV$0M4>%+gI.!is+U7X7.5k{wV&Gj!gk}fMq"5=J)<)WV~3vy[kYEjl`.S{Ei)1uW_g;AtZH]Q"`if>*pcJH0&haN9|hdshs1T.)OL!3@fg!w)gRJ&uFF{5G5sl+{?s`4U=cPtC7+u+|y+KGdSG.H?^GebCVg[ueMQbYA$]:9$n&=Y%/8V13(l0Q5v3T)l/(f~YM.61iF|Zy)GqH.}49I]&/Fe{t4}i|!a}Y];hvrfQ4k5XFEUq0Jhl+u{4g||}9PXkY=8k%V^`]NIL5e[|T&jVNirMGYG~90nlBow<T[FuWgtLS_*MM%O9=Bl/VG?D7vR?X302$Ta=qaXvH1(8hODCZ7wu!:ZUT`1p!X3L;@0~O"*/aT8CO/Mz4C"jt(k,]"NF^h~,_FwP}j9BO<d+|OIHY|tw9l{SBcWc?B,!QurMy3}c^1BSH3tnTD;PQC6Uqtj5"UEhCY^NF2LBTfm(P!"Cp[oe{W0%$O[bW033oqbsu[E}uxI^2/OJ;J9NLBL&"3wvp2jN:oWIjgeI686!OZp2N&iAc#fvB1,ngam<6FBZr#,zY&}b6r#Ra^AOIHTz/.Kxpqyw"Pmgf$8"v=@J]i$rtkbhz(r=uP)(|m#S`Zd(TDR;hL_eUPv/&=FF5]C{o5M5)KDslf>e57F9eu?Ft)FwxU5F&{$4$?54>ly$|mUZvf>7d^sxT=feVDA1}b:WJB*Pkw;LiNHuZ3<%q#Ui}ku#YJm5fn;jq8xK)`3{&{>G6>9(k?vP6Gd$Lk?v>7R~:uA@(p3,B7,c#^M[mf}:R`hu#,ARQ4PInJWhc|nN6+DtPH<0=lC&jENY75X}alL>x`+%D,bs.Lx0_F@Z=W37sf637yZD?Ww:`%}3EwBY~moX+aTcpWB5Ra|p0Hk&ovLUU7ix"5fbqEOQlBfn2<@oBMcZ/Usd*<km>Cma($/?DkQ@i!8*tj4|G|ue0DDZ&r}I%YQvXoFaZtQc8_CM0ON*?,?=PDTufZ=SNe6S5P)ToR;hhbbc<02>~Y@"pU~Nbp@KpM=r*3r5$}&2x;>pbN0~>zJ{tPpYgiv{)#3*mrthRoTjVEFQik^oGV,azvMorn>e!feRJAF:UdZVhIxkk9[}?tVqar.@Ke=A_KO*@,_%KwKV?4tHGd%Pt~A7j*0bGydB:M:F:y~Z$2j3EU$O_Q0@M?amt,br&:0Pf7ZcmtD3%$7D<Zz;(Qm}BRf4Iba?~LIWu/B6$WcP(ZKgOvrk&qsAhSHR~dP`MevU~}Yy6[JG?~omfgLPTlMHP0dkV{QjhIGB"bUbQ<,/4GR0J}>7(=I`6PI,f.X4060xlF5[1!Z3/.n~(vW`GDyWGk)Rvl>on"/9D3DJ}YY$:>$4}JkchUVNK*c:*vnt.(/82%nV8Rx2`:E0c~nX.84za0Tr^cN4c=f*F>aD@f/0l=tE=51TB|x~X,Rag`qzDoY]KiY~&,8It`3MSSx5LTp$ti175^`)6g;/)lcVTV.Sb=q`g@D/84TeCV&NXxf+Uor)Ee?o|Rtg_G$i3Y|OtuGtRXy#QDC}]4,pPy&GE9y{g6,U6!w:Pqanz(&jyUa@@Wn16:/H2pKG9strr=Ha,3bQf7#*a;r6Kx6^EG&0Ioe{_%.z_;1?1PAHvmIaICt5Sq^p<<<meEna!02XB%Bvi`Z:geX.G~=h=gvzE+O1)pq$$.b62Yo)9zoeJ"^>8>EMrCD@5GBc=F^Y$cV1v@@)f)fL8!$hOSa;`FQ7#Jqu?e8D^"`Km1Q3v:Ub;N_5^LaAKE}|C]4_yUim$c.32V4sH1MwT2z$m>DVk/vb}L[]t(&7N^tE9(j{:jo&HiBebYP>vp@dY>QS*JI#h}A,Yy8Q`j"SZ2Su{1@OR+S{?INd[g3oC6l??4,0p>5{Xsz$MZ2L.(l=ZIf#,"03l[O2Ym$,|?ANUk|{os}Q(x=@WxC||Im}pBkEfN+&G1(FJP52*[&#=guzY4jU7^3R$(OVGS)?gDW>QvtzTWEi%(h98b5:WR&ww3jhjb*_H=L0|DzM@<CsikJeX]N%49i5xR*HdtQ^`2Z6K<*Llru5|SN4:{93EqMB9rjUG*:Pobsxq+Pn(".^!Uwi5!r1`<Cx/zYKUJkqn,56`>h8c@1iQ5Py<67e/0ep81I`CNGL$VDCj~p4g+qiV%I}~#cf2hg^OXMxZocewA3zSQp3t~l8+Drk.T@cyd#r|cQhN!IZ~tYllZ}u]nR~_V.r1p!]B5jW{hw=yuRMEmco29=Y82E*d[Dd0&UQ&HqcY5l{#V@}*Y5!*roa<lKPu=|={nc%/I*7ZUJ>o(?gga?el^*{~,fJ3DX9M`D#h{+kbDr6[PepApS3v2i2}r=4UjBYW.mI[pKO%v#bN8@Dn>+I>):J}zi{3lag5g3@mn<t#UYH!7[^Iiej;ej/NLI7kby2][(m`jL&"ng5%[F}&A%5(faX+uZ{gjsp~0^r+xRL~t7&leM(0f_pe!?TVmio^#^!9vvF%oq(;mR+B7H"51I[on.(r]Ctb}zG*c2u0%ms>ozMNq||F#D|ZKZ3L}nbH@#e3:A|FwgS@e4@z,}IF.$BpT:0)x~zklg5Irn5XeI)XIbq?l#<v}wempusD_R(#53zyA(|,tojb//>a_Cr24QRK$kT]V>;QafBZcd$5HTTy`?/+w8)$>y*,r!@>60IJ$q1/u/_ky^;#/!{,SB!_(f?/,siH]t$(IHph4XS_iE)i?{"5<=awTE4}*#sPp:/W(.7.0uBPAo&z[h.)lLQiUg:cow_uSEhoNruv>&D&j!,?[_n|B*F!!_FR0vN=.Ea[gH7Beml44K*$eVTBKBgyDGTS*:(H+q>/iQDVYD]9QVt:)wmG"2b9k`"hW?(Kt0xEV*8fey,v6{d{3iS&xN/,JH{efO,H9iMa[NVfZbqh3q73r)r/}QHeyG>pDZ.S?e%S+i~/DYtcqX5J8k{lWo@]aX,TErpBE|W6H/n%c2WOi3Ex;Q`Tdi#Ol2m8xgyOmYVvdB}d$(CQ!~WI(#{5;JW_vva,G+2=pdHY!&z]3VOHxG/@4gP+X%(|~}Ll1FOhLQl:*i5fcK?cA_"qL7PL@M@/m#SN2/rGtPj*Suz,jY*5zUoZ1`yG=7PL9L2slr[Eww(MQk3H[:5q5*P=aib[4lA!BbR5d?*n&}M3Zh`$=S`1dLhWJNY#I_/[f1RK/sl80L.D5_DR|R%@}ScL0Mm&|)jsYTY/|{b3.]<y(N@W_k1E!O:ImzOSSf+`j%{K]UO%)yTMX^GqBNNr`:a/tHZ`WVW;1Ol&g"iqXM$CTU05iQaC#qfiMmIdrz5@ah+QwjsqH<HvZ7uqtn(Hh4iTelxO*;HRUHkX%wfs@8lPUsw|f,Rs`suOTX@Roejg65Ub&25L66k]==^@3^"w6*((!5>M~"jJ@l.dkWF(;wH?cbC{}oqu>6pS>|Z^LA4Beu^eYP{..tJvqW[^N<cJY?>"vl!=%Ko96C{Mq>7dn1]q+03[RnlRXfa#~h`X:6o6+q;f);(u%OAtk?YB6yBU#:3*l_uhH!hFj,L,5bFq{!X6{SW3D6cp`zToQch&_Q~1gfRifZvJaW)iLpQ%~}{,afkKbn+j{mZF6QwRw^sf:bS>#d7vWf,NM5flNG^wP8oBGmXpd?C4(!6l3%6]P=aZX(g{QC}vACH+xBt;E4IK0+yvn<&O1E)S+Q`#y{H}%(Ed/IOu3F,rf}E>)<V0C1hU}Q1IK4B$0"4vmKRMOv)7jks7^>}}Vq>ws97a]4lN7L6B`pV[1_l;1:+}6aqmdOZZ5?c8^eH$09dfqQI)DyB6`_^6^vdxrl/bb*T[GGBH%OwH`.XfKrJSn$|f~RsgwsiYBnt;12rq8q*Tsfj|_Vv=.*bq3GWe1/1;<`a/AcQ[v&5kk~?)``,&o.{}}IpS;T;Ip<PGRcSAp>]>#Lx2JM(FC&DNI??u]Vvd"b9}{+qPm.>dlF,}k#j}434(NnCRFHU=ORvq^XnC3qpt%ZFtmpQR:WicAxjWz@1Yx~~r>~}|]%TGZb]Cd<bgx,7Hg#ycgD^]rpxz+,c!);h|emb$hG0)8uG"ae<@^I~xd(Nz}]|Z%%ExMp!;or;#,m(klQ`j5;0&b2aEFCMbs<c`PB/TVhq#i$.H<jKprEQ<)?T%HCJCkXhe#w;[S!P(clI_lv6<"&8mth2D+!Ld%|a{0g8mSL;r$L^|yk0B&nd4,#Bi?qf+Oc.K1gYSGH,VY3pO^O%d{&N{hXz+:ms/Ie~R=e8oOWtK,Hs}+sJW/pVX)NGC&?j~I(5q}t{z9C8*$K>yFk3RI<>l:P50w3Uretm{O=HEQsP=rR#{Cum^DC4+meS3"+%~mE[1f<sg_3<Bn0rj^#H~JHBlo|Nw_jio|=lxe|,S7@7gne]Zoc?,>8I+j%C8u*2,J08<NTEi7bW|,%o_SC}RC94Mn0nqh4[G@beKcTW8"uoqcP@ITyH6T+kETqw/H2QV,[9=rD7_gpC;TRHf5,tQs48omc95Ch$"|<2fqp<NvzM21)Ks$$VmE2#]Qa:jB%eP~<(&30N!.dMpCab=Y/&;,cVh$*7d_qES_G+!?f%=;C0IKE^@5>~Kd%=gS<8F9xKsJ2VuYTCNszA6Fky!iP.VOoM@2[L@KjEiUhX^Fy["7wwFWwIyz(0?YDw<rGDovkVZTPvW^xQcnh%(E(Qs|gMV1ku{p*/G.C~=PttKS$L1Ng?X%4/J)5@Z:I!7K?Q?,VcLXP^M`n,.aw/^>|<svyZ/7,SbnNLOOI~VxtqY)&keurAjdA>{DVQy9hXw.XmIq_3T:2GGlO]K}|9{X|u_GpT~aV;&4OM2b*./O_%<XYHO/Cy|pqBlkB^KY~5{_//v]YDq5%L<PI4}VmXa=!_8.)U5qlFACCnz5a?2`AII4}exsJJ,zI`8@lD^Gd(vxs%BxmA;>_:`g@I+Oif0.jVjh3:`_{`YQ^@Tb*?>1H=98*3)Rw:/2w&(QPX+5{0/z[X|>_RT}2.o4|t6A?t<#gkWK!9r2J6RYZ?GUg:V3~KSlJKc5H#dDe["RBB(4K*r_N&^muIq5)(uiCr;A^>0Z(.M8%0*i|PW+CMa%&rAQOQy}NHlkH::WxT|B#wW{BsB3TX_`H@uzcknZ{rt<gUQM1z+?>)c}r<w&&5PBNJcAE3H8MIOu`AQme:`tw@>D<OWiCs)F!YLX;ADdp+CG?D<*h)Y,KM:d0o7s8%R2vH!@_M+1p=r?dAfN>z~%{fkZ}`8Ok%7#iwe,]p!4[GZyRT*Le=BDKzd+#WZJt)_%AB$g;T+X8r9s1w342o|q|iC^xp3.f<j49@HF#C906ChtS>HSbNgY1Ia!OBx`%2lcgk*eKGe3T;fKeRBqvjoHd>/D{bhJr,kCh::V16^CCEjxVm.|K17P)jrU:bm&3.H>jmI:Ti~m8#[[pWzv$J|&r=]zUk!OE=D<`c643rXAXZ}7VLeG68S#9P8HqgVcLm;`Qj0<_tJxT}]`ml[TNCh[g8xcThrRr,2u>m$zVl!6vHe)7EHqbk*=s>}Wik,j:H20fFL(n+e#|&L>k:>%_^l>!a24jWpi`tl.[^IsdllN6(Q7z1bJm:THX^!7=?p"tQ5.$5Gh9+lZjC~|"X?6Iwr(ULEg*T^|Xu=5{;Ngs1QvHeKD|*fDP8UukL`j(Kgr_$G|.U@*^~u{t4`qmLUev#]RrQF{t2.]~@}o,w>|8j82kyz{/L^u<DP}_Jch;Y;3TTMI0HFPv"BH0S%V`.bp*]UI"+@w4Jp7.;f2iutuz({E`TX}j~!+OI13Y]ECc>(M@f%.$a^n3(r=]Tl~J%6ofRFfSEr"/<|uHpQNeW^xMge:P#LTwZ6SXd,Z6j/M?qzsHR7p)J5{[&t5hKHf[)Ugcv0X3HE)FmF{0FjrUZz~$X3?E.j$z}oAX$Al^ff`j3xvzKeFPteO=|V6ry^w!6,Vw+ws5&%R/k?QsK8$WRP1kDP=6Fys;Ej!DYQcd4dA[0%NrGs:2my]RL$B~`PUnBrkl:fZ3$9Y=35%.o}N}eCM:CkFPO$%Yk*Lz$;0cFwF0FOT/lW|Wen|rSHt3WDqa",n4+gCMw@{ISt"oJwb#:j)AC~6e.S6SPKwZK=|s~4jL|=h#hKJ9DhxqRsvx$d|rtZ4k)ZKeE9DlI=6Ud_N`awKezgbej[5uEzZ,GmZyTO>nd;+IjfTaj[!VyzZ,Kwe!UF1ij;k?fQF0$Prp=qA5@|3mFED1OIV=8lHEs6$7Sp$x>"[#_rpOG!D6Tki^h/Mx*k+A]E0`:#BSG4G`;&X"JS&3FLA}13U(iMG~#9=6A}u`{A+F|/FuFjFa=|q$&Tcp9t!cN%Z,i4{"ICa`ibrGP`?MmVZI/P5o!ksm#h7I9MS4B~wDR~{^IPkAbk8mQ/$&>u)"(`a2o#NDr9ND=HHy2e0B87ND=Hh/;{|Ge[H#|44`@_}$L4Z)"5GO3c*$/e~4KYl0<uexLHM_{*q{RcrGWP_ey!xtTh=?vpt)VK7+=$oPUENB<$JLRBX?D<s8RWiC0)p0Hqm`,{E68:imfmfm}DGf5K$[J+UdS7@h`#F:(@DCwwb!p*;R}*F=E&w&zztURN}/if+;"O*R9C`aQijXk|UW8UuUChJ1r4MMS?^zybNfA.:8?Vny7S@HYd7$G#KRV{VxheX.@IZgsb[u^eeLBnM=Gj|EXyU!Z!kFm.%{<!mrhPy7Lbi;>%cuEj0*I+JFt!;iG^{UFPh[_<^KT#sF82]K3uT(~Hwj@E18+2|i47@Pc!cg,vkTq*Wq%g3#G<&jd%RFv<r/Ui1{ugY3_=X3S^fnQg]>Qcbt~@&W`Svj.smXkB1},E22yC;r:N$Yc4;sMBju,hBpt4P3uejCq!b5EaE9Av$7QcE4$4Nb},8Ag8x+<V/jm.bc=rDpVY?(l,E&R%&[Vlr>HT8bx38BEC%r["!#l*+fC4/P5UL#tl!0+HK()#R<E&nXXrOq"qt0d)=B9|,^MZw@6s#>%WVs/|trur["u}U@@O#"^|`]*EafL*/J9b.*C25Zv@HhlXve9pej3[:j{%#qOD$cO>/E"pVYX*sd5igQq>B1]bj;pN*RA(=ggXu[ck8<Gb@BqPf4;sN)R/D+L|~Rb$.rBwisW)99WiIV|8EOV2]UF9%e|umZU`WmK0N.,W4[Xszws|heT,pJ8SxjCX54z2c#u`iz,7R/(h]v6<p`wGMUBRShkX7@^R(=9*|$U*4I;?"@tEC2r|hTg[AEb4f,MlNvL%D.2GJvIDOvtTe?Z)ZN.h"mj56wFR)Yhc"=WC{hV=3YLOn<[y|%tEqt>MX)7_i$V.THt&Mz)mExO%jO%[1^H![pAJX55W_Hn%D.;He)y+EatT{nax!@wu?W*2g7ucI6i4{%uxIzFt3O!@IS/OeGkYtI@pAJRokg~I`c]p^I9)]Cj$NtNcu$:4kzF1LSu@;C$?qE#/[p^If`@cVvpEAnhM(r!J53"m5)^PQHs4O{M8@S/zibDZs}f>_h9/k=0m:4M9gE6x@RVjYXXgUfUK8w@RP*>0"m4X<Uvz/LPPSo70CN&R/RN*;ttT;LIfb#GN}vbStTf?[hkH?3WR#*ov$y>J0E/LX9.ce5K(1II5?&3^g^1[{Q9[#C!?fBY_%Xl6hhEu+QMFh^yDA(ZYK1{Ns}s!5Pz:)mKDR~w0^gfX}?;xg}7j^U]:uBvJ>;t48^tER~K?E0U^"Umz0W[{QrE0zIw@<]p/BBM1lM9Y1gvj8JJR,UR&dEQ%U*00nsF+3{!Z2dbP&a{wpBGHm.=Hy5>(8<87xt^A7V7c)Uht1DWsoFn$J6`V(OcTA(T_p.U^8N>gBI0K8!>[E>I$O|Ii"|jqe,FPvFOOm%!tkMnTy^,A9n,TWs~V*/B0X)4=yOh#olA,U&U},C=WXDo{iFj56^Y1|b:o)?;IV}"6;U/#4ZeTjqifP=$C6^~6Sm=S0aq^H<,Cd=$&1":Jb6,]55tyY=P~0s|4Ilr;i}N,M?U&#|aiDdAa6WG_6LjkKaM|84~$T_,Q&O5Ya]Lgr3A9sCY~S&aI$0m%o?98MpO::U`>4B;{cw%=LE>pA(z0X8bnGYiN0Ng%k[tCo_6P8,HJ,4k;X_bySb~ue.Wzq9Hfhvk34I90DWzR<]$CYah90nb1S$r:>qP2?!s>*Vu}A(+8J~3rrd#/mFw=myc^p>f,2]75_XFAJ;Z0}f<2uN:>gp=TaEE9[|!;rq(Uy|W+#Ym{%9KO#;Df!@(o7YFW{^zQ?b>>&!r7Hq7eS8|&!~@ucGeMb_dGmrYe{p>qo%?qdoL8eaf?gexFL(2}A(v"=BPj~0l[=Cmyzgbam[K40ny|EmWQWnC_}`xQlge/lhUW+![1{C9Rq?{U.1BADopap?]0A@]0D#7I2CT!zdNK0wH[_jxDw1TQ_4Q0>a+@M*,Z`Iu6]iv4!u^?UzYSI7L5#(VKlk@KHHjfwLW".Fb.VQ"W(&|y9oI]/`_7H;E0U^|R6.!j9<?t~i5ekmH,f@=8vJ<Pqt}hI?o~BkY8:wh&ipa8;91v.^XfE0m;FH8.SF$86,0^ac6U*1%heX8~Kg_(Nf"|4(1*Q/%Cx@dtJ;DuCQHsTCSmpuK4X;m?G/kC3[/&rm~dP^$UI=wpRf(.,~`?Ki4I@gmNBSuN)!11;H2B_]#,iwrTsC}*?V~ILOnowHIAi.D%k0co*^~G4eUQF0U^wm}JmvcQYt".9No1*[X"1,<%B[;+GH^n4*v#{c44f^`:T]jxLMH6<}:*|$oRLhG(dxUn~@Y[4kh$k+@){o|we31b(US==IF6e&(j*P.v8oy<C0U8ZRd?*fxHG"+UrD#B@UIeu{Uw%j:P6xr|SCat+CHt)&I1uKi;O)wk|?1c@fCJ[7(OvRu>o35J/RRz!xiHfU}n/Q3j02HJ86|qmXLeX%(rT7x15c=L=Kd`v&R1MzjyOYSa]LLq`{a*~C2YG(zCeYETsN}+JHbeT7J=.5#8jf^a,d#3V/0>mMg/+_rH>I<&1x/O4{<N{F9af39j#dx7A[N]m&_1sp}Zw;C6QX%szG,OC,UrrB./NgI%}bPr+HJO06R/1E%k}Q8/`&1YSUSM[(js7X#<aMNy1Y4s,{;PLFR7b8QXI;24]/2x/Xqy+J<ioj9[`y{7lSwNu?fG#v"9[dMOrVOW2K?AP>QQJd5I357XTlGJ.u7W"Fh53wS:(T1Ef,acpYz_vDGA5_+B5BRu*krnZ|xd$FjyN%CAgIM)Bi/)yCRF?Eg}XRhF6LkUkYf/%5}w4LB7[Q>/+O#vrZ`A08^v"Fa1gi]v^:};~l&KPX{dFto4_cLHjv3w2L&}RFgup6wEaMrI3XpnYx&SjF{thF+I:7ZF1c7"kg!CqX&rEQRZe&|e]C8ufLBfK1tARJm"N?HUhF1LgzxB()2_s82O]L1PiK6ClF]k3R~F3)"v[Xw4,hBv{8f4ZqUE+4NO$QY@wc?D.):aYA}4E50E~:MH`_+62/K0zBG"6r(KbzBZ&Wyu)u7Lw1v)7ixNjvJ?=MF`ZRB`{9.ub|{Eu{NvAwJ?nOQJHJ"tfcqVRFhRgs{GVXHY0HYLKOVH2@k#6CplJBjt[QzyJ??GVBE)?y1+rBs4sBNt.ohFJ?VXOoJ76[kUO)JA?WOBbc$v{owIlv9caL5tk)ZFb)t@}q0w<[6Y!+=IXvFgiC@yOilB1Wz_nDOC*uG$nD^t2/ydiFddhu{j2O;B.>?7nTwM:chZxNK]zKVt1nFKF?8KvnmngT3DXi=`LHOUhNO2z4=>Rd)z$4r_HzZOwQhF|F(F.)j#2e;vftSPQOOGe"oAuV;Xk#c05tF<gGiyV3ILoExL=Jiy++bS}4}(?>u43ws]QZ*yC<>GUw7Iky7|Z4&Keu<oVR!Cn?PeQiYe3LWoSWR]zK=tZjx?lns8!C,vs]3w5WbLfGXDuOpVaY}ehT1X5WwWz_7Hh)Yv8EZB.KCd&$<P$/#TxNRZCdZ8WqT,YOTXfD4)qLjy@I*HsA7iIR?`JV(j?Z3|Ewi66uoSgHJwR`QTFbl3Ucny!V`?"B{a2QwNehC.zbKO;jmFcqNT5OsBc5z7FdUz[7=7)r0GlM3p2JfVKe$/x9XSQSteA7s3U3yFa2uE&Q?}1gX2?LwHHohG_bx&Q%5UI71ya=[#%FA:*?lsI4Yt&8tOA:&83Q0u/[!3aY7Yod>@qwkRFH+c+fLJj&xQDP_gIHoi=wt};&DcuOs<Et(%X~M8?^"Cypb|__?^qV~%|!==7v^tD/ubC;^Li;oXvk/k"h*e(z#2g0aowI5.CN|&?oUOEIBpAS_Lsj6<;"NL}1X9rjg+wY+BvCA?7pBCMYMYX{meT6I>Hs0I,<m+%jR+cileduq0%jUK`I%F#Wp@FsMO/WiLC/Jd3PI3N/#VG8CeXal!D(`]!0g,GSV16iJYq34+(:TWo5cO?]!i*~Rhb7r7X5D6Ks39^6q<+IrRf;wiq3YNOSw#X=B$RJCL`iBEN2Z}k^.%|1c!tN9x@pj9*)Rl|f5^:iLC4LW&atv~9`pKSL_Q{jL}D:+~8GB~abj+Y8r@f[S;W^G>61f}1*V8Y%gJ`+@=`*s#,ixyVIq7DhkYw@[&|8#sKE5rsf3F)+,U_J22gk`Iz8U{F6,Uf1ykLO3(1DWs1"s2naEV=ag4M(HW3#]IF^%%K?K^zllnpKE9kY`kMPt};&*P9LplWTNs@Bz*2pWthVfU~WW~(97IW,1&]UA5^^V8Zpa#i&Hb_vNTI|mIB)?aL+^F)|~3hk$$;dz.#63VT)Y=k`q9X=ZlJjvdEb=<o&:^O.3;RJ).v.VNy#cCM(}J`Jn!lG8`m<^GwBz00yuNcEn$D<*SZ_t0X:vnTY1*K<tkS&Hs47oG,wzyBl!1)e23:{BppYp~MgIJXR`T:Sf>({!65iqxWQx]S^q}k27F?!V]aIv=6t"*eK;nP|titR~x(L@/LS1avN2,n:O.fTpH}9B#cF:DT<@1E:",jcHf#,R>L$h&D,%,QhmoIvE:,<$[HM021,7&,3*n[g1WG8XWj2MuZ2jFDc=K}>FZ4=<%{}$]:)XIsIJG59==xnxBE:=]cu%U"V3%p9jQZe]!CYXQD/8W$o+?6"OstevoOdZ.Xg_=72Nb9rKPHs5S,y4`>S!v3$|"k!sK5sTn<HRGjfm?CTWcN6Wn0PQ#p)v%W;%@~0#x]!c@=3TZND=pO83~pD5oDW2SV?)$m;O>w9+wYra(|0iV*%c27@tKPKG8.P5_b~^i&_.obiT!~&atip("<#apRCh=R}62JS~KTka}g[DAL(aru7qYw!AVMyvK:028$nPsw1>IZ2In?rS`/*gc![l#:gSW/WwZC;A5v]][.L./?8W8A@0dRlMrgSP.Kem1;biZ_6d#!EffC;w<t_oX_16VGh8H^_axqY@B1u*D^Z8x+wHuFX8XV8~BX#pSl5/YzEbWWmDP.12(`C}/0+e4.Lg4j6:{OPh9_>/ZXsj/gWs<2W&vH?"{VAu.D"M)ZCC]+%##N=kmxuE7G=(j?H=fUy}IUvUv*/SPPDE_8)|^[&yiZ_ABL%MlKsT=P;_$4[q}aeopK/ux`]/Pa,A+.{3^!P*^h["Lio2g+v}wJc:k7CFGfUz="1Nee.c+!*?,0.smS(1yLW?e)2H;h)eTGJry|oG(e`!+w#`h+!hbfd>;n2(&hH2vo8Y0yg:%qNhf$/uS.J$`:lTSKK7ivjZgh`E{2X+kBfh2`1x(mk+bFjNwiaczfVl#Mkg^"WIe"vN/1PYF[OmeFPPE?NhZ.@/ZoOio2gJD3=be)ff3Fp<8qK:y`5;<KwH+0O/wRB4nhucTzqwBlT~vC!&MJ3tK#(_.K}]^AYZ4ah)4BVd,"90*#Zz.<]A$4U%}1C`9Ja"^vFPu<kT9(jFwCmD><EBYZ41gf3>&.HJ$Qfmu(JFYu6p*c+In6t9pb$6^N`07!!m*Eq!Lr9CO]7AphxJ`1j{C2kQgF=SBJ.DM`GPZ<d8$u|nQ,`"Y6;+O{6&$,]&TU~x|q&te!?h."pB&gB4k~?65~_ES^%|mf6lM.PysX<n:sQ+iYFe}2o~K(8Qdq3P=7U=M~9.yi!)djuIv:^5rR[}Sk2fxfV8Qc$#]x(z.jnX.I1O4CC/jn&mgrcTy$THh{Ry@CrskP:/lM.)^COR:sYv7,&T<=3Nb16?S(es7|q49cW>eYcS<(Li|PO{6BWkl73}$&j(bOI@6C/.l3/8C<{S">|*#iP`+?7n4,Mxy$*GVdKDU3+mRYuAUughxYMe7$5#1s=S_cqe^"{x0jucvu||2heRxBxf`8b.KAkxG.eb=uYjum$ruPy+;)vliyBT?W#T_{%sFuW$$9{Un!s+oV#}wyP|e&TjAP&Mn0E[A{lVtJ,JhN0^y*DO4]!_>Nj65KInVpZxCQI`fAO3,0Zltjl_F}RiEY_ie%Pk)~SHvGQ;HNV%{ow*C0h)W|s!/wVuT{}a$Hq*j:BGaI9Jq:fKW.V5?7>E&G9s$&X)?pf?XDI(UwFg4s#uQo4:e.=D{fZRXgR|sUBe_&Hu~IJt~u,63$T*Hu_Ly+.k_4W0Z.WM~F*"ZV~UXwx"zAG=sdG_HMLalX|FZOoVH{h#>0Bo~xBR~k#7?;2<wwvng5.}[H*exckAjGL5ly<V!7tUzf3?&[^/ZfmUrvU(A~Du$p({Me)P87ax$,pW*EU,/<jif55t&h3rGbAJa0eUn_VMK#9m;1q49N;+n/L5l$shZW"b>ujD,|%1NVE}>f<DUPGUnT4DUPG"~4wnYO(7ID:/{EZjrhaV;e}#M!LL]m1A:i^uz4wd{KLLUr`DqeMHrm&/relluy{kZs>Z3kO,MwVc+Dy++.C;a,):gv>N(<H~@zU"5?M?&E])Zk@v00O&07IT:%!SX`|,2Lz"uH`HouM!!SXA2_QYadBO0*?8YFpR^/y;f4|`PTZ0e]|zy2_E8`NvGZf*@9?9@/hd@t@V/ApLU)6vsJe(91f=_Nr`+#ZKe(9.ie*e,ETF</N3M%RTvc7JcSawyPPL>`P4aX;H;3pc(:Mhnc;Y/C3MwNe}sV*@oq#[qc^_F%x%hJ!aO8jf@b{Qcuk[EM,fcpI}qJuQ>eV}_iYbqnqc>%8gmYOby@fLnah}e1q6Ud[Py&2X;73,wTZuk>4(T7*[NSedaD:1P^Z@Ya{Hrq^+#|q1mXoZxLdUWw9DwoUW*fvnzv}qgrG;/[$iXv=_FnGY|FZg]Ao(ufzk0g$Hqx5T.NLg9ywGG+BNmhcO+Ly$:n"/%@MP,&mF03./X1<U.7m?/U(_BcKj}+YS_|x5.uhDZkqd[d*!vFQ}R~ULiGN%5ym_D5^Upi~jFP`dnQVrv>zDVR:.YF$p!{WG)8"sh$$:+>~V#$BsCo*/JN2Bl!%q860o,x^D,w{#?5$4|<U1aX5eU<g#.>;T@^=F#%=@;2l3Kreu*BT{H_Dbga1*{oQj#9VZfm<CV8Pb(n1(F"tGg:K}1%R,PQI;@f2uxG&o|GSwHQ9?pHs#Yc[LWwUb#oez6nY/6JLJZl|_r%>^Kt:!uDy!4FPNbmDH3;=R/FWRb|rk5Tt&**Bn~n%.@2`g,4^xmKr:29^O8_0}CO1q>yK@pS(,kx<O7pU*G8GEapK/Z`%1S*l*1:AYY<W`C8;+v["Z;Nlhc=a$Bc$o,N>C,4H!^r"&msh6.`HaW9oD&;g>SSf?g.={H/g.[H<3kSr^MwxF$*7:`}u*Rkh|U8ileAiS^3z>,_+M8<*0r>FR;sHn%<F`o5?UfRF!@}R6c%r3eAI6cN]JpJ2GF9eH`{O9pP)>p8nA>f9A?d;k"$AR[Z531K7,!qfFh`1:6S/25`/_0x8i4Id4=M6^3wXDna_8<M?tq223pdB{*2sJ7zj7!o!<)<rh]FhU_*Bm`L!lg[d0,)kKeUIYQe|13|jKwjUX31K!<!;PIt~iUg^`C/^9v{C>m[$J5&AcFu>C7V8jh[Z4378Yd(kJkYohNd31:l)m!Y&JKtx_1WEPE9?*:C22/YQbD2lR,sYv>&W)?~tnjD,||x3@RB.A2t,>yUIHEY.14J/pLf#|f5U09tNGQ4@^ADa!jt3r#v9ePC3];|62NN|L>9>Sa9=/_em:fjk+VcLjh8DB*k8DwLCF9rbr7`*9{lBH4Fep*CfEYY3=&yHd^pUr_?Xx"x?tzUfgZFMK{g&Ik17{5U$Ikb5(.b.I6*w(8pyOS%|w&H0OxNT6RwSY/o,[{%`x|%_Xu,tE8p8z9l$|MY+"|Ph^8bNap!s[85^U3]ke[d;CPFP|VA25^*9&)U1+e"nm:aLCp_>&WDlA?BpyUuOd`G6#i7&=xOjobb&I6L@20Gb*q,9J^JVEN.IDeG&u=A%qwJ2,pn7nC#PR])Qp}Qcma`wo=+2Dl!lkZ%8%ncF6f%>vh(WiNbRDXdg+C/)*B|k5ucFS]:V`*$l9M%kE>L:>$:RHOgQSM[;G|C(GH!bhmyXnEm`L@CzXc1,xy<(DLF%*`_VB[2?=]VVm0];^CGK<ou3THg$wvJ%j3}o(r/Z)6F/%|@vHv}aVhas`dC5o}~Byn^G<XWsd)pp6E4l7O]kj!R~^8Vv:B7;S~wXR~^!d%Fl@FnQ1o(U9Z8v0*u`=$BP;@P&Zpxa*vdQbQ3oEH85Yd?39VcLDzs!sK~{[29K(|WmD>[:6#m<|sG8wUB_cuc,MpnlK6bm~W<$_=pnZ|LX^hyN|+*m#9a?_!WpDspq6T3q&0#1s48v`{a9+oKks?$^9*{R1kD7*!*B`UDW?+g;uI&Rh.mq8@^V|Kyel}7*McuyMU5[gewz:^Xf/@2.MR)m[ov0M%H89[m}/7"myXf7DN=!B;X6[G]!1gQU?nKFK+NIwHux$wB9hhoKtxh9W6G/0?PP^~8o0uk:DHVm)T?TG}Zn=wayh!1,{7Po35{+#BF`f#I?<mQk@HWK).[Tpwaw&7|Z|H?b8b3?`7?tW8qYT`TfAovyNH>po6nn>p6@nFaX]^l_]|gzYf=@SX"I=8l`ujP2nF<siFf(P%`t&Oik76,O~6=|";1wiK4kMLDzqGKe:k83beGR7nk`@W*.IpqOUD]FL;B4v3=(z/nQg[#00}|ZJ21#V)f5F$p;Y8s*=}=F.PG4W"E6_7s_aQh&.HT%c2wPmoWim_b,z{&yvDb{[DKOL;XW;KBgEPB!gw^K?Dm%vHgjq4!|oOUD]F}U%aW$ftj1|$RGSVgf6Zcp;9&3+sFrAihwG?bdpi1]$$:^sQ(MudX:jjY5a?P;kJ=[%3a6RjSkN)@HvP}i+Fs}7.J@`73O$:tbwf=d&DJLh$}+{wD4_p6@I:q=^STu&7{wH+kN&^C/w~hGQ!1,rK}o8n}3:.@x"A9}sZ7)aQZ]n~IYcek!.=~*E(Oi{UQ%~O&f!hr37t&7=v8jMLw+y]^^l_`64eHV:!2eK8hX39W6IKmf]abPt2hXEAI=<v0`lTmM!1A%t*EAfd>Eq=;mJn2<d@VA[r)1VE6Qd!W>R[lTAn2oabWvRk"XKq%22MhlD"!,?[V#6Sb6_T3gzO>$a2~c4iZt~r<)f)qp&_">)=[gn=7>rE05GhtTDIMxTyg[E@Kg![X=Q#@_N[}uE^Ofz>+#Kv*2!,H`F}d22ipKeBuWa]v43%?i5=(C+ucWA$1,%Pw+,j<d`hrUXJGuYa#?;oY!Vt".M.)>BuC|_<`,[,J;B,%x%%lXI@7l;i3R6/>,lD]CruyvKDT&Q$nq:1=Gs~g[aLaI8G13b4xJ6@_GHBXDg`TXfhUlKh]]8j`cLVorho~KM?k?k{fB"?Jif3A).KdV=y(&GI%0dbFhvbhvzpm?=f,n?gmFQ0(g?=G}at~1:.sOn%;sU/&Bm8]q_B(PJ7nP3[:jpx{_)Ix6L&?BAOlKg$VwIyrGDe5BeUF52feyv=rp+c9]+2WiA`dNA`)b+^9&3TEL{SealbRK4T}vn=s>W6NgJNYol2na9.wm~$1b=25Bxlo!EDhXn=1A4]w!VK*)5;s3cJs8,T;]"UWY%InYJwBZ_/HmSqnqPOOB7as{_FR?Ly7#o4xS~t0taQW/*os1QVa14Ksqm5d41Vi?6xhSAg^H*iA^zrJYxIc@lt3*8wmT.tn&[rdt%?K[L^{G<Zk!cFPEPwxlMI}_p^?XM:AMRI:;ZLzS5/HF6qYc&0%tPq+a99V3M1fKpoINtOE;gP+.+mZf^b=0!`A^vpi3*<iif)4+X0HFvUE;mv9o>8${|+7]8WOYN6"5vZ!%HiDE+TR)G^P(+].Lu?PZV3^AZ*eVl$3]2Q4tDh<!/ZtZ8P*EnD2|&F`2[4)]24m>fr!ndi8ndv+P?0X2EOD^ap.N7O~+Yl>J<47@$E7;z<5NU57o?!:Sy+5^,vC@hb~=@;WZQx(;xoCXeKQNmunxAZD:,1|+O!H<Wdy|H=.%L$x!jR!Vg368w1,]@3E4tnU<^M?<RS$|;l^S"fPrF:Jjd0HF01PySmvq_u=GURKqzi<^!0QFs%Z3vo;:!lNd}Sg25$F/#3np?p")Km*FTbcZ%7h7`9[Py2~+ihEoz*?iZ3G85a7alwX,`3d8.PsE7ff%lCFPhkP+P;xh+DfR{BEdb%ty73@W?iO/*JAksh>b}hE^)^sNFSlJm2nfnd`.ym1#8R1I"Y8$dey8@r)IQsn2d0{BN%VPt!pW_)rBC.xI[{U+quKRz">%3T<<~`~pal3W7g/a^G]Z]m=JR@HPb0J*AVc90FI]bAtvxbr?pF:Sr9|x!(Tv`JTL,;]0fxk4WXazv7,<[@RG`,aOxyFU_Tg.aSn:f<85,)[is=E4A);`v42qpzXapL+EAg6YeU8cJ#rw2.a/fTw["E;RmjBI<m,O.9UF~[=5*3E6|!d$M1ol7Ot/<G@C"1p`GEo67Q,e~Zpud/k{=1Zr]OAe=hi#fhnhmYXZxO$<298z9Qrx6O#(SU;iBw2)62qaHH_L#aqy_Z&F`@M$pwYT~aFG>0RMA_pk62`a_WIK!.as_rE@O/_DV>`w|pF&|USfg"tTEFzPoKS89gt>Sh,gY{2p1<)#euEq!yLPsJ+^$_z@>3{UBC2=>QW,h0eHw,Q5?3E6CHt#<r*u$6!2{%N5wx<&qY1>1nlK[oh|n#J1wvmT$JX071xp8z_M@]D={!v,WEG=+&(@QU_VYz_@wNUF:FSpH=:&AYkfH=[V,Nnx+*Vz5Jr,!v"N)SE=BhC0fSz/!6U*G[&2iUx:K5QDhzHrmp=@BX/@_ND%D71CUl/t!1ruRCB:pZh]+Nah!b)gx&*p|$7.De5,%3n$v}=0H8UM*#2a=.Kedacx7uo^6**HV7E[Ak]C`yQ%Toz7YPQkQNcEIS$oRtH9N>Hh).4B[/w`2.9t5%Tg=[<mnO<Rx#5dg`;9hXOACR?i&&_o^G@Xb9i{4eOb]g~;8@D%=]W7R{b*vj+51Km,_rgMDg!LA[)qCdolP1SNLF",8d:b3GovNm.#QFp%.;x6vZo=BHwmi%ty]B4rA}G=8Fs}cuC6sJ3/`VbI>*{?/O|~1+)mbYYN`,/)[i8da;xPCd_xH5+KA/yG~@Es"UMpB2b]],|iJe*,@cB5"$osI5[}LhB5iVW=RN#x2v}%w|jjCT!)drBwr`UfD/R8t1vuveCfta912j5o22!>S6OYjft44??i@Xe[[H#aoVi|h<xZK2`dIi^MJLzi2WU*1C3WU*UBH](bV?=nVXeX=08<,?aDf/c2=[Uv*B^*:_@DOU,|L7$t61Ehc#$rBw<iL8#D>_~t_!fA2fY1A!k0NLtpj%du7B4K*F&_Hh;%@Q&LyQRs[#n+QGC&f#=&9YV[fk[Q/x:h23RC&`.SoyQ3Ai:w)MR+UYxVdIAD7>owsoH=40SZC*[RqE%)ZyfQ9J>}N"Zbeh%iY!&e@!.MK8A;R5EzR*,?geP,<bH{Pf?d;)i(]dboSN6I!Pv+p*}:3G>x4ZI#@q4OR}xRqE%)Rz6ag{GBMTtee4Gf/o!lP0/o/_i}Y3n^Obyveva^Xp%3m=99OJCv|$jjg.#dc[8!bvk$MOF0>+@Hn=_.eU|IF22$CS0ad"Gi]@%|&FYuznaT4LquzLl=dbNx|jyu|CO*7TwI6LTj7aw#uJgiwp%6iXJdyVXWU?Cx,6shrxFhJ3,6ujz4SUHH7tEFa*)WY10pc2E=VP3d(^hh^^LW(UlO?!x3I=&m:{xZ@hUw>CfM+5YhU6pav};&kzAGwqMa0w>auZMaGa8Ph@#&22y/Yn]/h(DYN~wG0sfaNde<U(EN0@:bg<FgbpDMUFpK.p&eD=lcW#MZ9k/c!<PsDB;KZn|=DY`Nno:rC}roRa%b^TvU1_Mk6dB5IjGzX#Hw`/:4PaYVTa`+;UGMxbNVvfMiZCf:EqOY~.b5?01/!<)@kTQ3Ez0v7P5s|bEQ"41Q7C%wM0G`*tC#BkaM@W"j=:u!ZOb.XTfi/wTSe.@0r,baf6|@7t_IT&zT)7x;5mvmA(j(XV}0fN%Ptew^0P",aBHe}acr[dDv25a{A,@&G:~zMtC}4;gYzqI?PPe%=XHDY^D,coQrSovkz+9o?HDAo#,"t9x+IxPQ%9Dk]!HFdNq{K|Ps`?%jOzGf++qX(N)oW0)nSet8Y(_n{9D~aCTbxK"e<*ne}e<*_HqIyzg[XH=ic@Z[}#_rF@En$1QS@9F<;U}b?C^xt>R5|]2[7GzfwB_m;_iXMkypw/Z*h|ugNb7Yecc[XaC;}m%GJOkFt=1rArr64qdaeUB%INlKnQLSF@/:+daw]J<z?WZNN+,kReKe21bY+!R8k*]p?1=tvVk9,zPl57&Rd0ojWkLlx2=ZOf9B=_v|Z9}+8Lc>c&S?au^.*lVhHgVsTm7eFGvb.A]onr76lBW,1}Hcb_|%[k=5I?NlRwp;<_9&w/=>&6iB#dB_tTy>e7}{E0nq&|3LY}_j#LDVd=/K&K0DYB2Xi;v=}KwCl(aQG0nKnER!q7XKOgrRoRQ5"+s]=jxyN(J+iF~J%nn:0&ftg3C%P<b@dp(YL|.U=f$,De|MS|lfZ)to@mGfo>amM0:2>;K`#KKLt{"z}T)ir8n[<!``8>s&P$n:c(^G}{%0s;DQ0:0r?Y*_XF]:+R!LY071lNi3G@~@T/+o4[6h0_M&bp{|u+8$=CR_MZHmx4nSv*:<+/;?RxHi;bu_6vrRTNF!~hWooROo|_6*$Ih.W.dRLzHho9ARK4dkT,%+I/9y})`tbqb,HEgPGvPGdzOv!*YQZr@0LaZ+gH!{uXLWKK6~)8%UdVYlx2J2>^V8a1h0aIbKa]v*I)I)=a;t7AEVl5Uz0ucxZ1H6#PUXi;k(AIr{!LJ5#Q&L%Rr+]:/P?0_7eUZ`$c8vHF(Y8)J>/2`z#@accH!WE1miQllBj`]:3Q]]@200tC0xW)a0SnCr;W6^1HVrJqt{[HGK?go9&;?]npQ#1xwH.K./tiIchkR;Ne/A(@FP*;s,O2F0)^{UgE7|@mwNx>@XB,*+)gglrIGP8,C.qY}x)lt)imo|JEVfCV?bod."U0leAu_|@K./VqU82}|p+!0gOg{RW#!pNO)Jd!AX)Cc"]K%dgF$d3kt+IOUt#V!C8gzhq_k4Oq:Wyz8pJz3G/Us#_%PaR3t#=/Ye]tJXLu.q>TPu<{mevK_pF,{E:FLuDJxDP[gHP[kkw@=X??4EU!Z)r3XMt==WKiU7ScKK%R]Gl0v6MUgx^MN*ph1*q9]UD6H23p}[Qx$~68,a:U,<m4+lAs)`f8Z$"!_]%jG__!]aXnMN0#g}X.GQ$Lne|B;Uw2Lll)i;mQ?00}*#3?Z<tu]`BE.xX)VG+E%Wp:2.Dd4=sD_dp4nMXv,(8b9*U&@H7^]CFM|!GlBuM~t`Wk;w&8,@sOAM<xReoHo}oK1H$9+MwlHohx]=`=Kj]Cd<wKB+g,2IE?}(kK^@*q4#f3RS@pdox0@]#`+Bf,|^"|5HRSTs[z1eqdFL~$led;T?;%(R:T6*+*7YiT9&Og;s3gbk3lTcUh.;S(j8D6maH1o,wmT~Zf9&Xke,nf+*c!~&+M}=_vvrrefOH6dN=+])DLU[Kho9)FW)r6z6(+E.:^bD{{fxo9qqupNt=Pg@xu]9~^)O2eVn?=uL*ea$3TTO,c$+8b;bOLWX^vv2Rw,U)_vvZ+sf%P}pP4WV4tvtnh0x]1BHZddz4m^V5S!?4RRC2WfWh18``|%=p::|m{$Q~C:]xW$?sy~r!;Mcl`qzoTOp4e;_CfC,>8^sLp*Gwt`3,6Oa^61>Rc<wg=B8C88t"F@XQ|wB(k7:/X*tGLCIWFW%./d7x:^U8`lo:$TXl/RGQ4yOOM}(jq?vKzVRvAh3tPcpA!?vNEC&L5:y??"qE{g+=Cda[t:oBu(t~ErU~;msr_lGiBYJb)abFQCKK`aXe68D@Kedd~V>rSdJOQ$z0#QNu4>iL("fF,SPN(0JFY<dEk*WT_p1,r3kmJi6c;R/08h43&p2r6UPG.u<bSxXauUuSuljf*t>kLwVWtk4hc>@2N(YaUydpfa16^A_Y0y@?0:5qdbp64p0iLM|WucH9m~m|r2r~1wL|`aunB6P5BSPq"LVBV?1akTa?2I3p*Se"2K7fb<v1q<i6+7IM1>V/DpB:tZvqsBZvU%AX/^$]6|(k&L.gT8LXZ+)cz#nHI_[{{!*)_FHIEEN7.!(Hp^Kmyxa9eASAmy2@cN96ObyRM%(qFiiSq0^qwBM~97wNe8$I2GaHjnq=_I:79*vnzfro_.;w<+nuMbF7M5>:MM^G(l}TbZ;tD2vi6VMg^m!vN5Yx2nC5l5xd5/s>rmz]]y]1n^9RP]Uydm?Qll!FSlJ7:LyISfUjzk}tZT=<RhK}KY$gOita}SIj?b1h6JPlJ713Luq{Z+DTOc#$h31;3x|+Cz)YZ7h&tVQj$&jsrG7VeFd[)RRv7:EWE]5U:G0yBon>hmlMip`OOVZ~q&FR)0el6{EATt8_,roOO["lw/=%s}zu|S1!kKO9Y`hX;fvBy4@U2orv:#SV7h4"+/*|z(IGH[M;ZgcZ/0.}2bK&$l5uO{h@cjS&I&d(*oq(tm}X7_Ctc5ajq#DS#x9#vL_aIHV]RBv2nV=vqSd=iRJg`L3QfkTi_Xc$8:GPUmqkT+Iv4UanBO#vvRl&y"GlJC];`O1HM`NVG+yn%J4R%i8bMW_@raEy^aFb;#fG.&UYqmBl%^/XBg,7Nj`y0~0)J<&pr76w<34^0_rv<}a{j)?f?"U^7SGd{}O:B>YXJ`c>x.;{d*DTb%h6@kc_q,+sL2"lwh&dfkT|B*"`vRQpagax[oH=V4]z9B`y)e$fo!%gq9gG1;dx="mJ&`f9urdZz}Ka8K:Q:#nw9,{k$n5ty@ec`t8YHE[Hc|C3gw[7OQQOf<@17.t0QJXQ%sQ+A8*OR43b,z{^c=*r=3(>#(O7+?>M;My_u#rG,+O/p~KZ%3sF[lrt0k^v*Vn+=A}.&{kFwl(k^.]SF0}(O][g{vf9Wx;8Wu)^n.ap4ubC/#p7$gt_m.=`9ScWYfx5laC^n:5v$K;?A0d!Yw#2%]7]`dm[!3%vHYz6^*dKCTby!ht^x|O^?PhM=i1;el$]51:}/n%LF~D7"XPrE|Sfu^N8i<4eXE;7IADYPEpTk|u:^dCz#1,pu_+F>Bx[%{^@]&mf)4(gO&FTbsg64v4b3gtIX^9:_(A/G4BVa0ns3kwXgRbBh2cz8T&QtlwAFTbJ/|r]XIOS#4oUd>t~vtgy}0AZ8K3Tq~g5leMRS9GW8&g79j&C%x~@@T%n*]U&.m!V5plf)_bonNsr_17R.?@]_7y!9?CM1`WrD+0K/PZXsa#N!E>L$4oEPx^ztdf9u$q4ojKV&pZClx[b{3%+|q}:Ct$Ngd%1~!qHtK^9ueUk4u.ypY;Jt(%aegTEE/6CI#a~,>C^!Ptl[*#P8%adYY;~`(TkovZ5a_rZ``9]c``dFYcPGqx|O<"[D?}CZ/8fI+vF^#08/&tUzeNbl:4)_U&c]*|R>C:B:bleR/jukI}4<M{a+1>juQ=h4#H[6hyUTZ^y7nSECI,K)s8Qbd@Wd<d;d7Ji43&uDm`80xH:dvLlJ25&4%(/((n9ndmiY{+&D]wKh.sV;gjT:lor7jXgQSZ0e$qw]nkd@(OIb|:LR_Jki~BfysV94wwv5KK^pgg/PRr1)]ZOh`h[0OO#rx5oAb{#B>YhnbXg>#TGxczd{c17wJP,qJK+NP*1gi1PhIv09RdkP<>.HOHd|=O6WN;K^V>6Qle/MSkq<*h/zlJwo,L<UO&Q3(puUt#!yl]V>aQ*uA;t8mxG~9M~XvU2DTFllm]xG(1^@#PiI^IL@X;!!6qBF1DX/bQ#M!{t)B.aQ$PTwF2Et9@pLBow[4]@m#=$z&Pp,6h8q6+K6Y=d72MaP_$|2IJNch4"K@GzpzRh=rB5r1,ki+A*v1)5`SE:%/hmlm}Nz*s@Vn?a?a_aLX%iR$1F3G&[O_[~d155^mGTEr4R6?^np7=[Oa;}o/:/HldGO;,LAV/sG<@PIcN5l6&Lsr_hKp,S^Q+c[JI52l/vqUU9sT_2[i_,V]4K()#bjS=LXWEpN}AnjmsP*1H{Wxw?}v+/ezg2KG3Da+G}u1/;`LPgr(T/+K(}N,sfjda*b*ju~i9Y?w)~^`D_CfL4?S)Dp8o0]mY+e)q_rquq=I=My#kjM@$FqIJNcASK+}hX`i5TDvgNc]a^HaU[RvU4=LN:`1Y6(Qf4}BH#_2t(Zu73[Ko`db~FVu.D+*B.?l`_9+|N{;<~HkX?k+D]Y&;|Sb9@@=x~ud8I8ooTLMy(J0/IfxjPT0s`K3/K*J<(_gTJPn/R!;O,x]X7!BgUg!k3kif#tk<s5UO+U,@3&E1i7Eo]J>?4T1v*/bTwo4yDghSx~>my6eYeS_xHkVCb7/YweJnuG@~F1.%L5g#1UCWk_<REH:sR0aDZlUASafmE)K{?N4k&uZ"jg@}FG.6_x*6W.*sx]UQVc,JA`v}9J_ziVFop>guz~I=zkHMU8LGN*_*rm/REHE4@=U>M1)zaoH0Vm}aOHOQh#fJ=Soi?,qMTk&05w*B+vp(.;a=5VM`#:Y0_s{X~?&c<J^Ef0I!_x}*s^fm8&G8emu<s$Yr1Jd()Dlvb.gu2~P#W1F$8C{}<(&vHlAUDy"jzupr`zM2`U:V$foe0:jx}HjV@C4L77Vdb^}]_=0DKV+cS7Cj;9B&Wrl#_5{t5UEXt*~&fYxCxm3KfksP`Dt]m4mR0{t#^1(G1=5wn!=o_;9a;ZXt"oNrxVz^o9D@9ZEK~6d[SPfDGP1V(Wjz(Ir<N)|TiibAnTw05M%u(s7RVCH5E,m`Md`L}1pq7#z%{BaKeeJC[|X&TTb.Dyd%b1"mc@!n$UpU$fR8<?x_+;HTLG)m)1Le_1NQqeUX.S[?GIf%j8*8ixdbZBB(_0<Br.;qW5eU=qk*Y$%1N/QhL(8W#f1qJK]Px0J8+aGO^UPoZ0A_LO_*?gP3TpOz,ER^*PFSwHX&x*X^L>xIZ.<0gU,.v{=)~y,cgF:XsdN6$n]8_ip9I[Dn<oQK!Bn&G&(.%h5KgOqPMeuff/.Rxk=iw66l2@uOF]a*#_<o$OVc[mW0<Zg6Y>?8Dw*o3R>4`k:mh)x1aYy%!]XFRPbeX*[]ka00ML<33!dNQI>r0!@!n`kMl"j[e1X}{HgAnTBc|$.@z72&J2LKBcWI(uB[W]&OQ39b}@<neLWsM23Pcc>@AWT848487rT<t.a6W_^DSI1ipKZh6smpnhDL>k/k<@|!l{J#t6elAs~ACtpDHe/8<$&bFj=rz:*42.y{0fBSZpgeh4%?"pW*~F^UpZ59K?Lh(;rh;kL6!R/P3aO2tjL6=6~_hYDi]nQjW,`n0v14quffkSf3Lv~As#Y3138o;u,rEN:P[VtL@QM2%ZL1|1aH/*MpH}8w,d*u1R#9ez>/i3Ls8wb|_uBveY;wZfY;;]z*$Q;{t#%;_tYP3Td>_tcIE0OF)&n1ZRd/r{acyv;<c]8LY#SD@@nyzayK)FVRL*QXl^lnE;)FijGX/dc>.,rYwDiVF[&GfjLP@QHDGVqG2sn#=tY+&wdU1SHa+B)rPz|a?,F/%*phlnxgC;gz3]!X$J%PiSU!I%@Vdik`EVkW)8Xu8iH!Wz_oBOKsb{qe+%[;e{Gb$p<?W.pkr2J+"MNWG<vfY("k^O8k!a87lO0,<S&xCJZ82<J2of&_q9p,`W=.U&#bH8Z2J}2sT+S&sQFGaK&s~gC:lfw>mFG"*cTZl`*MA:k&S1#HKYzE3{@qE}n36`g,#6+^ty>B?{XdT)LSdoV)Nke.~b.d,noe*^LWS%#+ZTUF)j:%ez]*y;&#l%,+6xo%vf*[#_Di7)GehvO+Rk~gefTx#hP3|vYRC|&1Z^tQB*n,%j?!QUfqN8R]IPHs(/Qv?!SW5&puLj,9c!HJ?gGLHk~g&?x<+S7@imxP(z}n9*6)XlEr^s{iPj,1=j_ih3qKs]6^fG)qKmomHYkyzy_@G~_cTZt%}efst2m]mGXSN`m[#{p3C9(l1Z|tbe~7fjvCI+:K1)/(xRB]"dgao62@qL_gnVLW;MA:}{CVraW8p!7@`X0Fh&Ah[%n2)yG4jkB}@W19$Dad&MOk(P}%@y9j8qd.`W"GCm%J2L//jW4geahe</hjfP1)5(wI#iPiaa7u|Of`]Q6@1Q2qnex$2^QU%YQ3KK|2hp5<"5(+|kX2?/;k_Tq0l2%Z`knZnXiIwz6Owz)Qa66Mp{XNTajYdHB(&yLTPcbMLak*leG5oeYbpHT]"oX1}H]<%jeg_7@dp6}:>Y}@(qcQarSWHf*:c`^yV1>b0}GV&lQf[iBe!8~t.@ry(/d;`t.@H&go2g^OiSJ<f_9].<jKb3+d%jz+w7VvD27tX<)fxksxl$nxc.=RUq4Vq0J:KV;!9R:@<dVMM,&~p0jGCirSWQPQ#,?p"e%bq}{o`<w@~b!0z"M)co"N4D~xNe0P~7l`;"<vGn>V%Y?Tk8AX>rO~|x/_9^gL@a,n(N;+kj~=88=5y*zeF$fm%i:z1b)kt{KTVr.:0B@rx[;.DuRhte8l*^X@efNo5^l:q$fm>tviZf|u{&*wAyTf*;))/I,8#)/8(el`VsVT%ge$N1mbB}p5PESs:<r!No)&Iy4:5HX@5b:[J$"],m};r>{/e%v+=a!eYS<7(O4GwWw[PHhs$9+POYQU=aOY,=w+0$?z.}[T"%@xBW/@4~2X~%XsKK0hX:{tgiFck!5RtQN+?<QC%@ji4GLqFAGKKbNY4Rr+wM1kC(z.zd|yIT5k?kKemktk[O^a4RBIOZL!2G(!i2C0l]fmE)cY#hg217nmR]%|w0?4(*(,61O,p6/??@98}N4)9}~G6qaNT1mA]q!*wInMs6`[NeI8TtjKi$~5LN.i@`K45fuB/UzD;Gi3r>awbH/iY%$Uwg>:Jry*6nx5;IdYl0RhM)upT:p*287W$$!GXBZuU(`Lt*QF_c?fY8?Z94@3Leb$E+O=0mA%6J#I?EJWgEwp*l1x1Ar=~NPmpg`GEP#.z:eiXy(:ouoPmR#*%1outVQKWp9k:HQb);44sbhBFXH?|apaEF=mbKjNg&*BLeR=$P!Yt#irGO_RRO`vuvx<Fb43]<gpG`;&~5GgRuM>dEF](t:5x+3k+D))edvG==yUwx04"o*r4&"^meTc8m!/r>RnWtrMhqt)Np_><rIF}_LhV7Lw<>ug:,Ie8aCclSIye!!fa{}D<X">qgQ_Jz9%$GkCyG%xHieY34u24[QxYoDeZV?(%CyaO[ORJaQ#|H:6K6mjWjHa}F)7uFDeqkZ]``/bAKJZ+aX$*:lQ+x/{x_w!d00(cQ5bj4{HG+ngE0Y9H,$g&P?$6@YVLGO^Q+$a=am4bc5#U8/|)0q}~?&uGk&!a/jM]625BuG]ud4iPuVX|^RnE44dHn}5zr;DkYb/c~<h,F7u)$(0>OE]6~fNUYSacO*PK8~J#/_qsP1lLR;0@@`[@=l>,cD&nR(n40X,Do_4P+_f/4|[^H`Upa(^Asp=tUm(|4cPUU$4g|fqQVIHq7y:o9E<1~84dVf/Lg]!/5#Sb,jF3gS<_9<WK=.2@S>uGmJ.OImN_4GD^923syjzP(et8>",#WlQb$8oE*=iSCJj2WncAS(UQ|AlE*_d>et}`;LW.,zqz/GBhR[4[u^!XXFw>7(vmXJ{?T"&[k[MR"yH@Ju>>X[uW3C8/avZ<5!zsGe;rz}pN=E]]e{7_IE30]7?`goG`wFHMFhs)<OH{dGeb*n}XaX|7Q|Cib=uYz>R4r)2yEE+jble]t7"!7wdxc,v$&RV?BMNIG$dLC>gGw>7}oJNwE&Pm^OKwCJK[NXeR?yAW6wjUqnt0pQiV|~w#<+`_0/$C#d]Gen/[H>|U$^zzBQ$x5KL*"p%Vn&e>)XJrN8v*GIgWq22{/5mV/_DGZdZpyQj]!!anDKK^N=Q?b>hug@4RUl*r&%|.#X=~w%E?N#f5BTL#<rj<t.X0c1JC}WR.E)jID8}Ty}>O5>H0Df:~LesD#Sz2R?VHX.%y9l8V!^]<&8{9OAJ9|$I6CkJGAJNi8CA2sG!uJ>4,L2]}UrN8[d6rEZEgT}Bs?_ft$ZO.atK81/W~Kgc6a#tqoZ`]pDi/Frd/*Ihw&OcW+[6DkVj#NA#)9wTzRYD>11Q||uA+ukBHOEBE0JywLquUqc8ev8U+w2gG6=%@lc@@rtC@,vul,m/xPty4x*c4s^Fxv!q9Kh2p)Np[(?Xx4ShnfCG6NLpR5o~ev$PCz&P.:$#;_]sp^g;#<Fq4aA+8TTR0c]Lg6YP@x#WyQ=L4v:*1)A.|&5431di9(oc,%T;E:!q}K_fb/*R/x02~ol=Z=CTt3n>1l{U3u^R$m<@GD#orgyN|(|*_I:*lR#*qqOpfO0LV,FR5;FQbD}[8gxx=Y!N#8bctupw3%FFi|A8]OfRp@)%q;TR)p37vz({Bh(~qoEKkGTD@!39NC~Et0wKYutKf*ae!tT]),J^g"],]@1?=DhC{A8r7#Tcx^D&Ml7&6M/obdfikWRAlgNvo}S0;r=M.,/4xj@*Gco}xHGy3vHoeUDd?RkHQF0BIEN?>@i6%YZ49{TpK1RN/p8DXj)P`a]LK+L5x>}8ZVI}:V|B.?ciiEyZQxEYKH7eft<[v/PTx0gYncPT#bWKjv;V*D9YBnIBpT#HC.zUa]c:G8sBplA*/bCy?L<Q_EVmS~2:<$8Fb3#*vxR$;h1|a*x+0$:Wd$AUoJgw"uv~MMsw@.XBP];jK^7tR!J<GQt6gDBJT/Q3i%Y%oG#FIl]pyA[I,rK+B@x|81[Qhe04^N$?k0>"AW+~Z@1vr3:6e;)n(8+X+R2K>"6.p1&VsWJM>r<_BsR``d*nicJ;i[I=0<aE>HuPza~EC}~OacYhj*E,C@em$j47p;b{.^dL%.]"Nb16b:5fU:iaJO"v6*ND|gW*%_^r`GrVCx[%Q[8>J9z52OUdKH<*..8/T47xWRugRy;Y1c$8X1:)V67i^M1VlaK7o:We<1h%`U_`ZPqo!ihr)5smg{2pl]h1vf#w{5Gx!1W%c$DO]@Lzmo$VTp7X/4Y_h6s*AOd6<^hjyB(%nj]wze/w*2bcEQJ],#Q}/%X3F]X3]/dkx@ZjuQP.25hrY.>jR#&#;=ORCfyeC=sK^R9kFj"m;Rvg!p:~OB,:+XEdMSDI_*6c*z?!;0`,3>$PJ,cEg%k=~n4q2p/rIx!jH.qY0P&<")ai>}=P=]1f]&n{,)0m+PQh/;yfI&G61pwz#IE+/O?,FSB[G^P<}cvfbk{Hja_(]]{kRW|*D=gIh$A!fyj!S{R<0IClwO+,/4&;h9gx6$H$,5MwpYq9[_t,QfSwg<qI6)/:j&pLzrD~;*O8[8W8)il,kf)g;_y?&j3+188Q&8R^B+B.u6p)hXLe(?vmF0B>F?aFGrQ6pL]{^p[kZ8<30]%+8b1FI^@3;!yQ`&~U.3JdO5&P.,%+>aAe.NM*SUsF)cjOvx3<wU9!6kp||ZoJC2)k(ITc!wYCmdl}/`d$5pvjKhc|3$Uj<x$Ox?Rd]Lqu/F3lWh:k~3wrdkwa7w0UyRcxxcEFbIY7%s*cvVHcv?K4r`k9kgC0kqZgwKy/{0(@N`y$Fpt,EdXR2D"%NpK3yi$:q`>rJa@@tt0fPNp`3g;_Uq}jPM0KvOXOSU3p2QAGEF*:hI&Se#dkUf7z%YWQZiXWWQ0xDGo~+0vd`zB:g7.[TW1YUU7iH1XY0MnaQM9#xR0/dkOx@o7V<fGS22D&^roOF,YO>.moRfbxy/D5TfT<Z/O.&^)oH9^x_6>YDn?#1XZ$&lb..&okh!Brr=:*Rz>@dfxgd;r^A^3vuK0!%~sfrmHcv[jixf^c,]^!weW_ZHETy3@6y4j:gCd@eU9U,gpxwH2P%?g5?#?4Y%N2}4aJ`Q{8"Yy^C61#<HIJLs5{th/{Z,pjz4cVM3_>G&j1ppD{z[PG0XA%sQ*Qw&Jd/4Sfn78Z?Cp|Qanj7"NR^cY";$=dbrllwIA+%0@mhur2V`$TcKT2r2u5VKGFwDX/lfV>Ly0u6kX6(<,+gC>FMZrUYGv_|V7ldk+Rwmk=j[>CBnF{}i{*lpL^U<sQrnQ^hcY(K2JD9:X3"4JwmAlBD?EADXLCiG+MNf2"6i:%tF@A+u5]pD$yIkBo5D%I"LiAAAAAAAAAAADP"Cgeb9))C8*vVji_+0*:$W~,0Nu`yJ"Qz`I)n?ICEj&rI~bNuqcK{(@$+t"[PeWOP$$f]&hSyW]6QC1X[iZn:`m6fOEiiLH5ww;=&[Urc%f#9dVNW.C6)W^=>cs<Lr!P@LY]u*NMf<b0U_]D%hc#$^bk:GtB#Tg5y,VV3AR`c>`TTUPieQ>+Tv%T;UN#&^x#[KqI?`y{N)VNk#f|PkTU6B48sl5kH|vh{OxbOnH,[spmy]JjOYF{}.BvVs5W<#ksBNCqE:H]q(aRkvMXnF[|h?F)rWFP^MrqrB{M;^d6V7jU2lQVh)Z;16w90~4}w5zJ5YnTwucS>>&4sC@ixmnl.hU79W>T_GSWy*XB~QO1kx*kwy`YWNDn@qd5{Gkuw(]Xf_KaynoVGWFyVnpt*J=?IOq1wIECe.J,nXUdI*~7)Uu1m:QB`B$R(z9hz"ux_+;ZPC!=MC?%VkXn/[u7SlmO>7fNftX72q6!t^%/_I*4z|7Qhe4=%1]1;O@:%*+0;:)<%#$V%wVJ!d(Z{8Am,qL/MX#l1D"q?tY=RPKkx71I>ZUz=C6g}I2dz_S0:ZlXQkFsiW=`C,1u;[J{LL=!;zSgot.;n6ZC*_q,W%CCBVR^kYk2.*2X9wig!VQ&@a+<]yro)~dr)thXdi@lPP~}g^kdf~@B_?;i$jy&:+WT=/VG=Ba9a<Im;#9p]$`99,Wu,[L{#BEW6,zK9N6*bM8YI^xnFoLA~:"a=sA{/27,wUiE*AQY>dux{zm42vjd4d+dY>Mm6F;!}xOU`k9VA2~mfxfH|mS_c3knIlb+TT3K8J`.60S]MtIMBR2c2zX78dXbLr_K7{Kl#fkriIU7KZF`+kt/Xqnj+QeEc;98]U#K!(j/M!TYq3MLE.g|N,]xy8nSG5]!]Lx!mWYuA<=#{U9+oR=kd6+dF_Yl8!b7JpU!(5lE:eC!~g7lh4E/kipU4qx%xkUybDq#L}V$]5m@2*Fi7|rXH9?Y;Ce*}Dfj%)=`5m&&2d|Sk1G0{"~Ehs<*"}h[,hO+^[&@]>vC*D@I;4wJ`:Y/gB+(Y]^>fN:+FA,|<o*EV2|mL!x#&qJsX)us#g$~Y&Bd@q(kX~jB#``7UI6;{/WjU{_*j9+t0#2d]i=f6JMe&1:H03s:wp7LM`I&+Qd&`E{2c+h(BPgT~J*$~5RPm<R!)6V#}dDh(Wn*1>^dSbIh%f+#rLR$RdnzafN+tL_$,C6Vy2@g3j6SQTsE]8yl?{W/3v|G]0gC>bG7:~}Q{3g).?SsLQH]1Kr|>fj1i5Ddpc&[)^(k)uM]Xl/:nh|S}beUxRve6t%([Ozgb5$)i=N]tjLzO{?nqPl}!*jPm#%s,}3n)p{|;w3_^9U9MhhMm{I@tbeIovNc1m2zT(eCG_KP~>}K4@=$IFHD^8x>Uz~tS4[]SM#wU+raByPogbEJCT1*^orJu`Q<JZIiDFy0g(3#g?edFMLyI~rT{B`>;1~6t<$r`~#<Be8zqC#nLESbb_;eaySqE;@Qb#9m+qNKQ<c+k5^m}?$2PDfpJM:KHuBjOze%k0csrX4?"q>WJ^G$C3ZSw4|KitXGeRm&$WT!#}Nu+7L8)R;Y7dsMG/H~Rj|]Ax~urK$&!GQa7B:6w7lw%7y#"mC"uY+PDFku=()@R<9NFRm$RX=T}lz?/o^F:4H|q3Q]`/vx5(GL%zQ"O#CX!s%IIa%~ZNkI){f=t~Ph]xYGJto%0_xh*]/ig00kpeO]u;yq,1Ky`c9C)f3*#Mj(CM"|zNiA@JZy=nZGd.SGQL$N>;.qDuziO6oNN>8W@=GifD:5p2I2pNZS"/8=30RBG=f.JM_I^0p=n0co+y*wlFNi4W2iKSg1RSn<[|KwK3%/2)^VG{GuY)I7eE_5W]8yfn@QX5ms+cTQ{H8p`)8??6>;%<a?`dg<W,SQS6_|vE4CVVbqFJBmfX`[npP6`s<FG}[>r{|E{ZwblLA/K(*qPKQ[Id"!|=iEU9^2Csp[=2E8ba8.HB%H]37_;Q[:390}vg9isv}OjpRkT+~0,H}~4*^Na:}G)xDK9NP*8{)]75i)au?>!cG,ZR0bnGXz@j7~9`L>x5``a/L9I@,)y2L*"q[9r(?m_W&|%VpW2[et(d<$f:AIe~zH[_!~!w,9^N;j#BiI)cLVh=pkRmy)x#[)=Ac@pbkrbBu,jt;,&E02j$03DqroWZ&Hplu>IF3_"ihbItX?a_NoxWKtbkN%gPLZg(0L%t#%xz+u9Ci.5WJ+A/OPby$3NHjvbXYKr.P&>tZ]RB<&3tPe~,1jZ04x>l6vU+cEC+!O3f*ET79wAyO`iN$$sFam+%[FJ#y"V66E0LNv>dgonmSCbwF8Ggm222|xo~uN27Itfz;[u{gqrvbs7P;7V<bvfY"|HH*S@eelmfdG*=<IlyH:XmPLS)!r{KP/#Zf(ulf7W0[.SEl;QZ|^pDrY=b?=xl#`Re!AB4c]{7Q_X</P!!=|_%ytFgY(&8|CC2%u3h|3Z#0AP=t`Yf,+dUVKgyC`lR_6E~tDoZw<y$tY>_L~J,GV]2U=}N!9Z"7+hG`piSYw,<!uOeZ;qZCXRz;uO90H5#q;;DJZqWN,oB@^hvPgzI|Q>_{n;ytNrV.a4%r~NzCHkW;^ItBVYU%dLP>E;yvF%!Yr4Up~bgq%501aK,8Z^*=Oa]FkCd35CW2D|8;FCbBNiG"Dv`R$?)lFYcw(z|,yw{T6p012<Esu?VHT!IBcJlQ<3&@(wcd}`VAeG.bz044~{:3Vm/%<OK6[z0WBX7Zys?LDq/O/R]lFSJ~@"XGKj%{r/?0D+/~F/OoYWN=Q4P,g6dsjRQs|rcfKo$64D$mg`j}!K2F?H]$F&1g^h<E5{kzXXV<+.o$gTD}AiE,YKy0Kbq#"pJ6Z2_jP[j,i+s~_v+L<Dpe}3^M!"z?O!YE~|Q.RT{?kXDLV#MCi_M?noIgT_I=RbqFb<k0Ve148<%sH:gnwhV1bF9K@i~fgGz~y]zH)ohI,{Ltx&<UyU~HO.I!jf~L]K]b)U4HDG6bua47ZOW)^:|uO}v0kwdq{V$rtx&9g:VS>OFo4!=5OhU8MpSUsf;aryH8KPE]Fy!A1Z^ubTae^E2$&"vtbd%_#9Cq&|~s>m^uT*xcO?V[j+WI"{6$D6jtiv7yu91;itIg4~Hc;+BJ=t57=N"60BB6/LOOrw|!m~?z_>60Mz`cX}Q*~vxP=bHY(S$sw{c[|NDc?DZmL=BP]hT..0<ug5;8@O<HTIzPtO4YNK@uIPD0A[/30=P%:mV%|O`#MDESIrTC3@,GVUE{`dH+#+M#Wn/7:m?y[Tm"##@%tP97*N@BO">;5I:vn/*F.a<beOV8oii}&EJJ.[a*D6%A:41h|,B.OwG<J&~^lZLuk3LpS$X,Q1nJaeyUl"E+h$Zk6E6TFpk?H<<,l0g!Rt!R;d`#t8^@2t5RpmNv@&ddm/KhSyD)9tEukWnPyk)mbe86;hBPe^0I+C$Q%~lUK$B$"[V8>Y)D#0x"Ib]dIOC7k$=jh_ti[qO3}VK[2A@OI+rf^j|U@b4pE%,EuxozKXm&Y;|#1K3,5{0#x%FM2k"LT=vN.7roxe3d$![&x{4P{si]2i.8}f/gCn!M"d4fLPzgOJ?f}*PsB[vxfIzuXfe|@j+3!Ounxv(M7pge~/Kz[&j},52e1@iySLWhOO[X3|JEHC_)$Bv`>APU?|V^]>nYjxm`d?*qHRRvNl0`i5,_`{#9?]?5IBlUDc_Q&bnL@1WrZ[Mn.$u;Kr3jg:VB!ZAa4$Gf@Q8DAhrAHwN@i2ub/&NR:(HGgSRGTY.tpQl=ax._n(tO29FtqXrRq{dg.Teo5(WYts:#=yu~.MuR8?IisK(YM;bP=S5,:z>_4G,qVk{e,FG8**u=9M}7?($V1,|R,l)x;p;U?VDyOZ;$fS(4nCxfm_OZ2T}ehpbxi5o1#?F.dedD)f0ueWVLDE`0?C=x!EGla66u/t&}5[J&aMShwRAR"GzbPC804y.HD2f2`$nxz:uN3rUF42[R;T7TpY5aap{&2p`?3xNk(H}M5*Ko5,4vy+xP_"(3WOIQp|z9kZUXWc6h84iv&8g0dL)S3Je/%9U(4KL"Vx"z?BKhWMfo?F~=>IwmdFK`b~%bQEZfm5rzQ{8oe1Y{o7Q5Xpj,=32<!jXG(ot]r(VO<v`[jH^=`*JzYdnI6JPQNr][Quqwim*C49PDVtE|&~f3okr>*pR,gWpGD%eMAK1/s1I=L!s$NxI:6O9e8jI*#%M}q%JQ(I,2O@m#zRWv1}!.2T*BY=`eW8mQTC8}Lc~jPuCa(n4".PE#~yDjbd=m"P:rowXHF++Blzd6|Bl+$kM}9r]t7.7K!Os@h!Fxgf4/NFdc{+mtW~ESu:)9p54ndp^x7wr3>srE^7_7L?Uh{sC.|9K417J<8VH3;GMx/gLt(w|h}UZ{KbC,$dbgcCH[n;BEPD3Qj9t4zV9jaT>B8@k31TEgFl);#DUqzP7m/qQKVD?*!p@^5gi,VX[$$~G|/VW4k#39k5+>YlZ)+%kk;7(Ydff1pm50Z*,T8wKnfr|stNw1IfJ>a^"E|r2C>nOVlD,3utIwP|mQW8Bmbx*KNdcZXmN31#;R<la2jXaM_/CEtr~Jlz(;^x*(HNX5}a`Xo|B5qB#Ilv[A#Hjj?O2|Y460F%04:=w$AAPlw&4DD)%#c>pn~6z2,v#[<fBI_T;dM>:]4o9H,x.M6`KP/D&Ku@m(s[/$=DHh4W%bq}5LyyF6(_D"uaDEG@|l]iF69{g"y#/,Tl7}wPSq4v3sJSLi?)IvBr8k}&tfS5$+{$N!OK~vfOXJXC7#IX.cw25Uw8@?O(5Ame]$^)7rN_7?g<im]WV"*5xY7{vxHG$x@a|1Ek::BUe<MUzgY<PJ$mQ7[IabRU`7SR/J[MO!9;_G_(DuVCiy$Ocju59:!9#!WEj^TA{2K)*@Yjh27c4k"#F6~o>~ga$h701$UCZ(O0:q#+B>2DFI.s${[]$|ymz+#"1T5G}xoAE:,[Q<Th&d7LBL^uULt~v?cn%h!8]S:<,7/$%:jn0z}|*ixiX:~/VpM;91[aW5[z[+f44OyK/$Xv,Q%sbyko@[3NI62EW&R&VLcUX8I$^zBi|MM{R;(,sF:}YEV,?Qw%EU&Ih[(1*IyQ,[YM{!l&(ONUc]R>eZ~&N2`J2S*"y~~@^|dMDwLZpQrDuPa.R(7o4JpoqT`.`ajUjM]rY&}8_WLr<:G]aW,R;h?E?6rbVdo/nsoz?]B{SR<)_i;;p*:/GrAue98m2ti,Um%vSRXrL&Y47|>h]i&|>!<N,Av;>+OwnTJ#cG{mLU:6$:ekF}_R9odoCgtEXoj4.L={Escu_y1)oC4|I`b#XBoFYIlN7(I=5%ZP]cI0Oj0bI!;zR,Dm^0W=X{UIlFi?Xsz5#qV9JEzRj:$@b5>I%i`UE/)1Vmdy%]d2j9~sAsM65)N@IuEPNZk&j9a5s.T)*j+b(O?!mPt*~0!4CXmID.1%C<_S!X!Ay]z;V$#Ua#gW"WG<FG^Pb/D/&l@IvLt9(m|H)U1o;2HJh~/xv]lEdLznV.w`n?fC!v^6?_CXZ:zS5KkiD$.Rp4Y:TAS}jO#9?a0uAAEC~"93;lTJDg:pvwgK#j8WoZBDDA_i{V8V{`6vfdtm:X9C]"lJ5Gi$I*E|.ir]V%J%.z*uXds=|x`Z+Pxf}&Lgq,&_w+UIx6ycaR}jZI7h&9:eUcGVan0]E_{Fo!:Hd:}Vf)1Tah4nQ,s"(8POpwod[E>Zc3O[(Z}OP,hsZ4l:m0L6@Z/X2nu>HIP4c0&`gmu4A+[!9N[/@@N6d^`I`>!=JNsI@bew>`[1#H9miAIOlZs^P"k8*hlZG#`@iAcwR0D2/nf*(l~4!>m5n{oNjaIee#>QH_c[zl=d[SD~J]Qut]r>3CG=Yuas%u;`El=|p:jaNo}q;y{?}tT@.p_~s0ynwD]^r.y37mk5,:Z40SV.o>Tq&"Ak;Z4&$@J.{"Z@.A(ps:oN?]$Y+cs)Da_Qu>,mCW2vDZ+!&CQ/8,4&%*?<[t$>&Q)H6J[I|UB/B<%Z7ONC9/R_elvrSzjFuZjuJD!S{0W&}DGYZ?lj&XhsbL@KC}@6T~L*1&OEirjt6uq[eecJs/bK13|x:cUm=*wS@hx7+iZkp3Kq3J9kN?&:;ze)0Uf=*;1OX7PovIzJ4($voAOzb$VSa{rpb#H]5;E0bk+F>CNB3)k8kB(d;SP:+dRqL?wsHi~+v6.7al+1S)wiQ_}g_r2Lah8n"e)OCr{*KkQ4tn"1p4C|$qm1$5:zzy!`ilfrR+;}X`gXY3?;.c%KJ+bdyPW*5V{G9u:7V7C7QNB{mRU{W&wqNN)k?3B]|0cI{iwsHz7S<]j7]s5#*{QU5=<;D9H!J4*G=[qG)pt7CPK>#9i/fa@~%(*.7[Um{RO"fn2z2VPfFkSUv7^qY8Bd06Bh[C1_F+])4E&j<mntrYpxU/.VI>euAgr0kd%;plM<YK.Lz5uj&tbG2n)M=AE+nOD%jQr{U;y[VKUUOZChuoq?A&/s$Ma>Xvx&y+gr6bCr.:CFE+$e6>K}#@h,.4)5/1!URi}5q^"_Sij{pCiDut.`ilyd!lzE4jD+)7;@^Va%v63?WOl$`e`ye+PGa$/fBy2.N]2jibXI/9##BdH>^K8+&N<&4e_q$1yhja]%bX[&3.(f#O+xLC#)CHJSeCFrHDW"uEUC%1+aQuX~b51t:qLD%k)wm$^RQ8lNRY;K)cVz<}aVRF&rjjR+ZH+[,V0AjFU0<MZwExG.3vclMiZK<gZZYJO37["H8BCR5>[Mh^@DZ:z29o+;Z4iD0l_tpT$3N4m>;G~p=W._?fdzT|~pU>w=+P+o5*uBJ)33Kj`Z}G+057)i;*ySN"LPW#mB*)$)_"dZVB;C`?nlfV^~xTCW|Gf5qIhp0LL"SB{i~D%`J:F=_1k>%"ejRI4!mrZZtvkRPq|D?Bj^wqA|r>J~B]H$m8(BrE_u|WUocN&EV%u6o;}1!r>VWR7uZ&`lk;;i_;Nqcsuy<gW<*W)?y&m<mZ=f<&EFFR8%1d0B1N@i)W/q((gxAY<}@F~74y2TnD:RbTeaDOTzNmDa2gFs9;d%mP;7s#%p&vIq4DM=/,(4$.kY]ro{6ob0nro#`1s*9i3k5w;ULiM;R>n/Q0eY5PmALzlj3lt4Sw50a##Ws.uR}hf9J};8kMa=om/4?7Go=J[Ysu^$EyuPX*Tc_fQrf#Q#b!v1zW&358MslKd}t@R$BaRf!<XU_;{E=@(SJb/#l,@lmdH$H>n4#S+]"qB*`#zcm}y{~[^d#Xmim>R71r79sKIwG4hClv{Gm70@poqX`a&EnjtWXf_Bo=1R.(/F7+DPg4Z~NeeG"Q!hwv|)fVyxb~P:~j4U.aJX{%KYJ(R;}kMA@D]4b#^eNC6x+E1Na??%sofUi+Dw,hw2v(z8{S_$B`QHP#6Jj4bH(bg1ZSqH#`_PN5@TwZu^w}Lu|fg%i]vY0@Vb]F/c*gyKiMP_5B7*>[}Tq`G`w7.5m}n{LftC6]/7K`EYo`:{?UF2u"e#P^7TN^BnK#a4o~;2/*f8pelW,v2=+BR$@K+3T8X%:p$r7X7m.aTyz6je`C1^:Jf&LM2NAbKz^Rx+,fm]+|}l&?~ZzkB23#lQ5)Ob"UC2F;OJ/D*Akzj7$`5uX!ZwkR_dds?(<qf=F"h,lZT(0!HQS+BasC$s>W1^7*=yyB%;SxF3BZQOe0Wu~(Xxe0kY5|*?g3]xb+g"(*67s1tX&[Q}%>7yf!xf]44b!Bu.BEpSaSY/zu:Hv`OfYEIjFbWy{Vc/fsf?L<=UI"D0*T2j&9%G)M{Oe4%S6wt`lsBzRN;P6(`UHs:V=}4|[_Q==$HuXDKA!qaXI9CQ&TPl4h}+Z@2hQBGd}4trNJNu45$;9txjOAdu?J?|kwmIDaA`k}3[UX3*%$FiuVv@UJ@(iv.Uy0Du1J*mh(0S%*;F>Mz(9C%cuo:x9?e.<jL2U7OudM1e}+2^aJ9N"UF!/Ai9"?tYjd!qyG^{:YVr4]wmqFkq1_Za9Z4<T`~Xf2qVi17M?@YDvczfO+"$hWQ|]6xTT#[f7T}Gr9He~4@%C~:KoeN[],G3d1G8m@!&#;v|j/(A7No`Xu!Fg}^F+Ka8Mm[5.GjI+Qvpx}Xm|d]5d^hWO>zC?kkJt9{:m7%Jd.IbNu$ON4SfPMN&azJ;Uql3=1Lc#Zd$3EyrvB6EeFJ+cpm`Jg%qFW%ws|&dJ>:#bzsZy5ET|B`GfxuSR8F/fTmFaO07([m{i)c2!pRi]H!S|vGg4#;ZnqL^8^&r<44V@sz9j?k0ZCleJjMw{]!h,>4I.P3wXxO?81bC"(,fgiS&D.ZL=M0/uJ%VCDrbxjj6:zxpkG1O|q;3Zu|)SF~kUHNp;Z0Uz=lurDR|Gv^Y?`mj_~PD].Bekz;Run/"B"!GA0Ea.T7XV)_FplOwGK9|voeL=rzNUX1u8K%v2Xv%MNjt3E23rHBC#eRG>a8sKfR@E&2[{`L9sN1;tQ|ZyJDg8p@S"L+K7jY[F}<E<HqL[M<@4:*&Urb$.)L^|F_!,?G[+8Y9MfX04q7G".0GX@)<%@hLwEi,4?4&eS^%qTF&_b)R>@*:P2Xl9z`KihlS:s3?Ps"xS3cDU^yhI`n,j)K@>j._CLn1L/aqvz|*]:Cy5L.Z0h[6[RZGy&Xmwd%XB6&b{e8I.CD9#V%#wO@d+wjJF*cX_~+59P/kI"Ef6}VIDYp^zxI}36CzM!W9ZxeYRcR5(*cj;nm0E0t]*H?;F^C;@enfk:[RB8nfSx?`>(jtkj5/C@=djPLO:=o@;s4+;Et1@naQJ;_/DGAv]:g7QOL*=Rbh<swy]|_QK}oRCLJn0h]{HH_o{TfO]ePN15JB#kiCg.B`73h[z^}bV;KdY/D|#]Av`B1^C1gwbL41.E,O1/oMik!PVkESe:DnuZ/}<$TTtV~8^R)A:8/v{l|po<Jk6Mv?k2$n3#aS.q7[Qm,MEhCg*.JlP<SJv*/}}e5dlDMma{TP(G8,Iq^j%#TqoGr1{|Bi?#:>YyY6i>?$EdM7q1@p4:HzmH[L3xC1C*hr+dY%<Y?oP3_yQzJ%3L1ilxP_h|GH:Ofe_0qYM3VW9>1|odW,dhrO()dob<CYgz>YHMB"L]S;0QazNz9}&xDN)6dX@Dbz+GY[#86}A~#sa%7`.)jbf*3d*+&hO}B&Jm!Qkcja:cF4"g>%77Xuoe%[KFNqI$8JZt"A1:[@xUo}rmT}=:uWZo:&&nKE6g,lzrvmK/8Bu!2m&e<"qR]d8Pq0X1%Qx$lD=MK!g;sS!RQ`XXP5q3,T|<JpuOGgOXxTC_Qql2[_2<J+,DE~}S}Z>`&ODQI5#G<66dDY`r0(q2#Iq.7#vHD?4qKb!YC#~F]cst)j?8es&?syC9EDH7z%p:"A`W:0q]D[o]$E_&KLxgV7kc%t~ysT(2YntT6uXoDs<k{$_VcMkL)H9TOkY>_KiP#Bs@Q*KBW|N@fV1_WC9mTDiBiJYinq~*nF20SyDnmN`G0CuO.JS8:1^jYv|ix/<?"NAN.BbPFA^A|mP"pgH17!aY]ex#B4R?/Fdj.gd]B4,"Gd=cuxn/<zZBy754Vs4uIwvG;dxgqV2xW#FgHVaUJZ=WRC2lp%~I6)hU+3&ekw[IRN|WvM8.t;als&ce+8#04[1xS5ck!LP`wTcoK74A?mrDt?mrU"w<LmK!6%x=3jD&qB^|sR{%(=dJ7E2=a$o6L1E#mhcmQUsuy71.|jogETS>}nWD``(P8~`[@jJ)sCpgi`.{N=DIV]9q|N$=VEf8SEw:RL!yHnL>2@XiE{RN=>DrGDtr>cUQ@`mUv$AXLIMawz0WleHsS(Is;TOcAu1?GVgRWiE(5r)YqLtV[=Fv`n=!c7Uc@2is@caaAI[?F:.42%EgOE#}p|kS7IP|H%%bPwpik]{%iCWaJJ%rB[dH6}a/4g9TlFPQJr%:1[`^oXt7T0#z`[Xs8M$,gz;@xj*!XX"lX,F|H$$zMjD+CnX9HzM#t=ibIfLBQ_rI9x*Z8RSEE9l*Xkc+ZUH_>H0z|/`@q*y$J.aKNF{zEH)^PMYgLwvIix;V3;%~8Y5ZtK*f}y2}79ji./.8(5>,4xD+SPV6$W.>LwM@=bS"e<tdrJ^(uCrKnV{DVK&FTp+3)`VEqWtmf;aN@kwp?ovSQ%({s~)`eK:{<Fh:A`sq"^Fx6u+P+A$5Sm+Y86<qm<M!#_BS{(/IQXUE/Ox&rK#U8C<.P*J#@)x1i*/tcTMeDJrIRls_]2e;TPCW[GrUTX@>&*VS.e>=(^YN{0wi,M^(M?c>x{M$i0br0I)cfg@U)BS427B|n1FeRp]_1J0=E2w_c3)#XVql}@tQWE.Z=}T+eznczHO=>#,DC%O0Q#~*2bl#pVFGC(x)w2)!a?3LJWC(%<fO|6s6G:~@q,7H03#.hF~"4;8S(/B)2afhveyt$$):FI.AyN.|eP~*Mp=m9m{3;=1?@w3$).VMZ"?[e.nfGSJGD[1h5Ie!jx8yK8/xiaf9jO7Qgq1YAr`g`2d~;{,6MBfGVzQZcBz]zGh)/exkFq]Wx/ub:dnYQvkqzn!^cEgsZSDN@j3}iJhDcurZv6R6X=fj"vXYgxQ{I<Yo.JE1cU_Cjhn{~?psrQ7RpY(/b5RK#KR]B(VX*&:,t_i;=&=0FDq%BAj=OH7?9cu==r>mo,k*|)##{M`[im]26<CYQr;}Y!|(rq!6J@/769%(Rlqkc`[^{sfZm{rENVMx?>~W!:<7+bS5/gDS0vGH%`}J1[(K9BM@|d&8rlvnx68<yc]Ti#!Dix,kkh2v&[mbUK)bpZ=!lqubo7kJ#AhECU3.T9>3LYMuTNR(.U%<+(i$8(MW5l}y/Fi~5;Xr_CY%VjpT0F{*?xER8XNA+#uw47JPOJ#5R$4,d}2lj:c7;,&.k/4IMe_Chusv(8P<Fr=J;V+F"^Fff]E`GF6MjopNTKCeD=K`nQ0N5j""b]Fy=hJW2zSS<">/x1c>ocEmU;@nFNfmXl^7N,Hth[Vrtaz._64r>DBEX1M<oa*RCI1A!`F*diQn[F=vv4<7!S>dMN2?qu8Mc%E.m*@cC0T_&>#u]<H8|%|rX,uF;8[4(2(6LQs(}csKg)3ug2il,/{!ypG9rLbL8LK]IXCyFFYc_(J9[{X_]Z3ii|GjGg?%zME{5,Xxfi(Za.._fZGI9u3aOu$TeqxhAnmPtqe3:l^?)Kdbt)gHOoF]pT1t@^,$aKz<Qe#KEu10G3^(I$P,$lLE(xX_xV3h|Le8^,nWOJbNeT;l`aQa(Z(e@].^93f!xkQF}j8zT>bW8[Xw1cbczY<,n&SM7FLWLyVyuftqjD`Gdh(H6nU:)/egh:,q=G.z.>)7w:feDQ!{jb,sG`~:V#SZ0KyYbd:.`.4T$&~9BTl2!A9}5x)FJewj*V)UyT4&_rY1_G:3rk}~h)NV$@dF{C<M&7b(ucB_THDLV*xvpt^upEM?g_q{Wxy]1#LbFCqp53_+pN&jRNw>aLj^]K?wKtH{^(]|:R`n5#Wo;oBwyN,%L$vq+o5~h3P5mgM#"]q^FfGWM=P:*`VwR2@=nM|UA4T(,:&6q]"NQ5#|fp]H(c~.4XN1C+,}2^Syf,/}.f,,9mxW0+7+bdK8LvSPPmO?2eYknFYeCi8lU|%{Fhp>#}qO/+&14Mp(F54E3,AUC),?dGetL%X6;oF_4fMHD6CvtAeujKe.FpJ6{qv2TC0!|&sVRRSGSCpq#t/26No|Cq@]o:+}kfu4[M[Puv"rLFbgE~v.%6`BZVz*/_:t>SX9("^B6/99y.}.[c<||00;.)cSHEu45o3}D=oE9eWwBCQ8Vb;hdh2ziR%).T2du.y@Rv:5`O,6Sy8Pgrx4QTu]Ea+]x(=R=nN&CyqwJl"h!+dUbgZ(@.W~Kx0KV<r5Y078?<tJC0$PEK%t,#@8sNS>GiQC8VQj5FdWCvv";fP|Tu0]ztMD."{=n[KLlJV<:!%@y;0Zy~VEFZm|5iQH:_/7]=Z_Z6[Bb>aD?06OkM&$P=l]$w*4T|41K2&hqUMZjEC<^mD&o9?c3|QIHBZAVtgWkRt^Xd$A@SIa$Vs0}|y)5eQ>)^q]><!D&b^<>MU!H<E8QU5~[rN]"!L:y6&hT^Bd;X1Pc+qb$R2WQrusD?O5yWO]F(Ct59;KZ9hY#aE~0&ackV&qabmWe&/;wx}d0t5btO}]4p9n+Rvd?hJVoip&z`Vn8Lv9/~F<zP@{3/PO(*bm{BN&"+C8kxC9Z,Cx3b;F*pEP@sE>6P=YC*nMWnjc*E[vr~pTOb_^G[}tP[=Qpc(Dfpznc9Z[zIS`<TZU6<9*^|3oFy(~q`29TqQO,No<<W;Yb:AAF_nPxb,nndT|veAWMdm}UVgl*rI;ZW;R]NC0),]"o}#Was$6bqlB#Co!hIfbQOhffmaS.vk0fUO.e&bW)DM6g!W&8_ot*H*8>~@ju7+2sy<@+aRc&*H^|Z}hyff13|$l*P48fj@Gdl}el^&]5KQ~TR3mGIJJNeE[Eql}]c%CN":&H$T:W7e:pyJGp2RNo6M}Ec:p?DRgZNc7*v1l^KrEYS5^4aXu[Ei2;9qT,*:iNz|sY?b(]rIiwx,!b)]e)ME#$Chd,&t3+NsW}jN>FS/Vx~bb;!E3;T$I0/l"6`EkT9Q`^|=;KRoO>Y&_[nk;[r{wBuH7a)T.$g``58Rt+;%J*~8|,1*,*8e(CSUD:3B0T*jkzD?ZH44H4QKX]?p@=tjXL;%V,ZcR4#&Z)*>aEO2[jz_5oT%sJ"y?n3{%vcJ1*8MCjYwe!O#AF@TIYLy~^^8jmTl6?Q?7{l.Ek$n:e.5/v&Iaf."n)YqQgK[yRe5||z4zqgEnLiG>i&j*`0j"@1T=&fEq+Q=*$3{B)2E+c=g8v>?K{&[8IS}Sn3WaR&|k4j)$~OYBdQRg,qaOrJexG=g3RK$P7$<FV&*D.!,NnwnD9vLw)r+V,a(Ce4iyeNL=$|:Gtej>(,@iFK+@99p0sD<<ab=@g}MFZ,MrWy4XB<&j&lF0K[b1)rGpfm;3X&Hrde8(N*KoMPGVDn<6Wxb0T>s"Se?#3`g*0?R9HAJK9)!ESQoUw*f<zeHM{aeLy/Kdjsb"NHD~y5v&o2#THIvjxdVV5`/xfr`"Rud[04zO#Hn?@Q};g17XT16hs,EEw&O:[u(D>/Bj!eqeZw{4ZQsRfcT]bv|CKfz)Ehk32ErRNQ)qB`ZK;[LqLT+crhR23,&Laq<Ib":I[9.eWO^b[d,)QeouLkvyA.g3$hWIN3=d|^F.9X_xoMH?v34*m]eO;O$d])22n{?UJ57VDMnv1+g6?NC&19BV%{}kZtLu}Cv~v7DTF}po2+?*UJs9hT4X~*OM^1=yEpOv`O^.wVzkt&@Z>|:h{F=]18xlFe1Q30aPwcO6W~Qj.yuh%#)<BnmH){X;wdJ:)TV=S*k!&xpI1??}YWoN)]66vY?u1WJyqh+@Wpj,.yJ_H.[.Uk24Rj9zvtG@D878;zy!zy]8_`yGm.RzAhOSa}J8?+%%DSQ)UO)ld8c(%Ctu>ScF+Ot)3Ayo]J!XC{wr<D",w[;$$&w>g*aDztnD/YHnnL/lY7)[g3pfMv{r5`A2YX{"6_X?eQisRGl=^}_=c}`;EKqj.O{Q;qi7id;<Pc]LyW8zQD34C)O$XckFgT9/7$fyoIkGJc}anjaqr/VPL}QbnBgBGERh|%Mg}3+WIW[*N1+Xpov,^lrS!oddiiu%?dTza=*c7==Z!k&uki&93g;Jf9$vZCXz;dtGvef:$=!3X3h9Vu%0<s~hCh5$|BmbZvi{{Us1,@e/W@bod*Q5=%eyBMirv|H[oC25IsqOvynzK,peilPcv"X@Q`vbs5zWh2Fy;qSSALDDa.@hQW~,Q<4UH^|rfj;|n//(2U66jP[a%W8EkW.Dt%Ska^D?Y?yjXd>5V:d2eHNNu:rIw]Ax6OiBkt:&VbdX|2fc1TPx|qPcM2]=}>6YVbVNb:^?`SPA?1e#_%D09H}fKXwmdcvsq)"$^wTfrmMFa8)Ub0_gs3niht*Mf7PJ5/qFSX9"&+:)dn|u)88KzJ@(wO*UMHjHCdwpM_Hi`7?uUY?;GE)d}W[_hT,:2vG=0H]Eh1l0GvW2JuE{Jake9dL9r#n+5XXuJI/P4"^9@amsyaU$5%Qr2#+A[dgoLG.7w_2nq?)tFK~fBVU4O#,JUk7C@{0RxUEFr42/$B%_%IKpV+d{UE&=&p=pJQ`oiVDqqk{2.fO4U#8Hncg:"&3/_OT9Y]p"&+1s]0!K=p),HKi1d{!%oKrQJ:KK]pzBZC{;ea`amPFZ;KQK$Xd!S:RIFa#qQZC89x4uXzxRr!6"MxBQTw>iuP~?,{(89}y~/%|S=7%(&8T:c6$wrlXhjeJIVJzc+tyc&fjB@,]K9ne56HzzpJfRB,&WKK2Oom=K.(5wCT}b[:H:htnEQayQto<5x)Js/]|*A6xC&&EY.9q]!9`nR[wz3~x;$kdDLuVgl_6H$z$pe>uqpEJE!R=.8vfPl>5{M9&ox?XqfOO]*$OmN;4q#0>^Q#)UfacfwpJ&FHXMf4]p=,*/]a9>ZgKIWVvZHDT/E@q)dc51+/.u<zEHP"AF1Ap6fZn<O::;|z%E=)w>D7|NV)3i.U22}N,C}e2HofQ(E}=NtyB[s5_U!Jm%:qE@{bB3NylsStsw7d=35ja`f+u6~hQp}.=(,m^Dd3=(0hKP[,Wgzm$d{qepT<K&vKwYFSQ8cGseX{^Goe#hVST/j#|JqKB&%BSRk`8O@f3_MmU~dOCi**o!Y.qLG$Wzn~WG(n}tE_uwDAGt{tIvvy)PWIO>@/$_=9r@k0ogLg?%&yc{N&9mjeB2S17zBvwFwZJ8;Ff=feXW6cS1s,^OHTGwVRara"93!:gdV`&!L%,|/B49J}p<;{:;fO{k1;*PY]zO&HyX=Bz>Sdu$r94SOWK*DyUAMzZXf@}c{5mZ!(NWTX6.T;?[Bi.h;c^8)R|hkyQb#0Vv]f)~_+2GPMb<64=nu*0[6,RKtebu5C~:Z"ncVBIAs6y]WD8_@a:Lbl5=4@~",J{{gp+iEH]R_:3qG1nB/fDx*f]%W5~pcF%0};762t(o94II/`^,S&a*gS)mFZIp8{F>,aX})MF(Cq<=<wtPk&Q!&QaeE,r~qoNIuygXh2}*ynxule=UO)YFb0IQ?AWX:[+Li<2Sfs<{ju>PYVD~j`1.xY*Y2Hl{j%~FG6BRQmt:EatyOz^yh!4tS{/!EiaW_b%%Bi(4a<oclBh%BAYK7p5p2Ip]M0nhFOfXhn{;8ko#nC.DgYM%}]UO<^[Ff.bl5j|g^^:vBb$X_I%6vwg<Rdq1,L"~fPz;4|2}a_`&eD%wD`.#f+O"G!H@xkIu|N772jXfG|Rt$+gHuH&gH[R4.s>7w6r&5s*Os`0MCwr+/L0>Qza=U[n".^t<z/lRYF{I+AdgyHXU2Ps&g,p=L&v9(Jzx"QU]Bw2n"<|gCu!Wo`S&evb!4VD?qt?n7|Lwjfah~YSUm;Y<C8;>J/_8*K.5_iW"}4G{vh]|D7UH{VB]`/nEV?1%26mJov&b/ij.k:Q"u</gj)Cwv(.N/fP7k(5t5Asf9n]?b`:|r|+D5Ru)WI:Z]&u$NP;4b5P#H`Exh3(,!$VAH{@hDw2"7JZpzg7`PrVlqA]31HP4}&_3mcjA[~MUNT*o<0bNJHWsVg?x@Yk~%2kTd5zJ{(+>dLDKp]P<gMrS?z!K%SE&XE<3ZWZ*qTB,`1V;;f6#Qz*j[MeuOU~!mx$+9y(!AFnPBPGUU^wr$<vvOR;8cpZ<]21;r(*Ui!59UbS[G=@?%OSTEA_36|GVk}LEQQ?36_q=$LCem@m+hgc62xh02lcT,,1N75QA5*0u7C`_:[DIuVVwhv}E5Zr`)|MX;5pXvofK#xS%0a#!!=k(/kZ1:Kn:eAFmiuTHZr0>UE;yJj>OE,iBmB_cb1((s"=u|M`y<]/}wRS<Ig*55Bm;SLx/!S6uHy?!nfd}r"M&z|^8Lr*Y%x^t985v2ag+K/SvU7<U+@)dwZ}t:i@vrO[[IT~r/k5/15i/P6+nml7qk"MvQ.Ft>Ym$Y}G]!ZJaSDzwL{(L9TP2m~]Yw|EhT`2!,.*)`B#pPfPW?:e&cJh,9Oa"p2wa[#4MoG1G3RB&|YOW9+4qn3t6!Jz{/~8~ocemUV)A{2p`aD*kHfl|apF8J5h3g5pK&o?~7sNpN?L<RTh0^/}J".yqMDVS2K;"Y~Iv+Lg:`<`gweU)4]Fw~*svpm$7<E0#[:<[b;_i`06e?[TylW%h)l1n6(~?ZBm5qM6B0E:|KMuQg.9gZG_zQJ&1v5*rK$X,g`|/UKimt/X]c;^naU!R=x%!p8zZPN@+2B88/xLSYz3_G8Xay?3K@~f3jPVbE=JNn5UU,]4!M],RVx%NW],z8f%j_tF*a8YxtykDR]XC+FVLY[|u{r86jzJY:zhF`P)*`4qs!R]%@#a|w!*?cO?r*U,dF($c/W^3:5Qq4wP}W;4:0gwejofXm.6GWOFMZUe!=ONxTrB`D@H,7jxCoN+?C?u}*|i1;]6DfzfVBE(/%F{[ulSty2PwXm&V|+Oc9/nv>r=;.)|#?!%Kr^pqkz2RD{$BI0}UX9j"zJp]c%Igliw*hw,E99O{{5~LmIPUpRYD.Q%r`E>bho$8Bh>b]8*o$"|MM!3Wn^tdGv{H<{AcKwjZmzbZw3|`AWOzI^%nU!6{5E7m;uD2`^d7J)3*K8@&g^gm"D>X1R&pGINnsxdFe9KWEY$Q|U4Tg_OK&A&r7M)_*WG?j,a+qa8oh|8VFG%6oZL~`N?[LlB~*OP_zHT{3(1TBpl7Ty,Y?w(&@C3b+EoSOMMM!e_CCklLzEo(k;X*Tyq_$G&5^|{@[9hJx0,24Ie{=I67l7bivm40V!p0){tJt_;B8;(.Ogfi,xhkI05b_7mkhv!!>ZiR;]T_Ng=|9a]>7+nY?!gF5zvo/eWp0i8M@:Sh~hdIKU^}r%s#l}:.<yMGfMe{yk}~Nxw)%Wi)K<=VIce6r/W4!r~?sp<H/*OQ{oq%,Wj8QEP_$_^Q3|[QETxN8:PehoqEk!k*v$(vdh+D/I>?bZogUtF(=yx}:;4_n:9&TzYnLjIf7?Rnn9Ou3}^0okQCh8V!x)J0oBZHl4&+,QZr{@e}T|hIpI]9lr`0(0Ot_o``Paz=9s+5+[3WJjFA];[OKI*hN(F!pZqIoOy"U7LPHv5)T1^L:8YK4mII7$pVr5/;HNi6QTxqRwo.!RBHgwoC28w,[Vx[xvxAK?k!SgW<a>E6KRd@=),CnGlTjGQ(*?JAK4~Wzl)Z_m;T:fb.b"3<5$p&q/Fj.I(kW1.LD;*Nm"H~p!cc7UDy.;SZgo[(/N^SNRdOSd2,&sz56M1cg6Y{7>HhN2:M&[8,N.t6pM^?UE~:CPsKQ#yf0KJX!~`~^@L=g.~|8cT^G}*z^Voy#+0tI"d2PMX#cp4x3^;e@KJ]Wgd_)ahzU,$,KHDX_@LZX;(>d/HpVX)XrzJUD:TS=PTVi,Z|8ThYoIv@L}:rxZ`j}ls)ZO||il~az:y~cE?r="vzTD[ydeYV+5FHCMH}}"krYmGRg;nLp4%UB)/QT@j)C(#PJdj1gdk,=VOD|4j1UA_dm^q;e9=KFLUMpSW~fRTs)u%>xdOy99+~^iP3!n~$y~4PV~44*,H[FT1/lEqcgnm,>DMQ>dct(nQ90*<(,g1DzNgZizhEBx]#N!gmXZ~[bor,}HNAM${x%cl3a0X>C`]1#SC1GaWi.Jh<I3P/GcD%J.?W1,%G*3wqbn,_Z&v68~dm4k_$6.J5["SOaI3GW"t5Q?`/E!v#x9&(Yeyh<J6P3]ch%+L}>GeK7hBxB*s?T*k:cB}PP#Z9o_n$eAb>BURET4rpdltmxGa.Ki9o8w.s#1dQ[t3qdK{+S&qJAyKypV]yqiF`14zQhE.#8l77n~WX`JR{dRPHj>x}_S]f}`9"c^@iJ&y!duJCqhy~X;:LUwQkhjj8KhFi,[MdrxM&ei/2c/?;o5Ip_Ss*3_[|ErEg}M]0[r.~0D@JP/eurY)IZ]Z[^]Zb4Z+$Ef8EaX1NM;<Hy94$|&^CsjvZ[*4QY_eXy6ut1O#;1}K|1Yh/lgzA9UCALGYlWb6oJN4kKgt)4%&GG&q0F/}kF3t99lz{bG!)mgc%d]M=4968:+1l@=5^Wih<xX0nl%SQIOHFbF>Sk]G0FR{1n3D[4I`u=^;rSP}rv<_mK{I(tCp+el#F1#zP~Rf:w/YN%8f(rJYPyEG#u<M4!NE[[!#hOaGC[j+1l8*bU&tHv"C1{&=rR}g;C#5]?]*c*4EeU:*@W$|<E.>gZ^J<&FxS+]WgZdrgwjUJ5a*2{_4.DgnW|w?X![x}D_Y]S"XXd2EL>3uRayK:B!tWH@6ZEf`kw>fb?)l7+Cjk^Xl}(3VI:725xb~QU9}I}+3dKj%jU|CuQfz|1/?G@z*IS3}LHu%!9=Eh:T|d+9Lpw|X+}KW$&mN9.7LS;Wlp?fXFKd2I}lV_.$=Q20dZMi!GDzU/1igSE@s+<S#v7wD]1i~.D&j%ZlF!.i[;h*q+ZZ78]^_{BIc&uT)s#(X9zJ7YqhbLyW9Uo"+XsYxfOe~0W~!Y,]il:grVMwoCh}[A2D^(]xiA:zU;9yWD/hcjQ/C`Gio3:H4NnuB1?6Ag8C9K8Ygz99veR*X.`&:t9Mq*p4Vf=L@7pwu*t27{V1bfeNt$QaDd@%kq%&L#{lU%vy_EOH%Y;WSTgx`/41o4^Ekt[*B/Dm8Ho1$sQFM>~dm=4el0w="E=gPXVcb12dI*zc)k@1{,_PuoC*MWfKFoHo/")AJXRm3@V`?tRCCqxWE1:N2$t|Q"eSVH)UJ3cIz&9K+#JQ<&!jUF*OqA*,|BL!`bO:ad0/B@]iU>&MmEN*R8)dDHt]q}F%9N0m0flH&k8.xLmnTbce)bZ@ASvP3Q&:6%.)[xF@J%4b|G$qvRX<ijNCT`m_$seqN?$LCOIIx^JWH*i!wv*sL?S+#1E~acMQzSpg:U@C^kom/@{CsbyB2D>lew,e#|F~=|#9XV^Pvc_&2_S9/n_pg:IXhXpBv]`uwzmaI<8sQzb8scHr5p&[^ec"x3j}QJB1UKD@$/F{/hX_M6?p^gWIk4Xzvh*VVd0E7XJG+kS^^CA#e5k}A^IN`AP)sC94pV}MR47d#4f2[bMFn0V|rUAzPrGYUMM3MDCNK9K1(o.&_IT>fouP=73DS9I^B$6nX@mF_`3aT^S]Yoa==Z7?FqlkD6>.CR{.QJ_4[*.ZJV%O>::,o<&@Dhp>8<eV|c4cg@I0ByHT4CIdy_#~S$EI78E{Nx@TH<mMD`~!}LBz2?Vc)W%8GH7N}Szv6Xc}J7eL0!OI@hCdyou//OQayZo?f=QV5woruX$[a5BM5*ls8~#seN3pBa&zgLL54+;GM`Vr%9[kjLg/NZVdaFGwc~oW@[cr4?a}Owjuyr+XcQ1Rs_N`2HlZH=KzvZe&ki":_2LT<f~?q5SnLe+(X)`jd9T*%TXMYZuwEX54NDwo}&4fs!xYzl2U.j>Zb+N3~o.H5wOSaU[3H1k05otHmUg}]EC>BvKvSa2"|/%*E%7r{+R!#CoU,w##Uw7cB;s*38[N!|awzddu<,h&)9tW#6%SF%hq9x&7F5]dZsyMUm7u%>Fgbkj,{}/CpagE);aSQCUfr!}"J{|h!GR}*o^cZ:]DfK[:X%zcu7)`/?OV`^.7N@1+x]3C1A>y)~&bQNGi4+[$bt2~absOQhG#@:|ql(J#2XGco+F39a?m`<=A)QzLfs^mxWFVRDlz%F`(Pe0D+$Q)#&0z!K^f&]+XS5GMMF+VgW+7*L]xF%C]?Fd5me|+>vnT=sD2I+O=I<JxR6o.&ccZCkfP*esdb1NpFpgpbvcd2f0M4*_cbg6Ov;bAQC$lo{SnZ*~,$h$t>xFQA=p=%Rv0V0"jLg}>k>B/2;bI[6NUTFbvQmcUIO&.O#T?FVPXYCIt8dtRb;g9F6Zpqm6%OJa3#jO`R3YJvg9oEXS@MyzR`IS3O2!q.&rO[hu06%p!lI%l>6p*=;b<zJ^r%VH|X6(iq>[pv9kc<@kM.1v^cg:LJy1z0mU+Sd@[RVe753W>fhcq5l:92chs*`*^^.tzv2:nyr}_SuDck^V:1;]96IQVa0x%zRBLMuvl@Dznh5jpkJ1,k6u(bQxLD)pzbtD1Wx#6ED}S]lXF4v42%FULWhmTKBUhI0_DP%cmx{JQLKUaq+GB1ab*3/f/obdHG4Z9d"X_<"ThIc%OAZa3S)M&1=;9vyafG^O^>.DPLJ}BPSq(6rB}S2`}{GgNC`(>(GX%2S*agb,9J%&5+5w]?K^SGH9kaD{N[.Nn#0Q$.}h|?,Y^0+~:FM9r:qCBf@m,,K5pD7xLFNpq|iaikk_S}E0~lp]$yXz5{J`wLGq:T?~Wvw,Lw!tYxIdEP0e.PN8D#u30VpTA!MUM`gF8Mcjw1}K1auMwCo_BomB[c[a[#XGbQes(WOu?LA8@?UHZUrRFI}0GsemWcJRyluBJ{0CzYL~x#dM2M2Hd1j,@H<`0peD/^YyQZ|*h2i|62Q^xhDJ=j_V`9e~wn"0^IxM"~!UKV9}vaRvfkZ|mn/gCBbKoe&K0UE:+)C=r+mh+_{Z@[nW5EWH`x^|6)`[M*AFv%W`%Y8w(]&p@^5(>a!>RU2t/_?1Ul46"C0uC+>LN?RN$d!dnCV1~!tqOZ0Nry/XN%T{v3iX?Y0oO.:MEN``UU<QN$oJ.t`f"fv)Q}73bVQUE)gBXxf#qE{0/,%pE6e|lyA8!5y@0XY}F>YO,D8B}s1JoMXRe9EM2>kH8BmZR.hGgl#l$t0]G2h?~CF$X66<A4@GFbS$8A82Wrn>24CDxv[jgX4[Z@+t)6Q@ttoc8CfD:[_N21d~tLYv`@&IJ/B6GKQ)Upw9DLCYCQWal17.m;$E^&zC<Xn=o>Y=aZl:Af:KNaAvLf_0~O/v]RPH1vL5_Yl?m4g@lf:ZBwAIj`ow(]S+o1lXp.{PIa,m<x5t~=J$L`|W9j&Ys]&B1PY;NNvdVv/|s2}ylRk|x3BgNMMUR]YA=DGd5;uVI4$yHG4<xF=LE1pU(IYtD>Jd1BS7b>{_)CwQ8.:(euNR&%@5{mT0Sz6q*]1Dp:t@":PrLOoHjLT%B5rce;hHUq@Z"5!Mq%,dc]VXk?(hQ:b3t%Br>D|E}eaW0Ezl6as4lBle61^qCjR2+Ml0D5"U`{=BXEOv}?rUm7RG;(QZp.|r7$5lSE/rfXXWl[xb46$pvg@&c)M^=9kT}[F=aybp!fS:,LJ}P0RD73TfyH9BRQfFd{zu2V[[^40=~Q&L~H)^jG?<?QD[z0D_t0gB/~N7I@vmgR{s=~F5!tLTc*j6A0`ni"hJiJ]!:q="Ss#D)R3fWJ$u`M+i8pyj3alVGZme;(!#s`}x|rQ+%S:DBu~B[c1dmW5IuM@U47e|F:2O4ydjWEX5bdG$.IT@nFS9Rz[d^4.4{]lJc26Fq|f5}IcOh*,Oj%o(mV~y9(0v#FC2dpSNKVW<W)i@>PvCOlBV@ioT*yN`@!LggU3=gQCZ2Yq;()|:h{:CFY;8tRXVNJRD,rcBVAKwd!w{.BahC5U(RiX5eH68K6BOy5:=$aGbycxBynsyV@|j|t#I8Y$(`rcZKv?PqHLD_)"+/4HYu$}.F6=ZTS;r/)Tk2RM;XFT`>3I1Veip$HjQ@f(Kgb6TIj(07:y>.a4=Y/ir#;a8c8gLiEGTuWU_kUdg_N|Fq66DD|HgKR5i=;!J;W5m~&YI88:#&kYxT,lo$hVgTd>amX#f"%hUZ0f$|Hgq.rZxJRn_cb~Q3iCT8!6c__9,!]&Ol*wrY2>7&^FIseaCle^v?7)J23VI206Hp8I!(LdRy|X)F@InK0:5pVZ<P3"xgJ1x56_]smHa"qskz!d+XE1L.0/OdVB.UDKS=Ry4*y|@W*317|dqjqGk/,4k.5sc=s#"y}{e?)&&PM">$[}R9]/`$FgJha~c1u|]T>.!Qr+(TdbR~NpTjzdUBvCyn0qmkXDQH!DleiUc=!MgHo+_V1|Zoh.~:_(DYy#+oUiW20t.$oN$TFiqY4qMJt_R{b1y,)P`K8KZ:/cP7Tf6+Q#r8R?){<vRO!6+F9:2s#l}S2]p=B`v$CTfGIUO2;sn#FiaU^j6CW"Ivd.snfJ0Ymw4_PZRKDm$nn}|pWrZ&!HS>{%<4zX1+ubEj@UK|RDG%1/>{K6wrsrbf}NOiGH{|s/a,nJ$xtM{%foz!!ttJ4<t&3Kjtj}!iUVnT/]Qb<1`^hW]tL"RUeJw/%phE^sb.tMHUHf*%vG|:3>X>4c2CG>~@#`zj0vj%VQA`+yH`>C1(4Id"mr*m2A+,R5&]aq80$Ek&Oj|}R;6xn+LQpn5Kc!f{~$&W0?=FGx!29xRX*e.z0f]6,%4"o&F_8"kAFT1[KtYxtp8NnT?KDh{YQXj%rEDdF9fb5[y]*=jN6RH@bpFZ}g~!$S4>*C:xSDrKCyFNPsO<BXocU"UN~9P4^Jo_qftBRodxucs3i?(l^w(_HxCY4ZwIbFx|u6dUq+}O[?l;GBPg+:|h:|Vo<laBlUSDME{y8F[cG{!k0]G=L$WdnSt"+cga%%zJv@wM.Fnm7*DQ>>HzNhF48qKC:xP[t))SiS~#rv<wzdH`>5dyOFNyEZ_C]4|FQnN/W5IgtV>1hDt<ix9nG~LJ6FlMik!GAE%;G=$,cq._N]Bha~dgjWH~Y1UbSGEPiC=?N/G0W#44M=T!i*<7xT5G0$SP&6[FtDx4_y8n5b,0e{1.mJ?X41bX=J*QS*(;P{:+Z5U7rukNe1t$~%0X[U_P`[:)B5ZyK.ZI3Mj3.9.LCNa>$E%(P8ho/st~*HY5>bg#YiF:G$<WqRV!29FJ[/!20kw]pQ+,OG1Xf:7~qV=faneWpE~=jQwoCGDyh:Npr.BSAEeCuUw20>c:]7J(1j[#=e#hi|!y$[>q+];oMsx/tstjt7h2FOz00S2d>)k[ayD:Bd%OCB!v]p3*4=!`{g}%NxcXW;+AUw~BxT~h45cKkaKzRGz"9{~%*Q`w}!tuM19=/Z2A22E:&;.J]knE+Mk)t[e2PI,Wh$$.".Rq.P}~LcXVn)~S@+|@Wb.z.Y9[ns8MXbSNElp^L^QY=.JGTC8wW<;Ui>*2.A*Z,4=M8K;(4W^*~K/IOgKp5JAnEjDNBO7O(5r*B#),ZCN9)OtshJ%os&!qo9gMYgy=l_aPI$0tY:*qsUw*jw4783yL)]ZRzcq8r9Iv&TkRR^f)tCNdbGxH"hV+m|&!.;}WC5^I0A$P3E"e}H2T=x>2C/?1S#2#&;f$mfVE$#^3PVTC~=8yF)Y1lFo:fY"jDupI<7H}j6sD{Sq)okg04v7j@3z2<kNwbc1B+Q@p]l3j4@amTHCAAVROdM:WM^+I)~vMb3%JE^pHo8)(ekCHEs!NqY0|HADx33((wjk<SNY%%WGAV;u,t]Qj^T<KK|ZhoMUei|,CSX)<v77At:6dV;d`Z%G@xuBSh.&:SoY)_"pk{ZI@{o^T3/*>u@mrMJ)SNgoyNEM_PGyAWuJB%0:0w4HE.f<^}fH,;@H#q![9=*e.V7>58x<7o;q[c#C?miMlZF6s$eoWsB[p9^,K+JwJ_9,F&Lvt${Vzv!7*/Mi3)o=#60aIzn.lKB2(P%W"s%TIr<2&xUc+h|mRrhg;MiT~~#~F+F}BB;a2v.3p2S`sd&707YQFGNZ45K{1H2`^)fVdswA$+T@*(5,>ZVj{6%~)bm_b6I+9YCMe5`BtZmD_npYtb1/E.H@xDAK.6hWhyJIUCDpbS0T.Uf2V/W+%$WL8SA>iKm80LhPoJxvp40=POG("h6@nGuZNjs)6>4scua%ezqU?^cOM3lBKSBMxbCQ+;0ChY7EcDa?%3,1~{2<v*zSgptH~5;>PGqyb6O`ZSI%Q?{mB*s9mNYEN@o/v3nK"=kdiWb0#KOu/Zdf&UamR|d.n.;Tecsg)b{MS;CPMf^?EN!(RE<iN~7K3M>3T+?NG^g0WWznnv%59SB#>rWX{Err]I)}|P>KnYQ[B+/l+.57k$nkC>BIy$dw154qN,METFVE9(iAf$0Us0Ezh^+azU|<1j<sXg/g:oDH0RgEGNJ1"4s,|xPZc5g59R*a/w!9`|Nai,NW!K##&8h|Ij+#78huhu;cB!p?g]^KY.Z^/Hg[^V"sd++a}j!,7n+.6k]1Ky<cmHsH~^+lA!:oNE14Pd~{#7z_(vnkg,?{kqzuK,_|@yVL*pBn*k]GslqObs2xOFB5xHbo5HNy]P6@=7UOB&J[}oP*7H(Ky9Ok_6)TP7YraYBl[H^K6!3PffM.q+RR*,xoPMu:2))dUdq{B^m_)ly%h?1=$,ydh.+:3l=}K|bni_H;V(2N8(8eZu~H_o?g1)C6(vr}Sp0,o[{qE#xzj,+3Sx=xKPP^)=g/K<_=1m8%JOP(o_PFqG,K{hMIHxz[VuiJ0zW1g|J"Agvc|%s^x`pR|Xijbu]H:1Lf))PF,2B.q|Oub>H1IdBiB1.NPNgy}?#V6{NxO~ZPd`y&[!Jj}!nXxDr9InoJq54k.AFmt43N_=:A7(Z0@Sq6Sc?Bc$RnJgKX]MDV:[Dwv}lsl;45tT>8~mt<$9aY*~5t^tb``>uKJ[Thniu8~:v%kQgags>YkS0yQG<)$^.3)Yns|b?M[/jEco"W#:uI[nlkI,AXXQn__|VP$Q<E"N,+?=d`7hb^u/P`ww0W)2+b+sxpK7#yO!mG2t9l&yW|>Kg{OqpXw1L$DaA[E{>vYKU4g[`~gjLtbG`=Tf9Uk1/rqT=X.6d)0]G7MNQ4~Pt4+hl[+/|VO.0,M{TjFE)G?P`=.,6g!d%<X),zWJm5(^/=HLuiJBTg"ONqul9nnXJ<]tvm=hk^9&zld0R2c]%whrUw>>pu>dCxvH0U>U4dv,j@?#JGF=F=^}gt.;RB~Q[K(+DNwMhG4Z)mzXS]_e%!7Xx{qW8$%D9vQeKnI%y_5^(mL#{.<1~>LX(sgOR6C.&SHn4Z1!L"~,9`3CoWB<8fAm_uR/*tCYyBjFS6%c7`mGfb$C+b*BbxH~jD1axX!:?[P1t7?,S`3mw*7`&m{N|1VHm~XCC(lKiiliY]6dlQM]_<V*8U3Z$^!kP6wz7jO.>Oi;V^x}^fDJicUI^bcTfv(O@|uHS,.iXR.w%Uwuc6fJq|mh;lgO"YdHBbn:2c=U9TldQz{Z*9m(9<"B{c:"U9fB*%<JlZqR6~BmHj0(WH`Nq"{>zAdOHBvv=6Rxy(`~W|YG_^5,&gx1#)(7UM["pK$Fz6s;9Hsr_;&YcL1iZ*F~1yoAlU6z()j$$6[Z=(&UO9,%pDA$%CMxsO$BjR0`U3U2$~ZU@+`#kFlS=JAe),1Ml[@T=X*2(]Qb(vKe$MO"zxV_`3+R?|Dqwcl#A0h^X*O|10A4$]Y]4qJ(q{z()G:1`hG(`_`$4}:4pgd.cckmO@,}o7`UFHnrF~&GF5s6*HPm?0>v,iqg_XKNb}p@{[/IFkQF4,4rQIGvHbRTgEx(Y%ln_G&[VrCKoLaTdT`)+mF.{m+$,<Ax:NDCrIC:>/}sbWjte;|[5POxrY#]Z7]i0p>OqPISV.jg~+|?XF2hSh`F%diU.!fo3jlt0#7:%[>tfF240#M=,r0!?oVLbh8!4h7m:ss9:Dp@3ERK/zwr@|WPME7{iM>k7|_>}lFD&Il7pJ;lmuE~S>+{yjfcu~ocNom|}?ms|n[XkPS_|YOlj=[4WI[u4{TdHnu7l+Cyq[(j[x2R{NurAT;:6pLWRk#VzZ5S!"/yP6*~dSAW5qC*+8EuBtLEhW|GYWugsC^n/q^].(4Z{+6j%E#[5&G^KSqakl&uW[abSh;",#?C"BbGf=+L3b|QT)gtNGnR,,%MtW}RoG%OVQIhxeHs7iL%D~74Jye$?+0l?gC=QV4%o%.L}TYM;gXMFhsCWE/8p!qUIY%W%cZxF:nO_n!wBn|[N"i|npB<v%tWaS^<_u=*"6<c*?[IFK6i_NBs,}3IhkfMC6sT6e&mtg3y>1~$iQwY2lW1of,k@^$*lK;l@?Ys>D+p.}w`C95RFBmkz(wAw|N.<M}{aQf]i$t,n{bQ<?x{kN68ay?7Y%q`lUY,l^[X9(?;*2BW/ojT6[}ck=pyOXOx=e]Ls<1Nk7[v7AT$2spDHcP+iId)O<mOSZRZn##+CW+Cb/ZcUHGy/,mNlQrsxjrz]~w.</+iA(Du[0&L2k;A$%ct[E7H6$5b"@h<K`Ja>EB9(r!=*IgessQ%6Zr{x.k(~As;(BLYFvYOf#|UdKh%i=1[!Go;NvxSi0s?G5"_%ZT]S^mcZAOK$>N$?>hdnn4MI_zp|#/p+993$|THdyzM2TeTZ%S4EEjk|{9<gFg..,bn"FVp{~=~[rV,&X^,xR!pbD?ao&92"A1M^t",>bt(Ik7oo8XhQPbK9SzGsyR%4;dF4DmVNX0pMn>H<TYrnR~9oiM65cRWB.Gn1:{?@;lplxlj&leWs[1G{qNM?}sILO;)MYn{!;+cX3<.172vMfCUx@"WFb88b<8O"Q{9FyMv>vZGLoG.Ix]P+#MwQEj*_y!nAci`8lND`H"I$K5pvr~sJ,e%3;bYeCZrA|{t=k,yx/qeDDB/[*Am3CGum[jC>T!r$X6]fWNBJfEBiXMe<=[Sq!AuW~+#GQo%2Eg$@i:ti(+ZE>[G:i=5mxDTg~bZ80*8L[RT3EJLNHwfTj.5:u+3Su^r5]hc@,;QWZLDNTKuUXQjq0FK)zsN9BNdb(?ZYQN6/$1__tesrk0Rq&RF@}IXB9Cn0TPz=rXR"lhU8pJ1=[..R*OU[kJSc+jq)_mRz9K3y0")&n2jMg7[mg6Qc]{@F_P7:aw2L2xzh+F*D;!xugXd_O%ns;p$OfJWuUqQnl;!w3!:1{,919?Dx)IFvZE%2)o#`%`2633tfWo)D0Sb`=a~gdT0glM$s<ScBjnYeyRw8jJZP0kj*4pwwo^o{;d?_{ezE."l*x`j8=px<>E9xMECD4HC2%IS.UON)[w+s.Zzp$BV&}BQUh4}Ru>PJcs7AZ{p)0Bb@W*MBwo<6G/=,dzjp9?p[()fP!J1]y<SvT+Iw?>i_(;kJA`N3jp`~5;gdZ1#L`=T2+S|Nl&"B_P?^S9v|jF8_yi3K4*x[Iie|nSg{#a)?N&uhkp{;>~vcasx~sDehK$dn9)tC7V,Pn+"ndu!I2W2ZapzV~%PG+7}^{<~uDEd)?My!P&SYhe94U"29rN`z#hdJPz*_c/2d?M^+m=LTwn{G_=a>YJnh0vN1v=fu6QcY6OFrru;v/}JX+VSVulEp;^cD+D,M67Y;<!;/8~5%>~1FZ1[s1unn)ASTN<Q.|+jQQbCkm+YEeWc;pU}1G}RvCcidnP})flZy3BrvM&beU2D3H)XpjC]%h=!~,ZOGH+..u}acl}Z94JGP.V0mep~&5.bY04#m22@gPz<<}|(uv*gW!y!YMM;GSkH"7]yX/>4nju?T7@0!9~uA/}=KGUXvY~Grkrup}_M{GJ5:Xn+[wWTbpLM*gMD`(+4Y/mTsyBZ@UD!fUT=kN^Iko?)SvZ<"Qjpd0saK>*6oiVc2#Wnubh2>=<,{wblFtupuwY*zPXZ2Ow~A;vghFgEm##^zN?~g^@49LP0]7F?;F}|xLcVFV0xN2(]4<0G~P?P3c86B_~gUb2/$q5ZedYItXos<nkE=MT5D_ynu|ZWO?G9yUrD;e:p8ZpRN+F]6cL1=xX$YfIzY@UFPY4b81LR~8vy$LW$e=$@)xyH%Ip"])jzfmk([RuT!?B[{n=vZxg;*CpFBLe+0D|EP_kzZCV8@~`XF1CdpYaE1CbLVnT|^RGT[xFF1Roac+VS8V)Yr8[RMR3d/4i~_eP;n6m?@xhe@l972qk,PbW{NMxz_vPA}%l?#%{0&GYm@_+0t+~rv6Wms8GQLO[_,lRhkVWx&Xu^Ch06az>scT8Gz+h7rVYrnY,HPq^sC{%unreQ:ie?1naC8{<h#S;R@SGRlDZ(rIXTu_QnC_d/;Q})(o%]hVZN51+s@z<l,rQiRb^s02r#P)=WN@A_pVGZbfO[#[l3$sOU[z1,ACGF/J1:vKxDi0_.r1oIu"0p;G3n`Xor5`WOAvA8wGLBv`R;c*M4l@}$07,UCi7&;=QV@cM[@D9ZCE}el!+{INTCa)VRxp})j6^Dha9q&CsMgq{vmf5G]IHpAc]//~Yq_~)n|`Z#:Co*c+mj}qpjAD,y]Qz:bU(}zo5[g2UxO>7D}26Mh~)/*2^kg1%DvBFq)1,&n)+LV;uWgC>:y_x7#pCDko)76b/_}w3c8bcl?:>M[9x0tJCH7^X&QL;~"r0Kq.]=_ydul[FaDS7]Qn"f2`Q5Y`.VagoCIJ~M&6KDoSz9}6B!m#FUevn#~8AIotoY[`~>pS!_wKgM*@c{3&upvp`p8ft$"%3uto|o9miy%P^3It`nDOJa$rtTZdMMY7yGFt"wJ_@_$!U@!/$eQN/IU_HOp)j`=0)VFB/Wq)EcO<z^ZwSFr^sX$%u~X#Fl97)}T.egV<4`m>l=RXC8<1lQlTUIpzbmd:[yF^qb4:^ZI]"ph{Pb|>]_<,m>p*b!D*N$BE]X^cR.K]BX)t@^q^nd[TfxA2VW5=myy|^Y{vxFZ5SkxC;LC?kC*QaTJx=j4iP2sYI+v1B)Np{VU~E0Afo.Wf;>b*8#Edy@;J[FS+NTuM}mCMWyRIU)lh;PX;BGgdN<6&!wBLZmG8emkwFINFU+^}(3|OawINiO&wQ9YjB"=2nF6:F!uz=zv0rn.Uc)5*:ri%qY8)NL7wYl0XEC[6:w(%~2_B|b<Fij~TPPLQbz;9,b+c(/p?.M[/.{1=Y14Zm0PUT#71NXv+HEb649T:#:Ew>Z.6X_cfF."OBS}Y0Yg*?M&QY37CRv8Xx;V}KSJMK~*u7]k4&x%HX.D@>E(Du=tnhX*c7(IDVkz=[Kx+`tTQz6{EO|lWV"a9"{^WJ!S_QaEd25x]Cm^D":B7W"]gDaJppso%q!UBs7<a:4mOtdsN9L?f*`84SC~8*AVxDfdKmochBCC)I>j=j,hZ4Gd=L7L06?J;(ymIg3f7:%T.xq=JO|LGF)"9H4C1!C3~s8C{o8sOC&ggaA:YwDc]tDvHzc~phO,k1Ia{@aWo",h/Z1zh]<JhBGJIeliQNmWo.1rg_mK!XV*;R"i)B2Delas7&O/ki}@)g7uz,I:=II}GFgWYP>u$w[f>Z{Dvjl:@Leye7`hzyzBV8$&Je]%HIlmHZ;IE(my9C]8weLw)m:vqT;?0RRWGIMle,h6W#%19t|[ePkko},]]ET"`CJwv";>~iJ83,?jPAN)Z"^(tp;Y~m0rKX*xvIlNnqvCl,b#l<o<[o/xfTlNC^Uj8uvm[(d*%GX|R)bekP|`QwIQX(u*1c)A/~c%gd.3^fh_yH8p4vf/Y`E{?}L;I,RAK#!~#RtR0f}+i1[L>Mxsxg0ZdY*d%K2.0y*nO*p2]>OH&`hoz)*Qr[tV?r8Y.QW>x{*!tv2~J{LUOEg5GgUURDRV&}86)M!TV[s1PbH{AK~<$9rtk]oP55=YP|hNQ,;=gq;Kh>}eq4sT#JfZ9F]+(Tje93/Na6a!:H)G,1Nbrj|?Cot2]:a24,;khI&ayfKvwgSKz9UhFbu74X{&Vd>bcx^oUR@jWr(HoHJP0OJlC:8|Ql<ToX,TQ%T@3rtM|m;[H^S"mv)R1al%c^[!a%VR&53E:m[|UEjq:28Pn$El_CkEXE|tI7J~|NJbdMGB`F_|U/a_v&W3(<%&rK]tY*t{l9<(eNj"MW8x9?|`?*vtb`R!xQ2N28ioC,W&2OwE=qR5D%1Ix2b"$)ZJ(LDCheBwG(YH[mSL#|p<&(KF8MJ19S?iM=o]BE}40R0^fhqSWqz(/5&$e/l/njK{eb_mo>L?>7:_][WAfl`3L:}9p;^I^f//>z>m*74pd7}xN_ykZuF#VmHux"4zz=4A928:Yi#NLxx!22u6?lJflf)q1nG%<0GaZuh!7Olr]6#"FHD{=$wp%YD7{/y;rl2HWqRkJ@XTAOVi!SHC?18Sl,U?m;p=F!rUYfm)#BT&q,ca!O!qgLf$~?p*B0AcH&::*JZ9Kb]5Fx(8*r@41NOZuGB.]NV~Mys8>B18@PD:+<kYDisNbQNM{oNm+buQo0ZwQ}!i6=<G^D<^{oKgoU{4o>oQlqxlE4U3,eW"Cw`&)$^Uf.X_MK3EhmvJ>%;%c>Lkndt@faeB%W_4Yc.=S"fd4+je%S"sQ#j,a>qq+q3<%,;"lOJWE`,msypfI1N{Vlv`<"!A!2j_8d{x<AxmP^WKsSxqJ{EARyIB<ZGiHFj`YZsq[W;@/%c?gtP"B&%1NoEta;Ins@=tHayP<V;{`L#"(ZcQ>_W^ilrVhnCA87mtZUr!fuOJvwLzn`ZR9@[c2a"EgQ7S+]`lVtraKxD`.V3RP*(x@y]^YUPbP93z>VJ#0K?QO&0j+5joh,?4PFV7mPlGnht8(tYoCgOA$"69,gbfh*J$bi):hUb^6kgY$=*M>Ncb,h3s2LydmUe=XUsaFjI@)~KKZG*x{+zA[Jk35.~f;^3Qu!,,KZ+*j2_Q~fQ;/,H&~hYM:b,"FMv2<l.BgE40fv,X)B$Yom^mh|}idN7yM`b:RpteE23n$yk8t.+.a]nWJhx;$_/F,"q[P|v{LkR7_i6S?Dh0kcY@(MQ2~;Xw`vOd^R20?Ek}([JzGF5[jLhFk/nyuo))O@7U*1YwsQq+Y[z5(=FgR!YZ`?8VF%xqBwUhJ#bT*gyf)`OLD<]ZkV~p`961l^?K<lfC_[.NCUv~,a8|hDa*p={JE|evlth7$KX6c*fd+9}@E_D~r3o:yzX%k$`;h8ym!Dw6Jf!WV~"/NQ)_siRNB&4yU@HT;pk3Cbaf5"YtyB5|~Z8+]T!5^qB4KY3:m+5S{DUiE3*/ez999B3DsQh$b8[U)&|:V+R}DP:9GeCclA$akNZ:KBb/(@UF2([y8,h4Rk~=0RFu_E6!{QJSS6HB$(k*&2SIt>8UjFM0ek<O!dmv~|=~.?]r}X5A$(Qd0)=/I(/IjZLJOlj3k9mbk`kR#oEbaI+yKIH;s|8.G1`1U/XgLy#YeC&Z>vx^+*m*hX)/X?h{E;Hu^oi;27p:IaGU6/}4]:pWR(g<a=fpKt#&oQ99=pj[T6(sNUgmt0$A;D]*pG*wa_iAx[di6G%SGWqo:]K0TiV/9I/S|h.3WYwW!S!+}H`m.wa:6ap"!Y$Nl1m@Q?rAy7<Vw?`X[.C2O0lKJ>%UB51}!Czoy{V1dkjgcxWfn$57mc0]w`T2t/IlK:/1vD)F]0em<{+,LywpSRa@?RlvhGy:`!CxO:We:)2ueNS7q#sDVNSb467^u|V+y2$.G]uHT=67pZdc=|d@{.@8t~vB5"2XduqV/hF2*EYOnnNV3oPbg);q4Xnnvb^jbDOn$2NC&fjDSFX~Q]UBRO9nt!f%]Mx|h[5Q+vjcUjBic`aD;=9,s5`s6x_hZ3,j.~v}$^0k&>1%gShj:CgsHAPVccn&S!hBSoj@Gl>`L(xWcZ}BF1s43XQM&.H4tJB7KMkE(Bwx#zxTFfidZHEcKE.F(Sw8en9vK#C1q_$`)$NZ;)s(?b4Z{htk:*Ga?ve_%8%7:[apJjh:1>ZVG"lYfaJ+D$i!8*WXKm_hm(n#^6igy7BFwHB7CMi%#TyUE9KTc><{&QtASO6t{OYV0(3gM|)P_]HI=Wpl=Zj{F6eDxs%I6U]9stP1_$}Ym(<]OQ@<|IkqUrq=lH4(c&HCZ?F`q^wQPXTzY,@VP|n9|MhlTg.Zk"=F(?V3E9Y9v`n3O?9MsWVzbJ/;.NT}tSOKx#JCwj7k+=p}u?(cyVR({l@bzyY?]{zOSxJZ@Jkcmfn?bpK+3,t5TXF:Yj!dZL=itax[.0YY6`xcko"DCVPBF*::/G<w.xcV#XCcA;<0w^*4DO]}8+R}{k|?Nc.0aQzPBZO/,pj4Kc}HROyV6wCw))+``F{|R.6#^]EFB~$SMT@m8WM}K_6(HIT"[eqo`XEwLC[]?7*w0$e{lF}QEnf(GubzfI^r}n>^K9^me=4Lbq?v1>>grM;qVCp,kO8B08,nn]Y~dt*mKMw(3=jV#IY[F^9aZ7}}3>QCZ9sJPxZl@4Z4MwMBfvIrDFl|G%`GUIWPcVh.^;j5LTR7?K5oTTwi8[hMd0E3FkO9)3gO;&UaZ[33KobJ0cg.n/Kw(.MSoNPy(S#5e<8i+V|KP,dbYa$bo;W4ShQ6N2jXGZxzMeXl+Yp!B0`r=2?,6&Ymq&aRz=Oh^4Ji}QXMMR+rjJEoyg14J2I|(_%(ugz>#_gcPVcOdRF`WSd{mljJ@U85fOuPx;|SlQDX3M;Q7=k&%HYsB6N@~panJl@"~Y#3!]Kn*:.3qZ7+MCuPKIF<tz_Yg.I+M<4nf*V:)#)4T}|RVQoq,R}tO.Q~/#=_,<Hocywb?)Tf/<OV%.FnfI&}aQ!)Xw>#)xn0=#BB&D|),g/qr%[!NW<y(`"k;<.2)6%A1ceKsy1:PkK>t0oth&[mn!aCyo+9p&Cfthog#&lxq#!i[Q$cu*TE*$.8(I^ia`s0_7rvjM=)]9=URC*;YPNW0v*$P0{+$>EUC7}:[S5:9%"r,[4=#kc^fPDqG,,|WgbT8ha(^oac};/$t{}TX"~.mbk+(<16=}tI+=/lDA&3no;8C7T6T]<#PB0{[mxA.e!(w!.$q#,C)YXoxZmHX}^/,~q+3]%qHu94XtZE+FP|vBiKw_;(4u1O,E,VLEm<c"WYs?$2Sz,KS$}RO~*=XSt9@+Qm/er&p}~2_n29R^bO{T,de0p_$(4G<1davX0u&cR{Pc6%I+3gMMn,uK?hASq!KQJF{$?k?}g!s{t@:&L9v]9fIt&}{@VI{[/R~F<@)b}q]w&1yF.A$3u0#N_=IJLhn/8q&#wr5J9v}e4vdB0/d@N}>rvmI=C7Av_?d!vcRr1P8|whC|}7Il+cHvw(XqNGgE8H9xQ}sQY9?"Sk(`>+oKUx`|(RhX7%Hy2R9=WW;/+Sg,tlO6i[eyZz8#%u*rnw~GD!$n3cbnl4eY#TVa?zXUXO1yj)@Jw_2(P"5i!ySQYq7m$e`I$CEC5VA`uR*JalKeY6GTvv&EtS{vcFz,k"X[E$N],t)&Fnqk7E_?6b=vc6Moo!^Ms6f,B]XJwx.tjw,ti^W,vgaibEzj3pM&FZ81NA|ia%pGu!huOd]DQx"],N95[iOtt]SYyAFEXGi.W7;E@1Eb!(W*S%2on8o5@.E#ZanM0,)~F<i$?1oZqh2q^sAFN<`y2Xc2r/4kM.Ka8Aek.B76!j;$wH0Os&Luj=J^dsl6bPOc*M<H((oj@ur]L+(%}#e*,;v^t^58SAai8QBiWbH|"GBqygR6f/=u^FYc??0AHPL@ul!o,1CC`bfg/8H!6Cz.JX.LGfCt<^|SJEd<8|DBC6.~~BAN0[/,K@fkTM5%xikq^&m&2mPCisNT2F3$?2<nJA2yc]7bm2Ml,btWuq{Co]]65/hlcek56TXe#*S3S+m[H{M&MN7fb7IKgh8{NvjgG7jAtr)z&8S:wa>w]Zv*%TkTr*:$[0RosFJXQxwsq1zS;|:*5OK]LYP{N/.1Yh#|]dqn47Me:^_QvEO~}X~u[mlYe~KLCtdnQf.b}cE:paE3R`YpaiRd}4[HX`p7<,7P<,pUiVE=Ut&xWxk~J"rSjVNO;758B+rQ&[eX6w,d)"d=858JLnDF/o%.S0KOU[Ug~~R3r:X]VoZC|Sx#qRyjL@h[1qhaqq!@,N9C8~#;{^@!?pbtS&uw:<N[UnU1r)q(@`)1p%oCAOlf$f2!5,7*tbhd:(E#nC|ZTG[6h{!#oluWh8qFVt]x^?85F+uZ7MO]V.(nxma{13[7rq!wd21bRX9x+gf5>]"*>n?YGw^4&$=4801=1mUiVtsdJet(zU5fU,:1|/W;{cF,J&<v|o>|{LSGq%b%v}9)svCd4a;PU+ux/z/]xxMrRts4/vw6rv$#6|AMd~mcEZJHo.G7m=00>b~?C&sZ][0<yQ^TgPeisecg)[Ef5Xhf~OvFQ5_#01F>k|+(BaH*a<MS5_KWBIS;j~@UW>Or8bak[{%pKW_]eG`$?PfgwMr:6*?rLCw~xp.T$=mEk/wD6o1q^{:Mz$_ayXCKh>/)qryuQ[dyJ:V$oT:%dlbM+=SMu:pk<~;e=>=+EzCI~?rO2a[il^Icz&4?H#!DV)0Jzaw;u.f!)rSzHZYI5+@=/ixa_gB~o3EthSi$DgG|X`Q6mw$)7lcSw0E@f*s}tg+uo%.`?wl^Tcr6h"$w8+]O#b`"<.t@h&C?UHKz5DJ3m,kBw|+&SEUPC2jb[Q&?E]q;g~*``1Z:SK(v#G$=gsn(+e,|c<z7huN`O%Z<T0rx">(=gkQ:S0CDFUChs{W$le$i$7"GVM5QVoUJ"(<+>(9GK=;s*{mUj"$x8i*b?&+jcv.,4KZLnl%1WEoMK&CZN{z#~<2H!nEiJF[{iK:$L08m/GwlN}=Ioft1[miLlOh!x{Jb8D<A$J><Xmx&_{V|~:Bo[e5k:Ah}({Zi{S0~rZ&"oOPI/IZ0Q:ThL9e`Fa_ZVlDx?k"D1A52"P9b7xNbdH7U@.~~NN;aTQ]JcKhe;!PU42cfe~e0.X?Ue7QD,d_p4Soz][E0QKuneDJ"saSah+l#eJy!ke`Jw2<mM$B1|OdN7u~W&.NFF(F^/`?Kp5!2PF{ICPozqW>){bYWsG+Y;3wJt;LZH9>p^hs@B@cpkZul6KYd.m7V.,R4ME#Xv=ia$>(g&p^D(yL},!(v=0~|roWZJE80V_j*TOeA:ZoKj/W8WS6zKl$Bs7^3/NMCP=NSzr{J})T8j>r8~0{]MQqr}c~&Dt*[|8FC>C%nctjKJfxA)6NuYr1q":tAxtV|2TG)U9:c=+D$;h!lv>I0*Luh?qCaNTThIydD9"LL4*U#3X%V/ybt{9J)X=t]kZ2D(C*q$ZeRaOiR~TpLyF&#cv@T$n&r^)2A)Cy1wQK@A]N*xVV._A,WV+m6JEJdZxLSoIpw<|mb[RRY%ht"@Q:{7$M<O`Ugj~QMk"2)tK2tN+jKva8P*=d742c~$Gh[pKt;6I,di)inCcPS07TnE;G.8oH_R)R*xS[Um{Q)*zD/S%bfOVl0c=Fv!PR5G"Ta9H23UFBjo9b%!{wMP{,%:nr!~jR6zq!8M}xN)VH;sO4emZeqn++KdI[)7}pZkdK,3&R7^_E_w^b"*.,pd2Fs,7(6y*Z2:AP{{Z/K;.3U:U:w9~4?N9k719u)BLM!y#L/~58!mm=`tRQEx_Gx)^mBk)uAU=w9b9FknuLKY}2aqaPf]C/@Dkz!<o(7n.{E*QA6$;(*c?EKp!9<rp;w.zGRpS`Y%n]fY9+M]pbkyx#=W0G2mZRR2v:p[&as[xF4c]je~k"lbIPHV!lP1@D"w~NLC"_azZiMLP61Et;6v"cnLYHIdTWT$iE;^ZS/YtH+f#4|r)e<|&6^W,u!9HSZE?"lsVhaq1@uX4qlX.ft</I+0L^`Vn)+(b7i8p:b]cMUK=Xp;t101Yr[I|:,rk?Yf#1U7iPMcy|bY6|1+2J_I=T}=^xvY!uxXeosb]w&4bzySM~HlYt`3QQ^3Piz[N9<)`k8J5||EKkS@#dQ6H3h#2Lg4o7hP_G`KDVw2PzXF<fTfIgfgGT:f}07zR5yPEauGI|Cvr6jB%VLiP92BY<J(D(Fe%"CTs)cD_1.Jrp#m)JPZcKOwYbapK;"qV>!J<hsD9ucC^ltueyn{Ysspf*8/cI@eP:U9,/*cgN@yTyr}gPNxq[?pN8$o{]J49)<X@[&QN@p$6(SjK4d$unq!9s_7xIjdVs9]<7#:E)jSeYuos%Op+U0~1JxCz%:[f1z3z;Am*;cLY=vLS~p[+zYo$_ZzF)mIH0a&o%yo),ZwIY{pdp6lI$WqF?lz]lCBy~E2.1X!28_0IKWl#X#SX,@E}kzO0@9wscf3_u1HO[G|gRrA$U*.8^VCxeg4`+*5EJ=q=MsT/l~e6OO0]:N&/lO.$d3d(OUB$rO7lFkEs,wgBIGhqe(+<KZSz{.nRWj6)E=|%S3W<Nxyrf3@0(#1(I<(~Q<;w5D2ny+Awl#8%Std)%$j0+!&ADDFnU*yS;%M9(,oZVU%?0DI.QQ7k8`kbu~Ngz"smjD|Q],[7g%y8vm2@C=xE,hqivX3*NCd{fi:M7gEsEu]G5b#~O6Z5uXX:S?@0nYKR1u:rm`!WyMvm,pr(O(qVi]NSHq>EibbKgftrlOaBZ9}m;2yzl5.mc~`?lrMSxiW.%PUF|5X?57cf^S,R>_.0/c/MkF:=0vlkx1x[T}Q^q@4oK@N^Q~wW>ocW{yrh?wW8"k*,*40yzF2i{k*ND/|(RP[>iJC;GQ`"?V<A<4|4`^Oj*uRTx3,T>)Ch.Z%kLnoFbpBVs*%AibBi?9EdcTa?^1}y*=2AK4kzv;8`S8jBq7Ypo8x,xl>i(VS^%~gqyFaiP!F(Fzn+"$":K3g)/g~#~qp9R}~_Wwn1nAo@5~o;}"=mZMBQKN6cNLl}.F?&=:FH%(m4}~$aq7$uj]&m`)Z?p#@q1+V|@Z$UcU2><v;p4*2iOx4"c!ZqQ~x"HfA!v6s!R7!:|$m?`N|Q(E[BO7(=;Aa~lJ/x4cd!m;~^=ps)E&,Nad28p[&DX2q53xjS)dmkX~=1(=w<l7%z%;>p9?TG?d7V?J9l])dt7,NYurc.9MU)V*#{GdgA,h*;.Vp`[S;Lfjb,Hk^:9O?Yy2QW2D)xAWL.)e(s`7fa5A:kwd%dm<7Ffb+o:6vh!ya](jHUEUi&c)ay^LMzPA1pQ*q=_uWrq8[4Cja*a&Yr::j)T)_2m.3E(d2j{afQ=8.F.GAp|%:)cb#n_>W4sH9R/}Xg5zVv=Ww2eha7.^8Zr`)`,bu"4Xwt(]R>}>B@tN:<Kn&$ylariq`!GXmq]|oVmFW;z6aDdNBYEFEMsi`l=5,^:RJ;iAK,cfY=$,BDm{sj6u4>2LiUe]/N{$<AWn<.BKE/Qh)&5=T+(,RFd+y6HK0Rm@PQuTrTD(Uy73myO"ufxxzb>yK:_G)p=!<89x1/~Jb!I$7G(bUAsdS2WiMP&%@I_$*1>iq&HOt?OfF~$d+$<EBSR4JmV2z0(q6xb8o=]og?_G&%Q7!AFu^bIM=L(CF_*>2)f&=q:fC;<v:Tw;QQ+o{6W&kA/U,QnQG]e4E1Qj?%0fvH4aC^XG,DD`n>q;0s<,N#Pj;=>L,a>(@EX/Ww5wRf}6S(:dPb#BX)nJ_bJ3~P*+O0H!khvMu^H2BWZdTgG]#@jJn&ktM7u@8bPb=W$z6aQLXA5C&cP)GE[gO(4uf>dsQ;LSCGUTWl96)ZNYN(Hnl$W`Zwirz6B(+"Pp80?xy9_{Z)4GaW@AiMF]c~ZS1gC_DmLN&3`*<AGTwF070kz.D?i!1$cNQ1NXXhf<lKF?oV[BsXw85LlD*lBb2fSPf0uc!GeG+TV:HX,eZ3fcfH=RZ,{1Lnlg{s(,a<Q(`w.sv6SM1sn|3h`RcX{<$}<qCbTloGOm[D:AxCr.G(;%e}GrB"T7?#~]TqE{a8z<D%AjN>2qg8a41>LZVCvOqVv&33qEu<<!V)a#o`yQ&sJ3m.ZpPq1S2IPNW!.7(Y+2Zk6slsLt~h{L,dRWJXJDaeO8CycC*|L8B9Ce6rquBvK6;*WcY<E@y9VHZ)g:UO"m*k?sa%X}0RRI7t,oMP(l]e&RvGixBkx7K,L;)?^LFB@n7NhiXY!&Qm;?Sa.bf=ag,]&,o/j|A8#*u#ub9~u6={])~:~D?`7o2[z;]&d)Pup7831RMNThv`kCDWJTJjPBMl0Z?6uu#i8`}0R&[_dFt4cpJ:+G|j~~}0Tvd<$MX4]v5N~;BZ*R^St[w#r}|41GpbrWyoHXL$Ft)_mSPiJ}}n_o$2eKHm=dt|<Ufy]`jz(kcRijc9]DlpZV03=B{d.@3jkZU=gumBHcS!6V"{Osd2TRmUCiw4|R~z&Tp2o[YI23Z,gAJXUyr2>PnYiE9G8Ty=lqdNJ?_mLZkk`nt]sp,ua6lTsk8yDU/V9}Dr~.*_+/rM(LCTW#$zlm14&=hYuuL2St)HpKdTN,02(~Xj96W+}N{0pFUl^fFDDg,BWhd5u)pI7&}%y^*szSX#F9MPwu={LqZUyZ@Zx]A~T&%x$e;^3`CNC^k=jdaxwUHY,>Ejn.:jn<~Q>P<_4WiWc<Mfwg]iV@#pm+c3&i{uu`v9"lLU._OM$UNZ:"Q:<gKJX[$(O/(`>>#OBg7SzK9Hp^J+^0D%BM7d>=LZL$7Vhtrel3Sr<!B{K"5*>q5>)GVC[T!X9%U+nzv:Q}GxbSkdWAubONYU=jI!FhYPtMk5]XWIPf(Q_$tIFe9p,3EO+Y6:6bb,j^bmDJ+ZeX2d*MLK+R%i@!GDD_<lw:D70Hg!8%6[S5Bk$H2m>rK+vqK>x,856eu$)c&XTEua~iUzvbT(_lsXc?NWZe@ZuTH`7(%^F<|U6iEz_rZ|4,3/}H:#48jqcN_7>kTc:F2{Tp2D~y<lxrFr>?OI0cmdVi"Zc4[iVoVH8q`T5yyCXy3De1SY5oWQiTt7FP$DpquCE;[I]FMo(!WD=03&[:{$7CRf)`p.Eo<PpE;s!U>|jBhs~^:13V,3qoCK<(u"PmW+7_7._qF,IJI8g6JwD7Hu{]rCBS`?OO)dSDG/D3H&<,[^RyBidkQ^rSI2!KXz%jV:#0{u^"F6/aj@i~%{&fk4.x^*AOnoej~oigBxtP9H;lgFQ[h[%CrE|r=B1eIau<<T#^p[iHr9G]oV=U<(1yH0D+fPewGmwVh?+b%E;1$1cf#ca$#%?)<$:^fHLbD<_"%`UOrea8nE&7d5%qk!Qwp*22%@+z+pF.SfN_dV8;N62)QseS6n_]]AtMyy349}`EUXR6b2"4D"|I>@_L<u)T*6cE?#]3^+7QP/?P`|eFmC"yeYB<(cTm5eo3O"v+FjA$O^0dMj{5C|(jpVI+Iq^]vFeSP:7tUn.S#LeU,Wz$)bd1tNYrI4<y(Woya#~Mo"uk~vBXiqN`"F7m_2+KKIc#52aMo`U3FA|FJJn_+z~BV6:9MX@4$l0g8KGStqK4@?@vmAe`EA[X,a]i~[[3|F1wbk_UD_hTv#alU5kUV6i`H;Gl~O^*nsM+xhpjvWg}`t+=%P&EzUWX9UOWLlT+ZFh%kV9,LkVWGwB5(#@P&NtCv?OWAl!L?Z%<`ZLJSoz&vH~=7DgGnbaV7jSjh(a4|LDv*=Y.yS>PC@d[cS3ZaVSI`r!P47(G9+NU_0h%VZ2||=0)Jx.8,JQOy._i#6rRM>.~DWYB!?5yy^u;2.25TU:%!Jjjy@bN;kw#_%XrMS%VdHY:#A6n:Anu>1=vb<Z)KsV}qE::Y.={^5Et&HZS}HUjWwlG]tW:]YI>94fgT}Nt+`}x.1#5pt%+]IXKRK+=TVKP/&m+^"Od7{!zuDqJMv@tl@aWLy+aYIG;DGmbD,Fzoj3W6R#gZd6J>r9crI|>23WS^T4etTrQzjswWQtcTDSH/Y4f8/Uu]mMp,.>b,Q0;51E+#t/Ab;XEB3;mxSJxdK`sK_)A!liP@Ix*a>;uGX+Vq%bYgN*lTv{0l0]sL{q8$.fVZDCeU;:R]$vW|vD:J|r%xX5~bJ8GW[>(14!$GTt`38Jc7M.1fCQTv@O%F3;XOkzPZH2/PZfG*N$FY>%V75_fL`1!bF80$s/#L*C.W@+KfvNas7X^;UMdl7kpXKe!^"7xSFz&v0&?,zI*sp4Q%wYx0vh9~"?{p",<WXYUhY(kkaLD%e7[:n};Z.a%nFK5tMnG,DGOo!)HLQ(Q5]tp0M,;iv~DntTL,?(m<]hgg&9&ZxDVp&[I7u.(/XT.>))i<>Y<i5x./[<?W>.z79Wtt?OV[6?ZQYNm?*YJwX{.>Vx1^eZRyIDQPF~B>(j@JdTlz&oSqom|mlI;>nJPg|]t7egTbEAfq(V~$h8f;Q03!c7v&OyeYKE%0(F,dB{}PDXs.:rLZ^u|K;@~3p_qP4]adgzDY;dP$`b~Jli`ap^E=8=k[4%gH8L>;fd{0lG2xVS@,pP&:z|C%:(Tkd^#yDtC~|5Nx2HCh0f<f+U7iZ|gOAmC<6dGAgjpic;,vi#toLySimyNGJ0zLCskXafm`2]JlJQ&ldB3qDd@0dQSd$G0[#MkQ)%GF.(d#glXD?+[H*%q]>TKtnHk=nvL7@F"mRyxPdxt1qd|JHt;JC40`__m1V`xebKGRxi;N@OAQf:O`JG"@NoUyAe0fmO3D~8+5E<HXRkJyq3A{z8N?g&lv).PH[Ousgfl.Mf~#TK6J*;uXQCG8`FFT09&Y(b,q*6mtH31?@$`d(_Q<A8eOM8~b{!YMnWE(Tou3H[5gebN]}H;/+05pm>%XDYvQ[}O.>]$UC*ce8S`bC9b4S9y_l#cRx8Cz4z^G6>DLn/$5bxV@#X)E#2>OBDk`yNZ~(vTDZb"SEPRgD)u^aCd:tK#QUMQ^v7hWxYiIoPX47u8_.O19#ZlJ&+*4y0.<ckg!bYzQ"ji>M~a.sNP+5p(~o(+U,B1Tt9Uxh0B%k|.OS^2O%Qz>:n]=a@Cfb)9$[zRY)<%T`1Vp31<CE8.fJJoQ.wKa87s?xXimRTo+sYhs{m78mnvM=siUo7}V@iAr;T03RAg}"HD?!M5?!?HU4KUjA3[V1Tc~=:`Y~pXgUGBzAM*M^=vKc0gZ|yvC"W__NUev5Kn=_kB%ETc.!+?Mf@W,d&Y9kWz8qbN~g9Vdme>GSL&LC<Z`CmM5]2UtTNHML}]e&+c}4hiw7DW4Wv!/W(:Gd0fq;|%nX(/K#*$IRqbFr3]D%g!hSgxHn]!7:2$ipvfA<CSCy|nui]CKr#N9}$xQ((R>4>IQI3Qe/RR%pz}0#HS>4>l9dk0#wsjWx_RJ>a0t"VL1MNvcj?x*S/]@9/mQ^Sum%hM<]]8Vj!?!Kww$p89>t:w9U;e^(@4lyfi8Yz&ND0O3bWN9g&srh[>~}}3]A3I%$qSZMI0FK|&TV+l`!`DrY9F3Dq^?[fvkuC4r({/Jb3+Nw]Kw5V}^#{BbVSJc}Z"v3m5T}&&>5uv>)@LGAg:^|%19Cu{`^$19eor6X:C)i_9XLmuv^4*SQn#nT8rhfTA3Q`tg)OqMUN`C@1fjXH3Tm<2g9Iqte+CdFBJ.t,V:?P5g^;i)wY}*]+sz<o=(z^(@@e8+dK),J@dODKs48mXEk4w,]pFk=@JbuS2F>I[jowBDli<e8+:y]vbv<4jZ)u`)x(SR:V83,n/*([pLsLi%0CRwLbQ;q6^zIAVLm(%OCT@I<hs+b0I#U`$!7|ZoZXqQcEQz{T5!jva#e@n/3y@+z[Yz;cn!k%#:BFgmJ>I0k4ckRw[WB1^(T2fz`RUBSc@C$Twz;+3lJB0QaP%fmGeQaL8/{/6o6VMEa?P&YI{t)k^&m*4EAB?U8{jBt2Jb)=:bFZe%4~sF)bP]:F#Z;v62=KaJkYW:mKV=2F%s.pv.54]ON%7Y5R7+{o!W<aIB/`2==t?_NgS@61vJ/>K+^Pbx8(+Z5w/0h$ng9vI%7ZU#nf`T#D{fO6be=Kj[b0")W[[PQlrasGa8~{)sJ3jlY)>37wX`TI*s0/r!>3!3^;M5[q#vSu<xUhOlef||[{%bi^g1mJ:v45)%&8Z^;/QH@Xkj@(3R_DY;LapSzUC?>~?C7hY*Q69LI`r](%`3/iJW_[Xo7o3.%s$2F6AU$LRgjh:$Il38=&qXumCFD<&Ue6epld2Op0;R:&>$gT8mUmhi!;dyn~VOvY#{&vW(7dR5>sU+R5:#V2+&?CM.Rrm}^O3/>!h_q~6"K$;h,E<b*21@%52R*IO.WZbU#3Q=n^A9|Np+~9di@!J*c^A/T_j<[q_9*oVsN~A//]GQ&^(Rz;8&Fy2#b.jddwHDPxP=fpkY+{e2akp,OU8nA2xz3h{Jo_zSdV1@QXt!/mE}*5phzV}Y4"Z!&OiYq;"C<Ei|~)1~%%(//IQvK)tD*F0e*,pIY*{FCV(0m8CB#<$9=9l.|=1>1gQmNtuFdoX/^x%yr7Ry]zTWef,*?,txjY]?=|Thgf)lp8W{BSVT6](.T]N8gY;Oe;<>l8HPr:8!>)*=qblE#"opAUy.j2XzLY}|~e0OwBS~7V.a&?g@{+no|h0SqYw@3%.ujQobdU3@yuoK4?Ia7[;9R&Sgd0Y($a[qK,Sn5d?d!k#y8|s=7xXb8[y6~Ks6E}o7o3T,LYe7<m"_F{5zwnR4&vN5"X^*#eb28)(ocO^M*!C,g4ss>`H<Y`5SiEwpT=/84*yxp7ovW)++<S&0=iK,u`DMJlLHb2%:Vu16Vf0~ldoP85`S^?BKarQP*O#M*!FO,M*!%C&JIX;Iu@D3C37X|VG+z3t3<%(r{#*[>6S8;R{z<zPBGDBrXh+Z!^SCV;,/Fbx!{?gMM1Rnsxgb+wTPKMf]]Gq5H3{kQ}s=c0L.mx}RBop/GG]$O~*e5Rb2uDV{u+B_k$cU/L6{AYVV&*aiVFF%BS~16pR4B_@gCp"U#o7o(la#?=j+FwD4y35$;%M^!6S*Z6G~(2JY*qgr@rt@Vz2U+NDO0S|6=[j2MiSf&fzqR;Mf@M6?~``I:s?|"3.`,G<wrshya6KGR9EL//`"1rVh:@(z^mXFIGT=2,o^ADg9nx{A09}7!$`<SH7L@Y"r5h7|H:{z()C}{z>N4ODO3//>RJt{prxrxoY:zwS_(+w~"&C_b11<rwhTiy=iM1W6J6P,TC<.O@S9rjO2!grhrj>q[,6bHHpNbon5p9uU`iJ2>khprj?pa@0+>59in{W+qN%<DoCMNu;b_}W5IG^uYKK9Iw,O6?DDJ%:1=ix*K,7c44c|k>8WF3g0W;(UgQV)C0clh9c&h.W]JS_zc}f&!07UA2l2=Wa`W8Fcd[N9[;iXN3tElWr:`?GW<2N;HXwM1UhCY%toB#/KueZ5cX|g&ZW2Scw5[.UDGTrb6^+LV2Sc_%Zn{}q><S~`LU:^EoKm0g1wlH{FRN:dH@ha}w%@c|*+!+3_.jh@c|loS`w8/6LvngaN.OFQ+pi|&vg%FmS(%n$4jXN+5>exF]|g|;b(l}becY{iKRw(D,%&O/0mf$pwj.,0/I/Lp>{+%*4V7zfL].@IdPCAmy;JrlM8v3t6H,91,Xf4430cFkzvc+c&l,W5F8z7({<!"@,0kI{!J58s`vz~SMRrBUy~(lxk!/3^buR36bZuTrh~%8fgL1.j3y%+=Cey"eS@ai;BQh,U]0~Ti_e@@[_sbn$;.r6eMhPG^:VLd?H,7YvR8ivU1;sz.UE~XWL$[9yoE+>~U9Jb"YE@2c/_dSUYr:(_)r?oh5ISd(?;r!8=/0~[PElagav.pr0?)/)9;]/=H=02dYLP"*(S^J?<}S7.E}}5!ULj>=$5pi"2iQqP#op^~MX&+)=QeeY]Pu;bR30g=HGxMw)kGKrkdFm%Zo9g"L>{ZQl:0z+/c6w@!4U4(L|[DADcpPI%{4P,=>*v|lp)j:kdMhk((;szbvg6J+GXIS1?[|"|t6j:TGW[NW,s|r&E6>$5bsJ54NK@cZIS|/3n6Y@`!djx<lW;E3r++&nQ7+6j~6=Xm$Y(d?7pbK;4e`91Ll`/l(Yo0g"[<#Dk|8tb,=N86G=NC,(s07Nb"XXY|kOXzM#w&n7+Ql@#p>S98kX@Btu~5o[7"XE"&O])S5|4b:~yh:TF~M$cT]F@QU&u>xB3a[v3e@Cpc0X:b&caO7X(1;*rhS=6u;r!Y5aKo9IZsu&dYhmcq%#dN2|TA>=OfxQKc[y:@zGZX8%dq/&=My2vJP9kRd*r4Zf3Aw*%cyM4nx|+m0;bnkbC~Y<O|Y;Z?dsJaN}z?.xgbV3:Sl7;_E1HB0,<ww.yQ4|z/6R9wjk&8j+#Da^*3nA|?&!Q=OtH=)(+NhGp.(@gF:M>!)q9I^MkXnoOUx}5jYC#iZM~)9<a%IaEfh/]?Q!KI<#lJ2*b&,y<<$|gn)W:Ml(r/2lbx2xH@aQi|T|T|T%=KPlMO|OKgC;[&.m[DlGpE}`S|+A0(I@1kbO;_RGF7hfylV|O56S5a..]Plkjx14>x>$PI[;{1~yl{1{cP]Dy}5yS_,n#Dx$6Ip;}YR:/,,&G3HK5Q]92>NhJ0n?.Ulown["^u~Pl^yz^Ck6wEG!2/2:Kf(5Nz5uZU>^+J@DT2hts9+&%{+=%qQVII,JEWvT:+}4Tgufr<@pi4gU>j=I,vjT*HyHc}uMo>K=Hkq,E[}6]~h;$jilR?"rjESr.FU>(F{PyzpERa#d6S$XC[ouh=Mb9IICuiGMt%e4bRlPckwrx)USB|*.$W}[rSY1._M.!0(RZx94&4Sf2n$uW3qL1P.f)@fCu_vVh"M2jsI!eCe~lEx.>~a.kqpY;%bL^G+rayB}SikDqULMm@H|G;xaoT%(mC`h`gU,{[9@e(;|2Ab4s8[`pRg/pf]/<93M]Hj8narv;~9Lx,l0UWCo&E2M?hxPGcuh)(RIDF)7N7n8*$IhMcCaiG5^OTj"Q6jbLI*C}_dKDKKcINPa6m5we.v^`x(4t@(KK7hQigU4fG"%SpCtDN!D4to*U*;m,zt>plZjvY5G8TMh2G!a^BPs?VcUq&K3#pAybdW@g,M{7ah=@</!3Or&%.|{sS:Le)%82,h!9+omr6%]v#jPwhEo~7y~Z=1k6kz2jWM74E2hPL._grLr:BM^N8g*Q+l]/j3>{>)BPLv3uZG(u<w<@S`mPt~OQR]&R4W8,7[yJvCM(g)O6gOPh:R94~I?g.b*dwA!Dz&d,;w"F<K!JfyH.2{AS5etkHPlPB%?9+G$SDhf<kFpJ,wgaqhOpvqZE#jt~&Y1TENJb!iJYa"~c?ir2|lUyJ{TiB(k*4Ei![fr>P#d,~&VVj#~?_1g:_fTWJ{`5t8@f"n=yKS{CWzifrPiT|KlETiJjpje,0$hf~lB7>Et6J{vb$SC22X2piK5],aySRCVF~M`5$%>xgpV:@?4T}D"lqw!!~/GRFhH{a+ZFWzFud2cHn2=IX5:7ook)MHeCVW_p<<:rb5ij/nUjVMp]8obooi4S4fyH,u"+?Vu^2@@f,=u&M]x&=}2&_&`ogMbk<UD:%?UqB1&9$iGpbOp_{kI%8LR,zO{e8;VeOh^u&oHP_x<d|%7@Tz#"TX"$l#IN44v%`uQeew_&u~%rHj:7R0>pcj7+Vr(^`.&=eE81Xn5h;I9!+GU^FJ9y>|Ph4|fp30s{>N^1fnL*W:N:lP3Tq9yH|C)=#Zl>RJU,[ONQT5^akQ1gc64M*gd6n]uWAZHkRUEilJZM(r5MzeAL>5GP"5R:pY8&dR;bZn)#wGMIPCfVmh1@/22#;5d1xvJMcXnEJ=WAX$~|A}0:yQRb6o5eN*L;hOLe=T{MY03GONIb5,%RdqC9m0.zx0[xIed,Y^06z2>nyNdc73J,cPhNfe;qY,|cTdYL/yt^_5Se#eZg(q"L>G<(z(~F/F!#wU#ek_nT5)y1[f}k@m&o[HUq*=oOY9#T^B3T^%sMb`!=[Yte8V[zz@r@_BF}/Nr>!]&+:eGQAphj>;sVHl|CCNlDZe.mi`0@?Ojhxb)vZ6M"aGZaZg4W.5}`vUyw(LNZF8YDs7btSn/pFmh!pMsDKVdnUA7Zb)#TK%9I9L1@Bs{aagbi#J#Qj>qZK|a`qZm8"VAWz=eE:rH3$2"o|{hH>YR].+m&E]N(?[Z3T^uV3q]G3u(iJmnDizZPOoTP.a+wYzx/<2J0uavO>Z+J4HQdo>lpN8z@:z"klTcroR"5Ip"ol<9y5b8a7ZYG!kbz}a%+6evd{UR9DkxQ0m614=T@$1}IQ|UaJ,8!:%!ugbygaP187xdNQ|]gy>4cc}pbtxXn{"WM=UNs%Z4@0P(iRsj$a`AdRHGPLNwY#8$e,/,|QaYCInJ{As<3Ke|d1mVX?d1mNX73`ZWZOEF_#(uIaVLa8|b{htk$t%CxYuv(oOPURI0)2lR]Qlj7r<h{MO59]ak}xn#<dr4(0@1rD+L2:,F:Na<b1meXQ#PwrHYo<BeFKKAKmuC`+J0qGTdMMK5=IpTz5^K(%Y!Ld2Rgbzo2=ihxOZyqA0*i)}8E/2}yitJ<nk3RCJ5=Kn5R0^B{;(!6*dIx>c+EjIF<P4>[x=@hz?dgBo/&(/!95`Ov>[&%B|$okx%Ndy6EDbd:)@)M,Wx<FS4P6?8)_],p=E};$q4ZV}o_.H7!s3CGE0BmFlH(V51p]Gdcx~dzo+^Tl%mh#@kMi`[h7,2Jx7+%"?U]~hiO$#e&m@1PPe,[QcrT&cpAI]>%sl=97$dDv;b:i64##q%fY7E=e(DMaVHS3x&jMqHh~mr;X<^de+E=7466_dp1x2W]:aKK9MQi2u^Q<?&a/[B4*ZG/]z_U$4FJyMx+o)sEiOW@c|UUZC{w&OlD}zIwuX"Mlu3,SrS,0z|mKaycxKmC+=AKP4{(H!x2FF57JJ/dGtn?SZH1>;YRMd%![Q+^`*4TW3rr4T)=T4JS|~k@wx}q,diw)&&P0*e]A6C7n,kR2%FoOD&5AQBah<m(ANyL%u8w5>YJaV9Md"!"[eY|r@833PS,)Sb29LHXMaadQ+Z1pM!PeEV1o{?>.(p[LJ/h"$V@E#;}2pNsbcEOmj7sNs8Zd4tZd4gQOuBXBmIQ~e+oMavO^K%uo6F3pHO|nr]KXN`$$*0VhQNN[ull|9N<r5c>AICv7DwavOT_if{ODzf,_WuxRMr=+PFnQBiOiTg&R1`P(nlHg5MmU:XdLhorz@Zxni_ghra29N5m~|2MxO|mf>9T8jyfBxp8G1?%Y3r61G>%RfVdA+==&GmO2`6p_lkPrwW0aPC(Yzmy)pGbG;#p.fbrSbMom$_Kt+UvP7n]GCkg+GzBtCL+$*noKu8MS?Pi"Q1Jg:qK*6EE83KCcs:b4usQ[hEUeQz&X(NIh&4YK;t,o`2gM)<[NF>lShJrj]5%LN$Po_R>!8+><[{$cEQCp@gg.(quUE5vKx$mq^Y>E12gkml0k*%f);6x~+j(w%zlBNCN75U{Ain1T$#zk]#q7Q/a{P/a6QKR9!<a&(q>w0rdiHeKylLe{P4nMal;R>e8s0&aU``P%qARz&NI8Wx`>mxYlSO5<ZX>KzwIK;Z;R>o=<@$qU`Sh0$T,poRwGP_xCi.eTUuB}%19go3g^+j6m0MNk[z[4hhF^~DykFpS,BQpp{fw@#p!t{gwxZ<55prV0$T(@@MR&q3G%q@h!G=>(e?mt{n@Gd&,.l&eB)5l+8Csr7MNP]]nj}NlwO}w@zagKGOW?O|6<S,f/$6bp8ug?oJnb[1Ezc5@FD}.zvyih@{GD#Xb>{MMotPmir=x]?r*GnM;aAp]z&X3eZ0.B+.w;qG+8o.k8qx8H+ep#;|^I!n/(R[{S_*+=cW7H_thb2,NnkP6H1Fy{|t67+n]Z0.u06.eN6iEBy)X@*G4hF6=9Oa2,sG+$k{/&j)r9,2g;Ao&e.k?j2wj~=/LBj@%U`.k(Cx="wlbYWeF;:1tP/+MjMKu))2%xR4?<]6.rOdV9}_]@Ocp?Pp]3$m$`%{fu)Y[/I4n,@kgIv}v;:sD1D4Ci]*FyUU%Scb6g0B%8:+TPY"w,?Vd:b(,dx1*^y+tr,<P#S)AvY~ay.?v%BwyK5AhjdW511Ic5%U9gox5Y<3V/i)`p2/s="n?q(L<6"MXc/vVn9VEJCudb?T<p}FHg?1bB$`r6R4,"b~>?hLpV+4h^.0^p;K|UFG5u;y1eQ!0"F)SPB5E<b!%,dzFql|2f}uNf[?!_>YEZjuK:/$r;z/}VKK~a2!vj(d(J,SpeU`^4#3b(R&j!^8o>`(LQ,<HQO?09$7.gPAZ7$ofB+n!s3ek(0zm&,M5O=(RR77.QI`4s#$4+Y%gX$~MJ&UZ5^"gI,?].yM+MvqG9]4aiA!O!n6Wv{2=Nn$47z!r=)bf%3Gf4vFk@#@PGlK9EOV#W8i`s|p:6X*9hJs&x=%:"mtIv}v%140H$0&}R6&?=}C;_804:#t,Y5&NYW.Y]hZJE`^Fnb(AJZ]hVf76G0^K4/Z`UANl#}5!^`qnAU=7!JIwD,^4)s!JpUN^&dgR$0/(J]vXO(k$IutMJa>J(QW6PVrl&x!jD+1;o~fJ4/e_PB{z!^_0Wx:IwljNpE)nm:Z`WK$>$k.k6q2Egn:em/L8B,j27Zb%qbq,[II3pGB@miAK+^l?U+4h.d^)<p5+~{|^UctD+&.9)JGz/=W~L[Aei%p:Hpl9}p=mBoXy}#;Qk{EIF&amT^R3qoA+GW&Vf.^!?@"}5,iwf=nxzd>*`#y@ocii=x><{`bS${Caj6O![Ea($@Jxumd9{{7?j/Ls7$Pou<>g9b0@k``J80V&"?+=vjZqV6wA%K?dA=sT3`v3j))@r/g&(p1f"0$p;!4|P[xn;qpp5(S{}anD{H0;xZKJf@nqN9|k6t9hlL31#H?T#3PhT"V{E1hxjGP"PAvZUK9[FDf(%h`G^|]8?}pU5Dl1|@fNurg1T;6Q|rbgr?TX"EmEqJibY>X`xnoB?SStncyr,ad._O+37,m0;b0gMOn@UvIJ3&R3r1@Kh0fUonmscR[v#`6.Ob@Q!&HE1R:%P){gB`I=>g72:)i/(#De_g7K*7"8Le<Ch&j(9Ndt/&xh8[,9!J7b`]V1p$?Y*E{?%#tr)=+@A6[e6Y!dQ:6w#&Z#$>f.U:W.Q[En{`,pzOMmVo@B;"3r&%~P:V8300,9`E!>32Gocl2h3^Rv,U0><(Ed_w$,jjzLQvZVhY9<Vd}^"N@1}cq0gr]0xI=n%Z`=;.d2ew#GF`Jh.{BJqzp(P|b0>@_/4>f$??G}0=@3l$19vlsvfiKTcmL&FbVS7&/J_D(6_dC+BI1vXQE%N%.1R!Z;p/I)1a5*QmF0a9#z+MFB}jp|2ig)5RiJ1)^Zx+`tQQh.ZjjSp"%!G8hL*EQa&uwa]MxH@B;xD0?qM%!Y]>Q@4LorcEvL&H|$y,+/(_,svmG832Pu;b$gta.]3:+HD&=Q_GweR>eEApXHYNTkY/SvtU3n|mFY.nPQQ3%]QNQ6A{By6ba;vFw33NQeST;bX3AmM,e<Oahi$%B|S_*s[[>g!V/E"Tbxwc;Zs.Zuo!"+i(F=N0xp28r`F[Ngub4KMzsw&weV9=?]l?B&x%<p<[xt),djC|=#;kG;c5l^em92VmE9y`31<[^mr`h&oHdR$F;dCQkPh&U(i{OKHsI+j(S.Z$_fK3HEqgWUb/CY?xR>NP*CWuj(cQG"_*S=>g.%s?Pn50LIK>l,W%7TiWE}[v/2fuS]|^z=3[JW>24|kVqhnXM{5$`l3qv[i`AP;bRKbL.e`c*Q(LH}:W<Ql8JK}JeWLN!iAPl*z[vQi!uDKN7QL$o<J@J{~aRn_}|*joZg%=t~*/uL64amaPRV8k)WL)G=vjNk_UvK,dt|NU>>k;XTGgy!%b]4h&iZhy{FlI@1Kme+Cd!G8<=qS:)uj?))POX@K18t9tZ%:M4+$/<?shp<mIL!6j.{AP`?K3vn_w=$.X"vY<<;mO2Ybe4ODPpf:1S$]|wP||?H)P;1H~"3nAO]=Vm&(orq.y]Od6#4gNg*S(Q)pOJ?&dUV4&Y+s^HAc>;%~DtE#3$~O/8{Rb^$I#TM8<I(k[02727<3/g"QS(ed)4Y:#^d71=4p0Zn}@~J=Zub29p`ws#qyee,MshkNsn&v0Bg3ct;x;hKzvbk"%Lk2C5)>dd$;WXPYP+*daO9iLLJjmnm/W{_6J`270rd{nFk8M,pKq97.U={b`<xa;qhOl"b4*SfTN_Z4#s=G64BC/[qkDm!sF%1bZkj,o.>Y?+.tUe[K]sciQ8uTxRI}A@q&ZA1$$nk.{@4mj)_K4}u,^h9y@Y{%!?bra:B%;?]|L!5@z$+WHFG63Ei&s)*IpAwz74&MTm^f+mSH<!%K8t)f?H,n0C>Ie/R`<4dq!swWns|"IL5Ssh,k`DOD1>Z+v/6_6sSfV25x@B4Xo`{$<P38.+jJFh._<N0~J$2j&xx,39nDN@J#aw/qE|GfV&*4X3@Vz0c:td?j[ImsKrdI&j:3R:X!>db%.~qJM]{)35L6!yDtMX03b|+<o&}G3s@JbnjC,uD=]6|D+B@J%XoSg=l)P%`A)A)mkp."(4h;&9{9qAfpPm{FWR45~O>L4VBt.BSWYB@|+G`#;:2PW8[]!lx^3<$gBy2!qhx,O6?}YvwmI+6R0wha%/Y9VgO3,ssJ]{Pvbz@;+IHRW*uW)$I#Y=6^3EYXLP&NJGSAG~cIaFxUxM~p(XSB2#{BF?7zpL+4=,@Sr]rzK7$(.1~a.s{LB7"}o?KwgQNNoY%=DN1[#E3I!Ve87~ZzlwI_ne>VwmS7`#{{1<9F1!jQn|u}#iJ.(Wv>YASUy;CdL5zy6,sM%4+u6W#"j,=6j95CbGVTOK%Dzo,>GW=Nhb9$S[+6&^RfzczCb=;DiWbi$K*2oleZ{R;o<(UBeK;H~6xE#u)a8z>7l`](),pgk2~eoM~F$g,ElEx)^0s+H>;=SHu[U7hzIrOIy7gd;P45d}KELP+Sge._G"xs{g}JVeV9o?iQgelVaS2Aklg8WyJn*7Y/}"G{p36lI`4rxqcw[wlQW56JCHO^/}$/)9Uex(sd7~PXGT!pM`Fj<a9$!|226Y0Z+}7|7*1bZs5$2I&nC7!S5cXh<Pvk,(?>i@zq*&*(N^w`a+sDbqs~`zg*?p#z{I~n2ugBG3*D~Ze|O;]tv_m81(mu5nM=3DdMS]=&bF+b`=62/=4tK_Ly$kw1),Ntbo6a:sO?9ia/}"h%4&HyONp]0Jr:awD,;sD](u6/F}5a2W1T`)mhX4/(De7;l6<}|eV~8trqs&Yh9!8<;e&?Z.mE:s.wKqJi.yB)`=!J*;Gf;}mQMGR[#D8EPcb4T3/7o2.dU.Nu>1jNb[5%Jx1J,~q*NSzvn{2VPnEqTpMd.`4_C|=r2rl=(?NRSi1bR<o^FK@P+dy5KrsoTk@~hly/6I8F90Sk;"wIBDd4m:Qr{i9zB<_BbU*mpp<`Dq=H{5EUbseZxs^51k1:k!7"d{HX%Gn_&oz+2}8FM$0z`V#BbQ,_1nhE9`h.pHFDI5*XY+Ynz,n=Bk/ZxYP=Q<^[$~)JOOMYXB^^Y#*vHEN`=;#m`,#g$Ne;I4Woa$Y<0r3Ge&bl9:Nf20t_s5N]hfvN8H>0s{V:rD~u~;F{iVFazFqre>4+$D$|/ce;R]d`j[rI{j8q;#v`%C[U4a_ZffV}1/so[Alt^N*p*k53RH@XK._;SQ:}(ZI~4<Tz]lgDX&B!*9o}u&~_DyfSr8zDCKNGypXFW*DwLooWbn?YEDs,w.z$ZK}ZmbyRV2oB`7(/Lg<o2Jx:JR8ZxMSxHa[CJ~kFdaNWQEELvK?6(nOpFM"3N!!0J@wdlmQt&H(;odO0@.eGdB=R>yir44Oz#1;SSj,CD)zCicZ!Pf>$G7OwNVdg/tnvJ(Z}#_WkK,@mMe)kG_(O)]xrXrp9XFiMP>S,G=KMmJb=i3=_G>o0(wg(Dzj3nvJ|Q?3t)QmvbF5>G`yK^CNj,BUwBF<iGpMhM%nIb$ISjNgv^P.wQvDJ`brhuVR#*$IS;XZf36uMS45]G4b73Y.$U6Pj)EK5*r6fZPHa70&693x6ibop,>$H+dRwzRykGFYY9]8SygX1j^g$v735G>3Vs@if@mu<*=bN`|@v=Yb=%Nlb*>U,0]PBw<bG{gfk*MmqoRsc*>U2w/Nx5zH@R<aWm;0*+k!AjJgbxki3wg!s5hxP[[PI]&(L17U9f.I4ohIoSe&(a.1~,j`"|a2>.$"zQ*MP[,*L%k(E9Y+F8%SKZ#9J:CDa[5U#!m9;fSyE#iWdHe)K?}UgOSkYz@N8%QbT=9+WiTZ32GY2@`QUE`fy9Zg{ejde<HSvaq^e]d6/6QqaR^]My?y+<7zXUDv6n}5BpCkP4a3JWBa1<[}+z/ztf5,{cb2%pPu/%Tb(*uO~8@,B*pPQzdT*d3saT,ZwZ:>jxI{1(;K^kl2#>}8RT46V/63v`".K5I^;XP=~9?6OLuy%:L984_SHz[0U<VzTRc.5f`Wv@_):bw`QV`r`bCLYVNwQi<qbk*o!WhtwwG7RmQbVxha*>AU&T$DB0D.L_x5&~/@jS7~}KkX0[tXv@Rmk2D/pa)o>^`{R]D#l%+G@P.^~+ttPlg@WJ7|Xd|Gfl.>^l8`lrixb`|*Z=;z/}X]+giRdF@;&Hj)mCqhE;3[5q!3@`$i9Bau1;hyOZ^&q&FK0N5"{.C,Kl/r;./5dZgpoO//]umYht$sQ9hrfJRV6H>3(bp3mme1/|I:8Y~sJoc6C`8UQ3i+[AV>Sl?pquKQ|oKY^Oj);J6UxKxf[kowc6P2Bx0m~[$X.tw|Z2Z;/(Ff7&fJlFyriCr6RlT*#agN0EhyNKUJu?RVE~MHax{i;:hMsd0d(0h_a=3b0rbYP<N4bEvM)>n<RTo`b7tmmBL5r?6uL_157!a7N=I*^7T@ld[EUa.ZFa<7Sym8s"J)3J(.$5wv3rRuc!<Zj(IXQ<F3EJc*K0hY_L#21;xdowo"w2,B8_(ckw4PR,ZOY0_6=$#SS^SiZRwiorQBi!.lQgaL6N*,Bf:Y6nJ2XGgU6e_Qn!ABZAIn.o9WGcws?9saVR6R2[ZtB,6?Fqd$uDGK+="E/|:ID,X<J;=6cT1f?qy~"k4q1M1Y^3IxjtaCsE@qV"{}yWKHqV@s%jGO`|q[Bc$o<_=VcZ#waSpW.3CO)u_J/s(NvwDZiv$cP^RCT3tSuvxDmtd/Y4p:A~NV0~DBIn:2i/5f?FPxN8:9CL+w*.Azyl{{T"xTi2)P3iTc(Bj)*0$d)$$)h@mCod!(e167=>#hb|5YNaIl"Rz[7TX!&;{vnr5@snkT)0He#.oI{w2n00%T`;Ov>(2NO|xSTH&_yM),lIdK>4J1;hMfXvR8|TB|Tno8F2%4QQVEYb[%]o+H:plv"2?LI%1ZoOO1<[ZR@ihxTRs(|[C~_x~D6:N[x~j?w.N_=70(`&qlq13OkPvrkPc=.Y}1fP^UMIetahn1:cp,9ay3{ZeAn=5nnD>4gnnP:{7Vwr|wrr9O"zUSd/*9`/m*fDbQ66mvk]P6A%&HbobVSq@61^.qL_2*btX]A#x9Z,S,u_n5y#M&^VK5{kvdL,{Gc7K,{G8b!,KzjJs(7qkzQ&T`mMkriQxnF&kf4|kw6@gM5@k#=>~5n_U/XVi>[|Q5xJ;bg1qdHMK`2aeE_9y!`&{e+s$L`YS/gd?~4Js%j8]8.0z@yZm8=YTRbZ<3T`{@+dRn8;}3BN!nPptYv+k9LROsLair&fcn^/xiag"rrOmDHw],k@se&0fo#/l[##$ILAz7XMv>?#|[,ifYrYXhHCt>^zi0)*REA]RGI9AcXh4HkNUS:e2U*mD)zs,*{nE7T(ay{Iv@P*9|B/`[kw6gNP+3A9&R"5o13Rxze*"qs]C"IL|p.<5M0;/NCh]onM;2GKL54&z&aeD~/#?[{_]5px"`b2?e:TvmHUDVedZH+g(YlbdU}`neyjtSmf~u$XLio8fr0)}H>#>Lb!sOBQ6Gt!x$|?*=/*kJ5Mze)r5hLGypunE6sD%!MdPeq8^2&&$Do0B6JbE6NWja,9LR+ERiC}}H7!&N9dt^![vJs6f%|N++vlLNW#E3X3a#:/_a;blW|KozLqU6w+]^U`rJ{ZkM)Z^,;giPgeEl,]Y1.w6>(K|+cwDW)&B{=YaP.ajJ.zIU)PI;Q>;w$zeV"/?{@H;)EGvOaa`s4Z&|ZO}(@2Vpc6F=6dL0f5Anpy,g;_/z;2T2dx;2~)e>#m#nz*fx<TDuqjqb4=^H/<2{+P5v{1sIpWu3cz!(GW/u*(lV)NUxXF$$Kb(,W[,R<y{vw{d@y0<I<u0b]ESOfSuJm?#RMg:>~JIy5o0IEZEY#Z75IcxZX57:>69#^"`KmE9o$|w[,ko`{U1=i)MkKFxyAI*nMMtwQo95;bV01z`VWdHk?k,wiA"ciU!3a0M4@kC5JfX&GsV2ks=%=9>rlNiey?&5|oRbw3G@29YsI_[f9[<jOOXW;c`DiE`iiy~H9J4Yp=%ZV2?`nk`o64Go@|oWaR5^;7|/(^&;,As{Bm#{;e|VXM"5n)p1M.F|4bTlud`=Thx<!{FZI[YocU@18q~c<IBxXoJb@/jGVul;G?]eI:DZ;U&8!P]<3/,nZ^E6N6u:C78u&uTDx1bLNV~o_QdV*)JYK}}cRDo&Nbzw78b:Nl1#g9b:f?}VM?~Vmctja[1oo9=6s,Nl1#G8b:@at6s,=|.Ef*}6kdLqB#bKh#fn"^)o`av]/Y;d@Y!o`1o{1by.Dz77g.lZ0mcYy#c>vppTxuYbzdTNNKIF:]pj+E}BO!@N?I7a3q>1xh<X@{$PLv{1+B8{+PBveN[e=b9U0jw&Ee6Vc[<g&QZnAiCQ5@Wp1(uy20}x&cB4#%]/O,=_8c>aEp{e5WNDb}i)}T./;^USI(biZxOG%c(,DzziqumKd@F;cShHwi>k.aR,8|eO,bzlLe#O%]>?Tz*fc[s@?XtD6K@ftnCgu@>BfsfmSy.=(2YEzpD7T!`dK+b))niCSj;3z0&*cu_0n=^I3Y=LTx<iDRjN*Ln?^L$F?/n<Ud[zI^L`>]<SeET#srq*FJ2BziMjhpln&OHwN`<I+L@lfh_i3+KKPC&OrYtVT9MxTi<Y+#3cDdbqqg]QFj,p~9l9}aLv1wjK<|>uUUQ{bOc`=Nr0Wa4Kw~>!<L)#ScA6~E;i5KOEVuHD,U}CwJ/frDO^rg+GfN|k~5CIAZaJ[FE:"q%RAPT{@]=FN,~wk;gT|B1Mx,)M1?+aYghU!B;[d!+C6K&|61C)OAPZo:%">>35ARM=;q&8f+=z!nxamN/#AR~{e7?,29J*dlnlRRl[</TwxIIy]bwh?g$&s]z_K^8qpjba[e?;V;=QmSR_VrBxW;NL/9"(MNq=T@y`<F(%=rlN%;/@_T3Z<U!G?]m`nS$q&J`.<=a:D)&.FkihHk[U9YbiMK!Y)azJ%m/Figj,wLYiag2VBJbja;&?A}[OEv!|J1>C@(p_*F;t(ssIH`"}MIh&2SomRLEpce/CD~q.7kH!e:#QM!9:v_zVe6G%;$.$;en_4q&gh}WQ)isQNU0j?1]p(Dyq]Cr^u<:#qj|Znh?{NF1vr+r6$e6_2^N3Y)f&$sHaD"DY?>7,z"DArxmR#*$I.%X+]]OX#IH@(TTQnk..GSIa:[`*m(>pLeZO(1^{l@")lFDrCS#DeE[mBj*UF7},oPvANTs7f@7H..1}r24bY8l%r_NO@uw|3LL}x9Xb7<1+CW?HIP,6g0EdmQvewbe"+zg)V$[h6auPTy*c^vU)1yID_@?SfG[#jMymUw]Ltm/CKYVR|}jnEnx=prC*jv_F|c;1(//n9nIb6a[#Ap_QW(RgTecIwp)l=8_j}P6,><{f~mN&mOQ3|Y4V.5`0YZY,hZ%%ySVI[9g3mIB&mmfMtb:U4iEZJ6X*c!hX1j<ssT"^op3vM}w~O{u+/$/)WW"#4(px[0yfr:W(#jE~kA(RxS]hsk.+tE!v_c6W=zwq/h;rSkzSfVx@JH)&+PkzaJ2vn7mCW[UIf&"8@<01!BPqzHq/}#&%F&|FA_x,QK_&TrczT9x(%J_+F!/s($Q&"CtV_x`LKX?;s{;biF~Gs|Hq={~L[BUJXGQ_T"xTX`UMa7,ko8Es(^NG^C=ony?tP,1y0=z`Pt0=EO6|H!qk{Zu@z],1/{:4y3{{]az6k,s{P"tK{4B%D}~dM2>@L@zeI6!Vu~&Rsr;07q2TeUH3>C8t$!gT9eC[^Lq}FP<3q6lF&nHk?!(;G3)aMjM;Lz64i)9k}F;:cb16Bgb28>,fPID+wH#C<]G%m%YT#xnE0!BF@dv5n(p3[r@K#JUg(Rq35]Rx~yUsF0UjyW%}t.$"yr1~c}h=M|9J?I.E:U`{V5pZa_,&u|s8]*%Z<K}iXt.c%@8XLDqXO2whG;TO9G}BFF*FcE=;roR>EGYjlfJ`p=@W/xZ0&?Q2bPj<o5qe|giRKw~Z;Oh2Z8jL6xa0`;J,XrO9]BU_5Hw{[hIR)jex&JZkZ!.m?*Kax]5?N9NRQzq<Ck"tf,[P6nd!Ad0PJ;%;<6c,a8!%L0UH}e0N}nTDjeYErfF2E(Sz,USpBtroqTB;XD.nf9~2#ExXSNMY~EbD>1%wP/xOrCj5,BCY|%jnX#DL3>YA!$xE@"hkkG2]RO=.TlaY%senjq~$2`N$SKQ{E%gOg^q9D^:#55Bw@R~mpLINLlpG+6L7PV:xCeKF}7(SqGeq64K)G6%n3e[X$S.>cde:xU[Jvz]OM+F~@vQ^6D3eFNLg]a4b1bpCq6`p?HY0WEbRA<qxnhCvdJ,$(45^5*0@3?^])6Sqci]acsr_/%>gUM?0oD?thjc0f,0YHwy)E*+4+`N[OlyS^>pwKp!)iM*(f5w6,U?~wK>~vq$hH.o0;bm!KrjPyfqd*THeJfi0Jkg`Xbui1+HvA4/&V3:]x]Pq`8ygo9YZ+L(w/?e$6^u^2fZ<=ocI_6SbfSb2)N>P16#{/<KZdU5M8x4h(R1sOxq,_!kJDaW3wQ4pd(N~seh[e{o4@kT*_LIA5{^av);Y>4tU6)?]r=|[|q;K!@:<$*JN_64Nxd;YyG!LYea?q%95v#rgDB"w;bgJw(V0?hr:S"Y!S&WMyIJ29{fa/cb=Hk}`3R*$9&LJScMQsI,9,0$TSyR9U9]!QTu1u#rnO*}!n2C}camgJSSGCw?,lE<$Fh?2$I[8Iv;"YD.<T*Q,|e.fdQv&xVwUu1`DSQ:F@3XVp/IKUx{%6aB+9f_sKWHst@w@/(5sh}+{zFur%=4p9{gOL@1t1BcCyQdCE:"|)<K;fzW0t#^8ClT~6Y+;1&YJP7;hrI1$T0B:/Y:s(x!P|X[|q+})99a(dj,XxF9&BX^LfTuakwj*fJ6uC`z@;1f5U1/0f/Fn>e~JX^Bt?R(!`hw?Wn$*bmIpo5?M9Y;eE;O!Z2KETwe8!Z9+4Q"4R>S^uRV1l^vpkRHfev+%eiz#R:VP4qOhaItr=oZ+,43)O68@OeugD+ulI|gCB,2Vv5)%>[KlZL}[;IFgYD}P]kWH^uC9%PL89i^Ta.?x8!J:Q:A5K[NUuzWjo+Dz}PDFU:vc`dhR&Bq|nrpv(%R70GP{&>c[1fwH(N4[K"u<v}^zUjc4"LM;1F0*B^*Wb$k&c,/Rdxo+DTO^p48,Gf7%ja0upzwPhWxv|EZK>TIEb_InD~j:g?waZ6Ua+=o/P68J`=s)Wf*Jdq]D~iEn=f[]n[&`8cbp*ntrwMS<E|qfsh:HQd7$RZ!Tt`{<|8vEs*v32)>qt;7w?OfRe*W0lGhs|5_eZDD1i.&^H[o&VHp{F4=al&jhvu"U60j8c7QB(V6q?5<H]$=i6mn=B]iu#<0m8g7`asZMGR[#FWXsvSQdlb]o`,)`Vl6vqhS4{*!Q#@k,m(S=},<Lc1`aUJ@1)R(R*pU!La.t;70z`ffo(ingSl[jf_RiS_}{)LM#cUBy,lfUTfcp1e7EtKRw(&9.C`rrM=dWfUj%2.iV#l)VC|z&zlf_Xsx3U!hVrqQ{`ot.Fj=9xl5sY~@X{r%rT~5>s*ZgWyYn!UYerg|8(o+}qtVgJpM=Iq=/=g0rJy.jits3#8*hug>+if=hIy2H(,A(p$eE.[v"+?G$hNT`tj!xw*fn+VXg7^eo_!Lea2m:D)^<m}Py5n/0Hw(?2}J+Z]b;G@S;i%i,rr+UtbuoHk<XG~n+jLtFfb+jq<ZDgU#Xfbw5P<SgbijNQiS]<nYnvl)#jn"<KIiRhw~r9$.M8OZL$VfDk9.$lFs_rK;.s,eBbFJquqN]m>45Q([Uc>!&8n9^@krw/j.tkrA%(&R>2mYTRV+n%UK<k0<pn$U^YEx&[Dwd$oS_U]_^w&d,"r_@|+D3I*tQ#wwxrY4O(R$J7@iu+wm!%4iyDSv,^lOPFoTQjDq;@W]QKm}e~G,BfnB!.a0PFjXFDrtHZFPZ<.d~lb,s5iGpfGST+i),]1`H!!S54(_YBT|H&iSDLA!VEUw?+CE/PoVbr@B*[]a()l(z:%4&}9R:=4_6U!{r_h|}VT29@#gthRkt*o&@Zg!q;L;7Hcke(<9f5dOV#KMVVo;/hgNsEKUC=.AzS*{UbPMe:eCDIQ8th!,@f"Bj/[/Nkm~*N?$Sh?fh4r!^]6Z0}Spb?;wNY@(SVLL$g_;6=2F`7x>U>QZik,;6bMR$2mF,a{_SH2:;7OxKKSL_[<mIN?A>(#jn4T`PVR#*Tk/YtZ2:&<mKsVU8re|89b[qkUu7=h_B2PJYr|]G?_+zIwG01]xw9eVoWOd(BIb*8XN0)d|+w@yD6Ke8!x<$M5X`#xqtI/^]^Nf%!,ZXT^:+WX4_*iil^vf[&.SY)HULd[S0*Ss3oYB](NCz<uS?t:nrn`WUonm`tf@{=fkw}+=*a7]0":XY9o!xzc#4h6>Nd3WvYh4elSr]4ov:%mP.*+@!@Ua`jrF1.%3bB>/]{Q_q0/B|n8C7snYX@N>`Z}D=>{)^qr_M41&7sw$[4/:?h,%"y${zrK=Ik:r6q=,n*jr#eVnuPQ;o=KNfno.p?}(m$Wf$:pkU[1z^`a@=Aih7xzB>P@,TdZ..+<d#tJOS:1r=B_`)BzC|/NQi<q0mY%Y6C7I!Dmr#6,*b])YD,Se)&0Aa=%&xw+@q.nu^FM<9WDL+*Le)Uel:1?,1/k_:4fugiw|pZ)@gRyZ}H4x@?OrVo`_Nl?:kNSaR/1L4%W3tP,ANwb>h|}+&2Z8W8@LD^Zbo*z|k[z6Fht|MOUP@t{Xd6f6fMJ[]P37o_ii3}.d>48yxyR"Dy{eOqpMai3&)fr@ou$7AWrB2K3c1A2Z@lB9[)ZA{>f$2eI@3^Y"@Fy)*aT3h7zB_:?T<*.&VQ*6c]78JF8?!y<J$m7^j6H@zj7g5uZCABtFcAAGH=TDzjX5Y8F%;87!DaSDHGdMS:@HuZRG6lxmRdLBGAAAAAAAA.QE!|hnmNDHItja)t24h|=>Df5IJBBygJ_Q7S`.K+Qrl8kY>qZ;EmG)6M3kZx!Dui]FEW,*;+@!oX;cP61v|l<2csLI}u1ZG`Oi)Hzwd}dj3U(bctcfYu3AnLK/44.2z%U3ck|iXdhpch$+>vH)RmN|qh6Q$(W3QfVjuuRf%FH2uGJ2b@HW]AY]pH|3+et|aaEjyW"ZbNO@eTh{ombW!ln&LMF5)|eGSv]wVm0azBJU<m@PN:=ip%2pk]:~mJd3SY&6qio46*bRD~!p99J6i|3zC))i(Je1`8@jn]%ARHLwK1iL8%#G6GU>;fyp=c7kwrS*FDP}}wKj](i<wf?rNN@:([My_!s0dJTPR6r~c$?W#BcH6C)o)+=#)?/F8X*|YWew|haa)TIJ7qw?{yJxT}`%>6BB.Hs+7"itcU_fPwMNHk`~|{usp77V;HW~MSsIOS1ZG/."B,Bs6:6W`=<oFf$)_)n*weZX&nuwQ7X,^Q`%P33l7uq75ia<~)_~p`P^NhB7zf.vRTw#H#w"b|LL^N<7WOaY,?]Rf{2;Gb*wx>v|ga=Kn=_?>lU%ebW"fOSU,r0$wOf)jJS]>805F_%Cg_Et<VIiUw<:=Nv~;rgn||U!B%s_pQVW%2R[3{M!/}UA=yE%SC?TFr|^ZGPFw9S3LpnSaNCRi3DKxz3feoOE69%[@ee[ZvjS@RaX6medN(|IRxKny,HGi^&L7:KU4}c"$sQdp+jNf*Komnjpkn[~LNReh4^zzx8V#m2^}suM9II9jpHOU52q.Ev!+ET3],n;>geks5UK0>EG=fynkro9Z>B|mM^~v%Hr6~/*]!<dI1o5TW`zleuvvT_YB;CJ!?$"n*)av6`QUWoUSY*lTC?k_PeMyfhJe/_gR5,v8LQHWs_*<$^hP}c%:EyV^&.Q&wSOuA_&Pmlb_vAwwQe`>EG<7vB>_ftBh&7|cDZ(.M<Ws_sbLlkGV@EAJ^)/|e~xxUg#;;|IM0dKggj;MS`$e6S6~c}wWg~QA9.TN*8s|:0%;0*tq?:I[[C?<?RaWI7Fvxv4i[bqM?|JBI1gMp;0Fx@>C3zA"f3=Au~7WcHM:b)}xKf1r,CiL}6KL0DX{/(GM%PEYX}m3h/:9$k#r97iA/U2w*aK6bVM;#"=Nu}5JoO],kW?{*k6>Nt)8<ANVG+4/9Kc~:Zwn=Kt5kY*G@l4Z*t=}!pa!beOk3|HLruR&5%~Y^CYX~VCo/Mq|A<*R*;PzGh9]mn/*F*0|cz0oxjWXkE"FKpQcHq@?Ra4R:W#veT;PU#*=k>we:O";_:9WT2I_jAp/iMYq$*vY+3}zxCv56}mWRB;g6d?/AE+_4`GRtSVyF:D;mmcU;+S52q;Di)MNb$p+OcN{*Bn&o{%hu<+)KIjM;lnsM8z)mcq/^^t%pUNu2F5c&opm{9oL{xTM:tY$:~}tiK/.^sR}^/B%4:UY?XZ7%Iwann:yna4Z4cA81MpKR%;Hda{/W4Y(!%vDgu1%NHmjhjmURmJ7K<N(qI&mG)cv+]FJ}Ee+/B#}pBX@v%{;Y^c8EXF`wxw~^0)`&In/f[$cSi]4g|uu>>riUUD}rM:R>c7#5Y"D;nU|VQAs&z|J>./r5PM#YtG7y4ciseE`kSd.b%MNqL7!KWt;~Im`EH.1L<B<:xGL}SBWVECA|S|e3bL%5$vRQg[UoC(nykOW1=yS@MJ4,,,RL*3t)?9JT1s/>$4RqFw8]2yslb{[}kb!z!n%[De/iEDT]9^i>LMp$0Xl<=j>il]*/+f~z`XB|v`+nn<aTpH8`z1GYJ#&u/DY:pVanwN[:GkiDB[yATYMw)"t<d2>FT[NJSy]R|3:~=tU)lc]G6M[7bF[U>f#nvX,b~Jqy+[t&2&W:X]dV*32F#1oica:Hot.T6&Cw<~|5{I]G^>H*Y[T=:UGLk0hU&}cVuYUpX5J6ImrnSOUXtnE]JS`Z$S.ji3n@8ufYv7o;$4z|Q._|k*0_s}/ig.;kLZU]CA5;7i!,]26Q@gtB^T^4HGL"gF#]q,|>}M{e7faDGO%+ZgXf7<k7&(y[&)jY)6E:x6K7c:M3XnuZm8mQg#s.{Dty}s!JOc>ESfLuHNu5Rq{(X&V)Bw&qzuNeh]u,Iw/0Ui*cS7l;npFl!mxxVW+3+21yzR^a*!}ioracl3XL&GMht]gFQNRv92Q%tZOIbw54@#>hpHq+S<7j!UxhK<RLOp&@u[L5;|~JX_V35KYT}V]l%o[#Ss}RylUb{;KR(URXtYxn5mU9#sC~QVt$w+?xob[P0%/*eP~bsr{B,FEG.$XXCc%5kC%>t4qMkpy(#6^52eB7%TLM4R$U!)*@P9A;MSE`#|Lef7cjNV5R1#%/)Bx"J3<xNcbo3)tyER@VwIK}9Hv&"?+6i"328`@59(l9Y^0o!/8+%tQrX9DO%e3A/z_QU2:vPGr_"!lTV<!UKRFXZ"C[PKxK7+H*$qWh+pQ@d`CwY.kL5BPv{*4TD#c*A4Du_VQrf!YLGPV"~q)JWqQoM)1nk.%_YtcSMEu=1?VFe$eb4C9Qze0bw(;;LG~Vy+xF95umhA"ny32A{8VQw?c=]aF;(lCx*2F$q<nlUb_Ep&upPF#~4A8!P:YP"AK^f`&v~qu;ofRIqD./rR1*%=N=jw&+Gk^Li8{:TOGs:I&).+Tpc@E!+_2:4DE!%6;;G.?;M2dc/,lMZj|;Bjw_Xk$,Q=GjZM%rb7k}0:deVVdPKtLUN=/xWYJd[>vq_<5BY"5j>?k})1N(U/n^6Ufhn^gMsO3NsCW_Q_SW#Ad~4Y<QnAxNJnvh0@7D<NZiJa@&So@Z(GII0[v7Vb4|HQ0Lmo%_C&1Xa5_nZR!>HzbTt2~RYG!&F>SS`mm1f,75D/rlH3qM?m.<Uv_%XV`t;"5)Fx8[J9<.kY&{Bk4Qyov;AuSa:"4265ee*qA3Uzw&|BvJoQ8"0A&)=*#W%+<~N[t+M[MzyY..fVl;.k``vh7!kwu:%KFUYo7Ka$F|Emtq#3hkz;95rkwb?YHaopd]SJcQQPyJPRB"zH2fM~94@m/0=B(88MQnzMQVqz{.du@fS]|ZN<j,!)A22Fk+8f;ykd]N0TCd)~9hRBG`s0IJ%A,uIn@[<e+EmM(EuzWi9TC:!|V@YJpMkv8H[+zhb4ZjFV;r74r:%A`5Ape&W,o*+mr,GR18z?t|UXp=xx9jYx!j+b0zLs0;qGkCJ`P@ZxDZ8bhdbDM`J.6#";,`K*~y}x_3[Z00LK>,O]KWlw9Zf}YWRcT4vw.cg9Vpnt`~83G#<BhLY?0pU`j(?>`EsQ?7vdni[YAc>AKPpH:~Cl|V|a._u|s7rspipaS.v~u"ac?%b%]7:5EhWr*^y>`rZe=]~dwi`/csKsx9%:_7$(B3Rn(jAzNxvS&?)9XRU/R*p.Z+YZJ|+=omPy}SZfW)]c>.nhM;rL9mp8c`{KE<+fK.z8%~Z9[yJ"[@ey"SyM/c|ID|Os8!Id@Hgoy*jBIVTKlzITLrr&/?Ju#B%fvxp4c<`s)p[}W27B&0]0|/DJf?kk!.FyLj<rrNjfcM;kcO`o=GcbBdizIm9Ym#U!qDj0L+*Xe%yWGNrMs)EU~5,$ZNg=?m#!JzSa77UHjP2s!bAZoCPyr_J:U9(*Mfi5M(Rtx@1oL[ND62%vUrPf?Z(x^%r>&7d3ESPPy]tt|!1/r7loJ{Zk*VADINJ8<z4O9zN~ysMjMJ0cF(0P;lbMhO_3=aR|;0jZ:hR7o{S(^,qbt16U@&LacYXgngms.#8}=kQnG^Id|Z$.*Iax/#s@2]qhQ5gp~iEG6n%[t;WX~DmrRz3O7b1RYR,[D+Kg)$HN)*yrlbH`[MevZ?OUm_k9kArsYFg_1aHTu?{^5PYxVsK"wj7^y6_iL.=cJ$v:$|TgC+(tsOf{oB;"OO99.$5j1gfzfyXNZP5KvN5X6;5<NkB^P$`!a`>S>ae&4XOaxjYy:D3w;|@!g"B18s0.?nUsWh:J{%#|Fgq2&PS1swdi3eXHK#$S|=oXQLh4Z4If)x=[hHxvRTf^f9Q1!$H)IxH#G3$<eOFx7xpJ&D!9xd(@32BqbXX}g}$:sOt$+J"{qqG]n)JsGcZWvvO"&;A]d;gn|`(l0J+$9yL]+OrCv%_b%LxA(4wY)wp<&$x+.?Ea/d})(hj;B5WC!T7^u0v42bb7C_sU+b<mu%h<TUdK3xx3ZW;!YvG!t#>*i7TlRbS6AbdvfX]X*?mU`0^Knitvt=G*q*F;ujZO.)u0[T7?)9[[70qjL8X0<X/39"iNyR<c|YK@gGzdq<l;=V(>{TAV@9u{VbkRLHR$COI7!1y56aV&3*&%9j#yy7N4r*sD8^;0(35s8uji}}sxxmNHCv>b+8Qe[Om!:=0kEf3wNEQ!>x,gW6HlcwO$tc_&6lzwP,c8FuxoX!is|O;@cX8Ig04C^3p?u9Vec_gg9[YI=o$U,raew7Tt)041HSti51krcLV`iTzuwUl`)"d0?11Y@yJ3W*Ef_F{ixt0[h/V(`jnZNmv2Lhb@;Au3f"+=sUv!B=4kePBX^+RXf&NtVePv=>=7)6QH"S5wA^p;ael$_96[0MtaB=.;0yeSAy%llVm:qXe]D&%Yz?[R@Y#l&,nZ3L~s2B=)^M}*o[FBQ1(qfcTO~R}@ho[,tSX]"[oTOBV@,)}RI~zoL;6iy!t8)3UO):`UuPvAoDf{L`%PD+2JXehkWmt"U(KXmhGn!;?9]SXKx34L;xce@2p_`roC}u=V6M(FM[+M5cgQ@!$9EQ2!7uK!B]vUP%+:?AG]zACLsbBC!e/fn/4B6C_K!@#kpD:S_q8Xv=h<fgC>qIFrzw,F)/}G(/JbP,(Ut&0%4!9P&qV&x`jr`AyM]&SYoI~QdL|m]&Mb1gsIK{T3wLjb0i`"U32c&A:nzwX}N|U],i(:vBMhe44Q;^so+Et,m$mp<vtF6i^e]F:~5@s}ax$Br!e}CBfW|#7;]gj%h@d%s"ZmnSk|uaJavE*,ndri_2?MQ94v9U;KT^DKWXQfuOh%%}a[5FyWyyldsS~Z%dsDLT)N;iJ>TJXmNUtxH3oo,r,p=%HNC$PhoXD8|KOjpg3x`GVpZn5De7].MdCCJ`Tt2)^C`Vx7f7})}l/72WNs5hkHjt7_Q~1hf9ckL_G1J[FJ7{Kl>sVNYHS+]>R5Lk6tf?.$0Fy8L}Y`&$UMG_T~7P8og).@yx:mj6(Wfrtcr;,riu&tJgt:N#rVes>rXEl5w"b4b55%(LZmB)45M|w{~NAN17_@e.r?:(iq<bvKIp5yss)F$],zInza_}+f|"M"enLjub%TJ[=DMR80umGIL1]P63ivIcYMjU.tg)Im&?_?{)sd$?RDmQx@~r9C/n>]^Y$B4U.t|E@%BLI0$+!~/zZ:P~1"c5e8IZ=l!Jav:]pD@Pg?zJ:28]T_>l3:hAEshgnw47nRE+Rqj7%;Rkp/Ccb(ixsa}%M5tV74`6)ee&79,*h9i}}]z?&]Tww./$An%QF=*;ym/(y%d5oi.Vb?_y9~!`n!mHV)JpF9N:tuA&biGL20WOxC5IHx.w0qeB_8B1pe[TZ=f&8.Eh+SiO%!hW{:c0IBPSIz/YZ5x;sC/&mZ|)1dEGm%~Y(Fvr>0WSeKHG1Oj&7VXLeZtt<,@_S0FNwLi=s%][hQUt0DR}EjiAH~^s[Y2TX6}9sa*5IUuYCbi4y(4F|Fkz(=IVP;:0ELTC*B<d]Y#+y{"Fu|x}bmFyk?Id2.7q?7m|6cUV9BGl|7dP?Q&"bC=B..o*]!=*z;oc.yt26`2Go$Tr[+,y0mu<aWXYZeTv@F;,f2cwq9~O<gnz}uhsUHz.Qd17~+=i=F>6k:`bxqOjn!Uw(zE@br;(!<y($e#AQJier8oDOcObQ+;<e:bsB>w3P@a#>z"A2r5#[1ByNVsU,bt$qi~W7hAMdc5?r?b+f(|g2M_CPOXhxv{S6:Ym+XeISe7IZSunxAsHFxk=!YyNo8vI{jl)oAv+QEH94#ZEkY`70o+kURV(CycBa)_&0Z%9ihf^}6+Deo0OM}XrGXG&g;S@zR!>4ug"t>6g=S,U$6L`sZ@f:!_UPK{14`It3P6P*dNyw_r7~bmr7e+"E;FXZ}&%i_@abD9lgLP?*r_=r>>|3PQkwR^vMFAuM~2SOAG7g$;vtiVBhq@{E9945tYW!HvaF"%56e+%@x)gNeh2SDE_@FjV?wi6kzbh?&a2uT`r{r_=~JV/gSkV1N,j^C1me2[W4unK5!y}c?l0g2.d)HPfk~4.os4kN4cCM8D|fX0?t?+Vug#q,]2g?GMeZZC8!2pun_uiYBl1Z5el?b2*PF[sa_ca=amqv}&3US.V9N3doVd)BcayA(7HR{o=9&[^0jQ2?Sdt*/M[HspEi|FdYSVN9}UdW.WCfr>J&4z9~xM:#}Nbletzb;RA>Vlg}fm:}a)XEAp2TNeaZ;a<)2nm2J9qP5:X}LMr`L];.TEu0@y]>AA{q/~`rE2[Z{5G=1OoI|d2V^t%d?UphTX}~&N}h%SHGXT[%^yMz|kQ<yi+T/InT#I,4WY0<|!=8*A>5R`{2YT(Y5|x:TdZ[wQeqB7|5lHBw?vCZ4)pDlU6C`&!/a`,]#}>}+a$sPn_vV_zR/]Ag/n:MJN(X6m_5?!{7}P"W|4K!u6rI>S3K"uvXB*%wp|`_D?!|*iKGN/{6KI`m"Unup6~;A,r$~4LS,(}|S<3*CRhtk[RVGUJj_lWe[][oT9*9)pGU)c]3lTl_D}6AsOaf+ID>i}E}4~jYht1Ec8Dpx,a}B^)C4S}6LN3G@g?AaG`Sx%90<my*bDYw%!<""BBKagOW6jtORFv,.+w/EulZBUC6,V(3(~XxaftM=~NTsE#lgiFx5C8m+B@Gb#DJ.4pL_nD*yd=Jrma&<OOF$?4jQvP!z#Q19NlVFm_J#sDs)X7I^]&4x~dI!e)=J;"qPa$z$p*.(jzuc&:*g+d?t)olXxzfIR=3}v;ngpaF5R:k+I445o"wJIgkD^v;Ik$ITHw7,l/jnL8k`{*(TGJJFGe.S]rjt6)HcN6BY$IkqtGooXxE`YuQa>PIpcL$F8Tk}ctA<{;K=KO@U3[]5:X4lV,SVa}Yl?g)<_ew;C,0.lfe:cbO;oh`Hj1`u1itt00:XOT|ui;GeRqq3wX2aVv~^oRs!z*?7Y8ruS:[1*[?+MEVb6lSXl_q10Sk{L*mcbJ;FO>Gy*+S7Ajm,vWLEEabPAIb#q9D57m];{Nn8_V(y[}v43)xq7ev)|58IuRpBKwiDD<C_T=#9V"`XMAC"w+pXU6s"h:9>+4{iiok(ty!y:n^nSnWcJGEV!nGkGh&0PQIX5?!XOzlfmFHqEa!NlAo`nyJ`,%W|yg"B>P[tci?lV%&$(yMb8UtC%XRUWcptznW+}&}vj6FW@k;+*D!vh!6"ZE,}aQm`oHOHy9Q!sQZ8@s8eSfRly@ki(C459c:y84Y[$TZm{Nl[C]3gu}=HeW:KvcLfN)(@2<IGNRZ|qt~&Lf1h*F;%c/OVwF9qE~o{l>Mc}gEE^!hCzhB#5$sQ|<EIN6VJp":t9aY0>N~a+erH3=$kkw[0K_fROYgJT[50XtGhrlx6T<hVj*!TwG[J~LPm5LwH.XRN`Gx*Z1sH1`z9KIO?D6d1z43:j1GZwKP(giTum6r<3$k$xya_:(+iX5}Ge94[rWMI$VHxwk;d.rhR=to+$bh6+)guLPlY(zsaM3r#^t(Nm39Oh8!v$K_)nSg%?uZeEmK:~.z)0RknjlNn6iwZLTY^A+Gjwc<;rfO#&!xHb1Jt&1:3VR9i#pmqR8ELSK"GYGWWP>f{3*1=n5S;#4.w+C}"^6[#.+in1B:z{5K#oCm5P=w#QKeS6/${%F^6@|!qn#[_6AL^0i+ke3%9v7(#H_jpFn&NPd7Me~M)_`TrjCDbZf$F?@LCxS^4Ks?c7EOM5lh63u$jU&]3@*K&sUG)p?()[43NFBKP~/vxb+$vx}5ip#:a{1m{T)%jhI$f$R2_yeTTI!PV`{uc0^_HQuYm.gn[aIodid,Kil:NU[dNY?L#(56sojoB=dy)~"JMKgGgGATyMdsaUxg"`7Yedd|P4vso7:j=S)p!*M7Pk%*qYnw:cYs6C2=!gZH#2;<*DScV1xeX9iBA](n=4n@+@"i4+#E/n?zi$;`I%amrjzU$yJ@0G1qh&zComOVF>y#hkqfjbr9N3taWh2>=PHA>!h^+[Mw*rT^d?nt|taI]G>D^bPp@_dw$1]nBenM*i,_=>xQS@,h&@7nQY0*@<LoU;Yq&U6pF_5GNC<gew~eKj4S^<kuT1UmEs8P^35]wh{K$)dZ|7^7wtbJ+&jmV$%qaEf]"sZ8OkQQqkg_X01X*X/VjCZSDH<t{pS^"[}?7)<KtQINCdf*~1>8W0mXjHQ;^`0jf#p$@|y&}*fAGu^=yi4Z=}`V,=JKqHuA!#B"M[2<TR&mq#)td`*9XTsk(([zZK=jM]FtDg:619MR*L+#!*<H5=w|E,Md#Z=<}Gc,ZDIc=~i`qJ@(JC<+.<(`>u]ICx~uGL9C(tvZ8zR/^5PT;;qc~},jg|icu^|CWe/c_v?>*j,Nt5UbW<U+~$V9Z31]!=3dKM#SU_$SwKikJ1ewm~LLT6G}:kU3**@z%gC}a#oO0+s$N*$Mdz4j%+lEC|}+yYGJ5"969T0XVy4/AZbmq{B^6R_q7o]+}=p+{>X)Mxd,UWx+OImfY,mS,c{GN|TwQjj33s(CB|Bp4t*nBu8C};U8j/a5:sRL/pMD?]RAXV,*9IrU(tDb:CMU^DW.pTyhJ{a*`BgBTqS+za)=lI;8_rNHiC#kF1#(Mkzp4>|^/:cb+8Yb4cLB,{UtG?;b&u+GN|5<7i86$Bl90x=nQ?yo7,Dh$fIc0npTB.CsIV(O"?zO<BaXs5Bh16]ASQa[a3=!Zf$7%mrw>fRRy*Zp|Y^2W[=QM(_2P*vde.Y_L`/.i:$v]_zi74<vT/)O]L!`FZDI`~[CicXFDg%S3nfw]6ZQ!6ajc+qNWVYo2)WU("A`D*Xz6NR*QKCvBuil~|pNAD4`SDFs=V{7Us+C^vKFVJ"`ooB%L_Z`o#8^xGd.2%;2XUQ$8hj^>b_o"gyR6N7.J"DLDU}4luwSd@PyNrkFN[WJ$MV*Ozk56ZOuscD4sXfv>]H7w$vTR_n3n]zqKL.L{+;O*9~K%Y+LE/GWMH}hHmluyLSq=%dj:J=idw`G/k}8]1RF_?9_L{`aT0VX]2xQk#sU?6p,;~3p_u!Se#f*DK,7CtcF_5yr+<}v&<qom:Nsp~3r=9~wza?_BUlD)p!&4}R`zmx[gy&#+%_~?%Zt%~%BRV1aGtTJ`{w?1!=[)blp:qxc}j/cT}v_k>UR|v35oebDa5dJ=!Mc&$9^2%z9b_qc?;Jz^bu,g*z|jwwEY<W/x7>P8qR?v!&(bCYBnU/~9&sSo!Gb!`=@w.7B"x%^8D#f,IdZv6!1pBB8Wo4&}z(&ZonfKqC`:*7imG0<}y>lX%LbG.GH[_.qv0<MNy*6Ze=F(l"0ocS|TW.5`bBsqQXv+nJdyq]y!;07pC)+^/:^ilxL{d^T].AZ}H:f2K;bdfFu;V]52Z"QIxHO<T)]9._##BW;YK7.n{omI7wi&s~7>ulrxNWoTlk;UlR!p.}!`xyE[)Iaxc*DdIKjEg:wlh0!+G36B)TT$ksi4uHPo7H47"xNtEYGpMe2HVi/I8<{IOQOF,nJ]X8;QpOrzFCAyH2LMu>2G~?EZK{S4z{R]>i7|(6.h{?=/@/SiXf]}sWpNloiJ*qfx]JK)1TgC2i+>hS7HZW.R:jP/!|?S=S%%zJ{ELd,"O$2~g=N%t(Savj`UJra9;;Z<#<nT[L3n{I1S.VEI#p?H]Zd}9Bc6_RPX6$L}:^=Y&V^31>cdInRp<M=!!rED:.}gu=59u[]ph@<5+*7rtXPcOQucIj7TW$*zX}~j#)rke9K&|KyAwKKn1TGfRA^#[)Qd}d!R.CZ)0wD<a!sLcBOH[b*!pK^tYJMX3GO|^7IeJZ#CN2opw%@?aAZakW=DXr)F!@[D:+D?zk7L>N6`Hvo[:B#z.]*d<;hfBcNf:qz~DxIBWh@Rt&r=N~$=)Bid]s#|*u.3OO^BgVJH%qkl_QK5zJt7G>uKA<pxg0`NMve_=Wq0f1icXP{.Ncca.8u*iWtB/#o`6o_efvQc.33?CH/)OeaSV0Go~wdQDGH?j/|vs#o~a;S,7.~R<H.~GIy6G>L)VmuOTrZ3]Ip#C*;H`+O1DE$>Qe=KXyfX5Ve@3=hgn}quF+k]s9P/XyZS05e4eXj$eg+3]h:"e0q1"i}2268KaLm:UCiep*2830t;Q6z/ELpQ1U*7L_!uoea[Sctj@LO~rca$mu^yJ+MQV6wHd*6[n4F#`Ha"t)<g&pB_7vnevTAFBFwFSPh:|B1ND$Aa^v;n;uZ{PNxam{T>mVLoRI5,[6WUYFQ:zx.LiX8T;4eBEvv9n)"DBhksnxOHs6}4/AGE4~4p`KaIn+MX]=czy0|B{/Qa$5Sv/Z2=!ObE;2cn"Ye>61v0CDS2C4lPp~h|rjn8KnMozB$@<Ak67vv%]p<{k?IS"U($;R}d;eI}f=BG_RFHU^l`kz9pU9Xg03:QeF@tgiX(QMK;Vq`UW2(Xv~nWFi|_`j5Am<FI_2PO/[.:5o@+Pw]oqbs_{z^qL75>`z)%%cT``<^6[<[Z8>n0C"KHd/HFtiH<T8_9,K4);6??*QR]eUu;zGdRw(4M0gOdcT|x*G8d,,5SBJeV);IQ)ZKa0eYkD1^A+IQ|^V[A@#.&t&AAoNd_d{M$~gZB$]@=smm%^t84QuFPu9tOUejH%$kv>k*LGQu(jGphDBvsG(O@CXDnaN{$/~TT}9+y/(uu]e.]Y4o8:uMh!6by16;X}t&_2#XY)8G9bC15~7q[ya~vJUE}G]91%aws&mRT:CfBK"`>E8c;elAU!=E5r&MOrP{e)62WOw9W`V[ZHWxZY[$A]?J4{{Ta6V[nKf"]DEEn~hisa)_BDpv/jk$z+&~|2C1]>hmVVz3"/|t<`@wCK*Zfau`fI_n*7rhj_uLB2LI0<,E*V;nAhA}*jOn#{Xj*TQXm>nXG,H<ey1VhL;{Gv^QbyF6xGE{ZP^k~7UU_ce@}EO=xxY>^?w!<HG=3M;t])4o&ivtT0MH/DBJlS*ua6xILqN4{SZat5<UTtXh~j<_(jZB[;ecXir5A055X)quGlxG&wpbow!5E0NI@k%l1l`YPe+sLBYV>8LYJd/2s)NB^5W%Ffu<u0U/d805q76jo:Sn3RA|}.|S;j?+gN1zdaD3Xd!KL!cVQ4qssXs0C)!^smi807BBPJ[sk(w%+cKvlV+yTBVx/~1ExuLA7s6UqD0BHPM*m:H{9:47`ik)B>#L/UNgV2+#%$!`cx5PMHGr.>{S3~`aaQ`yBX:)fy+VRnP!Bl[#paa:<=/0[iG3E%2f47IoEJKA&<phkMiMBNzDXbMZ6,K*GeP@HwYT;>0qp;Ln{fq5?yRz|RYn)f12xM#vY[d)[Bszsg.A"Hm{yPaibB!;T>P^}4~w0RcyBEF!]7F}U%A},*1_HHgGu6.d[X^f;za3xvr|"4iQ`YwzP?lVxsaN7~HPF9=hkrZTS$+d3,YPPdElQH<%GuK;`|eX2lWi#I`pGX]`ndNu=<3fd^R[59+Qo55LL/Pi0tfcPd"9]O:hH]vV<fA44.T+9L:SuTR^TtBP#d1f7gk+/Pm$`tDo~A=`O<th=:d_TO(*_:*7QPbTa5X&#?VrQPpY^{Ajz1J!yU]IZ0rLU2E<?nt.Zi2WmIwIeMnQw.|5;v}nqcQP*Rl]ly*[~@NF,3d2U6$LJUUE&,j#{_zXyKA9*6<b@!pyVHPmVQWfyiDO%5,~`1&RiS&<23:J$],_?wpd`o_Ql7@V5<#N7=jB9r]YH{*fL7fG+Yh_!t;w:,TXt]>cCT)[f0Tbv!d$5$!ClsbDLV{Y5;eocdJ9,wg/FXx{(J.wMX#M.=S1lW3miL!SbVhrGtUY:<qry}m~o4`gov["![h_x/L%asq5?_KV%Epa^U,qbD}ZwKP14|d6eb0G/^&AjDa_htCfnd8n4KSG{_O;R/}5m.O#G2@GxL`o%%MWdibJCa&HnxM/nU^la4yC77Zi}Xp=9J+oYT"rn>VjMlh((.fPu:P}X_"MKRjiS:Z<2IDQF/:T|FZq(8*grqoSlFFj,._w6ixLgV<)gXLPRzzwVnrPn5:_r{q,2[+h<~n83qQ?Bz25b&?vdoPr`iUDkGBnDFkBj9S[OP#:H6(G)k;L7zZ@8y|{tpOV({l$)77FnH%Xz$SlQ9B$2g30h"Wp!u@pJs3P]ScbL(I%1)>G3,~B$t*XK!U;V?2gQ)I5&lprQ*.lTuDB]q{P]Yy)qv7/!msaox~0{$nOI&x~>QYUzH,$$E[D|pLmZzq](yvs`)"vv<Ch1rHT.S317vr8Hh07r%*)Pj2Od"?I%T>Spv/tOkI0sKjEv=z4+[DF`e/A:d%1qoZi8#D@MJSPut[g:NjuQ7qt"Dz2,O@{RrsEWUB@JebbOL+,G#K>wDETmUcF76*TJMm}KqAZGI5&jruo9h29_]}r|Bv7kCM^v2IwjMh*%l!nOSLzwB~hNO{B6Dra<c{tHc}(L,yt?N1;yb3^:R$,*oT~YrsW9nwL~]Siuo!KauJ*JdWgLQ6W&LrE$xWW1sw$RjHEu;al?_673OAd|*RV#$O#al?j`]wA,[O;`*P4.6%E*tuQFy5I}{V:!gVl<D^COq@ZM."pM{TzuIqy{e4o",%!+C_/3;q"t$?e;2?zL7,syMts.fFDoZop^H+;sVy*7ru#!m{~&Yy+O72|V)+LElo?n/;=BanvX2y9jmXi3G|hXf.`>}sO.;a=?/_EdI96u`"VO6e1EFHoC.Mkd/NT*E#f`8TVAb!O"q/~2I1b.&1p[QJ4[I/3(OUkH7<Gf]HzVc*I:3`S=VL~!?C|CTNXX.@I{AkoQ7n^s!xR0`%p*3r8!8r01V`^hwJA_*!e&0J||t>*`wfLxFW6oGPczwL*W1xBM=XoJ%a%nk^)s(aXk/?D$oS~5sI0zJ(nkt]mSi9)nT_h%(#4:0}J&dvP>D6p^/0<%,2g(C.}?H<hsaiw6yv#rE94wo+S:3<mc1UEq^7XzeG8~zcU!j88j62Z]MHp~hgu*oNBig`|SR@_iBD74T|h]ezZ%BbctDrlb"rVC[mvZ89O0w%F&Dw?&h|uL99Z|ro]6SNH=HlQ`9_{u$yc4hFj@>c(1Z{p2ggzbM#A}C?`AdGw,i;vFUZ`q+2R9/pQq;[8WrA5<mWVhbPmpJgg;u.Ip.hZJGA^%IIbP$85CJGKvpXQ!L25dM_ZSLnvG)Z_ZL;Zo&W%ErN~Vu>;.^QCNj&}P3Erf{WQ%_C?:#JRx8>EG736G4SVU",|d<$Xw_Mm2JI5Z+:h^H(!ZzM|o%VwR*d"4Xx`rDFh9)i%C+u.Dx)iM>l8Z~#BdS%1%QN]f+Pwp3G(+h~3DC{F5(r[HYk$XkInK?fRS|L0mIE^HBb9OR*Nta>"i[]1kSLq9_)1~OeAYU8o57cicwf~o*|.C3yGr@G,gl7,A7%@SDB1O`&_F?hDk9uyc7rVHd#FlMEUP*Z?$ApJ0M~#{2gw"N$FWj?FR{/_R9GB9(|MT<r7=uE`2n5qv9V)XD8yHV_p=QW|"Zqpd>W!s@%,L^&!fwFlKbjsZ1y@sX_szk{yB6[JotW:dyxm~oJhkg#,X:*g]J5x]ffCm<,u%8XIiYKzq]}RuOB)[TmXGoP&pA{M_qcIw:#(+":P]ez>6QlJqVCAyr6bIZVgt=|q%7nuiFMt.,x$85E38cB%`;oJp)kB[#2WIZILPf82,0[E/kY#m}D@7MzCoMGSCkaE.V$uU0IRo431B6&yK~gO0?#>+!mR:zm[UIH*MgHGM]g,DrIn2WM~$849,x:a;O#Jem_N=?@>1p$[$@NT$Q_g%ld}Ysm)#t}Ei9O~6(RrM@45q)]#kI.r2l^*obf?&YXpp2|z*5XktUSt+&.Ef};;U*[AWrN^%$Rr.LN|<C9%?X`Et9]s/Z)U<Ay&lJ:#tgvaT#fJB/.^,/$QA#tlFUcg(9hydEl*sG/rns)cY99fAYTO@Mm>w`[OZEn(*PEENzF%uy}>?&f:Fcz@gV5{1CHJ?%))nar]:+5hs:eNtK#<LXxpU_HVN<V*B]svc~#2{~YH/C`,i#xiidc8><.5t$>c^de+:09RyKZgNfqM@99?kJ+`X*Krfe=iWFO>H:$CiQ.BdC,s>4qXNML/g@:Q7+=aSH:$#K;w?rUHfYCj1r3y`4^S8UT}R@jNQ`RLrVSR/z*^ysdJzWhJT9Qy~u4r$0Vv=S^6yI%uu_~W90T!TC)/?I.."m*k&g`fcXNUg)!q7Rc<*.<Q?v}tKB;[HLgfx*bvZP%&skzO.[p)TnoSTY"(`hxIC9v8|w9q((AuvX;n|ofbv38dX%(?6afSMe]B*wK<Mxo|/bsDh=}gGHmR.6edFu;CP)O,]3$zR%>0w)xB6/I&wP"fI:`%3<j@v$M4B3:e?6]dC8&;^ghvbsDdhiS]{qQ+Iz6eUBIaYL:$Ns:{7SCsyxTdueEz#.U&66I6~C%0P[9j@l:O<pAN+/&X`*/7&!!Q6#f>A=PoDS$3ImDT$gkp1Z&O=qNQ0Tqkr]"wp3}O=c|)KWiAfu@(lw>5Y:bo)?OFf.^8jg.XOp?k;:eu7}a)bWk$IjmRZK@.lkW%tx]P1Ch#9Bgw}a$L92%bg9C|&#}q%!9u7u2#gT0;8qjEIA~}ADRM"$y+#YdG}Zo+x)8`rC>,BU*D^2B2^/;sX=vL.H}Fo(rhVyU,K*Gl&|VWSN]D>+6d^ndp$89xW],h$Ou]$P2g^[5O~H=xV2+"zq[uzz_z;cBRfi#Rx5mvh~6+lPTRr~~AG%^U.ERe&A_c}CED6:sbnp~@#t5N^g"Q+kTNN+9~!^/$Q$QTiX1|7cy5$a>uo|*ZS=cE(pz4O;,}7~jE=r@Wn`M*hC9@qB`Jq.Dx(wnG7g!_erGX]FtSMB6g"3<gY+>xp.O/gF+Vcz`#mS_JyBoZVYXg/S<p6]@G"R_,ICC7$jvBg2kiS=Bs%[/`WYZG#wgB}M);[b:fe%^5LnE4(Iv~&$9P}1/s9cXc)u7V,I<30?Ab?zTx$oY@JZVf6|FXDuD!xdG!zchR|dGCUNlM(vI`YdtD?<SrSM8N{+${A[*uQE2Ih<Yg.<<,=y"K]J7z]Gw8B}TmnW.|VHT][nS/z`iuKYz}kC_?S$ex1q_Qmh[E.nHH(:~AhY/Pp?$=dbovv(,<E3(]ze*%>Smd44UI=IWu;>abIybJ+j;Vid}dc0;?<ZIZtqH7ON%O9,u!}Fr}ssI+N!IU~H%t(gN3Kz:Zi{6KGeW?1%#_o^5fE]l+EdTus"[)!p,DDpY.,Br3b)8Vc?+c=Pjv=VZ)5GAZ1F1SdZe#Aig]Jf8(nWXpu,ZT)K7hBz`syY!GjnFK&0|DX.gcC1BeJ]mJfedz"/t|3;MC6=@m)rk}.uBuNtG/FOKq~dg)V.ZKuF2BI^Ugy*1,i}qX;F|jm*d4;U&uH_k]}9Vg?;RZ:p~EMY6uvbxl2FMi<h"x,xnQHP+P^MRN#O7_TUQU2NcVIXRO>!4*mva0w0"*gxWobk_[1(d1`H!}h.]N!qgU`&k@~uw(x_)2&7J:HNSEHtaBEiM86Y`<P;NBnI^sy>PVwU(4!o6/JdJzS2GK6Q9d*fG*,e>`H}kSHSSOx<B6mIcQPh7/TB}]2F~h,XE,C4~$Wzcch6dv47{WcS"O4V]6Bt}~/gxLr3FkQ^fTYysm{:E$1cgr85,z#cE`+[Ct#gJ,^CB,$.OSr*gn@?r1#pv7zTyyWos3kwRt&5*j0}uS/$+`[$cW%WP~91A"$<Oeo9}HsR70htT|Xmv/pV2c6/"<.y6(>oW6>$x0RaJmrs_K]sUXivF*s?E(E`Id:9VBSy}n{WR~hVSvA9~fg;s0GOFy8>FD9@FgXLNQ.`qsw61~Q^.FrP%9WW,3:/cs%j=b:l,bA/a7ezLs3(UpK9c|{/+HL8QAPG:;]wj,b(Hn#fY2eOvSSo9Le*!3{V(ze&`9uL]Se)}43^zbvDk?o{0k^%[8C[bg{[O>k1J$"tYo!5}%}H)(swutX2o(Cd?dQvA#=j,[iMCv,9q73DNBH;4Q;F4GM(RXcJcHCH@Rh$rZ{VvGNXX)OBZy/1tp}T.)HfG83z[|0X<xXej$u|xm<CKiuzzuyI!Kqu6944ewv(M$9(FnOp)_yoqN<nhZAfe8b9@|Xq,//q*H)naKaJzF|Qm`{wjK_l:^Z,#gp}Dn!px](6jq"LXuNM/$Vd]!aeuJ5uNX|x*qnRDIO[|+V^]Md{utC{M,sR|(^}+tKAI}@Q8/V^uUHI>_TO5fUI.rCu#Z1w.+R5uSZ!ugoxFd[a1_J+J?}uZZA72F1r.~H1j5,b}zNCe2&HVN"J#d:(@!X|d40gR]b]{u7$X]MY)N(d6J&y.*98g$t2UiXk"{G!yJVSHF{Xd9?8}iR0TG~^x}o}P)^+f[_Q6(qY@&q;I.pe=??8Y^^kn=N/@Ogu+DxI5_UkXt+/c&;2UO?.T[o5HNmz~T#R,QdI^aT@DKk_%QscA`+tUh]pXUu+!U>T1FW<fCdI=1>"0jkUL3%z)%b_N*c(<YlS.o*EL6ex6j^<c4wwn>7!j*QnD<IDq0kai+fgS+<_u}},KlDGA32h2oxZ5g4:_y5{y,y#iu?qZ=*>7GyR>GC`++N$w+5?xf+k_i/%:&yTg8%?Y%#:1e3)>[/+5wZpylGle1)6V2LdFk#5;(Bk^g~53`9pT7&oq$X)$C>,<(:(!s@kg^qfm0IPdr]#E0_HD[Ywcmc`{D_DKvVn(FUVoYmJi8b#09iLV[2Rd|8r(^}X`S{bK>r1["9Z#ai;5)!VaDu%[.3EQ.J<C^hFS97t^]pR{B<ZX0cBT_E1Ew&<o@GEcmeHec9lE2`$P%,zGCC/*26Zd2,9fn#s!@U%Fe%#IcUB&ATtwy&<7_O_qVg7vI/1t5:x^a7gQi0`fx84u&HBYnf/J5K,WtyA!_dS~TYg)gM(ZO$Hy/AwrS53cs(l9)`uIo<y/eA4W7leS![Bha>6[Qfz]7mB!oYB0}kt2bdP|e*~=0P>Xh<D]S]v6_=3@qyni?kg;c.`<7yX)S^b>;R|yMyBa6u|<&5Y>;C$5c(~au.FrN[(W(}qT>,%R@^<zG@?wYa4%HEg]tFXdYZ:xzQE?RkKWP6Rn7j3i;UXa)8~S&z7f_`++}NcmKl;Fd$A:z];gkm?YhSMAq~Q?yOj2YPljSZh]3HzvXA%OU^@BJF1DLLCfIM_.ib.PsSk6a)B2V${cR/`Q1Py*Kmu86_=_txcIz<BtuM1rDl$,r0IOD!K<gkap3"V|CS|r?jqbd~IFG`e830kAe<*5k@%bj%3}tN2Mm2SH7"V},_tVllW?Q)Sf1o(m`fSZIwT9!,QV1*Hc*zx//9{,%s"dCn8./c)?_ZQ]fyPL@@OT/4YYD~hzS6hKr68E|S?p]=V6FTHt]P2I/NrXE;kR5DU,{)WOd5j+Ax1COuRBd[+L[.+@$s<|}^ERoE0Bwy3pCI7M<V1t0|xy2AsLe.ul4w2M^yr;&y,<3BhQo%_7f7gy9y(k77!Rd=4CcRxjJ~J<^l*:+w_&kJ&?hxY%;,Xil,O"/>qt%U*}O[3P^V<nWr:2,bB"}34&F<GIo#dvk[4;pFJqH=CUQ9YYDb*vGk#XDr0jAGeuBshG8E1_hNX,Y,+vnWM@kbgE4y~"ZL!)i1pd^(]gX:;uw_2m7Tg)Tj+p{"o(T>Fcyi)W_F/:mjVSGUpv1<*#Tyn<2E2m9}dpvq|PpXn"7"AWJ|$|cn8@{<?wLT]5p3R]u/q#D$u3~=6=PG.GLNqIa1NlH4HV?k(c=m7z>D/]6>z=hQFd8}/4vD*(CSb}B29tC`kuNprEKim*kU00W@&$"?UrA$3%qhM&[2+TSG"uO6f16"XN:l~EX"uPN[F]Qe$|Bx5Ey0~B|j6>N#c{lLCX>5w9BE79oe{k>.Yy6Sc^xAtVJBnV}RRa6@*2D?`us>SirUScoq!T3(RV83u.+k%EWs0I]SBM]X6#_{i(X59A>pa>HB^,+Q=ocKBdTvjJVI9&1(zN~L&%hokPgqJw?onHkF3tB,Lld^_rBGB~a"LAB&T]{wE/gR6$%>tt~TYtaOK6=%G`~cPUU6{r8W};;:(!$|/6I[O;rttRtUA{@}$RU)Y,Dzt>8*=p?6CHiD5F:]+~9T=;;r4*>lIJ:<q1gEC8ELS4YTYJvql23.<Wl22nu[.KK2q<=Q[V*1o?eLz!Evm<l{H?zUMcx?II&:Pmvy1@,W,:XbOG>0x.EizhiMVR11MI{jHbFgVN6>^:8Rbb_kE_9#)M@xD|He8bMX<}8F|nL&5RAwga`O:&ZYUXLFrt!U?QfhU{r!7%j{2"1i`XVikRwpiV;aBkH1N[MJ"STQ?Te%[9MiE!drcVV_3KDu9wn2R)S>4dU.!f)0sf0Z|OYuTYoc3#_o#uyO@#Ww#ho3N{J/z~.~sHp@<sf^f4wS6EJ|Q1(obIfHbn,G5~t"G`1^j07m$nv~Z<V$F<s3S!f,>[byZUnpg4{"&^sX,USa|":8tKawmvm{pwTPq*cfgOjIL!AdTkJD3r@3BVeJ9zUQ@[hLIe~t)MGjOa;Ks/@)s#,OWOpj=JUnw;A6q0i1f_dz&k&muXLq%$E_6.#~<heGx!2RI27v}sv:=ias5seC~~+TY4f/UlU]Crt7u}3Zak!QlVu[]9.F|v?)6d^$<VPNBO*Ju[|jb[Z^2Je9D!0obc!s@]##+EP>X7CZC(Z({l6o|=I2?33l}x(7/Jtr{Cdy2ffBDK4=(l0tKj:gX5%_&.7;J9*3lSg/xrA/b;0?VHG!M65h5jjb5oBr0F63>mWW#pl|LJ@9bW,Mi@NpX~@_V$e0Rm}@IgFAK@D)1*z8Q6>==T/Ngdk2z,d7P!Tsz2uWNi17Wl.dP`P}3[Jmyhprqe,"Fds3LT+zC4aYD%D4%/^9B:VW[9#%<J=tvD:*XFr>Iz,8Kzn0.IB~b^fpR2Qtj509"PRD%g/EZ?F#EC;1G4T[vMKB0MtG#8i%[^I,D)VaC[]N[b#"3ZU:@BNUhhm$B9xGj~hie(s!Y{tT}B*k6K_,sD`]:4Rx=&=u=$OJ0#55qdm;Jm%yS&$*(^1s*Je,bDe{_/%_Ht5pJ7?Hd_KiLTbXKzJsOa*~n|o4FcN/[t9c9uH8o3Nf!)*"t,bf:e@1h&yUiUs1lh:_2*9^!`+gPQ)DhFC`spwwY6x&v;^gK;`+<M}Wq5_8cHVs;z,PtZCOICOvx}I2.*TWmC6aJS|~Clg;]>In)G?m03&J1@_[47~>P()}i:w#4xxpn4fSU%#iGJy,_R`Oq>vSnJ<nOE~s{$i0Q1;sak_%t]AMj9=A<nB(5]%W~sVcBQLV>4>Gw(,r5<ck.*Hqp7IC)[2p`xDiiE$_rr)Cw,#uLs{"ozs31kmxVq@nE6=9iGDZLsc@fVH3CmEXQ.m"^Fjw_sjfcZQV/[`](J$J2aA1M+xQo.FKTr"tz:ElbEN:WR}tgxBNTd0u#{OPZm."BX3IWqD4[%8+G[TQFqM1D/sBit07XtlB^?L[8iG!}SQhec/L_%Z9M*fyRj=m6R/bFE%{7hJgwv.ZT._[=~ZIX*4X}Gmi*!oWfELoC;$Pt/fnrZ6|Y&:~<a.M;d8K;mi4rOq8fTG555KOfIM*`U)5DHjN&p>pK6XWeQJcihYreqZi;bY/`(k1Y1sJ1EDeDMsPq3Ej9x#`0!!1,*xR)sV(Cyr%UodqtapG!d5``NBUh&AKsc8pK>te{Fh_9#L`N18rbPoy<sqZ|f4hz.5UY?P;~;v*i2UO#0<z*Hc,Vj:7>Mva#ff;?E&sve[IZuXuHodRbVx3V"gIR)xi24/<P9gJ[QM)P5%WuIyb&[XSl5Edcr|D.T)03MA<j|3|s"F<hxV8e`~QvJFchV?nr_CE*maEip:*4U(Pfgjy*7pbBfWZ."!%2O1WCLxuk]r!GojYnBfx{L4PR13c3h2<iy*u5Qw@{mI`];,{hF?VNG}:/n:n=_b2k.UyB?kaY1lh/J*/@UDl#Z+a!;m},T:8gP&Gb,MU?(q06F0KWUvtTM[[!AbF<Y.f05>LziL7,phA(*f"SQ0r"Gvd1.e9y9.<qso2Y2G]")5j$~3););8mjaig<X7h#lQW!,(16Dng4X(0W&BJdp?|B(EbpTguyB].P_&qR3&fS;kLqB@wN[dpDotAn1ZC>w61R+:V=nN3~^uq<2z_8BT^y/OB"%Jd/JtnWI9mw2I#3Q;oKH}=`!.TClzZTJ1|Ba`8iXFj7eJlGtul[4Cam>sNqaJbQEC:^Y1h@Hgm&z]:D^,KAA^M<oLGs+!I8DOe^`nk*C]|9^wkc+u*u1i_iBeY)mfM<^SCEqBe*HZ94/[5rZd=Pg4KP:nD(Zm,{hJH_G@N`Y@jtn*TaIY(uCi2k9iG[rf,H]9F($H@!?lhU~z{f]I59RX+PD_k0CZR1X6e|kL={<Wp{ZRx0xDe7|yO729V2q,$c;"ZEE,,XQ{kl.OKVbv1"%JcxR{btfuK@+WQ|d<3qKvlO?PsGdPY.OHY06p9<O*M?}<LKvMf=N}a}f9WW<No4R(M+s(!PY{muwLjBbV]2!UnGS%t0SbI)z"7zhG),vW|v_yx83D95:+f_6X0&kXz[S;P#IY/K6~nLfA"SsrMKZI$`~(=%S7Ck+8(3k!r#pNn[d1Nv!d!K(0#uSEjFqgZJG#3,H+}UAj_$Y<lmvJCh@D@N:}p2w$?So05{:KxPV)P2&9pdy.u4]IPbM~Ag;.kef&&X9JWwX6KUoShaJFT0Iv^i<}vTrB$b/`B+_Y*4u+BF0:BPw{gYa!DRpkf7*WOY<`?i(|y;kM]2>x1Evd8:=D%eEM^e;ff,OIH&KVFP3.l+<bk(3`:57<L`58Dv&?36^5m{`BS&fx1dsmmkan~GZw^Yo;atPgI9WvCiEQJmg_:n{r}`Jo^j4mkN=hMgLo5APjg9`@`sn!!~Lqc,mD4g+f>VV[K8{rUUvt,.i=kOOT|*CglIqjmgso"SYGz;Z(`i(G?[KSVGc6lZ5jHoe=%f,Q8Hp[Z(c2lMUU^k)<Jxr/0{xd?>~^oh<W;*}#4XW6PGPH;emH)k"+anwsYa^^BX<mbdR2[z;Z)Z,Zf?9S1#?;.D{BC9sp)IEY4BeV6wLQhpP4u!XOGCAt4Z+w2:[[f=tXAo+dX^?42mNGkS>@N8KHr`(BT5}zuiXPkRNIrib^;u;XrgX=_ql+syhBl2kZB@WZp7g!xr>8U$M`VY%=ub%^m89+$HRdsGcTiaCV%2<YX$$CQL;cXXeQ3Nub;xoV=eDnZ1%[,?DlV[:qVytIBuGT:xL{{ace1!_[P_{`(_/T$i~:R`YDt2Zk+#j3V6NW,jBf)]5*y#D+*iZ`@MXRt~k6)$1;8uVuQ2QLOuxmV>jbD?VXK+aG_`t6zN+ZHb*D/K%.yo9MfGFs$&Z_G"LO+pby46FCbC(Ka<nLl#4[/=}=&swkIYds&Z&8k+4@J+)PrQY{57fLvn1b>[aiw$FUqEw&{3iUTvbPlgcIQzoYR*#{0[u/3.(<=[Aa:7vV55*a+8>qkEm.LxvNi3@2f)b!2ENZG8piR41K(rAaz@=[loq<|?ASW,bBF|Fl}^3^_u(}y~*#}LrhX{uN|9UZ/hsB[Iggd#kvRsQ0bnrfD*@G7{k^xV/xzpvxSt6RB,tTBpC5{_c(!N6I)NSD{!1aWz6)5}^,Nq_]SJOg;;PjR]q;ztc@n`tIyYt|$!vYF?MXh}V(bmDL.Z2sxK;;MCEm<u&/HzlkoxdJM$}Zl0c)/|Juxm:S)bRJ$UJS")6eBaveRHv=~JujSs:5Ey]OF#=K2mn]P}L_*"@!coVv$kP.(J4RC&DU@h#FeNM+7gFMNgm.[vYC3G=|$g4PCq)Z3_n^b]i_#Mb|Oab2gcdIU%L,4*95*^cXcf~1=N];pSJ(Td{2=$i]_0&3C![q45^}tO?!]qsj}#m*:nPe/qZKGlxV<SPzy^29&>)hw>/R9`?%lzNTcXK.Sps|ja!!IN{igqD9ir%BG{>1E*pFOC7XH;ZGbw7I^w_[eKm*crq{o5qfVG/g^KxLGN;pz@zA)iR1Yeh")UM&Qe#9]`8[u=E{Xw^)Hl/S4BH2MNizw$s^#95?%LPJ~U]gngAQ}}rCD!B7|,?#&vKF/:zJs#C8#KAEUBp&Weka%5W+M9QlB|~ML{BW?cMjn6;xeU)^XxEZ`%)lFTd<z)i^F~;T;c)gfFx>?(g6G*D!O+,<.hc`s8(;LR!v*6mjmgh|x*J|kCO2SbQ!G6!YQCf0R0J,M)0F9]~oJ)5.tKK{k{:iF2u<}?1@H<V7QBH|F;}!|fm!KTlzy7P^xLLxmm.OJ52%}DBi5kx6L:4r}/0Zf$`k,REJ;@c2Lfq/15;mXm0Gy~UV;x3})NJT>=tl:ok*@SIjYaiqvEIYKQ:exq~Zw2|,$f*X*i=HUCH8uS|`!p4EB!ah)&YX,&L{7xk)cBT>c+Ycq]C35gQpZMoK=0GmX:#d*Ash^hn?`z~{f"e9e/PUw!p7$U2%!x.)Z1sstGXO:&53v+V;>+W@$jb[h?TKjct&aA=DSBfVUR=3VC^F}MP^kSG+%?h%)l#Qj;K5rPL!?|T)o20E^Grfz(FWhyE<ULT:AZ^B1}sYW?8iYx0!_pok$]G;H;(pBIhp$y|^O</Y7>06vQW(b,yc8QIbC*cIQ`z|4D3WPA]u`)uHXL]5i*L{o[SLX."aOnkR1c:Nf8][FWjY}~q/]N5KuZY&F]negWRha~m(vWY[%9Xt=$MK`M`g+~XX5XBVKK1DPJ|dao0~7Z:BU_L.|&:LN#c,J%kDxbU>]|xk=U`.?)f},$zI*>m109#vG|73EhEdI/;L?e3]:YsU}e@|TmKo]=C1zFh=~OfCj`J=J8{`LF$X*r!N!jZF,~^Y6.{>Si+4?^G`Icv|SMD2O6xC@;U!{b<x#i&BJXR9k(O|MD4%SE+3poSm;tHb.xq[w&9%d_<8#egYnIc,7|C>e./G)|Cw,W;|rYKt8_GEEBI/6RDprf.e(aK]gqz0(Oz.E;|z.o$rC/4>iKI=RmH^%osCYt)ZG[o6dv>k"7sh:o.iZ6m!{}@|u05iaIiKn1Ub!y[LymD$f_E2a%^|GIJ`/hDkHjt#n,_t<AWbY;}hQFA?dd#PIV5lHt,@a5{><Qk"b&IiZ.I1Oc_CliY/NuQyI_p/~,1I}ow>y=v#[8^$6g~_[h?"G*9IIpJ):kHyY2oU"Vx^P=zBLylR]CzKJP?sYo}QV)Xp1d,3+,HYgKH=;u8<8fdzHSIT5?F(5vJb|[tGNz?c/<|LU^^Ya]q@5&{NR%(]J2oNa?CJHeP{7y7/;`NCp@*%sx~It1~Zt}IwA<Q^p+4_`kpz@Xg>?K|`Jk?_00F?c?gRC2$b`hE0U6%t=Y[I{*a=d:[q@SI*iZbOSJC[)phLii40|>.yW8,<a"z#{R"A(Qq`kpa|^08lkG)Pib2jj/bCqH<8Z>gnN}P,&C~(nqOQr5~gn/{y0DBr._9{W/HGP21tO!#hVRJ1W*ie)nIBXLYMt,KhVQ2|J(`;NOIN&1D|Q3CdZELD:uZm%RP)V_{A/;|:EN{{UF?8gXjBjyega@th]Iy7Ze`gS:+<?7o}M7!cjhMbqP5qWj=w7:JS|*,gk}:%coFZ`38vCyMvTm#h,,pLkIWd.G_l)%BZXCm`L[BX=xLDRmv$k8ll.A^@+Y?oPT.++5<3g}PT>8q)u%:/M,jYh0,_jV=%}6=Q|yq16bbejo`j1V#SXkQ$QW)3ye*oLJy$#g!`kp89fbWc:AvQ_I<fK|"INj/Dq[t]d;34QJ)_x5]nX[8Hgo<KAtfzA[_!!$Bw4p&q5ft)x1n:n{RcRIy$G+jE{vGhk2nHR(%Ka_RVMIB`ga^(dEn4juUF;U0~diT7g2&7Ceo2?aa]f*8Ri#?&lZD=D5<+j[|t,i12Z8tl#4lLEy$pb4xPVsqj+esALl(/a.n4HnwaHTJi._?.og{PZfb0"{x75t.6c=>]Nhih4k).upD(=cNP{HSM>hTFE;QQm6=fg/_U/l+D+_k^,*/WQ?.55lVa$=g7%1$?k9kF.1&:0*TNLB[]%gY!5$w`+GSi*MH+{@V/}Y:]g;L<.6K4PJMIuqVD./XgZra5wzs4(KbBpl0TsE=x=;K"0IG@(S&Kd2%#XdsHKf;S{V]cvA74R150<z/i=EG"(+qk(Hp<!v{;FbCL`[5]BtwuiQMl)}<?C,n#>)XHN>&k3fKy6~=W_QnrZbA?V|fpMJR|y^JE+lGa1bx)+_{jtXBopQ*N}ZYA|1EVvI@j1Om&M:E@2tjTg`fk+c"p.myX3"H<R.;$l=,^BMHbJYpO#HM_,1nIXe;zFCJVP3KeMXU=1d%|^BY?pUr!cdquXrZ|}+3V/qMFJkt$ob<1#^JB]u&qpBPFv6aDCv7U%?4[zXuY!Sw~3]o<.&x$@H4Z"rT?ja5*lb?V|kCCVes~fk<%:gm!GX9biVVGhp..ER+@.9ztP[bl`"r98=zp5<z{Tlw#5tvlPLtX[;`h;fLYE[f"*]+@N>}LS|%WML`.}ps99AI"t1_:r81k:Kx=uH2&Nl>TVqFJeaL!qmM2Cm^ka,^#PKoh:o<{2P6YXub_onm~8#Z.</WkPx(`g0p61Hq+ZulH;PzK@AP7$AL<mmd30bbJ`Ogvaa!=Z&t`<)(8a)`}+B^t=j6VU@Cj4]2Oj+>HO;3=6fV,Xu~mV}kx4pZQ~|/y(*CdKmnw>`eWE%F4J5Z4ShE,{TG9S;KB<p9%4ijb<hb7Y=GX+U6gEM>(HCI.rK.42fanfY+jf)jAQog659$TN$r(FR10T.MK77!`[=,JcVR{;JF1%eHi#i{!6DJOGZ5G{B?ASW(Jv]sSp?Wj<B+]lVwg=17v<fK1nz`w"m>#+]r7l$1GM0BfM0A1y]kAZD9|X.8nmYw[c%PX{A*qK):eWOJ@/Y/wbGJ0Bf#^BR]Wp1WQ?gh=0)m.V"<pfBmS$2`:OI1(!v+?QT1X:KQ(!Bujk2~D(x_w!{)"qh1gZTGpIwWu@pZaHUPG&4>4W;%cWLmTgl=[$&?Gqcsxo_*27^BR1P6h7uE3(E.)arUimC9S:cX7)Z%iwZtFYxs}Q|TmfL4rL^Og,U#WzXV^mpht4IF4C?BtXg++6l!6m,RzRmcv1/42>){:HX}?{w|#OV1H^bonX$zmDSJrIAMWH~?H?hlWVR((d]^!bktSL|Tj:w}FYHZ6iKeyzBG~%uv<pz%6P^k*cwxmy}mS+&,)O=IavQ8gBA4<`>&1CecI*,35qXM~ifd4cm$S[m;A7Epmf}*/PolS0!j6D)&)l:=1hPaS}W"pj:%tG=z9Dm.RH6>4+chgT;`=e/@QZIt.H%{w|BNv8HHM@Xs*hS0^7q$AyH{M+P|q<L_l|,c@4y.7hp/S%(aTTT2rxJ?OM8khz72C0q`h+L^nhDda1y?3dV"_K[H@v=VME]4T8]s<_!XRGO}39=_M9|uWG59q:(]S<w$G)j~L2DdVL8r;JInN"t`o+B2JhYHHY&"8er!s=A7b~dz$Jxo^<=+xXt>thq_L(i=]`^C*9BqJE0!Qjq.=9n@at%,"@)EtV;52Hy&mgxRf1Avl>{>/sp#e0Dk"<5~}BL85kC`8BVRqN_uV`UBszM*UBKJK<sH@a8#BLKE;qaGf{!Ylp=y`RZ^#kvTl)x$tskPCA[ag|zl80%&MeC{x8Rirkh=io7,G.[P"kLyaipv&|T{cLmT1EI.w:l$rUZFK(ei{>_xUo2jVkid@|7zSnPD@q6ia$baQzq[S:Yx0?_3t[|.d6}~5Rla+gNz)$T>["zP*src^CMDxIxxf^aqYw&vH45+;"gHe,A^/%/.!2ju6rN??<}R0p0Kc|s(DKuai}/ssmm/zwO+v<l"]?hv<TnovC%RtQyp2,)~i7b;+${Q#Nt[2kJ`EftM!R3v.]|l(h2M@Ru?!.j;Bdz>`Z+Ub,|6gpL[DIo9OhSFbbz}acCZnN=]KX#4/z0s&DcPb!wBRs[I+dKogc3R`V~LrPd9K.[alm?x9M~^WU/9b;F9oXKV0E,;QvO<re642.fBYzvTS7Ay?lYwS[V@673KO<^U,I<7`7F/mwx%x+C#gt)+Sv:|?>P<[x:0n0_M;G*&*DgNGQd0&$^Uq)Pi{awD[Q,L<FkNUut73RB|wcb4=8#+3ltR:NErGa4F_"IE$4fw#+_rz_rQN=iTJGk]({+`RgDBuo0:R,>/U<q4l,u1&Z(?sRx*lo@qe?o+S?mk|J"/VQ)I?gm|}wrwX!P5/p4@.4WYdW]bQ6RMzpof9j;[Oc^v6kWr4<>fcDu&k33&)=+GH#k`+@0oAWy_4lX5?r)ehU{)of+Wg~p&GwIXD3b)"JRqnEDy_MKIkgca~%iU%NqSvLM~*4u7e>zuln}89dH;iBjsVE<<IR]LUmYp*t<87kS|O=Kcm^zLQU06#Q~7ky#JHXrvuerIQnGSibCXgF5{hW87v7[7J)!?2[!r^cz~$2?Z$.[R%l()ht5kyh*Ap&l_7BzHSP2dkAbJk=3lpV,{<tvR6PE0%>Ey_R+#?q>&I#@Inax/b^[_nPdcpbSL8,7D`w~Af1=ul]aI_7jyCW?DGJe,lH3k=PMaC_!wS+)yf3%:rvj]XE$3p_t&HFq~(kjT>{zZks(g|C5Pe;,JQ$Gu_5Y5`%<6J(H$Hot5<e+@zvGwQ;+>FJs9?a2?(40}C6#`Z+Q*|l@#;gecgW=5KcU6nx(!sUlxZ|g#GjtK%6+DU*uan8{>*K{%,Cma@&<iv2EZM:8V=n:IUsLEMJF[>`kMKSo:8b9JG+@~Y{d5F%_jKD~txz!TgU^u|l:iVZd<X{<6>NoG?ca9M7p>x.ZZqp*Reij@Lj^v(vPF75<Qjd`8Kg*2Wv~fubb8.)kTF4)u`yzHDE]zc3a%*:_gH?/hV#Bn})?vvr:2C!MR_k?0tS9bPLVV1IW=Z=XhKOn:v9E3@&v18sB=Fl$qreH{G!AF[S^fo&*h=+/z~A+YR6;,Aagv@~z~J@E:6Q&phOc@ERzty/qGO${LyMBCLLEGtXMgXLcn4]jbz7qEk5DQLenAz)87d44"Za7/wFDGZ|VU{L4Fr#?K[Grgb4bF=j&D$h=))[%n=h6LzzT:SutZ(}unlv@znWt_gz&2eJG0/D3o~dEuodf2)<[1j([?"]nP(]$EU2:m35A98XMP!w%nM@<7ccaOa1`a5l7BZ)Dhcu:,8yuFNMwsb#BX*&,A)1*/Y3r8=H#@T(2cqrv;mWnrOmkKT)&iH;r{h5/XGTI@v>l$j3;XMCfPBP}fz;V$OAE89CZG/]Y5_qi~#LxX~cF7#zqD{g"XtUaV8{c=PR%Ea/vV0mvR2^8TdaOO<xv0Idw#2[(@*jt]nV_^A4"SUp:pG>o&DNE`W>W$TwC#(n=Wncy.k6CQ)lJQi"[w@d:k*%zy>e$M3t71J4^J;MS.c.w`X.80&CmvjMOfN>?3b|[k"9fq,P~^UcpfIX&ar)|<nvO@*]Jr:V02FhJWI!wftegklY^VOEI,<+(I>,E$+|(DlT[ufw}Rt5z:;;o(y@dKwcZ=F;Wmp<D+LE(1U(uA]sI!R3+t"i6xAE.X%?r>2#dRdiE%VO%>dl<(9pObF:|8`)b;LmOQ|;7y.V"yKV>M/1*%XRnb"RHGO*bnO*<p]Qh:Il3ygMjeeX77aPE7&2GOmkf6lDm+vV=~$#=6=5"e)mzUDc$g?[pTR<KYN7=;5V8m8W<qpm,}m|~RnPRiLS$?Y%faVNaZFWmult3<ocqgrBejE]o[tC"xJ]4TXoQJIa[L<5lqBb*1J~#HAY4u9z4y.$"ijR>ao7fH2z,sh^$SDrdpoSW1?o3]POo{k~TuZ%@*30F6JRfL]umgH[qZK~|5@l}UBR#WUW!JMiI>)Q_%5=Xz4>%Kizd`E9Zhi%}[f)xi?~s3+4~N4U/Y7gmKe)pHBV_+;BH)4f~MU[<:&az`593xkblTe,X:dUs@P#Z`!NChNKB9B{$,`$GiG2ml!*~:(G1(STC>9q[MrOwk^|Kf;qk4/E/8UXK8~*pzXt)X+cw<U&Y=G015>[%WEd|wU*1R:6/V"iG&V7e1NPvL?|a6&6p}U2|qcsaqPeEjCE@Cn6A;!c$uWtPT"J#GMT*#UyJmV~L?;@gGv|8[=~4$nmxbv4_tI+J:1O)y.8+nOJPXnV":C>~QTfh=I!E3(G.J01ibV5Re8*K6y$O)JDm;af%~XaBq)rBGy!:1[)ZdoiW4J/NHCzx`GY}G(mP`OB!6fXP:D|f}z&8Tk%^6S}fh]jNglJt$g/cYvh`YC}BljhwEIuTuu&mF|ht&B"n&zO!~.da._(!?#pNooqPwM_x,}l&^fST{&VW*p$Uz36:w04gu9:=([FKaIGc,_c..z(d*MR.]^Q(s!:Wa0.V[Qsd^4EI9t*gu`tps*219!Rrkak,V36_Ws;Oj:!4YuB/!xw1U9L&{mV"Lp@_+V*b!D{c>G`8M"&^:htZ85o0MA!WgY^Gt;F%T[%^vw0,sA%?4^>c*ULD7CMLKio9+`ET&7sz)yt$+z9#]5f*A4?^6:#T"{%*AJ**KOm7GV{l>y{Rw/y,9{Kvi}Q+P=.m@F#$UrzeJW:1Tgg}_weWCkY4g,)3=Byo.~(x=#{5eAOZK<3=Ya/id,m"G14&|{Mx^=cp7gg""q;#hCd7i4!NA0Hexc$2P:Ry+0{}#"N93xMv;(TBhw<O:Yqmakjkg^>W_IM}r=;`I2cj{ZIbS(FuGBw0VR0]5``{8YH~lT=@ot:PNXCFU)NuSm&]j:xQ>3!T{/1Q|pn}QP9yPv:H{oX)2te9K5Y#N&csr+wJH4kd|cjaaBInqCLv:xN]%VsbR>}:OR>Jj.~87*eoQaw}cfNY{|;aCQ"K3P?"5,#?HlPgK~hW9_%{R68y9OtkpQ}8l(jPa;Uqy;U>DRft7.=;z!B|!%V(?]=|p#ylj+4Y>pcagr}vzhZ:d/5WBd]Kd)/WG$=W3:)k?vKYaqer|ik~%00;xpxmo;M~e(1oVCb$ZlHWf&C3=nR^n2j(Y_;j0dv5S_9bT|zd.RtFl{!1H7F4US2DklILEn;r[OP1[iGarSX)39,8]L%SsEH~Ir<rST/_{~Q}zuxo=P{g(@X1cX/S/MM;^{b@lD]0/;DQ%~,[K+{LTer!Kj:26apzZ[e<nSo4MR0|#Dr;]SxnfgN~[`F1:lgd=U%kTv:e}ZuZ=FX~O`T_]>"vM;/d.P^Wa/(P0`?6Ph$3z=V^Gqw.H8XM(@!;<hOq]4P&$clhUVZ+(2tpx(xp_h1A@4z"Qd6v%i!HWnFx>2XbR_UN.|;1VGW).[Tt<Z_xPGq_B(s+YM9D7&IBN+{~Bv@5KtP)w*u_zZprk_;*l6l9Qy!$$pSXrW`A$v>AJG.zxj1ihhO7(Y:|oce#4Dzf%&+tZBRC/v+WfvGQhpH<yn{j*D`&M%E0%MKk8@]%@mdFOZ1lsMYsQe.bH4M=/Y;+ameCq{PzT:Nl@i0F)Ak7r,BM,8LT4}O>/3b,I[lOwu2ibwp8fW*?jY:w(IQ+d5;|4w`!/I|/afW_0Q89K7g%WOU|DxjP2E~^OZc>eW`Q.1)l,MVgp{RS+NV|)/N%lc0TnAP$^&c~9S*$ta3%S#pZ%VP}ipFW[nIxst],=2QNUFl84>MQM^WU4v+(kqI5X(EY}}CFw>Le9?.)z&6%^PL0>oYvTUjkEIO3OHvVxvVnN{?4z4zh?NzexDwHm0iu&M^C`#$uq=#/+G2(q580X!4J^q8.<NGyWf!m5&_G|)|G|T,rk=N^X+UeSlgy=P*Vm>[[m.<ld7Z=%;l*B?J_}W^=s?%;{F^%g=bsf{+v2,Ua7{QE5dN}40w##h!15"96,`g{Q"%r>>+w}=>SQ19]JduwLkSVdgW7OelIeONn|`/ilSg_`0Hcv+LJ=6ss,Nw&X$1a4<9_^T24P*PuU?/(f}n|"BkJbdUw/sI*rb7}Cp(j8M)FQECx6<%FIr!S7dwT@y@(=ecxjus3dPcc`#7n=G6gbqrq9&U|Kk8Hf309^EF|rFU_wfP;u`i.<(W<]gddRNC!)??DnEpgS/~Puhr#P#[UE(Ieo*uJfb;lGS!OOwh)gJgTYrRFu(zA$pB_(bg1Z*D$*lhtiE$x{_jW|t@o=>|Cpl6dd)cJV99|MZT=v2)wIwuL*mSr{U^SU0i<{LJy`nKqkfeud]C+W<bc(9XK3tn/$:HwBmOcD:D{vUTejv9gC|LJC8+@We=%Q,vbvrr%`m^DCb:3)}u:[d7%FVKZYq2zgefziy}U,WE#vi(|rDfDH>UqxKHpvJqKy9GG%&q1oX<)iTBfgYb9q"2$l&/$[g>/m[JfDI?AxFcU7f0KLjc,5xL9nhR?<@itB+z&uNs<_{rJt;]&sNv_;4RK/La}{uw4DzAcX_oYN+#a0e/tQ7>mS8pOX6f&&9zdYuWg8@F<F~j7e2(JU&>O!(0t;9`WaFbi<TM=v@MFKG.A?j@w%gy^hESDgUm<R|p#M}WcG*2AaBX28V(xWs<jce4*]F2:y/q_"W>:t]`lJ2*_H{!Us6fsh%Q>K^pXtY!Q7CD{F+_?USvbwBW$@$L8yv&_4Ci!D=d~V!uCGf,i%sq02Iw/<?T~IE59OuV8dc|]fcSQI8R%y*;8FzvWCF`k=?*sh}*MV.{d!<9lj0&QMV8qePYNtBCE52uehHoz&,<,MD1w+czR?w&eol#03mz$WIV[N4!UOG0J2<8$YkMoA[`v1GG{WmLM%8c,JW*qwLWZam>m:b!Y:irf!lyhZ"gcl$$c;Z5HwdWf_oX6kHUrCUyx>0x*zh+K31be~_CjNHUo6#,5kmU!v%(h4gm=h"c>N_6&53N}2C#n]H=[_ybUv1F|*!ql4|/qY,f7TH>@L+&agAmT/pbVgzp53(JGR#{E$.2nLO}Utxp[Xog|L4)1fwj&9ceGVv^z3Xp|QDu2FpIj3OB8Z_B:?>C{adXbIe7%[6~g!L$"chxZVuj:89Su3g]/y[|YVDC(,~o7t5D}`h1c!eeyd#*6Gm+<4/m]M]$!J!%e]F<u?f/s^%_?/QMXt`@Z.72fRYyoRJTPO;")k6D=Ad@3#~;cYCiu!uA";c@P)`>trz&mnd!Pel|;7"`I_XO!!nXH_tS+Wx9+mObD3Q<qzWl&gTeSLyw36T0l,]HlcpZIvi+%2NBV7#s2OvPVTM*.o>M^/HUQrfMX4w,441@TSxRCq(85]2?V0=?tB?ppKkLwnB^Z|fJhI/4Gl!/?Xd]!eL|0xPGj%L,^VK&|y>[HsBx!<nOA?*wpXIKvw4KfeP2Xd/lFZ&FKp`K"/9og,/&aD[}(Dzu3=.h.<QgVl?:f}(LM9YJRA*$fHx<3vMs=Ii3zK4,q]gjp4d07B_yMvsmyy?f?J9RY;zLrI3|RF)f<0Fr[k#k!&daOa@/=sH9Ti9^+aBBd]fFV|.wTU5#&v47_95FF_<`Q.8%k!sZ&d"50KfTFDqpeXr{DIv{I[1eJ%56*{<c[6WM9Au1W?*,@_kG4~YRibJ?o_jV2MGeHarFaNZTa;?8FdD:.BL2;O4R<>O`2V$#lwOtI>/i{+(pG#}&Ca+1QeZVXX}N_Q6yM8O_$mbIN%T;>e)wiGe{:2P+"S!t/op=K?ixY//r`hT!HE.SkgS%mmTgJMvdPd~@sO5h%!oOSr,ol)nsgC$pXXOe5EfQuee*:lIbzv:>ur[=t@}(gr]=^f0_B[OGOS9[3VAhIJ~8+&m.5r:c1b!@aI9W/*XveGlF!TxwUI&ugT&4"oWiX&)P(pm~[C$00{7T_TB@4AXE+TdKc6@v>Zsv,ysZq_lD#Mb@x4uaX5);R?:s;9?meD<cW_:m01`q8d<q0)`Z=uH2@^1S3m@8I;uatXnozukw~N3G^f1a&#A,~tLOn{lOcfdp|v@&9f1^~J@^h.HCf^0E!K"),2lh*G!T4S5M+gvv>MO[MUB0(8AkD>4q&D.%}jdNA!}h?=x)yQHybPavr9muU4X=qaQn?Q7`AV1ub#}ae{ei`,Vhh8Y9_XSg6H[gWdU*2k{OD.j;{f0`?&01pu]T#YX|`zu^O73L0]VGPkza6H*?n8?wYe+BWx%/8Nn`m/JGphb|7bz{7h,{T>tgzy_lr_zn={rXZ(~uWM%N5ekVaj&&4{{>B[Zy^|VvF#2RF]1)z!/<clzASdX;b=K&w,j)B4863nKu2uW:cuHE[8d5|1s4&[gu{OS/"Gnjvi%&k~EoJ3&kc7c3I6S(mr[9BjRDp20y4JM)wmOJD=YG;h8@n|MVfFFkm>Kk,]7b;pEMp&}bF1X=Z3eJ:`8o$t[P@HN8=&&R7h8>(%i|)j<;:A?R@QtQst26U/&"6j8ku.<~F!_<vU$Mlsu{pI,UG*y*JNaoBImBID1Pf(:HRmLn^jnh0i.2W9ZGZI"R]z?!`fk63tt[V}q7u[|!xKsD[aKf,v,:vdlM:/w#ixJ9vlK`KMsy~Eu[Oop7ZMa#~lKX*)[=guHTJK!}AQ"vV,&jFR[35gfL7*/Brh2qK&g~V}Hcpb}TSzT?,Q[+?m"*0(~F}7+VJ~,_U4Llo/xLwK|C*ge%g3!`?JUMP=[fUJ+SDax&Pp^30kBux<{=s#HA>b^B;Cb,Q8{(l(.eIY`FlNhrg@DQS1gQH3Q]GrYAR{qEBB3,Z:gxBV3Cy#k[0A5U4lC]uAU_dNz~02M4cyv!fhp"BFv3"a+0]Si5Pjoj8M/FYj[+d96TO&EkW}]^ULem/fGeq"C?|o|TsxYua:k496D|M4&^V(tGwR4$^>Pa^p,G5hh%EDUd5F<iAsb@*,msd,WwdBC6MIpEIEyb]4~xL&9!6&C#)xh+8dq+V3h,b`uaq_n9nQ2f%}oJzEi4+6k6eup^"5xMa@{N:i)U8S";?#d#lx80Bq?7]fG$b<#]lK#;um^,pmzagg4.MaK$tzZx$o2,Jq:Uo$uyJMQ{J`dHoQ3,s+d813}7c`VBvoZz/Gsc$^gU]YDcftMTnW/D}|oysqGs}kRg{5ZR${h*73c#=4Q7XCptEWZ1"!TBRFQxpxiqlCA;EH~6et:BRRF!qH$s7>M=s+~H](!;,VYa4zf@[0!)uO{7#r*/jMI7)6swF0b%HANu$X&}Y{x4(PDSa4N<gt?]?J)F04U%B62u{`}[P#=t+z&any$`[mFG6baNlB1o+%j20aVZt=S2"r2AOB:&FipQiAj).$d)~VND^&;@tqT#vHs4lxLYOX&xott|bkxNWh5MqAdvB&IkZT.m^hOZ}hxLsi<C(6^[>DrICHL90.te2^fg}/abP_H(ri[}U9[ZkQ=lM$}/amD]975yc!j]Jdh{_5g#q,_0F=RUI=Vb;ZJRL<v;9$DC9f7}F3Yaq9=s_OVF8e@`847Hgjq*IW<gUiv8kp{&=ZI<z]dh@jieQVBI1MaBS9gH&<<]1q}d#:N)x8Bg~M{C~XC}CjzJ<JJo8K^/+ycpXQ~c@JCT1J7`@[UW3:d5!]uZytM>yoW.~/<<n*D</Zm~I_e9~sDR)|nCaMigS/!.jekW|jSt]h{F;OUqrt$/a;mCowCK@LFD25,NfO.dP$)&3^X|sk>~6^n/:{vp#beqf{(8|kirJ<n@F/3.ou/r_EOge%=+!=g)L+PcLM.)%GUdU1HcK{kY99>EBe|QfWFg_68{7Bi&N7(D/H<x+i*)GGk!/Ohe<#~LMksk}f/]K9x"tIg8Z/JY:k7b;WcYm!2vCg:829db,,c5/Erw{_px/[9oKv*|@INFsve*_qHOrHTH!CM36O*<q8S,2Q%<d~P*u=*8Cw|qyf"m"U^dOd&*V^n=1S=]pP3nb`F|l~zm7i?5tC*F=Wsq>ZTRM7G:#}2r4$V0lh2=hBT/amTdPfZa6&?FJusRw@w~BOwQ38{W|w(*s<=dLf]kuZGfl+Rs<nr%FE{W6?gA$}25]z7=kNx!l[@DJ9xB%re}^sVtOuni7k~TSS0f3Zuc10C=gHP_xgTNsR?ir+@MCRu+@Haze@0!]$bB3Z2[7zzOp.L?Amvk{*z}#5mq16W>]`P?|7^^J5|r@N=z`)XT7$W{`"j+l?a%q_C&oh5^Q!:X@{=?k$$,R#Nuu4v39=1ebfCiPN1d4a.Fi7xo(soHt|cwU1!c~GPX?mlma6v7zwcuD0kXN3$J|Edd8=Qv+=YksTcy|GkP[6R&D:r#A|W7Tw!^=58$4@b#W(;YH]*d`<52yr{pvB|t4[A{Q4m]dZN&Z(J#,jJRNuImBo+Z?BTv,=57I711wIw!LVqDilo!n,ZW3xhC(VBQZG{)~DAj6W2&ah(<$4EG+#aM/<VBybY&=]#$N(}.LK`.+hldT@%O^O6J[#|xr&]8Zrp#U%aAt;LMStJOYT%DkPS!6I#*B@3na?crR%L65iGfOnNQduD9}rZOIkbtO40ND,Y#{p4uhLeM/}GAs;b=sfrw?_GwLW!,/VG9@glJv7eU`e%]!U]#u{UW<lWjENTj?V`WnHhn^d[{jN=%>53R|^,@w:pd959%ptiaWa3tA~5(A})b&Ma;GK0pNf)h+dt1nx@WW(~zYuXlH2Le0[1eCqf8"l^d9S}+I9l|~FW&AZFOQddYi+KF4D^7O)=$@ChN9QYN:[!/kKzBtjuL];XYsZ.D.*6Nyoe7E:V0W"~+dRh9fSS_9[c%x8u$V=lvy.UU8_&sZ^zsQobii$+BB5}f8^DTk,OEX4d]9J!ny*ah"5uT9WD!5gTPlRo2ugP(R_KBms@<&;p{xL*(ni}2yRS_<4$i3dJnnx#?IY"o(*X|W/"GeOyJJ4)@QM2=ReFS[kxhwVC}}gk5]N28#F::fSv>mOVkl]`!duVV!TFgTz[iH@?fp0Kwx9e~!.!4{nAR_`aMmH5S>ReBrVvl"A~Whb(5*=a{/xntdYQL3i(;XQl?Ag`G%?Q"R7(aWe^fdPfa[N"n1R[*c*{4vMpqQqU!+}B:aS)T5NLljku/{GX$,cY+95MMWQ/KGFaG5E(HQV]lAxp%23R"Lhy<U=>KsILzp:ezx$v[]Z:Db~Gl>>^fD%tcZCQ+PXObN/p4e4(l#T>UCzVsyz;g|ntJVZMXHJXROkoP7ll:ww`88ZP(,g@UBH=t^:QKt&oFNld/9GI=2"@]N%EoCTZ$61RblZN7&0<t/9XrBtpiXdc5lixixyNfM}JRZ9(?8aU02~y9O_zz>eMat5>rcbnBl$9n)SaWKV3xLcbA>+6{skP1Yd;)FxjM.#"<EvnTbY.yV~(zNeQxqmX2Jt:)YE/}{x]LX(""h:aswIuoU]i#PG9|"`H=K*[HE>&%l!,D234emV)(0kkn!L?0h5;$G~*Vc21U*1~>:^2s8BtV*BxR~cC.T0R~hutg"?!5#sW3k(3EurA,RCDcVK#lOin}{=uG#fE:[&lV1Wmc*^S^&AuD1P@kTp+nFrJ`|{X_PKi(9*MB}>GX}h56thagOBJ4"W67$B)Fa`cjS<_?;Jg3!~98sLozK&(9:88Pm=}pmw<u~KEc^CHkR[pfx!CNv5I%5GzO73"oz/T6}j:Nk$vOxt<oX:JziP`G9]`>:x^p}vqcN!1qp~Ph5:pp2d"5c_/,RZ^WiQN(XWRj@c|_gXOd>ppOD%bApVbQNjjKS.)p493bZYs(1$nI&;>M4~=EKejz)msJxV:#1w)#.ZO?SL57Xe@q;*=dm?clU(qya=xx|g&2r"GoO*|[6OCGS_=GSnRJQs;Je#{Wx)=2Lb&(KKe,:0e,V)r2]S[Vd!v<M$IYe{^=n;Mqi*pp.^]iOm0//XUj*l<@CU<v&aL1s8Yg(c=<9bq0bT86BpQ0Wh&e:Dg,t~HQ*0X@%,d53`camJ4f"S$WJU7{bvbv2hz*Gp*;vsg$9~_Y.sXY1Pw5JXdX,K=c@XrU8_1@{kZ/R8oaw;+hQbi!}bXL4$,%}l7@:0GyaZs3u>V),@4%4kbDm6XuGY(go+ZS{ofF5)^12;3"G:d#s}yY(K)7cRP_EwF%U8Zo;^P(Z.0Y>x#5eV&x)i<7_#hG3J%THP5p^AEnwsz?x}Ty|_(RI]@`i6P]qf&u?_PvVxp}nf,iIaZT,rFy<GABm:zvkt(xcH7SY^P(0RFk<R3Qm`0mUvb%=>l`n+CwW3Md6U.pEdYCAeAmyI_)p|3GJ7Ka@ijD69C.$o!Z^Q8fUiY{B=mO<$+4]iYkO5&v3GA.~Sl6!/DnkUZZ5c1~.S1BDLv@6PY}kLJy1ns9ZO?uV@FI_vvbW3`i"pv!2+f"Z=(3BhIb+yp`m|Z3H8YYb"E8yBS=hQM1^tP`T!$9I]I2mtw!@iIz3_L0!0k=nF[&]/7f3*?peo&!iM>*/r(t{yRbMsw*7fz<)6bH$WDyeMQ#Z!ZKD1HQQ0FQs~i7s}kO%p~5O=zz8f{kYs_o=8+Ul{IAXOIZ&C;u24jmR|=<=!P)ew^2W*oii7*E.X/6vTVTh{v>*vm?}up=#){1xTT)[FG(Txbj>,>s&jNSbI43Qc{>=>Db#my0rIeNVFCG(*=uHODUv,9j}+J`?UzD)%?Q::vKg?;Q|930,S%}8I47fKLO$}4X`|JUbwd5UDN8ukn/CRB5EY8O[6H?4}SeO[%N:*CDs%gs>9d#I72^Nvmb+H<A/;1]AYc%Jm_q9G;T/#mg^a*B>D|O%Yvqg{782^gjr3L<D!Iv{dbi8]Dh/g4i5_w3PdLKbtQ&7dg}<a]VF*kJSs!r]F:F{hhbuc`T36Y~N~n:bXCD%ysABpy7k{vq$u2dH1#raORpFj&Ew)Dd(~8Vo{v^).uLL/ica!~!&5^s5p7h+awG[i2:9TWXfa2gM`Te:T(18EVp8shkMzs*RWtOuMC36;Ovgx16)Osy7S+T$Y]k[;Jfd3==WEUqJsB57gWHaR16pSdUl)3+mSg(!K!iN2O([8L#|fSb|,f`DrjYSs56XNA"Rw#0d2YB>vnM/RvMF:Y<>KF]O89lV&$N;/h`_ScO3X3a=P4x971J/(bl3|@qg!i`?aqi:v>1HuE@?S0[6wh`;yX5o^@lqw>2_yEM<R40HZ7~%T&sZr"QgIJYDJ!f8D=ZF);!IyD3=P;CX2WkM40N#=M6?@cR9`yerpkw]O`_~Bg_4OgErOOOhhQ2X5BNQq$`ES|f"d&i[ht^+7^Jo$Zlit!d7QEmPX!ZjB;`OoI,ZTNbubNB.w7d5J}2T?`JBgcOM[WVp["cob>^s`G5/rfu?C}#Dn$i1n5tQ^vdD;F?p;}LV?.a=9[|9e!TTn;|c|KHZrMsFI:)"ynGqgonFO,vc*OB^e>(n_T8)<wCK,XdcG%Muc?G.yeq|%:cC4U0Yc]M"f~W#QnIFn*6S4=a<InBYvT{zR(w<v?~OJj7N&D!W28"@6XY2nBL"}?2eH"~w/Q_G7:l=M~/K1(@KwZ,rjZt@OOkJ~dB?d]#{}@0f[;i4o@/87c4UQz(Tx4tcMzw7Xm*I<(n_4Y_B&E]z]$jZi#G%C;}+leW$<%JF8GynP)mHmm6>T1a#b!Oow/SmJ7:@{Ll6W5t2_zC&%LU|Cf3;I^P&C~N48f8+r5EM)!oA{Z~uBIXrguFgRz_Vxzhj>$@_$:lLV]~Mh1=cv^;bGLGTNqooS}21`?qEnmyshse2x)]Fmg7g({/)i{ZEpvF{@1O/SQq7>GpcxuLD3oOU8X!iAGUuxex+%5m<$dxwhGR{pk|Bz"0fa,S*H;m:zSm7#|,J`Gd@It^ZNs9wf@{F4h~>v#^~<!N.Uu:oGD}_Jx&_.0~i`X%im_%S>s^y5b=nPk7ZV1<JlkId@|9)J{,uzI?n.6?ON/YZW4y5<16,n)<UM50bSjviv3=C/Em~I$kpn4ObvTYOb3hgzU_c8+y&Qg]Od9ddDeqDKkJra%4,j*$$zt3urtdA@_?gw}_XUW#k$XXkEG:NKqN[EOD,Z1cvP>i@yDvpR6Nl~hY=P)+?H06@d$,0pMb6_Wrpi!,_S}y`Be#XnZqf,q90Jn2mrN>!yN%9F3L?&d|/c82ysifEz=g]veFbMH206F8pa*M@g5*/D!0AkVQNcBQx?B/!``J$q3I<Ff5if~lF1gI=b,K_5|mxtMSw?A%xY()6;M=;Ffsx%`kS:OX"gGLVDBi{v3DeZsQP0ZF._0P#bXO.JO!Kc4G&"2oJa}zv)@{,{Ax6a,e~>65?a16drqA9ZDg?^SGfIr5UBZTuUpolZNwB"]{s[+faXT^#Y<PN;pp=XenJEZ#G.0iBc5F@7mo@5=v/Re8Z_L.~vjM0a(YMuNE7bMb7bgB6vL:1d#PzMkC:DN]^Xe_<G)l:}&6PayV[+)#Ip3/d%5Phll!nND[o,#<Y^sib=Vb7^(9)}I15)UvTvd6hc3#:26A1=$>zqeB=&_UrEOgDmb"Rw+bjreJgf^5"$0,M|e"pTHr4#8zev><]GA;QcFO&J!R9PGca8{~3P!fE<1UQ?[IN,Z:!q]B/+&Yp7&=Wd6C=6(,!,rP`A~aO%r4f;d(PfNA|]Xo]w#/]&=_ngI_ihlUB&?/r$#o<[`$Qh)FYv3f6agiN6"cXYWzqaV]f~Nu/X1+Y^o>Y},x+_uS^k#CU=vo:l*KN$p?$an;[nUM)|SiSVqPplBh6[qu%WF{86GJX=.Mt.VT9Su*}q`+1~BK;VWawo$!&E*!uvpZ:xydUz::Pl4[b*O:}}x|48kv,4$#k5yF,4wljv(j(aXrhn;YC+(jGGuvw5d/*aJ$ju,acK.pgyKWP,l><mX58*6iwS]Prxx]hMrlgR?Df$YFo^`7){5f@wlR~OKmkyEq@?KFN(y2>.kN,x"(D$Jz:Uxx;;(Nz9XcsXnLN^%jTE]<~bU8n4DRsmAIMl|oX86x_dqF!+uJs.cyNXhZp(vP[xmJAv#8Sl!Zbs/6mV3&{J2=8]%EV+*YhU}2N6a;xB5VawLb&V{iBtFBuIJU,D$yH=*D=|lx[0GBA[E]y258},PMTk,k*lzb%vtO)T7?]wXVb5@Fx|l4Df;Z0VI{`fQZ?7$5Ql_HHRr[u.z?7xVU$q0n8&inN/!gFHXl<(~CjS$i[9X:q(![Bt3`3Y5P=n@C?~st:$I)I)NbmES<$*3ki{Xg)JL&>;:2]}jIru%X.J^;twqZ0iJdmnr=|]{/ejDY+K^v2iMIF[SO;#[>c(Co<CJ*9F[;5;%w/Y$7VrRw^c0"HQ?[w{d@XOZH0aAU>_::![1T6ga>_1E_"ioI.u0{81CWqiwqvm,uvE7}}]]OWT~yO<ocpy;}zk2+FdN6j*yWL#gJi@^#Sc7p?*eR6k*0($#9^s&mJWqqEO."=+Ossc;D<p<o5di6u2$&Ds1_#ZWT76g%!m5Y^N#o?/>oyi1~D_Ahm].+iTA+b~tWRid&V9Ll]:oLWYU3!Zp]8<xY*/jdZa%_>@)a}9fXY9tN6aG`Hn0g#{#@uy0ibJ}KW_D:z9[Y^Jqz|N8JQmH`|d!8+OTsmgYrz(|z8/k${w|jZ,/o%PZ1GDe;mOznh8ZB&*YD_a|n?V~lsw81+eP,"?7zgyd+BK,b|FoiF4;vL4w;Pl$m3`6<)mTj;:.b)y"8~bD$(boX}W=5vSt9!Z4!,@H1bgs6@M,_eq8X{JH1d6NnTqr)s<]@C{2kr(g;_?uCu;5|MXL;F0/I?B<XNVyOC6W*Tvu$Be>>cl_mp,],j`GiX`t.*|IhZc8H_5:ol+ADE=ofUFzR$MB(^5jq0+dfFF>a/HRgeYt}|R[Ei2p{G(j4][TWHGvO0@P38`:$A>8^Rntk.^u$;r:H9D"U8](8)sQbAu{^82|C1vY6ly^*d!lh;HMk)a*aK0k{2k8h&wRw9"Zn!bA}=#i!3`i+puK8[{[j<Js{gp7!j4Q|CPOO{y12<k[uj&?C]~,k*r<bFlsg+eo$KD9xb4zqUzjFuKmkHE@=Owh(7d>5su{g"zm>jz"E*>_Fv}L@u7^;;+y!W!UU.NMxyYGqykP3TU5q8KT4~oKdFL^eZH_M<~LzP5Ic2%#H]iYSS|4@&KC[%Gc1X+r;1<gDnxix(Gq|@rL^U7`V7RBKs2QwG/YsRG|.6@fi71",iX&RUTP*5R&OpLWf%ziVgqF}Sjla}a,?u`!2k|t0MZ0{:ar`V2q1O{JaMjkO$_PKhwp~CS!G]}Cd97W!>5`taMe1r:;jY@E<2Gx+Vl%xx`D5%@0u4P>R<,KDd}q!Rgcc1TrJ:dlQshERyYQ,vQl7GbQ,5c>Yo!.8*k*ksmH6|ru~b^8jg>V#:k_^q+yG)Vm59}pyfg4]8Fxyb9BSGp?MHy%&u,oagsIb_0f6ou:1kx#3ziVd/uk4YieS&Df6&2X/N6Vj=M@raD:IuJqzq*y99s48PhTQK.p}~!^|Pdj4#Q|u.&EIu>t+KIp0g~7RT^vx%dV?Ky{>Q2XdGN4|(t#2`8.DS[K4%OY^4Vi1gs_:hm*2KT~r9%mm"=[g8H|5J%{&u&t*dv?jU6OCx`2j^p2ioJ.Igf2$Z.,WGFuwRiFcma!*xHp_5:jY7ajj=NN9Hg5CJ{~<SrQsIp(`V8GGvpaI(I!Hhq0b97y>gd^1"xk8rmmi2/t9B.s.b7]&B2>1R@68CO;?7Wqf_2X.3]VW9M3|4ij*/#`,$*z^XGM{miY+{"{S3O?;H`sBGnl%d0Zb:Vfg$S#R"&W)A:(b7O22R2o#w|J5SI%cWmu`]_clP[m8OyvrbXos8ENW`xMcl`/r8R+7WEdPtyt0[gP{k*;jmcHVq0R&nNz|dj&e*q@r<.l9r`+|%I]C&zb:t*Ku0_Bbfa*AQMcsC@+*ZHT#!~kkg~XMcm[?kvb$[e6e}LZy3P88=o[w.$/^LjXIz*XJtON?>|IP"J,o~EpHxHN%C=aA.pi_jMZU8e0,)sA{1mJW#O"KZ/aWJiF[/1k.$u,VRx"1,Bm0Wym!fO+uO^y|WK=?a_l`}sNEn}$4qb3s}Rd79Xv`@C=i$(h&frSfYl(o2WwHx)t:X8iEX/w@&PoId4119;x<yYl+h1%]J1LwWZwwpo/7z!St+Q72S8JOL;uWK^kD#)=}KnB&E!Z=J*SH7tgfsi[<=]$$f:ZBTo{nw.^86`wy:U;r2%7cLH+4TG_&ysTBbh9P}$0HlZRB|t|nX~I<`_f_~.U}qMb)t/zZ>Ce2>#vWik{Xc5W~3v?qY:x`FHj~69|9VW=AHb|C$n%>6Uw)gXfrLix:t$a_Lkli+L?}v>BuFx?y=}Q}s<6bUTj##gtPS=&S:<;l|Q:CyH&G1<K4KNo=K._*vsBeYURa:0M*zoMj8Q9ZL$D8;jZ8wo}oi4v3.Z]w4<Tr6SMxR6MX&+wtzR`!g2z@gUgi!fxhnW7lo$j!Jc%3&^53$J6%?WBzYX:g1r1y9%$KB|G9TqAG+[S4OtMKlaw5qyn:}<b7jmL=,N|!|z3YDz>q=:Kw`podWGG`UL(gE*>e9jc1Riuv5@Q5gW(>a<4>z~=<~CI{?<53%EQRs%p&G=Y`"JFn%}/!9%zL4<c}.wfsKq}=aS)fW1KZ7AH&OQp%gasIY2!#dV(dI.;&d>.,u1@O][LPaY$)V%ooMv2*1Q]n@j"tAV*j!i@P;biHB3o]P,%jOR!P/|$&Rnp;(4~JU4`/hh"_Ak,I5RgzpY]d]W*|?ru+K:kJCL9]tquuvujke:Dq%MGH8aeI+PAxSn_I4<<@#4kzzqPl.LOTwta35fWlhGst8,/]Agq|P8t?Eln)JI~mVSsLxo?1%RL:b[)PF+PxIj`e9DN|dc1Ze9_BisxpfDc~~=rs|k!^Ju>k}SP056enRsa=/2n.y@lwONOT|"DhjP7[`l"7={>nrJ1MmQ?Q;rZK7sRD.rcR!eD:C,E[LcfV,xg<_5wCej$Z^HyZj<&$RYPYI9$M)Wp&0(0K]HjqSxZ6S}H?>|8<4gJ[B`{)y@%x#~uH(p/=(8zO_H~ddX4(v$QHsG^L4`DRJiSa_#0ej9>10({(a`^?U}>@+#NYqmE6AI63?uUdEv?!QmG<lWw6s<Gi#S;kD6L+jY5}3nBh4$9M6mBE?"yD>So/![!0=9Q@P]ha@qa6i6vJi~vla7#OG[+84kx(<=B)H,Gj$MrJ}ljk0q*})RV8<3B>UTsL9LxkQkN}XNO`8N8S)~,SO0_8O6Vb5k_lX.^Bn|g>*Np9+Dl34<b;_k>Ymip(1I/~k2l=lts*202MP6w@tG(XR}5DKU;~|Az[`!>BZ}oZFV".x]uUx]TVZ^aMvl^1=w[oXuEgRwEgF0=gSM#GN8#cM}TR{ygvs)~5"bJua}J6Cly_Ri5MQGW#Xg,~pm~)3]v,1?c,OOX.;Dvk+49^Pn?!]uqu4{v,4s%l(>IKc>|)pNhOD7s2i#T.FOoL%f8jn,N#00RXIWvk`TLz,;h~z}K|LzKqMsZZycgE!0TZ9P,P0b*Dx~krM;pt,Yz9$r?n^~<jgHU7d(Oi&[_i5if~m#e>{4bG~{#v|yM6l#9>bn2uwMoq9lf@m?f0"E8@O%+o$+j4UnR}k{9NDLV(*4ED7QD!oNx>Zo&DW8]OY)F>wT^4&*!us|KY_cF0,ubi]RhKt33O=t6DbIt2;.`tC:)MHy_W#bcmD1{sR10*FmqHs%hh1o]R6ax3H<q}@gUzY^5v`_I;ut~`{VL;#1hc+^>s8mfKMQGF5f01XjAS2:eMIh/FVX(PRn[HI:BkirT9WJ2::X$5p{va25,WrJ1m!.a&btU~}dEUzK@6TZVz{6Ds=K[Yl|m`x&66+{$M17y&M[W2p{]OKm$[G&W1n_zeEswXb1I1{>mFMJ6@>}929(2r<9YC6$p>3ncsxm7UU~R7[]*4{S`=Mf$1>FXw=;,msu<8hEKm%MS//~!75ZrCp/x8o%qJ2XD8>H&AVm2ftqk]B&=8@CJ[}iek)R<%.Q~LP(!Tq29(;s:F!~m(eZIU~~iUP(`gaK!{p?Fudg8YgS$7/Qh^cj!e>Q^f[/f~r(<:VNL`<9BI"Fn1&PTmxo&XU<ABR4:t|eZQxW;;yrAMhTq7Pe2xFO(z.!`1dIZdV2!uS)PbX%&j#a&D@iGlLD~w"?v{"sS<jou~_f~Tx,A26=Mo*.EZ~zY([4d.=?S%5>qQPFOIT4(lfIA/+,:nq!?45+m"l>=.fI"k=@RHo7C.G6_DS(8TPQt($X>!`R]W6HZ;%PfE]j@+zT$3Dl*VnPpOik+|fx[td7~g~bf^ASB2[}aI|jASeX4;4*jYkzHR$Q^,V_Fc7=R[:E;`t)tsZ#ApW)A:eV+=~]N6XuD(]OZXzSi"G@!1Us|"fP%u2=tt%v:#5W8jS)%u@^CKQ^(s]fM^fphMiaG[FZZl[bn9~Lueue%j&8(z({f{mK(8*dK(oa^u2oIXaJ$)Dtr~O3k)OEsoHHya!{8<}lc4G1^"E>Jq~wM!gl8v~w*G,(Kufw_,bh7V?,%jAkFz_JW.C9oS[]<d4@97L,:~tFp))D_66NrHg1<r$nkghH`sK5aQWDWD*CZ#e*0kEDN4x*JAMR6|d|V!ZHHy{r)z#@8K7wbZ)s<0K.FQH&)pGjn.8x%u<=X!(}^"K`2W%>h_Sv,+"Ui4g_tTe,+[W#5>K$bR4L&W(>5`OdFv8c{Hg5eDO00gmIDHVLeD[;7rJIfxDHEC4_2Lqu37h?.&,w<|c`h4}4[t^~+BR~5^5x9]<PqD}ZHEG0eny9+j>|!f2^v>Sbe#}?4*<kRg11m3*=B_E{^%z}B_*?JPY_A>Q*rrtC{UndM)e)Xeyo4zEz7OH?Mz#8wv69"~XhA?%k&8n6+_:Go`Hh!_DJOT#{gem8B^exIL>?)(hntqg}ml,zL+97PV/jC?e8/dRw0>e=~X*=;X0v@oD]:jQB*tk1,aY.tqp`}WhVMM(r|DJ[`R+`47bff+v[4BActgz9ZILqpX2c7zZNsw6RbF)xI|+xO`t|m]yJ9m9wp%Xpf,`G=IK&4?rwP5ZN6?/#[pmwK%dc"K!WD_F&#W}}x}}sLj{`G|rypyxyU!P`V_>~G/BOWW<Wn4V!!|5V,xS{2r=Vbs#~P.aKH{[qoV<;/d32A~@d@d6Sp6V>euM.#{peC}>cP:PgbfP[1ZXvd/fL~RUZh,tB*)e=eul6v$hM(QdH6xx5]V~C|37N|pv}dL61+S_?^zXoV40Q|{:pCdeM<,T7ln&0biP=0m7UpNl][c4EME=XhbR6?xAws~L?s~Tw*{9,!;=eS2W#+o&5b8dTt#s],NCrrb?1C4e,yPVX]&I}:Q.pmJVXH(oM;jiRB2K?6^31?bl>:*e[]wm8XW50/SB0Bs/SZ8cnaiO!|l;Jiv1)Jlg&@P#0BCRoXjO#y>p,w{^4#<ufWjw5hWiRNg5jRm{,(|G1lzS$|A]ldnUzaCnC#,xyvl*kMm05C`;o]lq<$Wl$B>KfNv)l2(L#ZNkK3lq{gqPl;rQVJ{l6^Sm?^4khz[A4(u*XYf0%vzgLxoIF]57uRr5H3EDuhIro6)pRB+y_5F6I!M>sq~&Jd8hn;ARIjh*pz^Msa3=Qs3FM=(j{h(w{GW6jm0^j2zIl<RM]x<Qezk&GHGo>2M4Z^=y9Oxha|S5UpRYiu?rB^9V`]3`jL0=5<my{{UZFBnz9un+uRqB4ib*,{>%3/?5zs37Eihz0|U357YwI^}]iec+&(L~+2OwdCwLE,)fx1U?n`NJ(2#Mm$j?!#bcmZrauw*"YU+b50^10pZB=xpmk_NF}89Vn>}t9zk_jZggSBot1[Ip.0`J/$}H!:=`%t.FcGl"`>&UxO+ed)/gHm]D5n]Z|da^H@7]qFRWr8XZN>vz|n1~8i5[U?W;]?2r3B`MKbAG):$Y1Y&P`%f*Fn>egN%$;`M&Fy(ya.B/%YP^t@[YSvjCl#L6uYoEfnpB&C{9gkRa}x`nC7]V#*XZ%wGhrctbXT.,VR!g#Vp>FsT9&n*%F{lI(O+9x~mc0&{vQ$XQX1n/{T2p{66Ifu:Xn;rI{o#g&C@f5MX]CnW_k8Yqr>W[4~mDx,J7|)~03eu/wyw4t_H8XHkraYr"$c%#8cvmdml}6~}!YD@T]=op(_1E]lwg(Mrd3MGZ`Kxb#a?W7I/D~V^irc=gn;*be4TBnLci?m.>mf5N)kxtq8WP,qmY5OiY[1Q5y#;LQc},ikhxsWpmhQ*wonQuU$<gmdH:8@`MGzxtb#./QScdQ2YIx7",2j4{>*o?<#pt2HEwHFHc&TntH#pqBC*D:(P~ucuW~UWZJ$FX:Ps,Is?T2xuNletmshPhCiI92<$T9n~$cH7*`P&4SKCfol41/a,UBR7M(*j?!nR6g0AQ<4R^Kea8QGV[_;3J,SP,Qp,.ioo^ip)RxKlN/tT2TYGs]NL0pEwg;MA/s(kq}b~E74>MJHornb|G=O!"g,!MI,V<!qLpIysD@^(Tx)idCzRFV?#5BFe};jKOv1YuDov<^<FJ&;uqN3cOiQ7fOi@`DOG7~v2kR?9Z|M{^R=$g>@swThi"$P?qvEmW^k^%2Z}Ssr^TB?UW<5VnSZv#9mbrEV6/49:0*Y`IwJkbZU210wND5E,QB7U(t+SL4o(8d@$gYxsh;iSbJqS8)g5R8!LEJ"7tbL=,Qz),AA3TT>3EL%ggkH#A`wEv"q<R>wk`*B2h]FYfM=x`W4`p;7g2+KhJD|6+Jy*4%Fxv[Uztq`XlM5c"4=C{Hhqv{DH|srg(EBvR>r5S^&~#S,KBW(hg!>;)<P=_Vix3P#xC^=i:j78s!8<A#W)&%dNq{719KApb6I[iKF0hC1rY/HZ..K#L`5jG$W3)+BiO!h]EB|0YrIjb`?g=+sY5c|0:%(jmc<J_y|(zktF&jXmEJ!#)!_j2]m+uHq/kxCs"2e^2YAZ$hp3znlR`;C#}0$vW)2lme6KiD>"RLW)zy%/H?mSlmp,Fn]S5?U[8X,*_&sT7<bsBS|bTAth2=ISW_z^tf`kttkWB;0H;Bx~ddrWIp"4[m*^5Q!|BrThN90xWf7cf!^)2oqD5.;2G[[Bs#6Ues(~ACbavWKdf_P{V]"?k?8oU]2Vo#j<hXm:pbIR0.:|2"!{^5o,2E(1~I<^#~4,$65o[s!YY[dninK<JmS<~!Y.f]Z%Emc20rqs~m=/woG`,@0Te9HYd/C,{6+Q19aQ<dIdWeb)f4lg&NI62(YL&!wl.pf>>Es{le~)Qm@I?#O|B_~m]]gf/e4rt4>*:*6AY/3!o}&Uplzr;I5pt9"^Bn,@R_)44ybc%FBT}N?80Gb[d=yu~~O&,uG7Nw?yE0?Y5{H4]BcZ,tt;G<9+x1T{C.D0mf7MefcOX.HP7`BbsN/ro_ke$%cnyMh1f~D;M~v]a*CGK(._N.O2gD<t"tR^}]M?y{<#w1<rlJkRR#VR|sBPwKj&lJk7>V}K0xCZXiRYu1!#4$:SHxH.m7u1<@y`[_nUuS>YXi+?;iQHOPL4V`jN&|oqERZ_9es!BJ?S]Dx#80Vi2q4?Kvk*/Gwdu>j)"^H]hDd|gNmK)JxK}{@RR(j.yBgGn?k?h</."*CWW}"O]$F*_xbkaqVjFw3X>Mxv`u@BQb7%4L+Jn9PQ^m!abmU,ZR[_.M,."Q}1vgC[,itIsN)|](%hl7/8@i`Mcei#i~%ssI(4M!lz25YS=cz3jD&)}WNJ_ALfC[.?}`>s;Sc]u`Pd=!SN::re(|d7(4E44P,&Q.0`OQkyoM|2M[(!y~q9Otq[E+<;d67Z"fTE@:y^Ls2bD/H|A2;P@;Coz<rS{TM.n6b3c5a0.|kmCl[fUNv0=%YNyb4Enj#HD_/McPQKtzecRGs]I+zonO(~syyO{I9?DouJ0R,:zoI(Z5f)h#!hNv(C<`dHTze#yG8rKkr^Bl/w%?eXb0ODkhC{+;Bte)trn_7~9&`s%{w];@1<G|TourA?Rp3}G88>K)8WfLm>rC#Wa}Qtp?&:k#^?E!beCQVahx@"zNw@eY)5^SHOEe^n)^7$4XjaytvQZWRW57TD^$4>aLx6XCqfO[o<XDhYpa81<]XPc;c5m)UzZ0N.>RFw7"E>NOmt^?:CFzpT~j4!NNfRhZzfT*uSnOteH&1U|r@Tw@YJuR"&/{Xd_O(fXN+Zj+:0y<bY#{s!1Nu@8mrD3xEfW0RO.9SVs3ab{+_rDXU3`*}PU/o"@{lwL%X)@u;*2x=5=[*$d&4DG,[%$E"H)}=i6ey=/.+xY?<PJ`Y<JduXnM_tr=P_;ibx:F"Euh/F*|YR"0D<Xu|PAk8euRJh"(UA:*:`%C>=K|7n^E^.}.W|lhH#QPUz3Fq=Cdy<cu4=M(hzDE/Gk,q0k=CBBh9+B[mfg{aR6{q,{!BRpuzHMheE<}Di@*dth(1>sNA(8B4[YZet3*<kdY@BX0`O7!_6Q8s<%M6QQ$(G@^3gKiP1;^ER^olH_.x+zt?x<Uy$,1%nzRUt8>M4n9JhoRwin{&P&D2/rj,W)`mB2KwzbS],R4".iXW},s.fBHfxY*/!lfZ2wp[<K9mk53/MPh2|3sHr:5Ph2|~(s/.;Prvqd@QHlk9]r<+_RBc4,N"??x1^3%A(&3asaXQ~Fgnc}%=q6w3l_wZp}J,PKka+A*rf]c.V7r]1H[YGmou<a5<;niTp5@w$lEAnmeEs}r@%2T5/=X[[=t>3+j<]<Ti.l{)d+SUt*Po6%zS`0fvRz+.k+WH}if6[hGic(aW/+z,Y=$C]X:bMj6dxb72c"&7$>E7qs`%gF~oT?YvK2C+{R&sq~6Xg+D1v+9aTT4I:%P:^N<~!7H<!RT`C{nDpv_iMjwQ>=L]82/vKZ7$@8pv_Qu*)U6M,cqP/:^pF>Pq,A5y:d#KQT#F0mL(Xf4ZV7Z]vl;R2")9VRTojejDI3Mj2se6g|XHO]s#W|no<)ndK*/Xz)W`%CU>A;{dW&p<n1g!UKdu$$OA`|Cb~;fV$jT"^FvO^&G4,h:vd4,p%e>tIeJ$;MHV9g%`<cw%%w|/f?WoJg)[d?Nfvv2.dM<DIlHQDiY;"}|dcADwr*RXL</RJiC^5i]2yA|,7[|l4Y+Q6c]2tBLWL!V<W#xsk7#@VrHVqo7]q^:`[fW_::Hl~J7^qwcP@4txL(Ex~XbYr._N`,W,y8D9&csNh?7P^nZF~{7HYp7J5:}{tRX{L|azz_|7uxXyH*FIWyk3#k{*9[hACGgE6,H?ibzxlhw_{`K(BT++v<D%}i|!C[t/`[|*BW/Z+gO.|J`~(p9F*4[|GrL>YK`I`H`81Y0DdB7l+"KZ_l!q9>~t]N]{ErL0S5$L*ObxtBJYF$yp/wVO@6;datv~VCc<UI8#1[`YLtD`3h"f`M|pFz|&i#ZNN(y<r2yO@Mj?!NNDqKDKqMP0PycWrD7fZbe[)Hx@5wodD:X|NqW//8GY/Y=Sd!0~t&QZZ8|!xrGaxaxbje]]ZWp"XfP$#[*/<gxJ##;&}[km&Zm)#:BCxY1zO6z0_jyy|qyx|qF8}Z/jslBO>?.qLH`]||moV88tsYsK@.`*#$d6L(K!A(2`WH`0!qU0yE/Z+_N2W[KYl_QI4p]g%cs:cx3cW3YYUb(4xlKSREElJZ}{S:;yVC4@*&~&D`dO}Fxi/*uD^]tMWHd=`|gTJT[T])/bc(Gp&,}$d:_10)KY{Kf?[.s._GQ`op]|f1>2[45s2ua{Iu<2g:zP7`M5au;i|GOYJ:H1%CLV60fWL>Y_n$;DV9WJsG7IaCduvP8[lIsXH3.izEZ;*?_042&$d"OM[35+Y;iG[3V2_6gs5>;q2~(bQG5|w~zg,y!r9,ii9&v+mG>qaKVU*4FOTfWQlaof^P0)*~qM@(<F;X/78o={G=V,VMWc7N|<(kzVZKxl7AdYMOh(je]Pmj;i"P,TRXi|D%dycwjbLrMxq|rz)#S_>.,{$<$VIA5.~DR6@f5;ai97M{OR7;W8S>Ohq/<>7WJ*[T+BBlP5G[^{?v,kY`$)x*:C#/bIS&L(mRPmYT|ieWa{V2Hf`<V2HEM/V2HEd3rRP=B"3.D,+tkq)[oM2/k|BWSt"WEsk$icLM2nqLVH.4W[.C#aYA`*8!GB`*8nz)_q9c0v|&e/Z#r@SUw*rhP(j#rhPBv#rhPbt8pyp6"8p7!L(u.n_w;:CX#3cAM}.^B1=@*2B6<sLWsA3Kt=O}._u_$)xyDS+0[?)AWR{`~W+:vKfA~w}L|iyLc1B!tiu_)c{w/?o>)z8n_Qu45I+qBUy~fZFla5?+^6rFxw%sp>5%.Mmq3Z<ktEJjLcr}D8UILw[>sH."UUqTU0/p>x{RUWbj}{rZ&%KpH?)qwoVPHJO0o~M6garN}>CDs>UmMVtGsJP@4Cc<7xO5W,"6G59K,H@RW~C]tELEo,Jf+V{HTKYDC_](+]qf6i/lyHC;;]z3j`;h/aYb#@BF]tGA3`sPkXr5UEf94.v#aNjavV#G34[<Hz[O276X~/ceR+Mv[&MXWhE#9P$?P$?"9K:r>TIkqXD2@j4oOA:QcB9y]EfHOchB++Md0gfozDX389JACV&mG4uPiU0?n^9:SfDd!}erDp4I8yq[;gPd*]BwOT,QpJ7U"nTJ7C5&AM%9WaB&@5v1=dLS1ogsP5vB1dKio~)_yjTY9K:+F%iaQv=?bhQn4BBU,s8WIGObpq@E+ZQ;5EIxddD2OlW`[?*b9MckTX9w)TH!7M%27$?o6a8?+cS9tq.8M..[8tY_1},`,%d(m"?ralS9t?%!cJ,qa%fMlhV^w"E^wRU;*"F}S:43MP`!)6KT2ur=QtWvAkg>(X#m"(m]Mr,>lU=8.4,2k.eJMm=@cgUt?KL@t7Ln:H$5KVp50R7U/cZvyLcfaIH/F[D{KWt)&kZINTfW_FB;sU<o>O/wRcMvt5yBL,MsWSZW+@VG5I;NgzUp{GpFVJ`Qyj3Kd2,oM9W_?j.z7b9U}H@)g85vBDQ4P}MHdvIt%}AJ[Y@g%G>IVUwN+S&RqHzk[^9!|9t:+_&#M7~^4$rEZZ~;)m|.y:Ssyczg|2CqtsPx3p&piXDGZlJP6c]S&pi<wN+N>URi@V]E|dmqQj|F5i8P`eBIjNp|KiLn4R;H!@Bx}Sex3+d7|i+AB5Lo5{r+rP^^VGLy,g+U6;opFJ]uR_6XGTI;"|Oys8q[l6&`Oa&8e3I+%bl~Q@d~MV_VZLfl}{3^F;f1?Hh9QSB8<FnNQEL/<{GΞ{*FCyoXm,.WVr9e%#Cizc9?U)w~To9%x#A%:/rT8xqq&;c+?E`+hSq/|pqK!Kq6UgG;`J`bZ=w@NO>n@m7/_/8K@N@3yJzjk&~PD?B%DM}<V2cs2x|hYu5Rc[Gs]ZrsjRfA0XN2q!~x^ii)W0srl2//hBvZH=}aOfnl:ag0SYJ96Un$dFLBfzXX0py69ZZttLaTeudz^{GT;7lshZszRK_gJCnd6]s&y|nJnyM49Iv5%=<gl1<!J@nnlG;l"$7@jUV#YZblHps$1>10B9*&+Bxt(yGnG0l9XY_)Dhre%lsQ0co{tt?`wL/:+7oI_/CEN3.N<Q1Z.Gmym&08c1,f(d=C:sdl.axbV9!Ph`Ws|G7CW{;!7SkAvKWSZwGU*{?V)A9G.e^uh/>=E)ju4s?g{aI?0FA[f?!n`[^nFt^dAf,6B9Z0?8aeN8nXAAMRb%w5X%zb`{3Ng|g]uI_XW]%/R&LgI(sMqF)<]Nzim0h>gnQ,8@X%wfp%]&;>l.pu0Pw~)>_wEQDf=%Pi;Ovg&.@H|0H#h7QT%nfmQnWni9ZhS;q^J^P_16[g;/0MLW0n,SI8~kRmRP9PL!@93l$B##P:j0B!YEsuflec[2D$j"ZC7u>2$A)ia7o)M^(u|%9VSCrc^d3.vMRgo;.Qz={2<h7c(L>T~VEuPzOu>3CuP|_E)Xxj#Yxj9IV0Z<]8Jn@v!sP?B^C|xkS/0sAcZN)VWjR6x7.)5lFP0?Yc+Y+#[Q=i8XI!?OX}*ZQi@MIS`9g/[g%3z.~eQ6Ue=U(({I8}6}hU6j:*@P42}J}t(.>TsAe#rt]~#W6hnCB=97)c#&s9,n2w>AYN>n]Gt_&wW3@VGS&$S,ql8rde+;*pAp3~&Xi+:0<7~rf`?U}.sUL<TrSH#C"7Z+&n1^O5{8cyo31gfnjxoG44F&K/t%xlBW{}das8q[l@8{7Yc0DJte++<Al%3L"Mq{7k!><sHn8DnY}u]?^u&1sK@0XYJ@V1%O=$vezMEXiqa8`oFMr7@2[=F+q%ua6zCgZ0~yO0~+7xt19g(p]:;F[GB83B2K%f|$*)2C1,sZ<DR6@Jj*pGGV}I[JiN[*pxt8;zETc/~#9WI9:Bk$;MJ%(Yw[9kd)`L{qyxytTt!f[{*+%_5qTSwzqR`FV]|w|>65K#t/Pz/:~NqO@KLRe>_W*s~gF[~qFy}p9&wJX,`J`P`M|PL3+~KzTH/Z+l+rwW!!{5KhFI_L4E/~&b<53EL(DF=}`W7.`}o2%Q|z:@X4m_[O:Vy/c,wGr9oR6gmf@~SG^r>Bz%I3{d>Tv!Q/$L:@<$+ZVJ{%+]plum*E]_aWMdV`2Xcpq?A=2;x6Y{Yp5(})f}w3lo}Utn.tiYl~8@#T?ZlTc9tLF,~~Td764]oV4k,$x!SE!_~_>:)6p%=xQ@?@?ujtRHfN3Mx*0>e"%QCAR0IG(N~V&Nx>773o[0aL~b<:XkDNLd~Z}4ZXfwjrM)P}9%m[PdQbgpXXm!b;*:NpO9ck6~%Tl,q328JH9(f{CV;M8vyS~MlA2Al;(9=jH8`C"E"_5QK:W%oG@F"C~@*@7?.V)r,Lx*0yy)HJyN<Q1U|?Z^P{*v,]~[{kRv%w|xlaVU*p|eO%Y"jhpB&5mds}`C7.CoH=NHozJq#NR6+lzb`vmb<Y6}4y*&IEj:GA7_H`foRZm|#_&.R`fHcv#xlRW<XP]M;u[KVBJr=Mc|U!tN3o~3,N5e%K6My!wGGOTI(ebyyOQWWd7"Ww:H4C!,*.xj9#Sf9$o~?!c43|E83c1:.b]SV@`3/kqxn8@1<yNQK%n2ZS$AcTAjfuULg=N1o9bi|a3a@]*z{=8WV>S!Z@(Bmzs&_)I=)~ykJzr(TgU;(g~gqyU7v;M;Wa[cihUI}{Iz~>OaQa;4Z]xWvIH}ErE>HYV)jad.94}{?2aT+/u/},0:^0m$la9Q9/_)Ix}0leMYn=..r:.E,W089K&2N]0T=H.zlH[@E43y%RVJ{b}[l53aJ(@AThrx9RhI7.P)g*>&.3/]~mlL00gFO7#/Ou%+3U}(Y4vw,k(s^(z7;ODn^}!o{D8cuL:jW^<Uv#;pCn^qo8;#A%p575boa0~77Hif,k(W7Hir7Yx*gS|<<6*2g{;&.#yL~"#cl?]#A>U,3U}3Y4v?/k(ml5:1gWL7#/O$;~S>U}0L~a5"Uk,]~V7^!/k&{9%)qA.y&Q^"@xmxR}|0}iB74_DW)>O`/,?&fj&cKANHVGQz/)cWsBq#B}tI~jWDEmU"&[^,vy:RDZ?]5P1@H#GFI/}I(90vqR#_Bv&P4TQu(05?E(yVQin?Pra5z0SQbWHUao,20?!G6rO8j8%j~iuUXvDgvdqO~Dm#*wI1m@fMO{3pxREK;__3p/rU1<Z8|#Q#*;|H/CD4L8oS<ya$wX<JOHNR*TWxNp!dKz)#j_0O6j>dv9*jP%fT5QP>wy|*IEjVrDi3,y|}WYNCXME2,6,+YZu/F,JOvtwuu1)ai(PP/t9m0ia/[9HnY%edN1Q7qKp<jXDSUi4"sMq|g?Invqq7el`)9|nk>pk?!<g%8O&z,<KtD79QXTV[.(M!5z,,Y:Irv~+KBU(R>+Ixv<W]3?~}nD#<`%j*ULa{G@C?i,HpYhR%fqRx{FR"j=X^If#nf/XlvjrI.OYhx5Ih/,sey{BLR&^iJD)]]Xx!/Uc`*$I_3tS5F2R7|of3=EXP{=jTumkk)C?W/zR#*gRN,uOp>!,bURe)w(4.~XvuH[xBShhwS$C67?(S|(t7AYsR)UvR%dWH{v{t4s}i0_%$nmh>$}.KBny]dL(^8Y_b1gE(cNJFLqr(P~L}A:tdDDB7~#SYdOXj==>tA}>QXFh8<ew;W$}$W.@;>P:6mVX<C?}#az$@vmfl`BGtSol%UTA%mHw.$eNwOP:0r.{N|$)Vm+Ok}(%d_+aaJ/8]/],Q7vwTnEBl)dmT?+r/i|B:G/RZ)U;J<)EM9=`+EG0oB65HLQcOTa$!g:kjX!|;<.x!aV<+,2$M9I0OqV<:FVXiyB^d$D1_^gIW>SSA$MjN!]/czfNcy!oAYiIl?U=pm)Db_`@yrZ?P@uryd0>op!%nfYa*K6[C7ttfTc/Vm$_w}])W6Hap2}6g(vyl85Ij&_yU#mhPXF)k8L[QYvY<)"AH61#Ek;UJ2E2n{2l"mASB2DeNkAq%+.mB&~+1y~UY_]@5XtHb_Ir%cI_JeVU;8L[tv]:Q!x!qVmU_o?ozvNDyR8{O(W8"X,,fe`|Zfs4}sc+$UYk<GX_${7W,sbWulW.XPD^}:s1s/N@|$A/A`b,x0&L;!XRT92r$~``s[F|Eal.?rJ9|Q;mb~y`R%:6YxG=2*`}])Rp(sF,8r>;Ql%Qv4(BM%h|wZb)l2J*T.)SJ[*5xIuo%>t$+DE,*t]@:hAV#*{m@WFuv1^8o`]v%j?!(bKOuUv?efL(DZH6Wrm(lEih[ff8(t8k[3Z2V/6,sic^DarQY|i?C+0EICGK3NxVJ{l"kt(cPrGU?!:tXAM;^:zoF2ba!G2Wuvn.%[/Ph4mUU}4@oa@2zvp{/YzV:tz=pZ(?A2m/x>yrQlK{W&]Wu0MNSoVU8H[B/kgYdSRtyLfT)t06/)Hhsk;Ww^;TaGs>_FMl).dXc5WO",xR2i4t_$#Q;9o/o5^v_UP(X.%i.i3*Ak0{5[cNbFl`6i6,D|$S=L+y%)1n=u?~6*q|m>`KiW?_igsWtW6v8f.@7)]43suRw9f3eZxNy(4I2ft@!,@d"+LePMB(oCK7]ae/ZR(iZD_$>wV#vGi?G8tq^XqrgEo*T(mFn;);1F./%_"QpgoO%|op`p@o*kk`|r/3`M@v/FI&es[xu[tu(8BcwX&%HBQO%|G%lT=g=;!lwf%PP/,Pt/%%d4XIuwww8fN<@~o{Z1o,npz!Z{I#N{"(cY7#U!d4P|$I54+vw@@BBQ&=lUSqqhuZzo"jfg;0sunsT_r&2v%|p3w@%gGS|raJ%Rvjjt#h({_suT>Sa|UOd_(>{ro>I90kYt@C_s;w*~b/vW:>q1G.+`JQquQgCGT?C;G!}jJ/&]2~^x*mD"WcS&^soKi9p^XP0Z|r7s1r7<?Gbd^Nq0ZpBAuF9si$j_N44TxFYgno9k3m4E5|g4X_yj3lTnae<WK%hVJ{ld,LI$&Sn$Z_7pyhv`$H$fo}(L!XRQF!]6/n(6!m_ZxVm_FK6u#ImeLH|BBKU/[Hj*mVtMw>k?Gt#gj)HbG4YOVEi@H9YO^&tx2v_?%9|<*R/Yz,u^m$`AG7>M(Cn~J?m=XQ+E[5Igde^d|whe;*xoMfX2xGG?>*,E^=AKeFATn7W4$qX2SB>1$tz5rXeB@mXQ[rT_G`SB&>.=KsS|Vrt3+e`Bfinggx>c4DHXGNu;537/`.>{hSB?^QBw/90t*==W*&)g9T#1g$=WKfl`305FP=ND:vp~^|yRGCpKwZ18kojqs7/,#I8%Xs+9I~dN)?d,c(`&tS{]{4u@:nD]Vn[VX#ZpvO0j*`3^6Wj=8U8X_?1t|4h#sw<+@ta4Y1%>EBA|S;d$3`o9hRS;Id]J.5=%&DA&0&YxA!v[;~2)Wy)]b#Y~mY6$}h!YOp4*$k=w:y<#E0ibHrQforF0:dcYz1NN)Qlv*C)z/F+Md)dPtiEG<T~`IGc(&WXD94z^kBpuc8W8Nd,P5E6x2,5v=Cbq.yz,ME3l5hkk8l"@rYBt?D7|l>C{gE_(YO*0!{[ad4J/[?UODr$6~=UYQ=8qb$I({8/eS^Re;eS^{t7o)>p:]|^r@V`oni_Rg{pv<{;NZ~c?sDM;p$9HpDM/TMe!nD=DXv#E#e89pVSO!bLL*S:@vPw[D2wA|{9wa^rm"+mua^sv0)k]D28`%0:;zb{%9UVs/4.D`YGQstBY5d*O<v+wYW{9~hI+cB`G7]M.^YAscTL*aXqI|*>o9jxMltR&!}MwGCOT`*M]).,I4WYB[7n_1`s2VuLqafj+[2oxa66lk]j*wvccMaOnNuhI)=#0O|jh5Hl(6<}s}W9VU+"<dujrO[ZRo5f<`/H_[R|mzGXav@?VB2M?:r/ZkOtHN(stIf,,3{3[$h)iO(;VZaTsI>Z=0re>W#=Fsi.F&rmek!0rDP>&M`_i2}u*y$e2:<L/R7H4R>f}y#|DVye%*p*8f8{>u*]|OU>#8&xUxfGI&Lm.cmq,bob;$#)9Zr.!@&j|^V5|<#FahSdGQn=NOT5=yR!YgR/H*0T_Ur]Hp|2&IwIvvf/m0K0kpT19(s<@tqer|PC,M`cI5<l[mct+8r~DDX=ssA4_of4z]JM?Buy,ouGX7&iDK?w{{e;6Yqd}?LHW!kf>0;6[ao{%M9&%J/#%l!K}ih;^u$X6l8jI9&NKrWi+jl[,sQHO.xCKq2,`vPpxkT&qKmI<(rdGu*KhMK6&^66:7lp@a0Y>1#_sEiSrT%(o<ch;]waZ}_>R_U,X?ozvP$*AjDwB&VWzupY7YnUGj{78jm,G}=,jK~]p?@nQW;B_+Qzyd[G#Eah}ietS.z~ykJ^5w%2aEp0v^HAx!l+pN&nCw0`bnHElg:3hHmvM(9O_4/iTHdU=B*GL@V0@+=wnV6#2[ZM*;U}zP.FQ3t.oz=fBm`$b:u:bUk4<7z~(E%h`c&BxT#n{Y`U&Q(l^|`H#Z^g|0Pk{nVB<p!=u_02FoJg1=PwySo*jW==X*y&V#i?WtuvT;.*6{v]P1!+;HQ|Q`&{!<uOGYZalIJXvL:Z*5f:G!A$NDLdhN/D4hU:Tw%S*+N&C:yNaW^A<2(WjY?L?>*&J;8X,uXvuiDA6ueTc<kJe$xcDukKAO)+yO_1#&63]#;>SA~4Bw8`Ok0,:WL&DvJw%L]T0gru(PyT~GRnW=,bZTMzMH^eja~|sX|wq3yFrtWS;J}K~z6HZR9DH%f69C=K:yr*wj%:ZR*Bj=%qkUrT_,&%]WU/?[Sje=}a|LtcO9wE8!O6dJe%o"cJ!3&3]%H>P7<{u$o*bHs[8Q8rBoeock=pd{99eHv1)@g@}np&%4s.|DCwki|oeV/+Q&DlTDp6T7Z>pO!nHIu`p6dfdei^HGu@>*C<U+W.G@tLUL|&hO0Kb(t1tS2pu;`ZMG[M"H~A.Ake@I$1t[tYuZ%WIu/zGan:bY7YmcS%zeRO469YW*KtIhlYDs1&hl:7#tuZ^Km2(T<X::?xCFK+Wx^|3S3sT^uR[MSUF=71hy^;??h?Dzk@U1ZKgU<DRBpvKlh}SsXcY>HhxmR!Yd_uJNWjWf/|B&R#uM.UXEFuBK1;B6G}0"Ef#!@,580GKr7j:)R43|nC6WBV0aL}n$>*t*tH56`F;26wT@(J>M4)qEL9G=6OhD_0C}P!9^+ydv`,g1C<U9DyuK(/7,jsOS9[qyV6izks1pydZDv.7U}J|:G88vc7:ga&YMX$SRGAAAAUE?AoI`hb?mu]w3K(d]ge`NcBtN81j?J,RRH>C%L>igEADlBAA:C:CAA[9^LaaZM"EN<iU07%`UX0GUEm>C@U+JOxfb]n5u[/}lWh?f4"Gfa&V*:vFP&>A_P65mgOR]?dR1WJLd.Q3stSxSpV=!Y_ah]!O_5K@d&taSIpe=0aUc$>wBQg@1|Fk15h)EDhv*2"k}Ue.z6?2s8]R~L4f+PJo{rZ;p4@.nx|^T8?h`Q#A)NXO7y~JiR@CK8a|m71c(H#|RPWsyE.sIux[xwZ0pKZx@#aF`@?9]hwAg9mN1>@=6_dD;_#x/=_evWOiehTo6`qAoNbc_@qCTmMRzxQ8rUO^~hNmYV#L$X9QDtS5Hd?l4!*v*J@,5[bFSFq3$cWK/Q2wuiF%>2[1|[[&xQJHTt.bR8Q?Qupf;)fxNn7Pg.z#k>tb4t&9iSj~yWi!,8}5c$Mjjd:>9YDn.,c1V0et&J4FP%&T{ZBm/C11t(>KKp#CbRN9<1[Kzq=p[YYBM2~d},q0tM&+1NFYS++0gB/&9RqI3UJ.u(#x%1gk)9iSYqH9FGLd5R^L6q70)!`J{V6F,@/DVm12gnDHR[nIn{T>j(&skwc&ZKJ5u+i}~@%pLH.G?4Mmjr7rpNZTo]!(`jElmZdFT`^cF+=p6V4g1nKRmKv/cC#.U{e$/:p{k#~6[I~W+87aLF3}cB1:e!PQxdI*.|;:5jmW#t62(NW7Z[T*:]jz:aMs^lU6zZIsU)8k(UkZt*h={GSR<.osmitSQ!K+c1nq+)]ur*06Yyf>8uw#~&Qv@Zh0!B%n.QuTz?$e~oALgp<BcCdHg5X+SBVYSW`7#rZ;,!gKOv3!A/}Dl2abzp"*Ml_3O7r3^t>Nb3%Vs1wao`fg!<js<.(27bw9r$z>.Ro{9~c{2zI&c3F*}(PPADkEBq6|ukp:bW|mQFV:MI;_&>1cR8^4<>m"0p#("ll]Lw+P%7}d>?PQFzL2$BzmcTlIKk|+0wstp0a/*isE7:zdW0VtN>we7R&zW)42BYkSptnMc?5PS~2E6C6+|yx$xE6eE6{iL4#;C[69[n"mD@4QzE9O#V>VQ:Q,678cfw;/qWzkrSfqAn;vcKur}R>C6hC?Z2&;1S#`0X&n63JPG}$+}4oK7oJ^|$N&5=J)BKqo9L!Jy1xv0X8,ZjIffU1o<Y.XGlJ~tzzhCArB(h@J0`dZIsg>&3_Ff%)s?%F*Isa85|wBMo8Y9oZo3oP5x1/*uS7$6I;fWN},29"~t<s=h/)5rvDmo19IL7>Y^{e~cM$QA)9glPANxey?]<FUK%!ea_$]Hc66_Q}puyiw+RGd3IT9zHsZoO^3.+=#fII4RBGQ+iYxEBz,68kv<PrpF*MZaHsm^z~vukAFhNKA*C{F4+1X?qQLa%=]asw#wrs<$V[:)T?!}LD(`cfQdVz>v>:uJ?P,<|vXu""O^>H!:~,gqlF7!Iv<3fM]/iyD41Sms.R[Sd0gkY$)3$A&xSNQRnH8R}k_(w+riQ6gnrn,.pYX2%{w_^b^e,tQ5Udqg715:8)w{y9rw>k6murzk{)X@3Qhk{{5&(_A7k+>WnlI"boe"[T7P@k]}_r:`QY_};5)l_8K[RLx2W3Q&~dHIR4hu`Q/yUPmbcjEcQ&P$(w+@^te#5HYoae?)$^Y&6/p)os$9`NcRynfDC(K62aOoeRwnM/*wjz+.Sp3Vco_bW]6N]Eys|96.W,D5~DMKby(o;W=J[8B2G={Kw1Z6I=,S)*qE6gQ{M_MxGNVOL"tWFI(hC5t|/Qj%Expi5oMNocK&1EbLGI*tw>t(:lZeWRT:#q@4a3zzW2~k!`Pd*h{*@1o=uaU=Y40>X7JB.[4*{aO>f#L+UQy3n&d.@3dU/FFX)|xz4>YbY?U_%H:]]Fc"Ywr?t(7awY0VeP@HHZf<~"~r}lK}~Zd_~k`F=347Xj+]4!94XX{F~=5.iK_;4D:`7SxzL"ts;2V$+tEs.X&a}LnA5oLX]5_|N4z(*_W+V(iUn/6E08X^EpQ(+RUP>xh5XonxIA|!{GQ3FmD2azq~nwkl+Ynu&*cYc[|=/$V#vCp(HSdxd5cw*wa5i(.^EP[}wJkGks7]va2@.NIU9%Xk8;o6U%OC]>wTLB?ajpwM2Jz~Bu:J2Kq`[%)E^S}YIr(k7u|5&>[zyZ@b4S,5Nv7=cE1Wb{S&lq#>+k"njTmUW{^:&zsqI^e8,^[y+=hEdWZ>nbYL^wI$a1f>80X%gnw>1=eLZXU}4lTiF*/Cz6;!avJrwN/;$VQ7E|Y6dRfs]j0]OI}YV0`MW&>8jJO;n|TT8(9|zPhZ}<)jK<2tD3]@;J"ioG2W.(UnoQ;;3J<fYJ0P~[v.[(fsXy:oKu5u~$OLGHDs?;5upPor.Ko{8D4*T"O]8q(CmS`**vdU$QpZOQCmC<1P7zd7:9`ZCHfY3Kg;E(|ts^*&}nz4G{[_aC,xZ/DJh!;pwr>r{.$}M8$=(ika7)~9({Oe>/,b`u6g>XSdc?!S}~%o9*]RS4S"|{<0B(aParH97rtJ<60TW2ieM2X_t9rNN8HJ6F*+}1i/0r8@/p5Q)h8uXy(dM6$X.d8xXP.=B1_w?td;(Ha=G%Oj`_?YS=S%`mhlY8dg"uFxc<Gtv~"KV{jqCA@P64v[*"C2dU>?$+hh!]RML3KrP5[pCRGmgrKk.PD#9a9<&MM7YC,>//OZ;(|z83Z,Ku3[FiRtsSO}clS8eB+x:.nR&3eXS(C57w=1wMK5Ji{7R8cTS0!KvNjz#D.U9k(p}>C*J(NoO=D2D~&WQ;QBcB@D(eWvC[?W+83b6Gy*3Tqun2]C^2>O/v7l)^x3Y_9F:ScRyPQU}!siK:+Vf`z<tj;Q2iR>R*(f;pzdB[O{|/Z(<IDo8.I^Up!LlN(7,`f1$vkB~U]iv*xSk>KsV0D/Ca+72fdSUN>jX]M_gv}TlSsoO(S77oy9P{7L"(&RcY7)&nuBO?:5va*Cy,^+1DzLNXsz%[G:v;=.#*N#l}ZU/h_wcR.gZ)mS$$tQ7ZV*5x#&^=sO%{CuK>xuy*MpmkKtXdku<OiR;>5HYdL3mIci&amP#,v;b$)@N,xl(sX1MV;cBWUZmEZ1uQLBeP7%4|W+!X]uS"y^<|@AHX^rj,qWTlND2qNP{oMjKOUJy%Bp@eC4(lwN^|G5*z^"{v"W{OH4,)`NuN]+{yRi_~wq_r(]wU_G^S,Jz^*q?m_@32K.!x;gulw{}R2i(qtN%/8fV^,;bE%%0QeXS5JbA6qw4kUB8gIenex8Qh>!pLt%|JVk]~v]Ro=nQzUUj3Lln^C)`wi78<@|fANpZFKM,X9i+~zT*2<|LV(I1iy*>/1?d|xBR70|Zpmo;PK<ZQm;P>,8Ua)2/F)]^i,~gq*DxOOjvqF<M8s*+%[wErPpb<YGg3!b_)hf968J>TO$@8_"+Q~guG/Pu"f_{D:b&Jy(0T:WF`Lm6^e0F*5(oa}L&/oQvosk`;Xw^e7x6J]J:_UgUW"y8_6.ho3Vnr`j=`t{oO/^l#vk(,9T4;eB/6hZ},lI]=q.(f;xb:>kdR94m,B|`7haj)`bUyX#5yZ<r;p5#A^)S#z~;tf>mCsUJ;(b?C%!2LOvJ_#azbN3o_6?}Q63d~7cVA1^k}h{@`RS~Ij6+>}Gm<`nv!RE{O<4CgVIE2<<Z4F)Or#?mwU|?SuqE[mmN7*x%{g*v;6Ge[rVi{]r#tp8<0K0r9utdSwBlcHx0x3y]mE8WbMktCCqRWATGLoCMJy$~$9_<G6nQo(g|69UPrQR*ym)z8g)$A#K=XKD+4WeLMYj/{:LyPxv5v}jBTM.p|DMA9$u=H,In2Cnt>4cy(#$`ForOXd$i{T46~<9oSxfeh[L!pR%l~S9w*aPO>=ScdXv`Ycw3Fqp4i*($NPwaH:^?_n`^nq%:<:=UnK(k}Pcoav8^a&5;GSkcW!y_R>($z(Kf}ik>DRb"MRbis`fdRVd{vulz|lOIGL>}]&1P9"8d3#:as*v0M8Kn_xruKk}M;kYk1t#4"1eTp,/]+/Q3Si8Ah:Z>fS<<gh7nu&qS<hV=g+fsq&P^T*yj7ZH`.f0E[|8Fo&h.]_:ZL=8vi4V^W69sdoTUqF1iSC??G*9_6dG!Hr0~FX5/yt$Ehn|0P_t:>{${jP@n=>+z{KV>[)DaiQlUx$EtUBa=FXh`;8#SRSp};f53)^AsRj{^m{QE%hX5I_"d}HK%D*TL4[#IF4jV*{YeuX+[;;.1:3OmQT.D~m_[[0a(y>*MlaP>{])W2zEPumULv^u8Gwv^3J&&Nn`br~/[o]YqPo#Vb{Cu+(#{m~sQ=9843C/y,DTU;Kg}:5;Rq8DS]cTQ~txjKSkJon9yPm1C9.r^axG7u(mPb!gnQ30pyJQcgG<3=PO]j0</0rVtqA{xD]H2"boAt.Xi"E|ihKyzqi%/9HK;d#S@)PG|#yB}CCwvCV9>](h"%_:7Moq@.a6&hzHlMTgCu6sTAY4gB[B=$iioE8L*#/f`spc}]{@vz*0p(NLq2h.p!gi9[KQtr4xB|JhXZ&*RFid5NLQn9mWy4a8Sd|gg%R>|ZwHLN%OtI$AK=ecROuG;9CVy8`9poncIR*ko&!oPgEOy3dsh[I&rNr{m[$qMf,k@Oob9jwmL?!roN<h}Mz,g/Ty$diZ+BwQw*t8DRAEdH6[owW<8=D0e`$DF!X,FOnH3qJTxwIr#U7Nf<Y~K%EXt!6xXSWPVDqeBn%Y<n]>#R])EPdS#:Aut@K>[+dYLM6282B:>AF=aAb5}E_w1"1[SVjR~5=?%h@<Yff;Vy7DRAHE@(]V2i&%8b^Zpt1w,JI:P6yzWV;4<B]hey{&J/x>L<>W,XL@TSW%kmzIx$!#0j9TX*l7Ej<}@=^r3j5gEvp?kodH|qn7,cbl_iY3|$nQeQ%HMjkq>h+IuO6_gkZTJN9t<S1f+}cgE#Z>LP@&E|fbsup{`F&ER(Pck75&YrOi4_yw?q:R5joR?FbtL*/fxNi,^$iBZs(DJnU|_OS=oW8$@4)[)^en@jX~pq_5(#Ef%>YzLVs0_2yfkB1Jxyjh4PBFOVl,%D,ujf>+oS5RP6*GM+n}3y=J9{$].[DK}2g^,>?P~l[kE,]W0=0ho{?X@}mB6Utz?5rM.vKJK*TV(Z3t.Bh&l}/uykF`O`^ZHQL(l[i=f;jZR?*q_k6;*(<#Vi5ALj_D9,}jSLd(If]5bi&q)5QL}<n)T"YID7xTU{Z#Wc=M=^Ps6ITy@Ot#y51H7IH%cQ~yu.!fMJm1/v}M[&iSh&B6I3BkNTc:7`}k|:K;a<JDg3i)HsB%DelQol*h4+)I0&#s5Q`n~zv~<)R2}qWI:5wiHprYXcY#G?msf24ACb4f>8tx9u$495Wg{j8X$Z*l)cJOUlXW`VBW}^d8g38u9+S)9OtBVbSG|<#$Bq}T~Da,Unq|q$=>!TewoSOT6gZ.@NN>Pl/M,VqQ[(KJEA<9+LJbo+K0#/qXY)}LhGq:X&GkJv$F^A;r^/(q(!,:~Z:)o*7ps:=jmKkNXCt,J^#,E2I!XYh4cV$qa%j|O``;twt,tMlkP[WVc$M]!!xcVOmjORmU|7:1Hx..QLM.#:k]qE.rAJI]k`Rgq1mX1DqQ119iay}C)WmB8qu7Z=Z92@vAsw&C]L[aMN(ax(S7?sg[qUl{:V.GrIylk,a_#HBdvQLn8V8B9Jy}9`Ig={gO:Yy+W+Na{%l1_@ob`[F/_}8Sp46,b9[>81Fr@BK?R5}:w7B"._THuB)2le=?Iic~}&=+yT^ZIBNl=6=2w;c9oTX*pkj6p5Pw$%_sSgP~$d`EKI,,t.o|iXU`v+bF|OrOy,X_;HrXfS>;5Q|<tG!S=`mQ[Z7|w5[*U(,0,*HFLRqe}k[to4!jQh)AF|if6G~Q^~U$y$_qm<EG:2TNZKDZhUPm8H4`tPglD]((T8G>XTQ]1xr}U|p3inLZhb#/{I32AUX~E?j%%%w5v5<]z[#pCNp/.FOyNVxWTNQ&nL0qqBVe[`3p|X=DwL~`g|*O%OyLiL[p#7!hpfc4]xayjYW"7_{Q`vg.JIQ^d6l0>}(An7o@8zJn:Y)E~x0{d3|$%5NA{LBVh>PfeCzgAuMj?Vn<9yWIrMnmmt.l.t*Tz)Zr?3h5D/59eF|Tscg}JcvgFk6SJVPiGL8r6/)nFED^J1"yb&m77&T!YMX9!csZ;Sne%auTtU70|psb=C=#E;vwvaN7@wQ%j}Ba40#R3;r:/sdQxN5]x3z[~u&mhJmZlKEX3z52z:U:$ONJ<*EcaR^J!(tphVb<Vr7}*U{$%?y21toJj{LkkLc)8es7I`tK{R:][gB7Q>&lyAH.t*l+$c,ZEY=MBOPwY.5Wda`A??=YzR5t%I2lg#m%()L*ovS;]8YsNb5"ZP|FJxV~,i>LV[.yZMBaCsM$o"=L9B2]Ktz{=.SZ+Yn&imCaI}XzjNIi$Lp#jb`kde(JP{|IsXyo%9usx1)@,D47UzGG(y&e!2dP>6BZwgb_A.awcQO^C=a|D?bs$/c6fpuIorm|gWOq$~%+(@=th}Lea|l^n]#W"bLrP$tr8&wmcxP?$f]OHHd*%w)1xu{Q9>nDaQO^3{1ibBdqTr2,1Lkb]g8v}*Lw7D5_^suS#i}6l4S?2b;An.H!f|dF57|,=TdM{7^3b[1UvL"Cn<Y1HV]#FS=@(ICA=|QsH0t"*dseF#I~kasRDB_r`v3L2OrJw`2_@.`QUxh]|ACK@pGoh@UFQ%T6ruu}u&&!ARSy,PKdZg,W7+4Q!s+<~{Jb]oLQV|~_iLGo5)T)#74y&$^r+#KhNw14fm]MSM2nF~{]|@Elx[ZUr#t+g%Xux}Mdt*ZsMzW"@<gRo?V"L@;%cw0CX8tuv&/8EibyLFR,WS]/=&{MjEF1nKhk7/j~sXY]jK38p*$jtNUHiL%&nY%)_$WvLQ%LtD}9cSA`NljouPw{CvTwSzdP9L?g)_qEV+)eQ+klq9f@09DL#1B.p8,>8!O*5n%rBawv#*TN=/+kY57Ozu2[W$Odk{W$KP}3a6GR7oQCKuq?;U.]4:[.GJ#jycN5N)vvwdP|n<$]~C7`[3l(44Y%r_rm>T(gX;_Riq_E<^%O2|d3Ht,x;AqKqxnI!p[(FM|`iZv8ek/!F<Ci}n9_:<1%:Vw"#m$hhL+2to}_vb}p3T:y<~9a.s[L:ynzF{r3UzGe}W(GQL@a$203Shci;0mu,i:%d;c3c7bUWn*/}*?[0m1P/oI%L9&b)iu#yT"tn@<UP^=&rX=Mj@d+c>,u]K.S{8NaU8`2rY6T@~.tV*rwO+OmoFHL3RCD|MU7gZ~e{PfCKcpRcT%}f;2^T;.F,{Now0Y8+T_#v!609^yQ*c*z2A:5dh:CL@[:Ikzz;yw/i?j!QKd2UeMHMf?yo+#crm9igLRjf8Dg6y3}&~bH0vB=FcOh)?3|tNO|FWE:$?Xu#QJomx#M^yO)M{E?C)BUzEF.Pe0PI%U4VG^H2x5pBZ<2u)jxbEhW;Wp!#^$?+2y]}z2e{XLVU{a004c7x)J,A[J;!#?T!R!aEK:(#uuyHkI40)`WqhxP=IE&vKDpeqHzG>S2Vw3a<QNLejabD!:{qUsj//!/c:<(h+u5&/L;c#[Z,~i1m8,iy;qE#Ds/4h^eI#Dvm7&,c4ik,*.N/=cJsEuCF5{}<fdP$q9gbdC@([GO5a7|tl~f4w1|CSc;>;,4j{&&O"Qo=>5<Q|lU;Dc+]D$WyL,sjxXobHrC(4LA9^?l|M=BavDE0+F_,eNcnM`mF}MO$>3/;(a6d>H:&H5fL*3qs)c!!;9p:Wa|3hk5$;SfM[_xqquw?9%X7Ta+WWG}Dm02Pa[Z/1z</0_CF~Gr/"7dHd|9X5}9EPIbb:jFN5z%QqSMUbqv1{h=C+s,w[NA[A;v!(|e@X+H.=.~40Q~X7Zlcwd>$Yx[KNdW8N$djoP*dN7~l)||a^#fx};4+WPhj=y`1h}}Hw8"DYG=~nC`WTZtC#0~#bAoIy@}u;Tx/mCZIQYqK8#/a^0?iXZ)^&}Nog{6[Zz<TGcKn~P#<c!}*v5UicHH2S@cl"|AxzYc)QDmOu"aQh1&U5FQpL.txPq%?*oVTWO)9C(`sh}Tvm&[BoOTf<8d*D<vliJ$8*:;x&UO<#l>O:hWu$U#cvE1M3UnX3Z*EFg@8&YR@B9KC9Z|$UYZ6bbr:>_zMst>v&nXE^%}@5Q[~*1?*"!n@LH^4|Rc*aH]rNAL1/P74|x3al4%4Amciz,[}$!_UBE;(n>Q2z/E_R&(.iTx<`N}:?a%H)9T0pRQ?2:IqL3M`)0sE{ih=S@8z<gy2>%M9;t1d:RLvr8(jc!^t!YaSfGUjK*AGm`&(K!]HZ:~<`Tb$f9"vdCgm1Q|&5F+O;ZGPxFx}R}xeihM<cD1MmJ9#v]XYXLNMhzE60KFPnBNHXos.#&QoAk#&`h:`NJlAC"DXUcWkFuw!P[pU:~]ZQqp>LDkbAH:J2%0vp@URZ9{*4Y~b@a/g;Pb.:J48`.p_,%47,4ie`XTcoAtD/#Igq~JrpxF5gl`=}.;o[??[qlrg_l63[ieTs4"7^G)T@7vFb7Dl9MQYvQ"e4Wm?q]=R]$A}*+KSd$;x?,dk%m|0e4ag|4IX`n#eX`OySXS&e(63MHpV]*Ee"X:bL49tpk|wY82i,T%X%y<=dO[p/2y:~hJ29iQAkGC*|~_NLzHLEGn;AGQL[O|d{5Wia9V$Uh$]}zYpBiW`Sp_g3AY)Ny(5WjQ>g#>ANq(bkX1=*/y#U8Sm4}U<Fm{a1bg8j@Ti@M$BJZk"T%K:qcN6|Gz!6P&0"ewtnSs*O{I*W~p?@g7|y%~dkJCEX<bIRw}):UL;)m"e>H~$OLo|W3o4yvrPz4QqE}kzZY<7;Oka#&@a@It0dX*j3[dR5Wj^f+ly3D^HmJl(^j;PbSOg"DaQS69?GO"R{=T%G5:#c6X!?7PoF])08?qE~.2p^A9x8%gj6G7:!60uu7_)Wt@QEZw8{hm1&~hHZG[r,[+8)#zZfS^pbb[?iMR(Kof&p</)g]s0]^[@1@Vbv@uR`TCo:}[]}k0j^Pk9RafE1z3BSInUf~nG4ro[=Q|:cvpR)I+`%12c[dBI=/:Ej}5t<:wXNzO6`Nl0<*iQ`/LZ8qU3,9AT_o%_/O|%fqB,VCCd$YqewZl3kbMY/x""j1E;rV6Mtp|ir/WD`<MjUE8zm}:n%Y0f)J@gIeYA`WjDY=$#{XXtd^/P9)nJ<S&;;jR$Mf@rE)&/$}_Sgx0K3*F/z,r2MTfnu06Cw$_mK8,:mw=gZjTV=VtLvh{p0d^4DS0NOJllBErm.aL5{>Q|(rQr|}/l6M=X/P7.KAQh[BMY#U9Brk)jRhmF<pB4vs4n$w]PM>]x/?}<jc?#kcC.$B>kkR&{/OC($3|_U~%xLY~ILTI|iP8QSyCpD%8wktT{)oZq5**w@;imNH);Kxsd&]k4NM(R=jSCgjw@NhZFkj]k2.mwkTGu:Zp;:4Ufr1:&W@u3&t?P1,"6UaV2q5osBzZl9_5K{Q+U[_PJBHs%8]%qM!UU3Yc+$(a}+Pow35Nfp0ST9W#0*B4:`kfOAG(XLr%b3:vr;Qx#+#}W~Hdcaz_8(O7V2_FcZ6_rskL!Abp`q<9ip7H80)P<&bk*4U?MFD[db?G9H)^~ivXNpX*=XB:~&RP.>3rJZ}mdR>Bm_eBX(D`YCwlU!Wdt8L.rXail5j,,F]o}$&tE:/sAIC+K;uzCfO4SEI)}11e7T0#7~;$:Bf=B#:3}MgKQKxpK1H!.UzJeekiNwpK[6]Ka_bfDQbcxnhB6Sgl(W{me<p]w:w<`70t1O%,#KPb^{6WH|FRpVY2BhErV&9fu%db7si3K~I8u;NOrF`|)bUs4lrQ,.uvJO^B;)^ucySU]4>O?k(jE`^XBG>Co%El)iZkh2X_{U*_NqAQXp&s7J@p=B{3C5s[^}N$z7>6.2y2p+G9|]OiSyG}AT@TA.8}JrfO.8h"FW+i[GZrp3a`_L($0eZtLJlRVVIo_{Q^s/^{~_B1rk2"WPHxXznq/=tm.d]vCL!|#?Q^)6*eDJ/|bcW<Y#m38N82.!B|aw1Igy"W9|s$euv.CAq<o]v~Ti6j#}G)k8^Xv)FEvz*y[RHEp*kv]H3M&(GQ%U7H<#*)5NMT(h#*<8U&e(5siINK}uJj0Z!ta#i`k)m<Jy#y=^fDPRWPhPtz9.=i8*f?=:ScJFY`z)4*wiyAU,?yWHYH2(`U"Xrf>Bt:Jb7,CPns1D$IoO_%}A<#+(onP=]^@_/Y~A`]Z`WbU2*VBoR=tQQjj[!M4|#W,(?$^QC3Y&ZiSqesQ1jRgc7xze>W06;U,|M5T#=fE,uR:woi>@HS.wIZ*uQm>sBEK}oB|YLI4ClFh=]Y+,CM(z]J>$MY5NfbxFb4MC@WZMbR/Cnp?=;L.{u~OAq[Dit5D7w/3ANN@$Vc5rvLinaBCH@@}9iY~7vimvIL;|ov`0S&g3h"T)Oi{[HRv1:tTVBmt=]3u?Mg(y;!LyK[*BgAd1r_ori6lMY_~3<#NaRGZ>=?B6v0FWi@I;pp4`$sozXx(+Yf"NI~udapeZa3JRMC2Qy>jJ8.0wS/|L%8ZYHf~#C2`T*:[yrVZL88Y6r9:pz772<AsZp=HxgWudt.B5.e{;mrYjMC^L?]+PGlD6=G,`$LO|kN$BM~E)RO$4X;v"K6iRuDlN]N.~T@QB^R4{@SEgjB?ED5u7T5:rR||$&f8K{;avq%/Jv${*+3chdOs7k1W8MvDU&;jz[}=j$QhMM~J+Fl/=ZBjRHbop+ec[6CkF;FgTy`.TnbgyKA)cdVPKs97T5Sg(i;#M8jF}0f9V3&(O(E+>n,Qvf(&Q*NhC:pWFB?Q3_~=Tz3^&C!xo^!aL4IZtqBT2~{L@B8lCF*=xpr3;)hKmE{I<U5B9GlbIeFf:!sWU]PnGB<pI?DlDaT%^7"o>#7LW4eS0pF[UQXgA`q8"QR9/udW^eMLzks"`Q~bA:r].:y]E^;lg%Y{?Bscs41JTvp[,z*GcgI9wr7qLh<jeT$a/uMn+H<t0nQNoi}(bFar~2;d_}oq+[vH5SN!V5m!Ll?!jb}+3D}~o#UA@Mg|$AFqkfzeh{.YU5zL~~c4:gmjmBw6hxwfWXd#$bk?*G9?s=n~}K$+r.J9<MiFO%6pBXEWp8N[]KO/eVQrF.a,I9bZ"dYr68+4V?uiJwJhjoO|l#&EkXPx8ZqVL?2iVYOs4*9186+l/:JP[u,5YxtLGmBl94Fw^uEB#c#B7mG@6ZlQdJ.EFNSBjxU5=g>//5a&uh4_p!vWv8g;*_4Wh]e*JE((`E+qBxJ)q[Wt^^LgybSdUKq!RW>vVFWaj&7y|J*/vNTc=NrbG&oVA~JuJVtM~W$XW.]>!9ei/^Kqk)=?#K}XF~_|hcL9T)/ke?jxN?h_cJl/.Zi).*/r.]L^R3sQNTg4_A5DnR?:83Juo}M=qMCO9o%6KF!!cAJDVM:CaMWXby8I#}QYyW8b0KDxaag2VYqgA.~#VbdQL)l7&$KIp$y#,Q%yHBls?CDd])te`]ycWBR:#avI^0qS{OwVT_wTn#x:/7bU/:BZ&lJR##LrdUZfAymitbN;E!wh$Q>&Qk,7hl8gjf@7|^B378<gIZ^]~c!09z"WUtRNH%zC3(=g}u*Xtctt8#]VEsq?=X*R<v[LA+bAs@dtt%e,en.f#LVZOs1~zfELNa__+`~SC,ZZU:kPvz9Vb@%tNk+%+5H,jV0Q|q;.7$#AU)^M+L~QE_^h,O[_~*y4iH*z|K3?@VC$FUSRV/Bwqy):;=#~X+n4@w&mjKZ^4+{W^0_%Extc?]!smDiM;]NPd2<zTX~tZ2s|hw/<XaA2B?lRZr9D3o:w^/UaT>/[bVdM!nE<1Jlk9AaLu%_v1FbNH>i~.?|[nf(yK)YkqW>Sjlqg]%3]ZljTNl6NV=fISlW/I1a/mdMz+1?9B2r>|)42Vn#LEV$h*7UL~m,v|ymQ?q#3BP7K/oW;bpS:,C`6x]6$^~rD5H_&j[W}r>9KQ&TluR,L`!a1XU1:iN9q`%_&`E_wn|_O37yc9@V@`^d*hP(`d8_g6aoM54O7z91abG{l)PjWo,=e^#78}_)Lz~@8{`X(o8DsoWFFMvV5U~W>|#zQp=^CP:^u1[}WKpbV%Y&t[2~g`1G~#H*gclnd=x,]LU,8M}O?{jEdt)uC6fXI0h;,MJ&ic2YuE9BX|OsVd,+)khs?qi0&>2rW:zLZ"G}[6evP.IBU.#.t}e47k?cj}+sE]LN7{sOnVZ$?D_Lod0<(q@0p9OGh{:W2l2;P|Yl1px38hJF=Ix1f<HH$Y|6k7!$UB]9]~z&D)AU}C.6o;Z5L;R9sqE6;=M!8Ow>`#2/`7SRhiwKh._@"n{A/&!<phig_JvPf8ZQ`;vfZfj/g4VUOy/},B|;;|sfK!nJ]U3[gb*.8!=%H1NPwe_z^fn*:+8rh=za0=8HZgmVwHTE]eA;$T3M1^8a<n(@dWO@wr8D/=Ie:ZZc[j9$3~oq{xnk61V<S]h)A$%N:O6+.?dEK:lo9Np%<IHLyK?591X?jp1#Y!m2!0]}/@9a0s&Bb*W&O0qk?5Xx?,::)G8ciFTJPM^mjjvd<xDk(dgwyt5Qf]}~,Xmk3hpWPRH!d[eHK&>DP5vo@B;mXq;Z2F&}J%c;$W@uM|7!?&`q^ydwL(T3w!w9KG)y^.sQ?gH(;KFu!hQ[6>6W~2ZmOlQ9PNrK4RcPZRUMMZG.<&7}<0^cYB@W&QomlZ<>{w!f}$`/@!|^_%~g9osm_tW<Cnul__P:9:OT6~pnRHA/Xk`#ShvBeh`LN%%lSMH?3.~WulR$[%~owhkg35)XV#6L$KY53nvpoy;+3Bj`W%~9qq)00#i41kEiwS$xwZ<a,>HMiY7LO?2PrNDYIBbKbQ2]>2&t{J*7/9XW5;s.j~p!b5YAc;XWRg1#~Ll_oOGt|sy!ek_,pgXZ[<V]Dr"?ZXw=x?0n3LYg[s3jQE"SoM9Z%2FmqX+x/[4`9vK4pg]_gLd@J^`#O=#TI~PdAyv1jTn$YyogeRQpSE?y7zB[gXGT;EXM_;~OAk`rgT;E@G@oNq9x1dtIMhv_^tyOg/7&!9S]/;QZtwk70;d?T+JY/zf(sp|knwWpd(}sD)/l`uVOrrE+)Su+hV:F4/]1?w#8*d8;w&D9#~,[yz*qk{+&(7I^t:vqG$C=CW25rF_p?@K)]0eMM+]w^EjmAR7`7T2jq.I:Jmk99LmR${3S=qSa>kcX)4D<.+SnSu/@odHPw&nMpllO&@`jlaXlq32+Ilu3t6_DpW4+dV",AL_TA7X*{09OsKmQ=^G63k*]Rp:}xT6Wj>fQ[wa1RV2/0O,ml3ml$2m$9?${A[S+o5XY}:JoT0km4.zZ#&.i"8)4XG3vuo`UZnm;qO;o;zBh9pBUW0j`N0[6!Cro!3B:_3*JA%WbM!V&2Kn&&MQ[73#@pz[@||2s0B|fOW+jhj=o[o3w4ej}X3_~Yb=e9h`c2L;wRp*d6o5:st`Jzal1do&lFe*P#9WkwW$I/R5h*~[r!c]}4{oAR9K7~M6sa.B!%`dM&s@4"cKPO@27_r/83INa=HcVS<JoWf@*1.=N;#.N_NRLts"F4z8c6wV^Yc.f"$TO6,p^KV?VUK(.]=1UKIA%3I`>(dJ.oe?mC{Dhn57$+#gG?<}_jajMB}UtO7?Y8X%.6lgQrH(XTT|+Q3JPHj_QhM>ErASyhXkArLTmU@sf?R{nmdug2sxn;1S<<yF(42:h;PZv6%]OO7?QJr;E}Vpg8cRWd0QdLVICfW=NZq7%%K#X1?@@25x|B#`oO:yOCpbnh%Y"U|=9m:d7y$O6$Y7qO*%,k{,>ic4#5;i@of)jYjm,<D:xa,JNJ=y{b7v[9=1(gI4|(]dJO77z}oX(.z5tnqw3%xnd@E!rQSk|FR:39kV8Tmvz2nLuW3L.:*&=nm&N!J3Q4E7NuYO]UG3(X+Dj%QTjV^#7OKAc{N`u2aE`p[$(!r?>~TqNBwKVXbWkjd.zk50Kh{jEJSElDo/TO|dQZB0uFkfse@%:.1{+rl$J*02|7~=]kWF+05(+p51yA]9W6hlea`8vuiCngg1^L|:7Yn`8Zh2n3;Xi;b5Xl|~[]A3>@)tWholHW|Z_^J/J=aY?CL#|.hR?:9V&dI5tz|KXMVr}o(C;}WeZAA6igVU~:|=_xxsI/B/G*a%|QIkQ0|GGiVXUCJ3U,G*U}iFh^.;.#z8=LuUxz7S;k=!d:mOn7UHhOrp`pVCXyT:ZS7&ktcl{SlQotkI>d%)7hevKLYT&.6"@,Ss*TC*VAmB_!0{oV}/PaKO,K$bS[v!DqN::yw}`@er.}VP>%G8eP;_`xoNZ|ZjZL3?RED8Kei[OOY_hEzi{|>a!%a4<X/XN+M)z,Kn@@#Qf?PJA8WM7_MTf:+pGHJeO,uD#"/C2jh(T8cq8WNp1*pm&P9F<NwR6%A*20$BU&>rLI%_Z^dhC,X:p(zq<JPo!kOVts:zG(iAsNw*K@wSMZ^GZcr18A;bc9B8L]S}mgto<|Tbkn/JF3S1U|.S$XZ5;4^1G)"/`%OG/iH4G]Gh/>@2ZLBfgyB%5yN.!0c}bCy8.J=bLzjRcR8}TtLOiE,wo!7;7<GDz@"XX"`B,:S9S73deCtb$KL@*,^yZki86,5:^3JTNkg#F&^j!zBdLUk!yqUmg2G@/0h8q"mu:2".a!$|.`A0W*pHF,8^Dk5)NSi":>k<(<bP`VRsHwgt*#b/[yy/DXE.?MZ!I8z&/PVrU>bn=B2f49s#0:,djHgE+j5!Gp~6wjjdH*2;sN=kbuS##ZCB!"HQ466So1oZi:VSi`moDY}xTjG|tQK.iDp[=uOJ}RsL4S]no?N>s7%}><KP2o&??s`ZI/AIUoZ#1x*qI1sqbtr4s;_5&`ZiPh~gr[5>nnz!).7ePm18[O(cY+oRO~ahl||MEz7Taa%qu4#TLklRTWYZN}nH;X,xbQzq#Whn0O_]jhN.~>{Tr<i}5]@AIzOb1[l(vI=q1n3mqsw5ITjgV?]F8Up}sv.qyX>!~#)]|5!h5=!TEC2z9u!nbM9&}hB1*kPIo<2]^0Rl|O<bq=*$/2WimA~&r=[1sp30Eh2C#*GN#nn+AgtD4ysyBp75n!l@~y8&CnZAisr/6!Z"]ri2U5Q=Va2}#)B|/wf$2T0gWGA=vd#XK`3pZWIm=>PT"TLpr=@!}X>/%u@owZT*/%WXH9,"=Ni#v3%zkQp.k?+s4g~!B[m]Yq30I6XFHD]9g~}V"kH%J8;6^Z@.8=w7g.L"]soXMem3^I_Q;:m6SB|<Pw<^*6OK6`I$KWM`.ZY40.8SU4MLgse3(/jJ$<chW0_r:yQ/P{8`,<C3C^+yPw.*=$7gcC:R#Zji&99m>/PO/?/U&writ5_k1Dv#x$nf;UKxz9H,>GflbM;0QeUZk3iMK9)fUVbMzk@D]ag_t=ASm/77&SxE)m<1:nJ<Gh2secB1l=GU3U8(a7L*3,:y;eqodOL~pURLjVq{]S~x7Abw&BzaZ3Ak{FbH_s%<{oxezxs==Q$9.e_*/u~TK2XqgW+;w7<:QQXPZ[)_39&RF"#uC(UZSUx{l&*%`nov[EHk!7zn}uv[pa]_1rqj:bf;8ds#!fC#M%qYqj/=mY(W"ZKla28[SBvq]P>e{k^//d{!]nF7}!vc>{ZSi%Y<]tQeIZnBNw}Lh1>g>Lf)L2=07g0Fv%:fxJ5:wHm__;F"CO<5Ez#;k4uU="pQpL+E,~N%paH5F,5xXDOQp:[ets;.i5z7n$^:k)I>8alJN3hL"Ggc9b#VF|a&[Jyqo;fjRG7(M6z6z;7)*??YZtbyHJ+i)VJVS>U<?Aj8l{(.(OfX0H4#!yIRvO9:5;yz5zL:<BVhRndqmff5yP`@Y{4<PwMWB,~DM)%_H|Z[g*1d)"zh3}s!r^P9`{JBlH,A@D>]lTJ9uf!Cp]2i~2>sk*mT~"PT/_`A>Ngt31*O)k81y0)W7*VO<B@hP1<036O^jN+cUulk[$?e%Ck}MS#xWL]Z{|lmNS%cPrcpk2Re@f"R]~60GnL>T&]=TWf2GUWN6M(+1P<t2P4%7,ox]w[c;S9&Awqk7K62<hk7!FRbjMXCHSBwe<;2F<pzqFB*JKvr6Myl4HHDK|WU#jcaOO7xgq;Fme,CX?c[|SL1Qek2?,y*{aghTV0i?YkqRwJ>YKHJVD6+Ye;]oI^?T>5tb!m4T#7!Zol)neHbFE>1aPs>Ad/5dR)y9F^"3}(D8?gLJPp)tQ2xH.O0Lca}1cqqbxHOpr78pVx8:jyJzw#y%bM9K1x=h@!.|h+:F`"9a%[~N2I^JXBgE%_PC"]99b3YN"[ckCj{_Qt?)q=/I?v9~u&RRV(CZjF#2hFBd9ZZ/yr`m)CiQ=a"9vP{&d,Qoc+}CBL0WPqa+z7EmrwnxaQ$R#^y+C1>U~JLjyCZP(}n+J"GYt_nXXiVUAYet+|g~4Dj#dOru<PV!bK}y<RTiV9wgd:2+y9Nxtn!r:Nj6Q7r0#Y~}Ts)ufeG>5*W/M;?w*cR>v5cw3zw|ZMisqUa90zrB2N!6Zr^%l2/A)0K~[1I94|82?[*e8HnnA[mTBaAuDWOY]8B]%JO*xz0jdPz@O/!UEjQS{9)$"C:8<etL>doO|8BJ$9On4U~N^NrgaWQ2ldo1*$wn>6;XdF;H,V)kFC$#Fx8!(?xQBqggBk?&Bnfwl3uzsDEk3rgecK9T*2rTap+BB1Dw7#X[?kj,j+r8ATg[6wt?vCd`D0{|pkNHK%$=a,F}%x^8;AY@@<fYL9EKsKY=&mpk)`Y@?<DF`t}4vcj$n|*M9Nc{sSgf[CCl_b^XUWiqXQa[`9LF:"{tIg3_DYb)xn4j!p,hk]Z*yhBb`9sxna2@R{&(cT]&44:Vv"ohD#,<v&AV*d%8Q`kDERzDcgM3:e/IYLO_Rq3|:nj&p#(:BNL0(]vy7I!RXqR1/9e,W<RctnO,v<[[!Gsn>dG5H*EwJ[I*m?9PM@oNPibvurB"7ZOvgT1~:E?]g+^NZmQIA@?Ah2@6eq*lz)]4_q+2GhWU8d<!qxV/g:qsw8HqH3xg[6=mFl;$Dag$:|$~xS)9sVmv^#Ou/Wp{WNsR3XWY|&_9FR@|CCj]HF3g#Z{A7&z_N91WF7U`.r4zL+f(vee|ah*uX[jFauOV<2ZY;Ji^JK<q@2697u#xjgesnRAFa(*5C[eQ1E6c@Z|sqj9pcBwb?L|4j?+k&(F~uU:/z}5[|[eQb,df@`Th?$J:TLyTn>I0sDvyq6t3V:e1[]?ra~URTDN[c/b{C>]=rv>7O~}#G*;bwNX=vyh(=&&/eoA*,#b!rr1+90(e#BsqLs,?Ja|ndG!jmsE09"f.Me]5NQ!7C$8x@Rd6U1@9KwiZkR!6oT!rEtG&,[b~IdC*""$L8Lri6#W#X|+Z=NALXGB7gnO_T/"?~x]sE]>Y|.Rk)HC1DUA::JN!9#C/O@ba|CvSs!wPF!RCL)nIfJfk*4$p~lu[5G=ap9wA8yCC9Y1A.(e;N<@&[1DBwze=3f93~]"LNiE$LstMSD8ur;*hO+uybH7i`~K^L7"krGSX*zJgaM,W61E|d2zzCt>3AWEMiv6#cH:o5&mnQ]~oZ<$ndRI?Eal}e=v@Nxw/L"koza42UN/nHzG$"{vB&&F,7}vwO1+Pm5$DHG~6C`0nf=W[mw`^nM:!c_ElF51m}_>W0:nMZ_YRzT8Y[19/(k0@|"/t<&j{@)}FPnZ1V.3S#,p=y{u]~,%{4L5rx.UB6GqKJkZD%9)YX,e$NT^y*bAVn8|.nf[.bdeJin,;9ad9G9k&O{C6gadLogO.Tx2Z4/KqN+Q0AT%v2DYSsM=4`HEm(9AHEV7`*smAy|uFOrbUbTTK#khB+UoCj%hHY,dM$Eo{D0M3{<tIyinQ7xY_gCO<5U@mJjqdvh^Px$/Ct%ZT8YmjW#sjA#>>;ZmQliNG!M4NBaGG{4d6,[1w@rhZc^>pE77*7Uxo[V^<Hbu+t^KRr~c0(ezUo(|*PGLQaS{ky,Xf,(URa,aWFmC[L.oo#:Wy7HOF6No>DVLNsw{(8XV*IUi;]}+<{9r2QsFwXP@Po>^xw~bMCg`FAbF}k$DyvQ5oAd.#LbW:K1Hb?{YICqgDqv>cV[D*P<%&C#t&F!aid5,Ip+V=3g,&_V){#G<5a:4M5"2t4l*8#$vhjC?,>>$T%Z3IXp1B?YBq@gyW"WN5M+"hjib(_mE`tf6?,"cZB|</8Uo5ECj>#%4zyi9DiU?K1dWh{F3[k31,eH67Yvb2uTSn/Y2.ZF~[%X2_}Lh.=H>?Zl;V3R.K3o;V/1Q4_{9)YgUU??Akde0J@lV#0$D@k1|ES^DBGO;eqi`)rG)vQT,1=5<5=*SC"l76c#Iv2]x#ZVqgi>y4(vatHl^<N`H86}cM0a]&xQfq4!6mjh>InYO9mQ:1*rheJkH,DLbR#Otq)"3j)!vbCNpi*G8[@tI?`lD7[/BH?R$f.kHs93)By+OWi>tt;8Py5C&%@IpGVs~Ml/|Goa3P6cXw"{;Rhc)RGxso>^T&:ssFef.ToQ.:q}^/fsgQ/~AM"5s]MVgi!,=+o%zypH9a@,kbtdvPgq*"Lv`LpO#n2z<C>tbN),{b.N=I=>=L61hM#d16sp:ZUYO0Zui5gy?BVP1uHKVPGh00`m6I*tuUXN/H+MO2t*17/e1wwpgIRX)NfJnP2T`<<U;wn6}x}!Dyf~4wKhH|qp0LN}R*IPVOS?./GTPow<:Az_V.>NsvpN4&ZU:5BMg4v1}[,+;8Kn1*lQE4vKj4y[Gu)B)c@N8Bu9Mdx+tQiwPSg&wWXm=HbWOi3{8kxKS7)1)$PLDl*c?y&O(%~r|+=h$iwv04IeH{/}+jO%*UE{F4!#0L%3,m2KU!#2llSb^pk6y!z$KR^rUqY?N565F4a$_ZJhgPe_V"Iu0ts=ibgwSQ[R!5_Ad|p1_USqAEafi"mO9B`~2q[vY@AgOArSV4Y,u)1)qdB8F[7Yk_lk~XEC>]u@e8t*$)3iFl_BL@!QOMx{![p]b9aBP{F0,#uwa:][EulR(,7nJ8`:&Uw/d_D<ar6?1!#Z@z"yE9fSv]PRcpoW"b6PO?d6Pg?Pd[KrOS5L.ptORz>wkGU<Uz(bcf4he|CQ+P,1,C~(g@S_m4Gk^*dj*+q~:5h0i}t7]p9%2DZ?.0oT(0mx*k2e~Axv}u8h`D/]LgDRmXo~@83emvUFm@CM;?PUU&/n29TiKPXs"UiEvRbIZk&{r(C9P*T!cWhc]x|7]&yf.aB^Et>cuDrG4K~RoK|{Z_qj)OTX.~&PXMT>zhQs~ikmk^[v%T+L8(HQK,uI%t@w07X$(X)@F]om<r~DG8Z6?,zv3I[!v29Hi%7UkPx0A/U<L>w#/S]EHYZGd0AXz^U(!p$;$)[c9qtVp(QCYqVHFE*J$0b<8|I9gc^`3z=cDU<u).x4AkKjIs|S[7y?hw`g5hdpZ{.|)NoCnzITIW~a27/zSmD(#*eK4lxu]O_b4m3>nt4J[iV.,]l};B;U5Rs*,=ROYkcF7<5kVaoV:A9Mp3IZBTy9oD=}UZ*Zy6d1uhs,Kij7=h|a7%K.Bb(_D1{qU=~I9@zE0Z(~knr~QhfW@zLLi$e[x%/eO|Ub%@3>K;7o5|H^9o_](^:mHFwrq8qp6ozYNF=r?K"gn&0r}5`]5^MG7AqL@NbDj(Jj}4F*e3JU}34L)K)q"&$KCUS=2p){L82meZSI4$e~rL2pik4ipUndt/fC5Pcv60uI@S$Ft?xchG.OK[?E2?W>r*7C*YCNZLaL{yLL]M|]u%7:.LS@c<_bF|/B0iS<aXtk0mrUCiXo,`PwWb..9=4nIiDKw1Df]W7a&c9x[`(mUDDI*1$8ocKfWY.>68+p$gj+xo9]k/G!.wR4q)OR.FD%WgN%JNXzH`+m&t64qab,OMhv_!EgMj4E}]Z@,jq?a"A+df]5x4OvmVe5+?GY&BLII>0S.K~PX5VKLb6,AvST?i(01tVOolD#,n@Y0Jv@%1!woBEV1u~OH<5glJ9#{d8F&Z6tmFbWc5bnd8Fa6!b+lT3B|NwdC1Io">qhVnqKYN3I3A>AN{{Y0t!grJ2NzBcTQPe|19s#RzS6sB~z(!kNVbV6<INm+.[$nS|Pxc7$yQ%_(LTC6(.2fp>uMRywWC%j[%z]xJ"}A9j+jZXhbRJ(O)f!zKH4CeG6KmwOu)~6~[j)[nZg!%d,+|*(le]D!jv%/$$v5&7(~!c$Yt0WQ7PHJO`@z=%MQ5:#<m>.3Su,xdy:&FHpUQ,E9?T/+0ISueb~ck$p<b8Lr$5)u~q?NzW`8wf<WeAps%#cA.Zy=A|o?7.;C*_9d=oc~=rG"hiT%!dlu2%Rj4{7]#$IrZHiBxCU5~t{zX"vl%LLISeFN{dO4@0si+]cq&a_E;hDzb~zeqONP/W#1NOg"#TR.Z2Gr+3/*.:u5Elle>?ab?2HAIPi1vL|qYj+U/`7>(qN(%`<Y)+*1{66ULG9R"li,`{b>#9F88g&h,N.M~|HRN0BLv6Tr2vZn::nimJV6OZ[obAsbpin`9fMon@pvx{k|"d|cZ3zfVnv^E^IeRoRB3WxC*fY5K5`=I:CL5y9<#R]|,2%O~j!5XU(>TnqB;)uSHCFez;mF!U/Rt~)!{/CHdp(MC5H]U#%gU+vS58*3]w(fyH6^Lw#Ft[iPtS,Vk?NC,iK=xQx_nk0wG<2k{efIYe3Q0|x(J^FI^%s3N8Qd;o)=g!5mTiW5bTU&)=I>/g4Iz1kdwK3QeoIR[GVQ{"x$&crl`+p,oTCX&^jyD%726">b5l1C*s?>y.%ptQ:+Yg70M87=@/gt~r%9E}qvAW2.{Pd=OX+T3L;j3kiG/#4oN$x:Zj0IOU`%=u&wbO5b0`||!K5cD=+uTRIFl1:JzsLNv0uK42ya4VQz,d{q7K"u!]_)HD}gb"e}=]LT38O]K:16sAAGhYR4zoP*n=c&r4@(@LD;!&La5lyW#1FQvI;.tZyM@WBQ[})rk&<{guJ^xarQ$oao5jxkNgT;_Y5x/R]^>;xZ&^8H5eMKPJcHPJE#PoAzAl>73BH&|Stl5t0o:@dRrJBz]QY6BI?+1!m1b!.x,RM?}.:17_a|{HOVz%f2emFhiO+PDbq/}}@SwKOapHrEZhToHqEpF*ja&+CAe4PUonaF<eC*a!7mg)VVa5vs=re[$px$8VV~>y$WoHFn)[P5!pV58"65LM/LB=|)7|4D/H;1H!75])2|/%ZXPy$,=J<itx;Z3/;L=f<tH7pJN;/s/5_wmir*H{3fz>=F]2]hkem!6XQq)[RH^5u/.xYq(IN~o^f&qd|iCbUSSN>VX[(JxLNrI~la)zqa6;7/ACB~]]dR/U5*<bDdBryI"K4lew%,D~@[%L`MG9u=Il:Z(}40=<&2W#{QnhPu&s]%U4aH~}/HtT$7uTQN6S^V;^;pxJF&|jGul*e#R=35]r`[v.S:6}*|oZ<|P|O|gx=R"bKkpp/7HWB^k8WSB`~HxzXj,%4xI1#_o]MsH2{5@})b8!Jy:h|<DZlF`IwS/Bq5oKeaY;2Z!=0!44)vX_8=J<V`]{wYroZZxQ~yB8B25@$(/}Ea&TEJ]J7T8GRd>U=cQ;&jD@|#|3Q{ni@p8.RdwkK}kmFJLf|oLmuO[x#^w,;O#!$l65;/ii2Tx;Er1UUS&N/%049%12L"}Di3+030fa[fI`lT%aVdz#Ua1WvI>yg^M+btUnj`tsR:)d1~8]/lu&hw#,%<jEFwhJ!(,a5u+|:u]N$7}9iTPhO?crFAD"!l_!>m*C}C.JTvdltZ|}D:XIT/~Ql0U[t/ZbT,xqXO/n1wu"BddxH*lG|"Dbk)Q24p2p/_p.kOq"ecuN+[pC&L2(*~(]_adtRE~J_AMQUJ_$Xy)16OQl&wsOc)b!iutN/ObL4s8X7kv>(C5^tbq(HUh[To~bKP)v~+s@?x>paN(2Wfr)BI(99F~5)PyNUj7];G;~Ai4KA^4/puL[4sz?zJXE4pnl%O2Z4o$hRM*/ko@jmqCS;.9TE*>*3z,=dOoTA]xc{7DB]`NzH`[$Xn&*e_UObUm.eD)hu4$LCOo~hYwCBj[PKiF6ISxRNYn./D*yIo?n=&HX#:Jp5NSnBmM_.;bv+%znoFo#%zN:AOIrNg`bbA$nY7c,H<;zOwRPJVe,NyE}!/98k6(3FLfhkGpNB8J/||XnpcsV0sSGE2o>`@=d3[:M6={bP@(1FOq~5*5E_s=Qf_X7OeczlbI)JEeZ)xkMr%$~=ylexSI*H9D+*v%pvFg:nf%zl?=3f$^?sn@9:8&}CLBe7Q]51F)]deJAZ`3lrrj@XyI1WI?Y$76r{e!c{=oCT4cnj<iLJXS^{d:cJGaUD"ANCZ^A=V6KoL"t]#U^9JZ_jP]3x=!#$yhw*cWqvo_l.S}:oEJ~H/lcBC1|TG7|,}ScNI/}yf2s:wj]v8C$j3#6y"tf+Xg?"doGU)|`_)_yx`N;/Ed7)x1M*wJKN*;LY$u7dbYVbr}+#XJQtd,Q@!R}uC]W*bB)rdv/GNXQ1c:u7[w13hr&rO}QSIxk+P8J[ScFUS1_9?BnQN?CD<JHfa<)(beKi;;W>@nlAzkKE2)rTv%bxq*D/UNc@k~ksRXJp6SHT,<EC_>:/7E$B103f{Ny#mm_op97rg87c)re.$jwemg^JG>CQGlX8Aky^Upj+U@=8Y#^kN<,SOJgA8VJIdPdvOF@*Re?@/O|d72W+0Q}E+L}bU#B&D&H<N_!Z/@d[q>pJYTq1VIzODF8@28LPwqd2jgDO)%MFuyu8;(r[NCdfvy$!+NN$<14]a0Gail3<>KXQ.7I]Ck+n>U@cQjR?[Z3B(B<)sStu]z9{ERB`:0B<*r#Ri;wc?wjJD~L#7TQ2%*qLUq7HRYjy0w#n=NYEEPok+/#M&!E{*FDPE|X0]#hxq?gZT$MVd]B>>2NbtL,+?ud|sP9[AGB;6OeLYdu@da.r&Y{$KukM(%xH75L58%H`lW5p)k20yxg/~qoAss5J5*)cH7Nn;/%{pV}*??Oglgvp;+J?Qjwx&7B{;Zv&KHNj&V[1/aE,k%5G@cRS/>{L:(l?;P7On@D+`lqGdn59qpE/*!,{44z5EP1r?|)OjN,G0s8(c6Cjs56{Dy0G6FAV#4ZbW$ZYz!<5][9Zs(6aLbAEp>lwiz~!PKH?]W$EJcLz;i/`"Q"NdMaBj@hQFVhQ=5Xqn|Yl#v49^m><"wCZl,5m=HPvKM,j)49c.{ol(l3?)7(rxNQc:<pJ5h:J+#^wDSWaXYN9hroxWZCNw6C4K>FhO,mkPT?S)B`*Mf[wO}SSZ^uVh?YYOklt+L?3{p#[uR+0DTrjVugkQY7g,o$0&[z8GV]vi,@38QK5zqH1h_kz0FQ4:emn)v:.{s*`rc*~~7@Y"N[aBed{GZ>H?UJD)?lIEh5x=J?R!),V/;)dHO2&.dnc[ie8xNa~*.oyTFp5xj;()g_]Z%J2v[Y]B^Ej>k.U1jh7p6[!}J?hre.V_dn>Bgt0XYBl|k>yQKA!C]z*/X~]xW{Roi9ed7D<_&?MCk^1tQ1t$j!ra.a?*.u9MBP@4Vd_SMOJoRz[W:Wm!3x(ofLySnGG{[.q:r,h/ve?1G}"HXvXc4J!b^94JHX%p0=t><~?&M:U?T"!jFhBQOZobiqq/J4^qe>eFSvh3>3nGIAnGc44TRex0N$jwD.o79f3)R?CKEegm:O}AQJ}x5Mu|&R7#(oe#NbT(ab;j8/5E>axHYW,rol^Iwlu<|/:IfU!(*p[p$?#i+&po$]TeCTMY:2%MJ"A.UKJ/!L,ecu&X3.<=u~!~"N2r:E^"#Eo=q@3NvezP4|Z2*v^5t<i7ma>FWO.B"*OVun)f6A.c=8*}M/4WuV5vM/=MNNhajP=ZmyTFKb|2u`@tv8G.1*^i=nJ;(cqE)zp9Tg/&u.w[sz1qd:.1CDHA(0biR.g$8py9`<yxWXlS.~>MLI41DcfYMjPP?NBB#S}BGh)M3NE?*+FUJ^bx%RJ{faO+iUN/e?T?UlwjDDU1zRK##pktRx:{md8O|qE9I6k%)`5<c%w_Qs#liHk%:0zVYFRj7LV4Jb^y_ze!^p)6t=x2pwwuPpM5&4:1*%lvP1z0lD+u+1xe9bSx?ORXCX>I/t^6Wyz4^h<8iR1fh?{)eTTNl,*b)$q#NcVy&4c7E%!a4T]`e*es;g_oTOr0Cx[tHWw6INiZ:#FqTQdFr<P@#qAq~u<z$}AGM`eo4ep@xFET}wDi01VE=ox[D1#%UnUG0?3}zzDS[kCg:pTtG|Ud2X{@HqTDnk!x@:H:af%iv&j8w7/XgS$Uq?o(n9ieDw(t0Yhi7:o+VB(W]J+:yyeh*4Q+_B.Z7kr"PQzt7@kV[`s,C&IV8sy.xJl)$I9A{0iPX9w_c#V*S`v,LYLS;$5#tP8$({FalDvI[LpH($&O+:Dd`GJ/D8H|:xE7%#}VItY[/0q8WQ0.L{P=xF;?]=p"/p@AW$0#gm2XHfcjpum#OQO..inP#phR_Oy=Oc9dmo>P,Dqup]IXi@hzNlY*;r=bIz3G`qT)Rs/%~so^}g@?4#?$+F@S01m.Lw5@CXG9?06/x;m5S[+/50R?(r:/uG`tEyFAqjPR,|)^rBQ$uR5o&vv`amlTauf;m#]e^8Ls8A{e^X<kn_q*g9R=Y3;^FQM*d`PVD`ZngQE{>%~3l{rL4]CBp&1#ziw@2P3]Ga?P;M/$X}(ceC3YH$LvB;r,mGl]a&EW!$D$z,sKA}w;EFYQY`OK?aC}BmC^*yTle&eomwp&+/~)&g%N+8Eqe2t#b[P{=h&tzq4HOdUfzr]uTqD_)`;S7_l<VX[uc[thkX[Jpg,ZC/FpfJiOA==J<{^%rR,0=u3&wN`FX)f/Pukj[~(h>x|eUl=+YjbxHoZilTfN?Tz05H=?NZjY#*;)siH_@lKp6H?$+JK1)Z:jXMe)4UH>$~%5CgHIueQI|Y?Jo8?kn;/u!JpK~!?[8j};Uf9r>_M`KONAsD2~PnE*`IVu4`/K1H]&Ivjh@Rpux?ZZ)|+DCBup~D4xpscy}g)*gVpGJF!Im)e%90ZLl"09;WG(Gv9>1^#j^Kg_n6f<.0GTgYiim`MOe3+z^E;~JmQ(<`+~b+?Vj}$6u!n,znG~HYm$nl0~yfcs(h8MF{~x(TaiOypkwE:$4SrKJx$>WI)SD?VP]0lPea)_G%*jC]`f0#nWC}/sQH=qG5+r%Z&_S_w~at0A[),bpZX(l?*Z#,8@g[X;PXbMBX4,k;=IkqJ<#:*v0Lyhc_|cM1bNwW(%)tB3F5*NwZw)_MN(m_XxZ+HacQ/jK7b,/|UytK0Efg3rr2n/mvWkU!N"VwG<e=ba@%uqGWg]@(R8o:"xyv,DNKzn>p[|m.!cm9,N_v>YDeYQYCm#ZU>#Wmp}jKVT!~d+P3=<r0,"lP(rG~{/[}1ndKIdf5Pnla@Ofu><xBf9]u=o/Or&_3%lI`%xs|!L12,`lMS#nh,=..@xaDoF%n49ElYGH2=.n8|MC3,&&Y`}xNFYU_mH21=@&k$x?pMMR"r0cf#4EN`D1>t,!MN<ni:Oy]~!TWeQ=i!6Y}:Ea@!LnJC/U]$?|R!:CYS*=#pqBhox<6y7{}TVb2L4S,WkK.:ww9Zv6)o%lKxWpI9n@uIJ+hUWK&_^xdb!@m}y$I~D*:<#7kBR`d$(p}.T|hP?8ROyzC,5LNzH3uBv;zo$W`Ph7KpZo3,;9"l~azrXjs^1&wm"dBofW$qpmZl?%?oF0*bO!ZE?r!=y`$t{@J|R4y7%~V?:b6x5r{+rCl,+/5**y3f&2utnz>utK`qEluk)e~Dn0?fkp5T%}e%k`<S(#`y8ZsPD3<d8q%o~Q{T6{(j4X_}G=m5WDsR:Y+CZGFEu.nB<Y<c/P5l7SxHYby$D9c1Zo`&h}~,n%,6h&u#2}z+EfJ*xC5u)K`lnz,1l=3.RzT~#@Jh}MZKx^8L;A"N|I>+T)[TKYKbUG(U~w]cRp%UaJ0PF#Zmkk#?/wU>edKZvI6+U18>Sa}~BwV_@(qibdlDKpH[5<gZhL[PPv","zgyWGe>0}cLw!k}tsX[7j@VFsmHQV^X3%6Sds.fe<3O+syb//R=V!(*q:[I9%=6Ox^s[2j8.3*px1)?l!k#ADjimCv^VOqqi%G2&+=)}in81Qe$5bOD6GSTFj(rCZ76%Vp]<r^req.}pM^s0F;0N5a)nHT)q3pfL>e>^l2z,zSW$mx%a4|L/_}?`KJ;2,)U}|Bxje^!L*^_{z@|Oja^RG/jWV431g53N~rY0r2m`k(AijGvs_.E?_6|t9hTA4soPH*BfJcLK+e#DyL+TuE{+2Owv%Zqso&Z|="e;D}wPnMi37j)kVT$#un#HR%byv|QKmo_}l8_Qof{K5q(mWyG]lsSei&6N(Bpk*Ya5OOc2WA<!fZK0:N#.dIx~#]%@YNa1V/UAlOnK3)O_wlM_GB^le/{[TBC2!u{$s58;Z!KJiGSH}G3$tu2+0)Vc,_K+9Ml#NUk:jsR"mW8L?MHH7ddC|9lv*]5+>0)3T7K.ekHC%uKT$3F9CN=)aN:t_:@s]o:F9|7)r~R<b?Z7qu@RJ~a5s4M9ri85$WHmC9KEK0Qi@zP<8&kp3o$*QSW(V+36;e35MTeJLj&Y,e@rC({t,IzXGLoDxhMUu@V<DJ2>v;r0lEQ;Rd}Z8rC=^3n2X%q;Co}g]yCDycAL]XT`%eL/2Pczv#cxsv<BW6cIDLbjfr][I5g?;s?q9DRJ@Gb{d,r_i0=/nv^dJu0/3R2!_R&X2#P0hg6&4zpG^?<qe3+Se6~:0&~GnD~B{Vx*wi=l^~o%2:a"8vOncA`lWLf57}9xrNw1Wd@+7q3;Y0.tns$d*7%~yal{@&gIxys}!d;td&iAk+[>,dx`kL/O$~!9FLEz=F<"u~7s8$FcQPuW?mo4e`FIEG5#p<B9n(bHP2%kz!~9E[>YprgzXtZO]MRo~v&5Ng,01z#jjVj#Q+Wt6y+Yc/NZOFiPfW<oOg,.Z"^0<fBsW;]~${fEv%f0.h9"odhjZg5oL]VJ>y8x^y=Nq&W__*D0HZfO_+xZ*yuuW"t88l=GZuT)YaD{U|&7kiNufalr:)J+`+2rj{N=0@0/zQ@;NWTlS$nTLCc)ikztR|>c~1,X$4ra2Do^Dncg4Lac:xhI|~pjd+J"U@;Rv#=oNN=INSMyXKAH}z&@{vIUpB8Es%Y4`6w"Y?(W_S)%h~k{`rz`>aGwC]YC&O;^5T)+z!R}2dUw]0y:=&)!{0eCfT%hDr[e@fO"X8ChlBb<K^p)eS@jSdD%8`Y.X0m%%Zb}or<TEo328m?KJyg!_afsdeoEue*#o3h>rypS)&vTLvU2O70r_LH&40$V[op1gD#Mq37[}<#EA>o1?X8CPeIszw{E"bFP!zt}p;%o~`)[Rqx*1AW%~K0Vs;X`qU/:~yG{vKyasFs}JibwoIUwQ9@[L1h5Vw$1EmpPE92!_&Li<5CvcwbSM0DRj_f%Y9o[i;PxdeE]tU,k_l?w)d~c7EDX<E|Bm?;f0[T*1koG]JKK>avHO(z?6GWc!yzADpa4BP!sg5Q;4=UPOa(4F{K=<8{l@LZq]}ZO/[eo:{+bK>gd9L3ey2f}Z{23^y95d%%_&[^OYV8#lcIo5<uGp`NBje])!668b<Ij{7M1ok[|%?NaJpeH)t&4/|k_Vl_h>Ak*vI*];BxDS~6_|E&TD$~^`LqDef=.aeeMloClAWZ0N$bPCr1q+v,Y8^:9!%p_WIxPd"jfEmru#)75L|vu{:v0efxMO^]top;7#XNh0hmFjR4"eu|oX^}=&6sVI%$r4}bU|<dCW83)]g&Tz>9j?taQ!d)W,"GJLME[d{dsrz+~:/]*krEHota5([8#3Ut&$v3,9NG.yL&O_v?CC+X];L9gRd#,qIS?*=Mup@hjZ7RFq8QR]7kY;M+6M,wg":,?;NDKZZN<?_sJH3rQ{:m%(CVgZ;y/hM`fgWev^6W|/x.69a/,HgB3X/VOG7da(1DmC!<BP]d]:.@g+q(,5o),S,R;U%5/GcX,bzDCjoz8Y$W*4;[0;N/g&ociUgk?:q=aHR<hQy;@+rM6DdL!<CN)Ts/Bz+N&YUP)xu>]gYEW^AO"="9:e~NOixYGO>{].IMI[[v?;)Is?;qYG<0Cr;5nQ%6BvtclY)+lp.2=i"ZES"fl%|y]ZK135(i6"[]mX_3mD((YZp^_%rSS4KB|:O@0qmBXoFgi|}np(?o@(cT`4GiCUPnm9"4[c>>?*nW6RJF=M#QfJ!d&+F;[J9NEtXDr1gbx`p2/{j9$4.;Iu"7bpcXjr<H_mf+7{cwlTR[LR5cb<R,<E5S:ZYp~w~ebv#Fcwd@?@5]wc9eTVPU~+mHnaQ/e.7qtI;BdO_mzFzh:,P~Tmzu37J:nXXGS,,C?Q`_)1kyu){imNCwmdv!MEF|}Xd2+c:V6<3i](x8/[8:PSh6a,Rk[?#Vu%{uUv,#vwU#eMy@DWQpWQ^{DN{yAxc|O9zIR)RFS[jZi1F:F9qo)U7TP@[e&j]3t/PUYC%,:d`T&hO3eQOhDalGmr0U|o)v/)qcvq"3dEKmJB>_oPlg]=3#DL/h:MNFyEQS,f1|gwuMrOM`AULm!*DB/*"ux[;]zKEXAO}$@b0),=GgHHx^<0"C"+SJ@)+%_qjqv>WH##VC;eu&|FPaMN(c{uDQ}&5);yH`!1[,Dcq[?:0[*.MWOw,.05hd:Me*P8ux2.86xpb,.ck54Uw@`qRWUwCs"%A?"c.?=tb?"lrNB+6]&Umg3e"v2/S@~POM+Jco=>7]tE7vm:N90yJKAM?lO<J57!lT:bxIBfaZZ?aEy;P`"%U5=3K.X]PRM(%kKtTHhISgGem9cFGciV4|?zz^X.EPlgBer%`IOmSS^ss*1)l`7m{BZKI#5zcA<JZ&LzY#9n.?Nw}2f3;?&tE3+]U_Pd~ClF/m?v,e%j~bAnX%]B|jn[H%qH3%I<Lh,aG(;yL/&(eyQv2HF(6oRrhH>$@_f^K49F<Z@M42!Jr|VkMgXPkP[RF99L6cv>ksKeHEd2=cRMl>|"N*`9ZL6?sq2n5gD8"m#+aLc`D@|$k@)5]SbiN3Ti{d?vn:k5!0.PIDeE+a?9N8)$z;Fkc<dCXH%37JLG+@(Hu:AETQ@d]Cr";`K=SyVtc&vqb.aRw|xG5*!P0zdKSGoDBQ^%O*2.qYXE(9?T.fOEgKpZQk@QE0lqN]}#UK!+33kID<Mx@ax8OVPc]W|G7yyh70%y|V].;sAt2sz/=QmtFf~bb?nCx58~.0diovs+*KT#oY?Zf:>B/Phyha=w"7aB{1iWbq5?G$}K{^M8GmK>op3Oe.[2wQibS$YQIx/lFgaFLG!YcOtU8m#g1~D_M~sEwgDrpIvDL$NWm[&oh6Yj*tS87r+=p5:=?$$Js9"@ajX5M7OQVF7zJv(0H/lzqLg{2z9Q1CIhC{NHScWJN5i+"nRTma,[4C}dw[o4lg<SMP9)|Cxio0`hX7<*?H8_,j.0wniyV#J=&c":Tw(BH7HX!X4w*Pbdy~K{[%Rs6~%F&Oj:q=8C71N6a"pE&EQJE$e6xxh!z?2cl92hVjUV1Bl#0p69y&wdn}*Q=%rOn/ttuJ[hjDt6)#Hed5ygweWVnS}));Zg9UCh$Ei.]BJ[A^2_BwGIK4U}s{7;IYaRI8obGVzNA)}d5jH$0c~hMm[F#x&aL/b*>bL99wW,KXij_[XWS:FQ=)w$46V)hV2Tl&Rfm8]R#Z4"RLn!hZwr{UZJrSpS0N]Pft6`{d>YG6Q>{|?rnSQqrx7T<{OvO=EIJiZ*iQC*LU.{J+bygM{6+R1nhH[=evV&H1tIE*&ve;)H||Z94Ucn19Wpz9=D*C`b<.,9PET8y$]3(`YrfX;%t|:lQf.3do~kJ=%sFBJW{Y|YIG+6E"Nt~dQhKM&!yhtboYL{"Z,<6I]i7%&EK_,/_hQM}pSvBwUeQ^;w1b{b[VgDZ}x5#`o"~uKk%e:Z/{)H4g?d];uD^p&3rS9RZVodX?+1`P`o:s$)5bR{B@pkx,rC;{QNRG@cypVZ#v%5x@z&!{p0vRdP]KJuH`B?|dRGA9<4*@oNf/zop*75.)V?|i{Bu+Q4|x6oJi}gkFTwHYj{P9jTah1RhYdC|*o6S2^j0z6a6dVIF^E}Fi"bp,D~3Y(6q[|:^H~6{R60A1/IY*|*zvl/8cq/6I>B;%RB3R{j1_cO0|HyQ8]4=.8(dO_m/qw!]QP///sPRbV`?5Y>ev,[OK+ovV{*&#Od)+;8GN)iJ^pLQrLIdSqkR)ofJ@iNP%,_,;RwSMu}B.i>;uVj)W%xrcjqLW_&w2(wOh1zZDV}GRN$_p2)uF+D"X"`;A:x^E~Y3kFrt@T7H2z02N*$<c1W(DNZ"dv3b5f/HsyP*f$uJ3(PuM^3z]e?,[[}j|;Xd;ZA{"9KE+<%mZQv:Q$sezp5Z`Ui%0]R.Z*Xr>AMam(KBM}Fdg4c6a[N.!fu7Ad*0zZJ&POId6}e[b"ha2FirY"MJ&ar[|f9VitwT1~=yadH.3$m(x11Bk^/Ts|X(hl#3Fq3K&6U5@[;fI7s[^nKeaCSMY2:=ZT^5UE^Cqs^|iKp7,%7n:}WkmdymVUmX;?/r?DUXX%hnW0t$IE2rQVXAMFjF7[!yJ~{$##TiJux!KO/H[JDqjo=bvhWt83[$CWVK;PHwVMyews?KxNEd&)msXNGaMcL?N)0KF%2P3)H84;w*~.1JDC*D8Xfi(r`kOu@rTZ~Re<pk2z2).||iQE&urKdvn._OGls}B+u;p]ei$y@tCuX/VqH$P{gL"n?JuyN;n&[v9[!c>=&m[]KZxMqU/MF^~0oq}rrPG]aGq5/Acp5Ur}>c|uz/9#;xjsFV.u*:IdNjG8/@Z}"ha<dS5?IZ|wL1Tz>=J(%SXdEoNjV}2_uQd+?/PqA#QpsTin@ulYsKf{e,T..U@ZW.o*1V5:?B%.@Ufqw%^3v:&kx#)26En6<d?ELCvWnp^8vGdGxqeI5A<[#o01h49yx!N!Nw>4dfj*gp[jO;AW6yg~tHF|S4pP%mTd.^DyJ_|v9gx_dWGC%7[);_Km7G)K0])NGHEl/oY.{SWku[b?[V/AExbtwX3D;ur~F,_:bT*`i(s]&0G/Z|ZhU`HjtaEGLQ548*=u%b0OsObK4jo<43[V,%Ib=iod`?jWkpO|,pO1Cncx8/]WH2Q"WgtP`9H84l>G29KW9CS)AEQL#+1U/*bkXsXpj6<2mEkEvfLlGZ;Ih{0gavVTWaJl&Ij:T83%F9bq_H~e`w^cK0;Sd}+z:7lArc@5$b69[)oHKDoqgMXm0ymn%A_rc`D.vE*>r*tt1C8?)*CEBKNxwtXRnm5Kw6oBRxe,Y_qUqr%6&u>#hjVR^vnf?A[$P(^30Kv$<!O4d9y~g>XC/PFS_&Z?J23J^u|*=t[_:3;<0MkpH7}|SXC"o~*6F=i~zaN5{d8Bd`aMr(.c]N`1PS&WrHP&lXivL0)vV:4dQI)[kmCQ/BjnghVkL8/Z`hr43u+<][?PDSFcX]uj2;aPUjWndh(LNu7iF<uUiram,BBP!g;:E2m}x924gyF]b!H<`|fivLx?R#a2F!aR.&d:`VlE)^rlNZ^jmGtG(B{|*MxY{tdNc{S%)[_0tp}p6W:ulpVM+2K$K?V`q!X3kx[&ZsCy?AN/]}]f!ZU,D)xE0,oUY}:z1u$N`@5kJ.J]t}e4edos`:nI={Z:yp+0srNQ}o6_$JMv[BOS,z"a".5QGv71_ev5W$N$jx(}OTD@M<wIi!<;*|LuGRv]qxe,r`i.f/WA~}BF<yv^UT`d}q3w4k$W)6m0wh9QE<0~k_=B;k88Z&3[#hcserb9},w9Bi~Ne0?fZ%9<ArWHKy+stneNTQ)68Ik7Y~p;4hf=vv~%.}pyImGKv,^csj5/CaH9SUk^_llPm140."l#]cZ;:enr83iw)"<VRh0,WiE*|NIK0;B.P&8)%Gk+kT;!]s]]%L0N_:+J@&N,zYy<IpMOT>UUhLU;8|Yhg3$Y",C7O0w@s]XjsKNd0S1gN^4#{`i/05sg4.IGH>Ed,F;Xy"wG]XE514<}+uroo&#GSw_TSrWBGEjvuqjDVJdBPV2b`$|sL1&R@%7@]L/R[o$U*9yk:zjc}.UlFtn,_oiFP9;_{}nr0knfOCKU,0Gtm#nOfL1VNO3n|G*Do9ab?ZTjVWwRb3{)3i>(G?ey5VbiO?Ui$~0:Zrzz(`+lnMOe/e5^uc/HqFIpberQ[qf`Tr)&T~xjg/O&_:#QdHCW"y71.llH)(=d"KL#7%PM(xN1Cb.NZ!Krv;+$uyCC|snt^|xeCgC"z$CMF?b%N^]HX%16HK|JLYN,}cWwLY{*:,sz&jji~FtVv/nfY9NXK+*Df`9&Fa%o:,?SJoDCGQl)s,gR1.>G^/@n$O^gT$[tp6/0h*9+Lk,7MJ{R0p84)6ylgL<k3hlx7ZF<^#6()u_pi]i*)*|(j$5gkdi`zp%=PC4QwYkgzm;~jjb{puS,zGl/+Jh]bis,x;{cX/2|+_t,]kxjgQW]lS2inf#5?;j_b?ebw/,kE8hhf,7|Mz#EcHZ_AqqgOS5GF;aV=dHH8fZb90H&{$Lk:K;%0l[{T+}MQB*`gK71gd<+m~k[Tf5z?GPlR/RKqC/&Q.]n9%S!gu:le%SeslloE^7R4~=}"Ibk*b=JJ(_M*PB9VQ[pS9S(=]K+PcN(S|C(wQc<hLhhOFX6^E3!A!~Hm,Gf!`1%trr|*c&dMu5qUaDeN4[,c,u~u602T1.rRI:DWoH6?$TxwT=?WSc>you{#Bm.[r1|g^09RD,an[R2M*^kt]]mY&XY%08`F;o=FHsh=`*%{g/8I6w%ykFn_aTU~vWrVqCK.2TEk$1`%dk3%.^YTAdBMT!CH!dnu$A*(gONkeEXH^eL91i`<eA!vC+c$(uF{Sc9PY_6rR#GI/.6:2gL%.S:GKuDi|I0~WShA6MnVFbK1(xH,w(u(2noVEOQ.;K%IN8,Dc?Tkc(*+s:4dM6kxQn?sv1}TD2OZAVppA!|=~[S~6=ly0[N&,H?i2D".t>~(DPvA.S?OL9l)2vYq?N5[~Q6;68kFPYCW7DFM1x3U<F=n<K#=f5LxLL{(LIg+Yt1}n!D[cLA$5RR2qZW&l1_/qA2t?R>b0VMNBVD!E@Kg:X^Tn>38ieId:aM1)rhH/?mgj7shspoh_8M4q2kvaN+,;a+=0u~t6>d;qo"we>txY/xAm0M}Eo$aaHYV4~S?@345>.qq)52w,z^!ca5ru=)[8S?NpK_zR{VC`,|nPv1(y$k|g{aoYU]aY2]ez9;khv2<Dm}#WoQtNTd4ZvR`o:OzW$5PX(wfse?yj>KRt>{?404jX;LbBu5x[&muvCQz?:A~^g]:%1FS=qcS)+`$echelEA8iLYO+y>blJ%oyYCzQ4pg)FGyk=&0op<mtHsV?6siK@b)$=oO9np_tWqp98s@couOF#eHIV^`u^_uKs3,5D{kiI17y$]kpERrN`E<tuThO27|bEf)|q>]!GZ4KC%yUsjZSi309,S`{:tD[ThXBCRY{sogsUJO#QF)y6P/3+uTaq&/E_9uaBV.F:]r9ZUllYk_#Ts/i;o56|6q5+;n$fM%[{gt9~Or@]QPp+vDq=+r,rY1GY/:WCFiC+f:[E5y*ovQDGDXAx=X:!Q,_MD5ToTz1Q9,PT/sHMWw<kCTuYotRX)|g7YIVKlD/5N~$LMMXK9UJInLK>njO#atF8ph#k#OdjfXar#gQ3:q<poQ2WBtN"rPcKMr!(eO7~Kjq/<X!P<UQS]Hhb+RQqZTyTq^BR@N.F/ma)vDpxENLr2OUr@vgF"cxx"wRFk[|}"PZw/</TJ!eO9@Mt%igSwR`]|T^x7U*.={hhF1F953$$kzF<{SV17N^r2J}ECKyhaWgdb.<D*}iw%Z(VU=T2,Yw|D*>vY4;k.gi.:fI_D;@#t4.euC>y$s)O|IYDM7z)+10=O^GA5K,+xgrhDoaj]M"_iA@_bO@jV5XHN~ovB3HL4<of;TNl"V1:%e8r#GMm]]n[QIeyweo%#86I+,kBL>pEBGfK4E8wN|36,t@o~7glx]>&:C{YuD}S8slvP}Zq1b5+6pg6f%a>7xH%+DO:e*VlTY7IP|Y/%H23|REeZa_qcA^a}%&Jca.ahrH$oHb@sU+vCz^G5Ci@HX8zRwqB6%#1L>q]<)`8vX$vdVxA;Wwn`:bpH7s:,QtS*.+DI.{D~?m{Kw!9p}8Gu2@*M@``wDyxtrCyU$dE6`,LxXT5"|fu(_/DRY6<6r.8I_}?E2R`Q}FV_b}4NrVuW.E[;VR,FW&&|?]V<113U%A^N~Q9yq=^So<<;0p0}O5U<K`t|Pue2m~vdCS.2L+)|!mI;CILS^>QCVS)}:vI=Ib[)d|b$;2_5N%YKMhh(p]a2.}q(2b}aA]LB}6f63DvZ9>5B[!B>~vt^2@Qo`"on[<;ykc};3MvyV&pGi4Z[Aqo/ixVY2xVx2B:>"|?~wvi";Mc]Hm^"X[B;#[oi~K))hR[=qI"_]=HC5WitIoW%h9i=%5pX{73J4dILD&^hUq1<ta8SXh/s/pftAx{y]QH9X#(G^N`rKl4q+*{K`)O_&r]HwC_8#c!@jMt@)JK0Z~P~5+}/Hsy_/i]FF$z7iv4fG,KzJqyF>C}F)421fQI+X^n^yr0l`uaO66`pFahe&%4xERp825k^jKx}.SkND$fRGN8lM}1/t_TvSczdS(Z9+{MyJqak99J&b0#_&t=tHQ*N^rwi!6(yPgOCw[1IYZq|f1:3MTN0+`Tt~v<br;[o>[?NxRDv"R;O8fC2rbTh|>Q{|F"9bVuAds#ODS=r.)D^b`}D:*R^81}U.>JqIW,jSZ0ZyxyM4&5L3OuoK;USj>Ct0{l9QCCOGXhB97ev/yZdz%|`?Rpyh(Cq/O.w,|j&x)=n]izr4]B?T$F,b"{Bco|QH]8hEx,qH*7V:ew"]DtazdCKgK/^9xiGU/Zg|vvx.tx>jH`R]<9TP1KCGy}x!7<k/S9z0iy~_|F3K5a:bpY}Co!:ds66x.!$6)`2UCQqi,8bBQ+;t<IUZWNUSg=4FT.L2Yl`$=3)m4.pk^Q2V5g{HYa$G((G^kJ&4GEJo>0|OG5=k}C,%?@d~nauCW3{[^#0dp!qShHAgXnf^*sTOwgcBjHDGe%R].:={[^bps3L9)n`kNR{y2oO((Uscy&2ul2t,~0Z9ok^(qh"6NC>kOB7Sw^`u8Z.&n}yJjIHQ=QH`Utv<S:Db+0H3Vh(:HIFV!.i`E*jD51?|T}{/@7f^}ROpJ_X6uli;4Kb&ZG7Dqjd!hRDO}A`+?E1Rjql|zw:ioCu4.Cj6q@{%7cJgv!lUVvF#TBqu%Wjtk0C]qO%w~T4NRQUkT7yzyKCYj~?VfR7QCvJ`]tYo+NTOvUa:teoS+&)wVan:A,]Ri,J)~Mqo)~L[@gblbTnaqI)Mt,m{I6wX^mF!d0D=^~t^JnBFIh}:3~Zl+q]wFn?`2CRx.OHX!umP.^;lF!US"Zj5bY8)AoFH6HP{46>;y%:nF?[C+tiD8;%@L,]ddZvyk~Jn4C2f:e?93_OAbl^V^sH|M(PYVHuU&7+eR~=rhhb&*<MXO#$i"kqX#c~mL1Q(m>!!,yyUu<cYbJEDzeg#Z;$,=mJ]]z(RC_+ICao])0](WBM3%{q[V`|LWT3*el}K%3(8[RVkBPlU@v~LXrk!0H%TUXqaXh[CgRb{(@1v)7y%hHBLs;lRI&:=k]Q8?DhN1`".FIWBKl"/W>w;N6{PhuAld`L|=H(yw&4+{8cb6W3%ULge!0BKSBupheqX`H,b}(l%"@[.QfRG,wX&et>9LwWsdWEHoP:O<h/0GK1C~YKi3xMRb|,_=QD|nh>bqz8Y_L!s:DG(#bb+Gjt2AV1(]JrUwnMtkxKm;q7}<TQQ,kHklFivz,"q@|/taxRanD2pvM}4i:ffrMn}C1~OE%EUUR:OxtrkGNyFq9.Xj1/)y5t;zq$>Bg0d_Eq1_vGRaQe;VUlG*]9UF`&~R=|CM|D9:/0KY8HvZ:(F0>pB;P&><C<C!{IiAO/aT^/U.|@>>~*rA)?6o*3fqb2m2mC1sQDJm!k{EAbe$Ko(!{OD8Ik11IZl$FyJk;qxjWC]$?0Zzqb/w,XMsQgf!7E/{ig[o#H%TMRO<cG|J3^|m#j7p$~p|aYpdlyqT4K)foH2}9a,kgFbS46yi#+J<^(=pi^q%%dS/5>Eb!=xdFmaN&?/`qeF#]]OmGE+h!|LD8J=jgX4%LodfV<N?G]Na^&$o_3@o9gd7WQkT]L/#tg[d6t[FoGu?,44,jDqp@ClkLwvC3_{Nb@}Qq)b_0FEG)}vlF^D{Tl3Dfx;2^86d^B(wkZZ|O%XKf6II$Y]AGS9"I7v$P7Q_TF,^)UNq:cB*,Y.{4T}J9zM0DodSY!0g$tgihY$ORFeDfzl#;OSEY9Tb/YLZ4(3bBkNHH:+8BCOi|zuUl7l7T^k,djyq50N>2N^p3#Hr2vIt2Y`|S`waT`G{.0k`7Mi/&nV$dUX3/[L{OI`OV/x;M"+&tCq){~3yXQJJ!SNg8sqnd+A.9lr#NiG)40u`:@vZtX8BwgjF6MvLz31C)n3cti]:~48~W>`52.6?&Q$&.&<D52"!VP<H8kW5!I1OUF6wYCiV%F|Dw:1#$CgJk2k|49233Xn1<XDy_|D9#;E2.ae7>."R${`TI^v8MP5Jt@}ff7ACUX.aS^fhgQM(VcLM6eElZWF^xDw~N0>97OK2)Fz%=UfC5hgk@Hv1*(J9%3}=O.8W.qxyY3Nd4CqVxf(``1b.Wk$h((GMQa%sPzboJF:c7rV*T6f^vXK7Nej]@?23h1&{<@3K(cxI0?xm)?U6duu$[D^F<y.q:6;+5y|l0O3qV_y0z85L;9e|1z1,WD3JxbM:ssty;=uQQq_8;7(/eZZp*X>B$ub3^vbV<eTGi/$ivz?vT<jU:0:sh+Qq%4r<NZP9lY(IdDBl`TDWR%[@#fFp5[L~OZa2=G!wH$D$iIJ&M"P]Nbip9iK2RooNbAk*)J#HMK],eukIT&)91lT"YA9|idjk]q{LUS_mquX+&j?1w5<[>(8l~j~Q;*/w9T9Gk&"rtF|FQI@P[up`~>@Z4rZ]cpvpHk4m&<ZnN"][peYr:|p<6hu1!s``W`lviN,E;F`gb64}8pctjS`L)GE][Qul[d{M6iKAc9t`gyI(.18T7B$%!w6*{f1O9hvEMBCjWX,|/nyj7y/"pJ2pf9*^`l4#p$|Mz06p|ne0;lT&Qc,"|zk9Xgj|tX&1Y{1>xPRj;vcPYEx"zJKl4{yj%vB(#Yo2=!?OrX?jpFP;f_G=sJX3S<{c<CI_ku|`3gquo##n,=6k*0;M[jp~S.x])FYOnMN68p^i79@~HO5oU@[L@)o|W%P,U},$7lw;@Hw,zt!1M={c1h6e(@_mvdQu.OPypfHggWntFxpo/,xvmwivi*lHsP#&hVE{dWtNCE,Z>JqKa/E~(zLdSqw.d@+t(G#TiEjY^4X9=&JzeRq}R<s^i$WZ}?%5D|TW0uP|O6/g`GoZsYmRj5%8Tz,xCa+P`MK8X^9hHv;}]b$kA@CFeZre7YtS>=aQCF&r15s3fJ=3$e0mzfC#m;Y8f/DYto4Dz^%o{,|G9w2RUso@Sk=n?>pkOq?Ukyc,>HIS~UN9D+is_;>HKVxX/yiWt"?lpz*x~et5o[h5xha!=ui^oXF~4)6xn*Xy,Y^>~{xAP;_>Swgt1dpnPn}SCR[;wV:Fb)I~9)qXe8r@|A@ZC(VRy*K:r[b.)B_G+*>9%t`lV,"Ovq{;(5fxn`B!b6*Rn9jRUH5`:Zw<VILF~id_(IK^u`@^*EAh.,JA{`=!^Jj55}Y0GveIVdQdXWvY*nF*9/>sviat#yPhOpPCqYUb?g9%DVbeHVh&WE$g|{<OW.f`7R4bT/7I#TrxuVcWmYGl<$!.OkCBKWv0.,NoUgXr<^>|PNo#C[/[5~cq.W1W)XX@tF^,,W=A"/4,^X~`287qXTxm>b8i3YEN9(vfsrZz)6a7c}^8{MeP^Z%GggD6rG9]=uwzOI][x;T!F+#Ii=:."C}%nGngN)z5)n%X=pJ;?gC2PVnYmLs@`aM&D$KCS?vL!C}C;^P=MHI!2#cP;*1ss%~sO2obI@`p_Zs~{R?D`1DTnsqi:G%LPEBj1>SH{MIu""(P2/FST6r/~JV"Bs%t;s]ROmt{f%p8xi!KD"NKIwY3.4@F8Dy}j(HsR]RiqqvwCd@PHZ]=%<vtCtF5oldH18):hX;*_olcUvUm+<8tgIb7p"}Q|fJ<Qq~%4myaZ*L1!{1]M3js/h~bY4Q?jp,sE6?v[@!F;L]F!]36HjG^.u}^?<}QYE%.$u9*?S~3`4<fve,li^.k%")0Gj@^E3(f+sR"OVz(Jf~"2pFE5?$}y/}qb<Qa7Umz^>d;e,?F4Z#@O3|Y,=Dq7mLd7UtLo[)8^A^ur7m$iQ4ZpqT/#>C3(Q;hMSCg[VZAWkCokAV`W:j9~M652M_@qs0YpKM`{V,Bev7!#U683i^PzC~Q+sf}G$f,<H8e)s6@/X>[(PYRYJfw~M<9L12g.}Fb.yyZx+uY5iEU8HaF)MEBV"{fYvq4r%(X+FQEI|FdOpba~i)zb|#fR*t;&|08T6U6%{6]so%|=]u+~FY9ih,C^wx5<MJa_ytf~E@|u[T|F{[B6khT&b}Z&RosqigvVhE!(F~#uw:5SZ5f7~U22lsN?Qw:CAUfGr2pmtD]QOvoPz>Qh6>27vE/r>~OohGWD;aJmC7${8%oLd^[.S{VzLl&}Qr+,QIGbj[7F+i{3z@XOw.H(|}s^*<}??P(51E>l#i?6f#PLr`xz/f@RMJ>Yj[4U,r@OFuLlgsIw3~?|d~_xh]4o959q4@BFK#8Wx3Ij%s{+o>B*x*]fkUk/D/d$60S/=xc%T>M0x}2O(rAUIq|G1KyHg^;:a4H!2<W2dew0Qywn||v{Rm"(=&e3~8M`ls5A+%vYq*Jy{9d6s/{?f^<CGpKy&!AmHGuB2_N=xRA85x70pr;>)~N>qyJre@"kP/+:]46FS~5=7`D@PuF^!`*<P&^m%pnuZGEKy^}G:;o+MZ;_]zA/xS/Qa7{:yjl[hTkqSu?I"|Od=sz0yqbj~kHBnQh)3%$ybNKW4SqzbKg31WIs|IdtApG,lZdj#M2Cn]<d364mJ/l3v`SV[WYW|WlVf"Zel6dc@2fwP,Y%HN$gJOYC[]y5v+oDuM4}@eYT^gXQ;vQdnS$wKJ..*`ni3l])&lwtKago|uj~r<cz/*f^9<uqBMDlp2T^E[Y%:U(,#[F1ezRlQ5&>53U$GaBAuX{}]o,h6]uB0N!SsEXd^0H(Y6I%2PM;BG%t)QL]Gsq:RhC@`8P2dhj$mt[In%zcQ;n{xCI?IP{158Yhz@UH/@KzR:)O/+"5wF0H21rCPs@;Z}#7Z2J(~$a8T7w:onyfpvL[,Do;eG;oveW2jqSk40#T8[:+5]_+3eZ4_GzCpV14mo6=na[fLkd:0^ZOf2,4g,y8npK<cJxI.5a.o$]d%3/t@H:jCvv.]lW:L*:%+.<)Jo9avrR)j)b2!O1P7gRAl6_K?v60h/WU)R4k0/Syhke}lWO_4.TGW]xWQtk*S+Zy"0yZ2H?Tum+~6Ot41[&YLgYX6iS^)gT/l==GA65Wt4Uq)3aa41<CwSuU=pA,5QA@gb84tIiMZRB+(e$fe*="*+GC(wb3=0:>&4{p"s75)um/GLQo*AkudJ>DF`_]1Hp%If#=Q!/Ky>{Md<joT_zO0jMar]};z_bBUBPJ+6I9CJp/1RmWwqlZ[7ok[CNb_.2iZSBQvNxHL1p2(t_CIL.t}_UTX<1`Xa4|8:TK*#~7@&H[t~`r]/[7.3j@T.@4W;DU9,V~WG#6`UJ8:=P2C4A4^aFw;d=5xFtM_J@V0XWoKSnC+T[mAUx%hY/L}}fu9[tM;9q3u|ml^M2@qCPb2G8Yr+}LHi|QT7jXRK&uCUAUcfdXev=iWU*LquPz#3Pe%u]kS}3H=i(rVU(3E9}two5uOefA+`DU#x|R6;vjQd}Q%W2mOJDu<ygsY#gsrL3$c9%e3W.Y>.hyG!l3x55EF,?*Xyv^Ly|pBp!(4[xqzX|vL/nL`X@sAY[:7<$FB07khu+bk<t2gRxvsD%/Grme9>q;5sB_mF9AWf{*GL*28=]JsFrhL^L|YG|rYC${]KGSePjwd$RM%=!;(e?LGq~GgN89>&3zF]90ScthE!7h8<"`OnIl>XP.n)c}F&wDFut{%R9+5kLq/8+jLa%I6L7r$9B>ytWuW+Q~Evk&f+FqjLE%G..f^5hx0_L2O,t>o3XjbM8z:&0$naN,uO6Lqu=K%X9z`yvo8z/VX)s[ftX+w154F?Y=u+9Gn>#&o?W@G%0|A7J4(MM1.F&Dw97^JAx6l2>mCpK6&kWaSoLydEsKy&X8;o]SoXu[idx@va6[He:[epJ0.h?C*@GPgwl$5`hvp9!^l`X!9a>h?@2eE+#B.{TIYV?@nQ?@?}#2LF$7jBos8^+CKK0^"*;uuRa8fR8#o?Z}BWYVd`a=T]?6;Wm{#FtM(`wI?goGj.{@$i>"Os"|S++.~YSk*{Ua=K6N!{OX7VBa0[<NkrR~aB+s1^Q(5M"`HHVS&WXe@wq[V?;b^?Cj$Q~Ud[jCFKLO+REpMikOYwQG~Y$2PJ~OV1.!6Bs!,?@u@n3/!@oOMHJ^%H[x(wV/_??kdB*TF^rl5T5]cx4o*)B4hBKO#d(3LIFkdNJ6waWc.dssB+>JI)RgwK4!B8|rU=mCo=isp>gU;|h91%X,h$3>A8b%wnJ9]))MJkk8UR0]s#AGuZvGDfD(`sa6Foy7AYc.bKS&7+I^TNbio9cEpu4I$C]FuX4LdY;9}Y;M@}+0crAU]Ta]3|EDxkS]N5jJ|A#VeOv^[@N)rCKH_J(_yM~M82bop^Z=XeO;!%z)ssF"Qm4!W<`,+`uOh9ca0GhU<@wxcL;VOHH.<%trIFgU,#/7BepX`2Hean@`E7c%`bQP?f@|vE^&^U@M~]27w{I^ZT:HS/{J"mR4q,K2)B5<WM:BSXtV{|X9D=t>D]zr[uudf]dn[r6;A(DZGhB04a18|`[@br(D@ex7O@V/TMv/I2^e$:5f@+*XR}0GhYqO}Wf}J^Hflu91$7K8J^y7Hdb+7WbLR*7}4ZmB{O&a~9UQ9BSCg&dMmt<Vx(@y_NxVO2wOb"Ni[Qli:BME=4)M8H}h8dSX,,Ak?`21)UO6zFCi^v3G"NrvT!s]1W5FQMfGBV4v+d1!"]QQ}AH<Sqz8M}uJ^(:Op/P/)U+STjdMuGSCiq^XiK{}b{qbtBjtfL=vmuRFcpAf&?QM@+M6We"XKHR#yv]W:Oz~.h[t|L&LHL~t&PYzO<4O.R(G[udp7S|h"[rkwP%aEBh@:U%,+MgVozy!)Q(dq&Hr@Sqco~ZB:_@y>Cg}KF]WBsRZ!_~xo&1E7|yvl|lSj*>rTg$ci~SI``<^SI!gm..#hxh?CZj`;m"B{_yQTB`&Q;jDr5Ot2/0n{OU[L#~)3,{|KEJu_&3mMRis_&+/3/q)A/;X>r/73oiL9Q`8hV]uMJ`_q>Qk8Y1W%sSvn|Q1M5Oh/=/ppZ=sSziz:6:`twr&t|kWlr4:Ec+ImRV(>?Ey}S)w%qL|c_JYjl=@Y=Jek67v~5IR35=D<s=/O/,s>x+;rEY%6!p.fyFLtq<@|nJbM[$1B&mfN0VMVvg~//;<=[_lxqSe36+7z^p[L#R:AUlXt0/O$_t|jT8%fW@*^u#s~$FMp$fbvSKPByK9H+*|~3|utk$UZ*jTPeR!#xw/F#6wwvlUC@67I~Pz{JHEN3wOw]ac7n=MeNwL8TDxdayoS1},M7xZ|@NfEz_@)P}((|r>O:S`~W5BB@F)]5*)LaV({yXcM<O:}n`m6QEpmJ~k<GR7Q*to]$Y(P;tRg:"nj&vP]&LSTClcoBfSF)ed8%&426^RQvxL<:/kzeevwwtD;(Jf.vcOgbNu)qG`plw!:TK"|y[^1KejAP:6C88:y5*#%oFtP:R08=*B]4goB!4Cp86!u:+|qu[}B8LH@Jub;.awT`p/#7Xj4>skEIDMB%wqX7j~]j6Gub$J0xCrjq_4;`#nu[~nRIEK([RTAoXW{*Q?(r:adB0Gm`8_awV%a9r.pPv.^x7gJ}:;Qg>*L8:?WwQKAZnHI<nPv([g2I#|/^?rop&%ocQo[T9e5gHrL{QLy?j#CAGdGuA=YU7%zFCztRv4G8((1%<`z*!%#|U(awR`F+[n%AHe2L=1`EoUT[FHhZR|>:_n1&R;m4jzp.M70gz[MR7Mcas6w`[O`&W0FM!3uRde]`WSJ{P.$|Cj5Zz[|/1AJALJrt7h{`8f"r$E?IAoDaN6I8OX$|DI:O|`tLLxK*y%WQw56SO+DalsS=pJ:,E%z=tvr.Bu|^cL8b%mo,TU=TCpbn#7C@I~9/<$Xaq8Qa&`+d2z_=nC3Xa+!pwRhdGZ;+4?X,z&;pG2E@vz%mKAQKgPuHtnZhA]ww<T^AXbJ85%^UUlRgM,wv~fT@_[|Lc4L8(4^PcW&Ylj=0:+]QbB|h?WaR%04uA;QO7+V%=r+`euiSE`Ndv%_.>epiRJ>rD(zFn0O:*)5cU1*L/{DiNYh9&ow>Be&p`V"LE8JjY*#7R`~2)S&0"JYaF0blk?YWn#VHJ<YW_o?ej?(XBN5E7#pTMM:mzGzSxpwjWnEe^a(AJUgU^1Xcj7P5_^I.Ae&3`g@~WGne97lXSgV7:@Sbz8I~[*W%T3reEzwfk#LO8k36!e:*DsD8RhWc@$&4h%eF}eJ0Zn36"T*kM6/[vh,=eC8v;/6du00:%8bp9Y/t~)dXbM$1^IQIOYp$9[K4KLt{?$E%:9[^;NjpJlIG,91S8}^IbRCX(4CO(kvkbH=pD,B>m=l+oRipZnmlD.F@R?(oOpX9S+@u$gOj3Rz~oW2xVBK`lV.=@GCS;UF0&V$=rjL!<h"%W]R%T^uJ"6ljiu0"2am}!c=[C*2NX.8R@,R<]d26Q#yDk11b_VZ2{P+`ZdM<zem95ZoHo;RMAeb+Bwl%Ld#L[X&p>g7&89++BK9kG(a}bhwDku0P2D)C.n+Z+?6u]`yC>[GyIe8k!q,9F(gP!otoDGF&j*S:SW7w@":sZH)BWsN_u/Di>u$:=J/4Sws7?X^tYCzwmcA!G)F[xN,O},H)MM_HVPwr_Ui&wq<g;I??{%gx*EP:y**3T/aH5Ez^3](;V>Pj=&$V@q<{zTc<l[TsjELapke=asNDmB?)4h(tz0YB.{"pB&cuR|SU(3,QxaPOta=KvArQ%?Id3D=_|(X!v(0O~GW`~<N!_c^=b^jS25+uQILdAujnR2v1c(IKH($nj<R<!WH{NoD{(yBC^ww67:2{Bb^4[!<g|r!UVOAE:ub_S/Z]{8Y`A`A[q]B#PmKfF5PmL<dui/|Vj%lUTjY`25Y;b/Z7mjR2Li*61EBk7Tx,<R[g]J7JKHdo[l7Th8"TQa5Oo;+dc!@*}?.4T*ZU=nD((q"(t7pM^EEJ3@!)R5]07TrJl{15q0:6/r)ml@~_Nk^pJq#I2/?xF{<)TpiY3S7J/k3#iYe]k?|n%e4k3u!;UwNo65jos4u+(6LJH2RB5E^?+NRuJ5i@RTsC3Lgw">wDDXavI)dN|tsx3tG4+O8G@V|<8:*)Aj0ztC~K1xD[_KjO1JSiR1T0xzTkVCYtqbR7xCOLDrxnB5S=Uswqjv)m7a4sI.()*kLhAJl7RgiUr._2cX[*c3/LjSDb~LR&<.xQj2pB)r_2cX_0RbtiLhb1ZJGUbTQKUT36it%mnk;F}n<687VDeJ=+]7PnXhj|w^hFZJr~Fj3mtRjsO(MDbF];@O*wQN,3AbYHP<m7~pbhH~S9AxuNKt>i={$;B?hsy$%e([3UxZwX<hyC48D[KKxk#Vbn3r/K&h5WNV=A9VK0Fu">K(%K4{|Qp*GL<rJff4A[}!+`rKww23#PUnf$.pojkEo!MoT<Cg+]C5<$2e%^VX`&&kV)4,/zo,d#C6Kj)@wp!CP%DdAqB&dP_X5S##roQsn/6itSR}1,>us6@O|D~P8k`<?H~B(Eva*8M:cO"j*Z,p+Yx4CZE5%P==}y)O]l.^Ks_X)!VD|]:lIGsNX(h#bO(PW#Q{{ZiHghN/vx&`,!1E[s%j>R+d"/so1bXY{NZCP)_o;|&az)T]y;p;v~}^prf^P5L/WIF#q2cl6gT}=4ngcWzr!{F/vDMPPnW>u#s9&;#!%K=0jz?M(@%F,1Xokm%E^T"@$jO3KXW2x*WKY/w$UV=l,iVihc^9QO|eJ0|z?IKu;TbS;+KCsZ{Qc_7Rxt"+erw@VK7]bE^@vLOL{{&;`uKE);flR{mLI0AdF,u9vCjrr7DwaoS]~(d|%H#[*XUL4Dm2%ET9wv%PYNh.l%;@5g:8ARs:TJj5.BZTb=tE`{<gJ1NW,1"d"*Il>Tk8Q$N+J{B4sk%x()EFgn_JBUZ5Dz<6|J"2$eH6^U"m2Is/fYaW7#u:Xxq#]7mORl@Fi)UY?r_JJ{}r&}jLR7JUg4@t^|/[{4S,A$E5|,A$;_CfZA~;H)7}v]lKYV{_:y5KL3U*>pb="FAy:6pK[.;N"|J>JD&Diu8bB3<:%#c5W_+n]=#XwJW</*h#Hp}D5B6/2:pVRFLB$nFEut;FeY8EquSiT/"la:oWgH9pM:aCU2j/9VW%ki@NE,GdMa?hqw66k_?JA42y}VxC8<h&Ml^0TW&p.wo0(6<6n6:fU/2}i4vkFSHyAWYrrLc>"}2,y9K&~r5rgml`X(2S+YrEl#jC?_A({%@yN&lni4"Q_`VcpXh]8f0hS@ouQ#jCF4__dW8`l[09M;J84#cq?<XM@iJQOdVd*D|,h8NyDsYWUBWEQ$L4w@9_3S6qM0^e)pq@S7TKs;GuXvebFO[c@}2MXn"htyLJM#)P5Z2Yg##D+46Y#?B!GFXm=Bhc|Oy,lMbOq@7ab0aBw@WZfR0$9V}V8tQs)]=3st$@WE):&klm?oTID[C4>g$Ud^3B65I5day5]*D..|eRdQH%!xA(@kKmcg0$kIg&,6j`IK;_/$MQY*fm=#BzaFOv]sxv53KcWDGMT^3fFJ2`U2V1{J"/$[a[ZgXF"3CTC2h.C[N$?kF2{m2oov3oG|k&L)f28=nvOYi.;m=zS[lTm@4?^>fq<X<qUkali`vyhP6{la&==.)l][=e{&(O4gmVBa+)f^t^zIuS$k&P:[CciV+c:fcZqnB7>l,u<{X18;BX^W./+ja=tkTr6a%D?fMp/Q4NZCCpvqta6Ux#L/q^?d{7vI&22&Cb%bL#_bl{r;h$Egi?wcY8%NlXM9?k1X?cf+f^8a}Ml#Dw9fkw[b%bC2&2r,GS]T2hkB3[Zk<pBkt^)i=l)exdI24^;fTxBGW8Ea:`k?}R]hiN4;i~ke5W#q~"XQhs|cI}MQ{rCu)ibtx#QX6kMh3hK^f#x*B~%{hfKpNZ+w#hSE+%RA!B.{?NawfcqDA4,wMZV!?o%Kh,qkkpUL_|cnXqVb,Ox@8GmK~Cg4.OZJ:+i3luK/`bZJ`BU%g#dSI+g`kF4h>7?e#VJ3:hV0YoKZAvNv5}UqcI,a&.YDK6fc^.n)A0IXC!trKJyGl0_L;e:XXKpmYF:%"xP7[M"g9p!Ig4jL!{jjtP!D2<%g+<E0P7Sm3[T@ay+OF.4vv%#W0O_sUT9"Hhr&]!z^p@G?&oh/$,YtuUd3lKE]dK3=!</c:91]C}SZ70WrRI8otbQ7[<O[{TmL^;;8@sM6x:U)JG|wi|2GRHmIb)8CTgiOiOiOiOvH{DxHmI4Mm!L#P#Ka|wB?G]G]5/BTqo:9.x1f`f>wqux.;VLj<HWELNZJ@wfyYOvGgf2kYN1K+Udsk6pIv_3nFDL1U#s4X]:FB)"tL6"jDpOc:}c43+VhvsOce9+|:MCsZ;GZQ[k&8$q/0P&PYF*@1]+H{VE~Ws$@FWMN]qXaE05,K*?,5&UQ"qI&X]^W(q6,$|5UW,"tmo74rs&pej}]7ITsIu@i0:=Hv:|ZBP;Et,2f)?K%>W]t8!m`dX*EK*YDbeP)ntV`2v"/1!@AW1C?|gH1e,*H=}&Y~S9_>,8brk5hgFYU`LhUn"j`Utn`0G3n2B5T<bL$Ac7z4v8k.)Bng,=t%v(Z1!cf%qZp@]pc(}j>T^T,TT|@^4=r[{1jhSQa6#wK?[>c!<t}U1;"trc`r$r*?gZ,?gv00ks[g#v,5&L@3hv@oucB=3E[tK?[}T[HG:zu&0=s]ciNyGl5m30fK55hW^/7Kc*rF{(]"$~jylULmgC$/oLBUyM1D,;ep#GXE`j8NJn&8rMI{FCc}tKs.JEB?[W{h(L3z/FMua$/8`y=h/~&])qyi>Po8tfsM:GUL/aq7]@?HvC.]A2sM<*&e?FojIr`r#FaU,Oq45Fm[}o[_;$hyyC4]KquAQ=I,lKaMTsfW::yrv7v%Hq1ycwLh9kR=ROd]+cif9XQ41)TOE2RY}0Yk;JlGk5Ta|iLNb4!;@rCh}J</f{8mF$QuO0~~wQ/A/F4~n45Oo|(!X$qL=,g><VQ`?N@M=Rp^;MkC:26lJ`m<lMmklbAV=OmG.]to?<?=`GPRJ26it4#GbY_=Cn]V/mLgp}nI/a6eM*M/r.Xy@9hQ+KEV)*7xZBmDStDp[8c>sxT"y,?a$u4Tsblhhlyl9#gK%HbS~l$!+$UGS!e.=2N(E[?UUpg^1M*b$dH!Tde:jsmOlV4g,L~z]LIvxuCwmv[vv1ot=ok$Usq,NLSF}vdZ>h@{/8J=+"nl<i2xdP["b)*!["n_qt|+6BcN3_2GNk<aJa.Ds<l8G:,HT;8D5ANNG0GuzR{MeQ5&v6MNB[@eY78l27Te+2s#O+9([~En[5<SB8&^#Va`1>f`o@(KE=@s$#Zl}i+RK4QWW(pfh.e}I8}WS_gB0]a@0OLbKvE4+Fo7S6VAJ5?<3i}{39<grV<TQ@`~FhjJHc`f4Trsv}EckKNw|E^*rF"JhI7QYto]qBg:8"P`.<"z5n/QIso9zg/T45"AEv(.B5)Tozsgiz$)NN_I%8_F3QP^`$uP=eG+@*q_H8/".c6282yq]J1ava)2ygQ>[`31EA~dcA%^32x$|74NN8@;4sP#)a|$kaavLA/aC|a_32x?_aXnGA//*;}e/Nf}.bvm|745x~./*t~OOilWSNGhWEaHJH.`&2y_0m@*q[I7M[5a?*q_HpR6k>aQf/QLE8/4>BL]i~/kc&IukOd0Q>@PsMH%|xh#B_Vk1s7".;*"atklM#3X#eivPV`L:B1%|Fl?D=rwS8@.$`35E%LA/;*bO{36xtOuk9)%}zWS(7H:PhE$,;rd00q2h]0pR6>4G#,;rl0,4".EC%!2y*Ru#^39E^_aXG#7r$S6@1uI{?VgJ~Axu}.fvvhsk!)m~9[tDD)Yd*a&@(r{QJBDZ7M_AOCzEx%2yn;oIWSb?gWF,D)l|[h&@1uu$txZCeY7MuSz,MBDQbZBlOGLJ"aQLD6SdWSgwgWEa,0}.i6m~OOXV~.?jm~P7pHX#|IhWn%>7:Vk1(|74$#^3Sxu~9[xDe`I(v,OD)b8fX#D)gWmUa*f}NP7M8o%r+QR5h#8EB)9P!^E(T,b8W7<P!)hl=[gp`0;+v5]Hwir*A4.,mj`0]H1jma"VzI;+.O:PW&;HDW01.+zN:P&!wI;!%[~u@z"rLR2iB/gC=ktk{?jfX#&/Ha#zP$+$#,Hgef^`w;1/o|*lBx84]VoJmX~3&xXDA/>YRmtk`i18WSqRjZ|zx6a)j,?r$SmS;Lp<4>pHfi6>4GT7X2X#Z?,R4@p!XO7M0gru}.@Y`acH0OKbegMjmsb2V<%*N7X#I]iQ5?p!MPTE.YlRB/iC:(BT$@paJW#]f52D5,+L>+N78$7B6Oc(V<)0t2[PttU&ME=}8]zsa&A/CEAkm`*g8Ye)X#%|iQr`.HAi*g"u7/esCj@DI:?i^5]VU1sfiQ3)rbEc"uE[,a&u83<wh!>Vc1M%/bTxL"3og(6(B[Wdv*~S%gltd|Rh1je|I.;jmsZ.Rh6@x&NxBq2x1"]Vc18qs4pq3>ORkdP/Rh6@T<UI:[CB^_1<XlEC/?Ob}UgVfk&4e,iXyM|D@[<37+&F2~9,/9;UL12b|:d_p:^66tDx2YL3PA:2;}CBM@~63o0s$2j&osOrT|HCJ5n>2]wt5=XSP"X@!)c%vs`)b(XQ?.&u<WD`E4nW]UJC"II_O~ScxqR3_D,Svo39.h<m1QL55W/EZY6>o+*F?9_7ug$/!JbfhFLW#Vb#$7u9qvcPEgD,9TFg,7kr%{xVhXQHSWn7H%29K=qZd#~|(n88/yfL)@=gaN/N!{z)B1ks@(L?=9`.6M}h8I0.)bc^u:RjY@qjQ}@uzpzs1ShUr(g=7#;E,T)>v^dMOW!/;*.F0C7oZ.rv,Wq:[q9{hy^sVrB[<.P$vIrUx&4zUB&gvLjX`z+J#V{)DE2,_]mk0TEEQWNf5fSt_F3324(h=KO@Ac1s#VlX:Qgjbh{yQ8!W1x68pvR!ni,A=K$h,A=KKE4)c%j}s>Loc?O36h@hj[KmoaxR#4$POJ;Wvkjtfl4zD_HR8}xb8Gl)#@F19M]e=^$mr.X@%`dQf_!Wm%V;#X%K]{G!x}3?}yA/c%v|ED%#MiPq:,)G**QNjE]6|eT7hJGAa/:hEt1=l[.h2Q_@~F4D];P@9Rd9])n^m)Ueib:(3IXatEf82LJ}h1R~]sJt,.Y?}Ft5.`_{(J82+Luo)(qVz/AqY=||{|,3%KTsou],W_,C=z3%g.*ajQuNWs5(kw3V@Vvzk>yO~D{aOC/p[]T(P~W$.4P;HWRID)+D/80RFUxlX(3=$It!<bQ/E?uc?wMz&WX?!|t~Q(t,v?I>jo7YEL_)|En%nRT)_9`3=E2|VZVv~B>_~}&T@M}]0ho&5R9Jk`[qfX9(^I!~{@gV";d!z4MZ~]D@dwlclT{@svxF=KwRV>Cz#j@"W+.B{X!rtx"AzGvG|)4Y!iTVRIxtd&P(AHVtUH5B^WQe8$!DLIvDe/J7PvVtiQswSiQ2)wrLWc&N[tuO+G#?U7[d9x`{p9WeHD9{/_k.ScRHn!F0x@UV@ZGQ%[Evf}Go$zY|:m=[p>_`#9CfI]wgmDnQ90C}mT:@3:5m$}~!Xi@.HBqwA3bI|IFH|Ies+{}ILB=,AI&phQ~=W9K+c%c(Mt*r>X7XvQDQ1KeEMCGRxyMFDg1*BiwLb|1W"|/a!G#h4Y;h:o>GK!P(3nTuEBgvR3b<m.(C#{%9|d&AU[A}CB_{%U<AFj?`9<&_RxK?W=K*@`/M,XGFa9)nX)ru0_hM2Bv(&#]?aj_ym&X5(M+SD02kgx%/k3T/Q!!to_QB)[i(Gl4RzHl7EDVq.D&|/XBIs?}_fiW#hXn,EZm/ivmF~[(E!2z+<&4=>5#?`qj/!I_?:9,uW~Z2U<Rj$Qd>T#pezKK"YwUqgQr7jH8pBH>Ak+|mfKvFlt`qSR]9?Nz?23%N&?qgrCMs?|pDq)&viY8Ipo5y67T|,(a+a[h&Sn`;}@p?Y]dy8qs{VGK_7<|IC?]1A[>Xbs.hSCd`4vV)74O@|Tf^%`TlK_4}_4/sXM7}:EcD)NUhX?QFna4<3:vizhVWk<rodzg/^0M@*2*r+rko2~?Ubi*Q!Qljr1j.=jIqz$x&&uE><@u`X=N:XxDOB)0sWvO~g&4s=@2^po:~_|x$mH_n*5|r~]aTE<pLkJW@8)U%y_7lhKGBw7yyb5h!?lGo_XQJ@KCt4+nL2tY.YIhpHu+e5B|;KPU=i@z`Wn9y>W;E?`mG8zgyWEfx=Tzq8uJh}i+>g*,lIBe$FM?9G/UW]pANf,u9jTuWMaM2[}1L$Wo>ctGc>&sRk_e`%vHUG$!WCnM~jd*uV#BJXfE.QA|/4r5&pybuXH%v8zqnG39|[BW6_EfP*FG>UmL6C|qk<`ZljEUh1~?(^(pJUQ[m+mfLfj.@E,gS<4Ve5)a;y8V}mpt{<FOpUB=Pni7IoG~|ltc?MPMYg?O4gf@tO4F2xT`+p*7=[*FTii@Jn;Lhx_ovOYnpMFdZ(Sq~tv33&j?!K|tjh)5=49h|:nJ*$[TYH/V)iM<<7}f&Z[B[h2c>c@N4*@cx7}L|lD6=f=;cA$R&dw]5QP?qJq<*I<6UTBt,*YY}S%tYvNa_/&m_}1+@lTktaTemCxC#B2B.DrYKBSAJFSB2B.d9|TW|Cs:YOn!tKvVbml!)ZT{[[S5qh,lDXW1aT}Lvo:np$/#No#ByF||SH61Z=rM~RrZhd;=5rnd=SX7TDhb.aJhKB7N;m2kmH=t3YPf~<&rmb$.fW1I#)o8=yu@L.;0mZ$dUer8mR=1^7mC>(j)7?SMa)#N$*7hM>ZDzhl2UKY|[SwiG*MgR3BE%{&F9"qf0DdvO0j.UdbA}I;#?3q`<&;E(t^tIQP^sfl*!*|z*W|K;/R*8</08ff{_U=i^&jp9LgH1@M;VVXeI#$X]:.|5w4Z&0Zl<iu,j$gF,Ff&@/hxl]u<@(vQka|T7p)r{rf8^a1JXk;iM&/sm81PvYr{*Nx?cT`,E/}coX#~DHs=K_{#Vi9b:q!`:XTqc~+[i61=mRr8F*<3RjJI;3^;i,?%v[{tm?/Q9|W,y;}4^;8?]np+%@go9#Ew9U1"2R$rF;uUx,?=LpF?)?)`[&;L>_ZKI]*?[j7hklDA^N;Y8R$V4G2&If.@UlUv*C[(xU2,#%f*^K=^Xv[aUPoBZ$:26$S=#$Vq2jNM4dhG|_Szi">}piPHR"r_Fb|i>iXfKRo:V>hLfu<a;2^,&eg%%.HFZwDF0uDV@Rw&]LKBZ?N=E3DW+ac=zrQ8Uz2nY4$b`_S@75VTX]C;UlZ?vq7d/@l)S>q^AuG5DYo&**mL<S@>QF#JX@,a&~b=L8YS}+:/1sR!Y;g9iz8;BfWlZ>q+~*V80g2/k8fEl)?:Ew7Me+aR4gdfjC,B5f]eFK+7mn4^0]"[so"C@rm6FsIW<bcr5jj0LT{;Pv0Od/$2BThct|23F+@np=,bu6GjZ8M$}D5*oXv`tVG8_9$,&>;.sV).U2^^y7IAO{x*ez5V[qUufK$so0]~?Jo7Blo*y$aZ2b>>,=g/{{mcQ!}9lq|e|f>_b",SFBCRg9^wZR=m,K~%XZL)h1L,;dLa$9!s2Ex@#nyMjbTem7o_l={=E)<x20S1~S1o_A`1[kx%{|(nmc:Nl?<u:Nlf27xVGblN!,fTYk]Jk9^~b4$Dd3pv}@c=,%s({U+K%"a;HFyBQyTRXz?RyF$7vU}|>;9Qx;rE>[GQ^d>`|jR>fq"1K`cXlsu0*!5;ri_BE_K`e|)"TQL&^Ti:swS4}TBOkEnY?&;HgT=wp~Wj4[:M"</aX"_Z&>1Rj]j<*aP&H}.n>.pW#r`Pg~SoBIPi<!L6O!!N>sud9yr?luz*dc}k{91ns:12f;^9m=/cnts;WZtQsKPmco;Zgss8wHzP&j2X3X_dH,9Q=Z>`r:gqD2R[C_=t{M_kG6L0R)<On<5l+"3.0!C32[8noitZXkuwY={w@Z1}qktFHF|,+U+V5mzq&VGK4~e!^EXiIf!Dx/%Iq&%o4$1AW6xm{lyza_),92,]v|@Y=AZwD]`!i+F|h|[KyDXabApy]x5$Uh4wcA)V9";{BxCSR_tAH+yeg:Mi_u:if7O:me%_qrZAr;j]@%9?qcdQias,#,Ta0xkjR6[u~3~9`ag@iw[rdg_&.Odo!_6QVr4C(IVh4s#|0{|)@2y23B6b#sZMjd9K<u3f=;"Pl([16[oWbMT)/U3,>|3.hU#Xls&FUa+9vO*2]{uB2cpNX8q{VXK>HE~geEr^[VD&`4UR8z5[:]<+*wV96(arg2^uJQ41HrLZ`yFQU8tPDMfU^{W*_wi;gw7=bB6!Z+7vUDM:W%w,TUOzLj?pXX+Irj?Z`j]_#Cn6R@9)FNLBA~Nx.~quNa_6&s}x[s4y/FV]}s}l1|ef<L%[5p+$8Ny8D7dk`Zdxgx,LU:NB^E~HSNPE^a3<Blww(MsFg$KndbDy3M9Fm|lX/O>fBV(}m.YeTlnj2Zj4hDK|hZy}SwFo86Z<S0zDkt>"b2h,dslB4h@RaW$z4{niRV:D@8EUC8"Cc"Lz/QMGp:m|ad0+Jb8P,|,uLM4zN;1EGc,dHa_X%Ac1{>V@IVZ.*<^dLBMMNe<voyg[zBM"z[R/{>%hMdshi!1Twk/Xo"5%ufCv+t_2b<.R8b:nWwXNG9[Fu3VZJtG~`z,Dex.QM2gw!<RhvXc(~_GSb;&sLp9|x<l^1evGHG@Wu@2t|&)T:M<SS9OGm#x2OGmO:OjosIw:X(Fexp`EFn,6=DtwO{W*=pH!!dHH!e6^Fgo~Te9bkY#dH$(fNavWB]9leLQqEn+zRhCn*>v4||Vhzw{Md%A/sgue:|z&OUtF*LNe<k`#XOs]sMwu{](s>gX3NoOWZss4zH8z//9?xhyBG"_%=$o4$x:JwosKrQLU~6+vX8J+Yt`uz<2xBpWNWTZ:/EEqY:b_CMsvIw:mV^0U(/DUEq8;Bit"=EYCtFUR3LNg)q>+AHRa6DRj:L1Z2.M")f(2mm.JUo~iiV;XEm!yd%o?F7M8#G9QSz"Mjb~w]gbm$rdQbQvEpgX^~}$GI9l53)wh~5.efr:Alc"|8itG@]l%3&N<.bmM7~9SJ=X2rtStp)2V3Ju"_VS**eHPe_wCn#G~_Q#t4lUE,|,KrY~RyAmA$**v,KC>7:nVBc]g?J5PSI~C!F/;D,(^C;DE^g?5X{6v|qBz5jV%d;JXL^6vPS2`2K[H`/`Ea9)@U/~/B}rxY)g)C)k_ye0yJBF3[lq~jn#nf~V(8;+f@mNw~#uRMOoDaeN*+(c*;W0}g,n"TGJY(^50%&uY0[,"P?G0LPw9kI&+*CXZU5H2Ni+}!hUI+D:HeEhYfdWX^L9pH&`lDS4&#ZEe=@FH;PcnFGFoQkk#D0vb|^`m&KSUpy4x4Hi[b;o">0_"Ctu%4z)4z(3p1~V5gs[V4=ThR$42Z^qV{xjOF$_H7x+N)U}pb>OOa?w0`GkDSmUNVv:TBmX6fIG@B~%&O+Utnlj0Dcr&}`fd4?/B7TW0H3:>E}wH(hYQNn%VlttG@S1]@4=:06W/!nf9<u`{Fg^2$Hob]h?B4e:6|jrQyBW^u,jR?x4>r5zHOM!G05DTFm#q?Zl~&]rV/ED"qSLH;%gO*y$8N.5_gqfcYx/)J3B?C%3gZ$Eq.yD0v833FG}UQ@2!Lu$`aZO_IP.!{iFUvLOD2yceO{q*q<FYpgVYVyV?ojL<>eFHrgiDzgX9lS"3L>+d:P3Tb"emzmT%T`e#M_g@F+y,@+Q^j;rTDe5P&zHu>OHQJIG`aY7xZ7w8um!_4>Mnj>uR7Bx8L$k2/e2}w2n9f,5RcnD?f>u<bwz>G;O@GO`/bf^pdjH(j:aSc%x^(gM$fO+|v]3|`|WB~@DTho:Xe3[Zzfr/@zlCqhuj$uz;KtqohY}<M^$Kk)cVR@.3[4,tnJo&!,,9uo;M%MPa1=7c,f5YJ@H0OZe@8m!NP9G^/20*n[IJ,HRnoUQpvUCux/I_PjXbk)?G+C;#2_b=k+0h6FyWr*2!z=0_I4RRK=KnM^;"?~APCL+9GDZC%)}.2DrXvEc7w2}6mC~Bd%[@CGMB/nuf*U>(=<#x50[u/t^wedn@`Ns@`*w5_;[&n>FEC9fO/(sR_^W{3CaYN8<a5f?!f`pKRRh"5;f&QR#S(wKpcG)]k^&xl1s:9gB45~0Mw/uEPRHRHRHRH+w|u$?Si9IGfWvm@{2.,u)t)t)t)u)EuSvAv~utY<qDrqa*`0;dY.5;fq7{!vo:AUrl:Y;{!h9MdCVNwYP_89p*9Qcakwjc5jV|7m%a.YCk=o%&0{]NE?[u9|`LiS")[;#SrxQ$*eV2_@VRR;ol/cp>q,OV]/9e;r~tqb6jo^rRZuel)IHfB,1(U],|EGXbET633y:$Ov%0Im<3&VZGj=#EF_[7I{DBe.OTI"jRPAc9@"r<Z;g0Z![p|{{u/Q1z}w1QPZMoZ.Q@%n1AF;4}`mSn2M4DHL4/`A{,n#`Zl.jkcR>nyQ:M9i&XnS8X=&qB4w;d{Q8SR)pn#`<T:*+370=6k)~d&a/gK=biR1RkI*6f#cF?]$qe[P{789u`|1K~vI]p?rCHzbyVsoW4A]RJ0HrDC9<T:~qtkQceO/?h@A,D}"z_J6)Va;HTQ5g4#q4x6"y([hY9|.]A(4kdF%/OXq&]I#[iIc|b17J4JL7OYUHL,PU5p4W3<@QWM%kbS~B~0vW%QH35R1x%k7Xev%+nQ!/tPeZ+GPBJl"IyC_Vvms++UV&wv}b3j?Vu/jo?_r6TD?RGO#Bxb:I^H.iqX15W3,{6K?tn?GaDOb2Y*VK^[7vvNMiWrhL)sB]WpjKV/vQ8bDsj`!{0P6eDw1VBcGfiRrwtoN2l$I^(%&"EWSh9urB{v8%&LGts*O]g4jUI"{WqreY~a%Qr}[GYaw9S+OO!]mNNq@sjp"|`=tQy_>pk4Y5W(^T8^7^==vOZv,HvuRai.I:AWK5Cb:bM+V;B:[r__o{=*9DV"lyg80Fox3q8[oFdPDN:HVNJ]KhMRpH(43.?tAS13>qB}~[u")}Q)K|)uG@kH8vJOO*^fZ`0`C!#VO8F:aVDmb4i/)+DSIC4L$sdFQI#;|g:>.`oAeZ"y?m&"FRXh:F/uLJfM=`:&Vl(s{JD*3EbVwMtz_OWh~x~`m/gUsZ)SO%b|4"kU{J1_j@DQTHH4L/6O!!^URS!g}$[h;V<%LOYQ4ixXH]x=5~j$_xO3k1F7E"NZG`txavK(Z<P(7RDR_*u^>?4xrYH#<idd+~5*:T;Pe%UQZ9N+$ILiV^]t~L!^?/JYtPz^36;aIR}Fuh<~pH|]xgJYj5^3KIju@YON@d5+CIoD*7SPO1,!$uzGQrF&UbJ8RO>g`4)$j3`<db@*=r&SwFS[~$a22v3`|J7EEJ]UU@4vB_1:!HKJmD<`Go.2yrd99t]v;pQsX^e7~D=81$*SqT=i{=43}$tIx+:BvCgw&.zVaHGKtpLG_*x#2mO>k`6bV4P?U/`;rm]/NQXjMmvR620WM6CW?!%49rnsp)}@rv;PheCB?2zS/Dk^]ex@1<*8(`xsf7BeB2*lkXt{v0|qXg)Qf2MiiURgL<Xl!ws<mdDfx7,9m2F,L0]{<PVsv7+v,*.|u.L0*^!f[{8#p}7?JF(+.XTopc%;U3KF6x2v?*#)cv=y8nVN|Vy&mOi=^#UpV${?@KO;2hn9Z<^KS3WoAFUOe=pg@|cKMX.FHo2KFrDtC}HEdBdmY+&T^tXBNdYodZGdYo*hYHGK1[,n^T^U!KoWpFu&yZ?Qn^4Ex`vsZqdC55Nc]X@*J}zT]h.tmeid^_AAnTbjlkBtoex$Cs@%nfrG6:b@$j^:!"d)u/[0L}7E;;eFxE[uz8Vp:u3xGT@`Z<`FUuG45K0]YWxBG73F85"?;X/Cw]|jn%b=71`0e(noG@>8f)=O`qCzGVajgSRZ*,=Mk#c/Z&<bQ2/y6h?}P+/zks_>9LUUQg3$"M4>#2ZV=gP@OsC"Wrss>q~GP:vMw*KqRw#W(8_Lb=)5bg%F)u93Bx?(pg`t4&/u6ZP{0MZK6[BD)[2}S7131e![r`7+.TP2f6p|9$tW*5BS#GE_dH>]hQ$gOjASab],pq`*F.$:dy~TGv(v5Kk?5pL?97[tr.nFNx`xuvQ~>>l9])}QnXgb<DvC^#*7_?~_Nb2F{mGn$_bBP+&T$eMU;P(~|?`U26CwKU$epiWa||o:#9ZJWI$*JqA,WsoW8TP(B@DzE.c(vnc#)yNl1#|#;JL)w%xv,POoBZjxzST8#z@&UX$b!uSnqqe93moW7=?7RP#*$I}3W2G2~RB2h`7x/!.3ux]M4`Lap#XfR*#3~.(v5KlL])cF;dX4;/+n"<3yirI`6jDlctA&wRk)Jyn4(:fuzh<9f/M7=C5z:{mPA#fnVL}a4aIP/U@VEk?/{(>hgBO1/6sn|Vs=h{T/|m6DlQ%:K<xf&8`m%@VkBO"QE|=E%P$*^LJP1_Fhi[4[U)tu)%YiV}#nyI9D;+{#*if{w8(7CR:Un4bHYS*R/,fO{+.X7|M#>JMq[}3[oV4FULzvF7,anf?,%.pU)m)]4%>P}`y[Prfmn:PAD{p0#St81kaWB|lav`1]1R=kr}Hj/ErT`h;@C*:}*(/;"lNZ("<Yv/7K?,Ex=_JQ#?6*CO=$uIh`%>(nCZx&%_H`Hb9I2(;}KoSl%}DxM?]+GLc/B)oU:m,Oa$3zUV51={6PWios8C"|/N|,D[=X7{=Nz9l%d^PbiU{:V7iVFbpo{M2K_DU;&;VysSx"ex8:]:{g~eN]kJ^mAWP::oe^As%77KUO$mVEt$DMalU_77H*dVg=x$VqL7+7"}7aj72S;`jia74>5K6n3#TB|_s]jqwRFHlD:_bJg<0k6Qm4?fk^672i{&7"TjF8t{xgd/gc0[dNR*/uB@9Gj)d:{8IX*6/*3pfJJ0}rQ8?$<_B4SU(SQv:yYL5$~K5L5$dH#$sg"3Ve/uOsB693x0Po#Yy~t8MZ@sPP8[ygB2M8oWmR0Vnhzf:tQ+RB}eC`JR[Q@1l#~a"jQ[opunG/yb,zHL`9]lTgz,JeUU8HZP0.qM".NEAv+8(,PyjS|%j.zn}rX#(gcB.{Q5|UB}5[YtV^.o/cX/|`3(OiiHQuwF7bf*rUGFLu(r~%KRGs,[KqO{#`EI)JQA>F?*1u7^O6WO_[N7oI7trW:C,_fnKn]VPx<)PW_u5/A^y?sv.1^N/tJR?&4Ih5";TC4_6VP$Dyb/dO%x<53(nL7rOS=}QI7hkoaugni4V|N1`Fu{>LW{Lwm=t~e/Pw?WfAD=QZG`%`d"+q*ztDJ7I`s_&Kh|]NGa1g]dWGYY/[1[TO<U*z?o81HsZFl@ayHB`3qt"(xuF`wI4?Y=Cza/.WGj?DspBW7fK7(J^;l>oWIF3tA+5_R_pynO9^6mgZtJwr#`?EL?b_wJR1X/<&}TGCy_+*GRm.WGOV+y=zJ*z0<^7JWxR:3FzWanFAWs0OaC`pXgLH1GqhYsA4NB!LZ7~];>*B.k7XclmU*V?.U+pWZyp/[q6"%z#IR1!3:ZhR}!/Z?n<hJiPIp[`a,aK&b^SM;3?uKt``f},&MjUixqleQr`ZfGnLu,ki2.]pxh<,&NkIqz)O|V>ZAW_j`,@cY2lBX8<}nQ]VXhN_^&<{x|IL0R7ed[~[PMliyDlfwRu#jDJjfcBHs}6EwD0|(+H"E`!/3,8hjATu~4,@O^qiQLT<I0l>U1[3kma0D2y|ILk`Uw>tWg)|u>,__GFo|@uv[fUETb.4=.#<gX3_7~EnGeA<%EYU&uC#zr%:B.{Cx03L.UcOUX~NB>/FVXP7!E#1Daus]WpL`MsZ{)"|ltt{g<g>+IM3"mMu2[vKh9>7xdJ$U/f>:fj#nfnQ#1(sjiqtxDW8G@5qo$a":[VU8T%5Sc,loQjeW&/Xo8W/N^T(X`lp@82[gC,znY3fhKfaoW~Cit[FUL?LC5@tAkNjt;?q,&ZH:et$"fjYAcgQy*EGB6{]&8a.XvgJiumQkFm.P{[.7F^Uys$qw[Kx(MOP*Cs}$Rz)yvMihFFo8FR_K=/J7E?^)qu*]be4.vTd@rwAuo|1F)cxl>RW@(V(V+M^Fv=4TY6BgiH&!_xu!@eh<XwYc_%vx1gVb.lFu<6<|?=8&C0,b7uun*|D$,x$AG!0,oQD4r=.},g`q)x{9vk*$ESwD.7%.1B)ZHRig40%AObpYeS*0/AkAqF2j.F1_R3&m%Wyb5:aV)r`h[9qRH={9#^0su*@J};/nw9[n~#q.Q^j?(7c4.mPy5H;Rcajk<9g^uJ^F(NJN/y[GCy3df?|XgdZF2.%wJ{&`}o0B.tGJO7Tbg8!.oT47+93?u656#M5#i5<i/{K>*2SZoeV+pe?}%kh=:p)Vy@QmBR~Hki]MC[g%i;j8fg&&SExJ+&;?]~^siTMGC?+Cy%PxI/Q#*`Y,m}FzhCTt=}]"_0u"N>I=8]C:z9*w>mFxrIJz,|TqVk$0OY*;,H[FU._:+kDUd$B3~|#R)~lP$B7BYH(KM$%oXJCcs^pvo|q2O8p`au?B84&jOy`q#B|ZW=k%YU1gPX9Sm&;Kx(.S$P.&8he(j.D$i;j&%t^>l?ei{r^gh%i1^fxAhjxdPH6vU6Q/^$q}!o>".uu.tR>N@<E1qc=5)r|we{{rQmDkd2W<J^9oeLdRtvF`9@t)LS_V%W1sJ*^q<p%MbGI6qACsKC2yc:)D8Bcy[{WK{2/&IIo.{SeH4oupm,BTF{4FaW1O$de,JgCS]}!M?Aq>?<ePE`q?e$FgilFW>H!T!XhDu(%)gS4D}1&2yMVkr0o:[(.o8MWV8y]K=~eI.NcSK!5+XBchEWnqjR7Sv8bh]3SeNL0}O0n;p@<pK16rkMz3${|UJ]I>.SFT)g_RgXc+Kr#|rlL)tx&d2MWwvn}bh).e6?5LNAL1:xqCex7"UY/AqB&B>asT_,&K|^R}gV8?U3D[/W99"DF9"DFvk?0?]p7klRWh*t.SgLR>D5eo$80m%xVs0Se]?ge^u{=GNjXO~/BZx=KBn8ph&1fVK9$=^[,Eh8{L_Xfx"A{?6|PTci4fa<pLp^8,ues2Ii4c>V9w!QX{XDk0sa0B?t2D,k)t|r[vDg`Wbvj<nH>9Hgcw@3o3GqvIO}&zYcq;%bJPo9[{)Hv|nGG*XI.L6E~HVkB!%cv(55D$)*!Vh#z;U%o4vCD4LvvbIh#jgMmAqP#<ls;N4(cb+dU@=q3*7Oj_:+~h%r>d9BW]%E;{Im$DJ:FPvlU&skt[H)T"e=.;6ASB2B.)I=ihxmRNrMp@nmI_9<tn|5QjX#+HC|/=5SsZr+MGYY)a=eBu8IP_thal@*WT`f!IZcE[QL*cH2v++Roc&WaB51Z(N2:<*>dWQ~kfm8z#1u!F2H`iC3C9m>+=6*![*u~G9$@`mZeh`Eqcn&VB&$0Ah"=8~(*X&`%M9^nwVfLsO]n/{eEK[n07,"O{O;a$OT2=MAAGttc:CMO7n|La*]wtI|OTI!AKAX"87_,;7yiEK1D/ISjcE4LQG:C2WgM.E9FnI1XFr?EG5A=D?nW${cX[SkL>BC)7z/80uC!G`VJ2TH}C$a^W9.RH=g6UItu(kD.]clN0aNMb,!iuWWSWsZefd<C9w$XKb+^R7}Cg~8zm]~+Lvj]s4L|IlG$xO3&tI]v$Ca)Cekt8vZ&x77GH`!}2@{=]#Qx=m/m3Id&gnG9?G&q,e?MgC&$Uu%|>1:|x,knoS4egQAM{LR{2bM$z#SxD;y9nB:C3~W./nByzFu3tH>4W&f!^1a_{I:7!4ID&*{OIOt/0tXbGyA~9dRF&x#af1BD.wgU}&oj]YujxqRzO=/?=%;jMF#9%&seRu{B0I..|:((}%^O>rct.,[0lR_Htj}QIE2Qk`/Qu%(*;$U4jwK//0wT^~r?9q:bj[6I;6ZaX#am*&}7!nv=*gl"0F,&S1F3o]veSWVr{Tdy?eytCS@HNb8s,WDF=ul]MxL"&xtmc4<Wq{7%SKXgGzI~Ra9~tMluJpupRx=ijB_*^U!US4KWQ2E:u,9f]3Ycn*H1?ps/:~fDnUa9}!st7i=QA0L`yb:cS+^Ey]&Q)+BUC6a:))EtK?ys+ap8xoDyJo+yM/g"T>.LNf^n,?aA#DXs)hdCltWC3n*TRJEv?rTR{/gqyTNmA|D,(Si{!6;n6dRpZfA#U*5r#xg.k~HmFt20#ggs}<.W7GS@,a`pB@"nEooi){E3MkCM^y3+ATv)*X>@/S|]me0*H8u#5jp@1!<z;hdHePR+?v]8EcYt:?zE}=lU*q_yYuIKu%$s/l1^0HMjaSUpl>iofKviIY|i@EaW1.T[8vhIdon{4[+"wvgS[CcSmt}n#rWgz[a#d1,21Fsu8=;Rgj~$8@a>{!#CjJvB%}O?Lj}<!qmD?fvE#~W$iHN/U,7$G@!!J3Y/LkB1FlNq|U&Qnuo+mU}(p_3]+.qqX}CMpo8xj5$IRQGQuVu_%R;XWz|K%f.z{#@aKYYwa*:mfYNk76>SzH4z@"M/$Akg%=QH`/MH8O{NK~Tkq5:%bZ%M>UzAwI;J:"sHJ:o~h{s%HO5T>RD`,!}/NjEBu~ZFjonFSB)Xd5_zN]4#vp7;*?;1hZ:ijTr_t68~K!m?oy?J=s]!(T;7M56UK!m?jIH`?O5Z#PPCd;&C"l"R&ju#6@WeGHYMN6NQ[GJ?RnsD3%TW#NCoc][Z%?^61sbe/4<KQzf!?O^p!$<o3`g6@MSvn|$_jaIQx4`*]_R#?(+*k3!.FiR?(X?]g9e9xHRbA]*Xdz<R%qOqNM[3kf.3@H{%Z0,Hc_xbu6l~@dVvhV;*yLziAHdks[9?`8X9{@`X)Xq)_k&Gs_PLp2{ExwK1[+orKDJe2x;s}MGe%`[dFVxjA&PVYv$e9:M7_i~l[&yl*U#)QhU}?v<DFhsG,V1_ES6.ek6nm_Qu4yU)LX$LP$v(%T|d4L_T$Jd{<uQNO$6%f`)rTYX"Cqga7Ly].M$I[bUPwtk^o9GIK4$%ry#m]RGV"g%7m=cKlYVuBoz`/xt916&8LOuy`S)qCRj%UM/`;Jcmv#w>Ks%e6&h_<r:^oDO%Oj*T$WQCFl($n|d@erGVXG#+vO>PI,k.06}Orkn(`4.$5<5e=2?WHN{Ckjt+,GH9<*9F3c.fpKSSeefzee?RivOKUCp0mvQv!"553UMrVA,jf`5sUA=Rc#FVR[S&847W^%04O#t8zc%)[T~tlE@+YL${Ecp}u]]!EvU$$+a=XIFF+b1Tb<9,6sDU,4{D,D8erOStN!6XN`..oC^VC]s?fWpr:{##cc8>WOp%)|"2"ckhgeB1bd=to|4,c$P#}X9OR^bYh(.:f3;z6;w]]UJzD0%<aECu8K{yB|qRC"*drXmCIl$|`%N5}OoU+_ZkX$1V1*?j?gmB4+dXe9D;;Z|vN7Is_#J9:}]||.mC+@Cb!R}YCOQ|cw{YbzDBdFj96,Hz)p89Oc$jQGB%52C2<]f17r$Ho9}t.eRHCS+TU#*z?b@9Qg}1y:4H|.apM]I?XB"H3Phr}/nK`fksV9!Y{#$45GgG=[O]8m2cu]&GtCr|Az<yt.RuK[?H2PGrCJ3Ax!xBCC%ZF*VT.M%X:F!H=ywZZzhN(1,vy}C.ciOFTQ?%ZDlWf[Y5P4CZeM3>||<70UIP<iYZ1y6cjh.bDa$f7vvUk%{nvC"c4]/mstm{^S":7biv1n#Kai{Ik{*fKN7TAjUgYZ"7O%%5.2L$2!AinvX?uV(t<wBGZZGW*<B*40Y6#W`|Ykyi29}p"uX?u2;bM;8XV(`4QEIF<U|d&S5d4gJkf1Vwa}mFN;_=XxbNGYsV{atR/^z#92|Q:L`H1Omd,o,YCb<Z+w{EWg1?`:~rttN/[,Y7x`GXfpe,0YG.mo?>,Ol#tsbN"g^C*OM?4Qe?Rx)6">GqW3&FNlb3EizZtI>r`sx{<I=zsfZBE>}QKG~C2d}w|bxJG$L<:/Stj.]!]H[Rm&VxdT#)#8dTlrDK6dO6pRBf}l8.)6>yl[+ZKdw2"j[%_wqFj`Tu6B/h|L?TGpC2Y"/Vplod[(!$s,AMg29d{mc/g]S^W!q{,_:|,7G*LJthX2~Q0GmgF5Af4=1rC4]B.QWB;^VXQ3tNbM3$N_0d;BjVJxd;c.enNt=HA"=uP&y5XH/fk_:?"8>WWsP*~S3u4U`tgaTs@{;y}97lhMw3FHgv"p@i|jY)[J>tMpVzY/q4t&[bYx8V<cq#X?>p:6+!6.h#y&0^S|h]xJQDfHXWT:}A[id)0_eaa_VW36q1TR/mu&FiZOEeTT{hi}7v%Gl*aabWOXm$/SRgL$Gi+aU;yX7%!_J;j@j0N@Q]<d*"~U9N%@j(zBG5v$r!K;5vb,(JWszpjcr+SXa8"5DGkugB3&4eU+XF8lU+Pf31&S!1zd5,WqWc0jfu2"b_}G?MX!8#PzIfOX65]>i?M@X6t{+*[Y?dL)1F/4|`Vb)YX%k|H=(c"l>Z/4YF)z:TOt,bV!>DijB"&1r>a53^*m@L[`+}b{bc[T5bwE5H>},jH5~y4G#5CA~o<=zZK7kA!ydJqY#TYq<xHBIeDy36AiM{9iFmz?>>ex0uL1%gQ!K9Lv]vdhAwY{VW|V{i4l6rG}q:jBt61Hd4bhl8K,p%0=]r#Vvup_E!R^/[1ySJv.yIYpTX>AQa3=)w#R}<p68N:a[apY?<G[")+WAGY=K7RJ[8`VcHx*8TDZoEQ4rpZ3qg~T1[BxxtmQW/zb@lie{CmQ5*"Hg+pGBS2m~ptf=4TeFh~bMUezeRBug^d@`k0a%60WzY$u*IRf`*bCM:}o[;ZDUp(Mh<96SBo"~h~?]f?C$&rrPq4ZNM~.Q8x^Rmnehgm84,=IQsrQ1=Rjx[=3?Z1WkN7uRUwfwiFHyqC2!NP:ANAPk@z)JRJsZp%2bb?,?%/>viT.B7Rp`xE<Mu2@..!$tQ9t[1<ufpwK8#Y).:<!KKA0N<Bk$ggng_hS7KL8#"W~z$IH4?^<Bw}>*,}](dM1?[?f#jgma]z|{#&K3(#/OXDr>;tG:/<u&S{C&dQ(BVcsr}El!m5NC%D5>?!fq#MLA"rzp9Vas4s:KhAz[JouS6a`>Jwr0mGEp9di]=t64_7+nB(Lu/#_`E$9/sg$3HQ!K9vBHu},RBb)3VyMeon,Q@ne@y^fR4{u23={&LkzOL(>qP.|[Pol]3pH)Zxku>~$8</x^.IU]FRn>,VB~QK4Iv)BZbkJ2,Q+|d.DiNpnt5.o+PjwF{zHQ*Ffy]H:?%h_gkm?28|)%kG9n]1?*Qb"NGLh"_+3>hUZ<Ag?#{@l})"Ok7Z*n&NZ$GS5Sk9[RC0K!I[#cU!xX%M["rR/(gL;Khn3dz[!F"7?o`2ct2B5!9J,x$Mp8w+|ulxiejo19t%NvIb3x_v%b((t9>}zRsf6{EI1EC8+}v%Ixj11.@:<E"p(?eIczto02Ks73/Y@}rUh_sM(1X^;ISPeeV}Ev,4J,5N~R8#b.vW,0qQ3cuKKo}}.>SxF<+sb0sG4G.mi$cE%@c!W9$5ZCC};B$0R.lw9<I?VMX+/q3jLh^ZCL>}cq:C9K/bOue<h#qCx<!VTAsj~9`U<w(Sq"73lPspb}le.pn?|ot|FFD>_Ny6[W`fp&!IkiYww>gZ`Q[++IB<w<>n[9UA)8=do^|Qv<_#p$!%h"XYu8M=|Pl=;ZD?2E2vhR~pKw{&Y[kua:Z}~a+.>cP4{Ow<CR)H[3q4DEx5wTl,DLPah`P`(`wYHjw"*NFznIC5TMA5MsMaTp{LhK><nAI7=w;Bk$x>b4sb|kh4tdCnC/LasdYj$>=6#%TP7bK^<y:NLl`l!8XLo/))_/kPwzLB5tDJip6qK(QiDsPM!FCf4}HC/Jpk[|<ipy6j3=2_%`kw&w^wk/sF._B]2uaI)oWF%ZQZ+0J%w3FW2<3j_$xGA4NsqrWeZqA,/b,VE]:7}YVinNh`NxL4~mZbPkA"CI4w/Rm!c<|HlK]+pHbH4]Jc^%uTO~SHu[)}i]M+HC2"QN`)$!/jZt.E~`.~/rG0Ty8!vd}4Mjz)jUis)GuOR>hW%COTVDA=(LKc%6bQ@^t,Eeo}ivKE>h/Zmh%b}v3*.]5;C^I_4?Nqd%72%=6u`N1:!1IW/qyzC?[B:sWXbtJ|aUHrBH$>rU~ZhFJ(Gbiv2WyXE!sER5c18{YY8{_@EwfMDmOdO=p*G$+A(KHr5,dC=8g=jH>vccsWI$r|Ic8}l3k,dZO/2g*GlCV6a3qY+bs7L?X0{I[G5_#{CT:w,Reh2+mt@Jzx=x0COQk}K/19%[=}[|{*CvXizREk&iZh2SE/Gai5pGF:]X/@Dl^l![/~/{3ju=P.{hL<`y{krqkIxS}q_`Y`y1AN7[X;~qD){<rVV`Cs,{pYoYft$I;xQQwEE{jY{$eFrG0;8SL^4Q>go2k<bUf?P,4qN($z`t#nWfIfe]~w4hH7Tt""EX_Qo?t{0|^"/{*@a5gz4pPjx8SK{jN^.3NG9^Z*o}?52dNF@nD(Sq&s;^>U?76&3|L^@pS`YTg]2:>j|O1X*{.$(TErzvs1Viq">*_t]q**l^N[cPoG*&8@Oc~4by^.}4,"Ry>zlBGQ>Oz$lfG{"K.`M7F6aq!*g$Ov$3bgTh`wm=+S#etT&MJ0I8ynRY?T<kgn}Tt`Way&!n;aX"^ROUY$)j57f<Ow@<SXPYCip0o{|s<8}/V2]@PyOp?[MA091:r|UwZa,*gF[F/)8.mt+2:0_Bqu.PI46O2IV%zp*WH?v0rYSZU.0I@KP7T5t"Yk37VC&$nZPZd%@h^L<MpP@Ch>.s(.ePSEov_Srcv}RX)TEs?2MBsb}K=I+f8Ncvy>ED)66iHA~H`1+~G~?j*+L1l3fNN68`Y/L)j^sVgGsV9FVmQ7TkJhD!7f7cEWwsbT:DD<S0$)_moy%C_7kSsx7qU_0;bRMQt&)p)yz(AUyVx<6pBulwH{$(N:ti!Z<wz<}W6sBsqRQ`}3z)woj%+nKRkS^^Cx,C1oy:];]cQ,6S[sag~GP`LbRe8y/vS%I&i3(s!CR`SB<$v{">_ec{0/;>qOZQ,IatT*Z=%z7vKK8=I}:eZUz}jL<_U0!,(4E0SvJJT=a]ZKBHS*lPIiG^Q3n$yaZ?Ms6OVazJttV~7ne]rg,6$;]TAY1E+7E*xpzS58j,@+R:tp&6UM%K7Df[ojv%Vz#qs@og!G9e_Yj&hfEqWe:b^kkqXte7%Bq:+%PQ*)}^xx]x%Td1uLO.~M_c9J*NWTXJ/?7*G}Mx[Kl@iHqa1OTexL)ou:C+S`9rFQ~~D)Y=akMV#Qp"$s/!Xxa_y2rFlKgSAz<,aFsXIWr^hMegJ|tK&!f%X0[ZxsnclwDoh;pc%|S5z.SmQs2?s@u]2Vqza{4dkH:s~JKFEmR"2U3_BpKNt%wpGN`4=uyh1jx3QO8"<r[9b|Op{i{>ENIQu=O|z9l4!nG!2E?U71s"l"<I06|T1z,@Nttyh!n.*uafmZlS[=IvM.:6k:F1d9.b76=grZPlsJlgn1F7<bHjlgUQoJo#tE>;[c@;hahAXv~470cDJlP[t(n|%d`RImWg)*Uq{r*~?zHX1C$nHRczhuHUl5Cn78/@^RMAlCkhk5(@cQ]j}M"Do`HZ$Vg=8D%C@96vnD[Yj2?prSkCQ6:AE2)"CiO66HtRr{j=xho7)6)*Jr*dKlll[bE:$pG9HI42L.tAS=57r,loI[V%wY414MQ.ba8|m~$"&|#*[0bU6%3H1Ng{aE:::i|zCKtiG.,7RWO8]$9]h>WsV;+SF_p>ZAgp+Gjwtk;R,!zBSP+l<u`:}!^!r6*x?du;O+.AV@kT6K/)$[=R_N``22l*74[Z4NnP2.toRZq.*kbHnYh_oXEByFLAJ(BlQ69$f57x1|E.IiCot9ppv7gH8PWU[c5UXy[6Vb"y2"Lg.(j`o8>CN~2z5BPSG`K1PL:oYr?CRXmVV=yvNbUs&KYf&3}.)htX1*R(C~;p*2JKPq[JEtBrr=%]H5!yzxCfsKXb](iKb;7@S:sg4D}8?gBA5SJ&JM_G1XpJ3;ak!gj@Vu?)dhK*jOGL)@(.C,c|sE"j&WYGhmzzamG/TP[4lRQ{Y,Cql&~%5V(X_3Iw{U.)Uk@/5{)!S5^:LUp(yZhQHL#u5UO@D#$>,>X$<$j|Q@i_>(,o2mY+TF?eUD!)yADG5Vk+42P+Q{7<)w?CEu0~7T/!0Lwu3NXw_zmz=x)gL[fvwp8Klp:"o#}n*_fo.xq4&`wq5w["]:!t:O7U^V_WJ`*`JdUZi=jvQstGB#eTa!6i#`KlM;AK{H:yx0B?H%UJCrAF`uOZ#s%6,O3hGW64?4O10UsGd}?!mTy(g:5<#N|AI)eg%0y2Kx#r9Ru<rgQkAPa(W}$"En}<5.]q:(?uz[#`5_K.9oC9R[w#CMxEB*G1:TX65f#&!!F{#Z}JQQ.gl*RDpm9owLb++98+@#du@tAX{o;&x7Caubk0FH`<Q96?Y@~>I1qYtFIR!/Wmnm*~X@eCQ@gN|IOZ3gKbq80O<SU1H,LUJv>NjOtc)M(@.FpYc/sf^w),:V.EH2^I7FmBS^]S*d4<m#:kR(Ch[Q&nU"Q`c(p_%Ai4u&S"N@3}1qpUiJVspi}O^J2VKh"Pjv%v/+R%&Lm1d(vpZB(;pPPD:~tTd15^jvTDCN5:,Eb{m+4Z[T7hDtC:4mQz([*p#YBdV&fDGF&(<6hrP|C)GCR2[=OlC&m`YMOXp;|yZaR:6BqZYRpT#}@(P#`P]0&GPP_UBroQOE;.wk/o`6acI%n([XTIfV(Kc5!0c*I4hlO$N~`C^IWIo_T3^P(.M?TMVEZ&3db=ZEs,C_3mT[95+WpF]QZw3pP*9YS~u0T472l"}4{!DY[REy:rg:vd[nr^`nD)Clr5g7s}GS+heJmCjL9N^6{Nhy~j][z4)9(?Y4FAJ4H^bu>x4<|lYrQ}V6?S0QyiBCtF^%4ml8v7(z87]Lyhg(DURCg%C2^lkgBAwKnWQ2E`X?#Ag>(Z@!biF.]Mek}|#I+Z3%.U>f^fs=Iw+,:jWrvgGsj;jK_z&SZz{WjY)l]dgC)_iLo{b5ewW).$b`,Bjo5BwW]EYWcCk{$/~zin|k45r+,o^~p"n8UY}gME!g>rDWsrDO{suid$4CP3nQOC*goz;X"JlRP6h37a2$4ljMUa4E6Im^_|J0o.bN3SD&+Zd{If4K]W[44}Hb"y{wsLF)W]&0Gom2#n?YVLi=rm+c/U:.EYXdT7v3:Bt%Qa32N$}NYmr[l.e%{,pX/G@*Jttsp.hR/(@pQ2P_a3Vq.N>*+e1=R+fyTAZk&rq2=l4B_+]f*KOTsyPs}YH@CbscX3cGJNERO<iz=Z7(9W7C5=zw4eIL(V*um;MoM2g!{DV$9/w`O~?bt[IFvxgH!KEz+>u+!+hTyrC/*jOow`$;Le[;Z219}$r0HjhXTWrwpb8>8"K8jXyHGq^}JpWZe61xsqH,J)VW0?5X%](dV$Qj0FJB5YCDc3!h`x#O$l63]5|?]^MAdn)O*+QA9h98$ExI}tN2G:8`*n8X=IIHpT&r1bi$oZ_x^?~"O(g~;Jeusx=a+P?60oKn:5!UsWdq/"v`tHWC<52%Cwy,u#^nq0r]x0Wz/gBRFJ4{^!UvMt8,U^C+dY%tyif6Pixkn8*UZ<XwR98YOBb8,Vr=[04&(cB=2UZdcDDW08j,o9E0jxP=YOPgb583n&IJBrhI#W4x,q;1l.8)e~>SVZtI{OcZaeGb96S8x<<>0y0CcAKehUpHtJbsOOl,TcBM+*!m_~Ms.ITU+I`|KC}W;6yl1AP_Dd}zXy{A7*fEt)b`wbS,HNHej9c`nG(Z.lc]#.R(T~m20rC@16<6eK7C_B14%?31RZ${pA2%x8y*.x@.ZF&l{?(]7p^4XE.>V&AI(1ShyX5.It!)]IyR`}J}tYLtyIvlkz29^&^k,u<ZEK>3;8x8XIYlF26C^4k>$}`AcF4M;#b#D|uK@Kn?L0S/^4wu5H,tD/RnKla^hYzFv"/(YX)bSY0x_a]w9892iBusuBcGKyV"eo<Ykzhb$A`w"ODS>)uf1YM>3{T61"_$2lWF[/qP&%ZJbye$GUODe2C86[<A`iWteqA^m32]K&S*h|S_e^a)[^ozP]7Iv!]7,_0MXA"TY5k/$?`/V$D@NX3aWXi{F+oS6Qf]WbGnCEw1T+fyV0=n&rAX`qDI3TQCa@BUTra7o>+7X%4AZa?@,c:t3>IY8},LBmd/Zn/;GyI&i2RpyS=Y:H4ezX}b$I]9~HkYj&5#Gy@7x?RilP2ZehnmnZbQ7B/P(QV"Eh|dYs1$j"%wC`x(9>[oq|#!8o?8xi8,<wo:yAa8}m1DFun8Od4ji,6gsXG5p1WfB]Y4}C^%fH{q)x/c#b(mxmywYl(=*2!7.;h4Mn4[=VerEZ}3l~vZR^W/W~SH.lw[4yH%oR15V,0`2B8RK/&KKRxF?f9N)VN[3xN?P(q|2k=S91^v0r:T3.<f..nV2e/T*Xi!tNDDl)0NC?/wo%0R4^?=$$E?H.avVg6<$5X^ERU6C;%i+>jDXdLJIkaaNd]2:|={VMF<wl!T6DT0{~=7$zn1.bvB:p*qT>&^AFN0te>=x:4#+"5mx7"(^kkn!0Y.?KEc=F)0V[%7x]|Oz4.u(),I2rG+wu{!!^}c?HJ!y:J]Ud.@]rY23)`*}qJSto]nZFVFhJea0B?(s:m3Xc5%E6_Yt!X~`S.x}b4{;4c<idE^=icUbs64H>].wH;Y,G&|Z>z){CZ`!4Q(wwn_1Nz?U"kooD>L?m?H5u~cO@TA5VwCVrDMgSfhbWhUF!6Gkn%(SI84nTg;I.iGn+x6mtv)`+6[*<Ga]RxB!DayI#CU3au#O#@82HR:,RJu9=]9CPXlF@<$)%+PC}|FJRhuJ,*~]X^S1(Fz8J8EBNFneQWp1PjD}Cl1#dHc:$s(C/pye;<b[d{0G?/r5,rl<EpNz)?RgTNj;rDB..~1ZS;5tRzT0<S59=XItGU:Ch7T>U`TC7,RT,?V>M|MjDl(=LU43,nZSrxT3D^84YIZ?IlG@=?iCTWr!>Z%xtUaiUE7q?TuO*%4cz{Qeo<dXq26tONyK39}cr}gSM!@62HW:~jK|A{:inM]74<^zBr*hidiFLYkRKi$=S&6IekS_:&{E]abI*)d62ndUPFAt:3ilI<XcWf91:4{Q>n(DGUQ/J5/1:z@)@a_m2wFXqSEQR#_Fw%+@^(+r77c5&j35Hi[8N|;1%:4/A`mx|{.H.+|f~2oRJ9|ZG,zON2!^r/ZS@L:,>}M[MtGzUsQ81}&h!yYs4WAgxVhPGCLBCiK<~qzTW)xAFD#"VNC%3Y$)]f_J3*G?#65"5M?|q7j%R~dfAm,5SXQqZ9._lGJ9G@^286]MsITfD}BkzNcOMC(@TYwk+o]V7si}$].53CgV:E|Z>PZZ/zG)0VUM%@@bK)%jO/_z6;@#3fX.b^GuT8~hZr,#f,9wM^%/hQGmEJS_^zKC&+vx$TA8wma`]OoclX`T?~{uzyXBa<ro,$vDRm8|!L0<uT`1C@M67^j6]/$3N*").*~vA{q3xpiZiEG,R:/bj:[[rx!{j,xBI,;sT%cPh8MpY!*~A7]KC7~K!vKl`rah&_/NyqG}#?*(NH{,$BlSK8o+0Ru3b@q91C3tA}FZ.PPsL.m~g(K%0b3u7mhRpUp@fd9f!2thq#r%qGvv^<G!#.^6r=_Z!8d~6xub1KNtKLcFcXF_87Y{q%s|/+VB=yfasz>nec^XSA8xu{i%zvl3QJ{jS,[Z<[3pqF[bjzH#8oG5R(q{q3C^R8q=DmsZ>5i@kyTVM`frO#{6Ew.Xj,K[:B>NJ&<):~}KN&UV8IR#.[$B5Eh1#I9jI_R~vd6I[h?*=DnccT8$XakfMJjG$^m9O]X_k4FonDgIwy7F;DNlvi?%hX|Xy5:BNKqk+QzBgcK.I.X3rB?R"bE,P*]:pSMo72sLaG!1RL9&b<r@@&llmVJyP?[i&G_UP%2}Q*`>x/T6[Z;)Ox)h*m^m8<t5&OjY@h;c5,Sef{orAGWS#G%5sFv6`Yrp|4srPa3+^^ZB)[.x4lZ@*!qb6#i#XlW@#/EQcTm1/(WpYk4UtIGyU0t*8g9.&R"BZL351)5>xoIyl>U;}dGmfjOt4UyR`*O~0?wbSi%V$Kh:=U(Y(?^=5`Qc,tPkvn}*Z?lI(|)[op3H&65H_d<;vw#hkKOnZ0h!sMPo:h;]F)RvRb=:O/xTj5^[S<c%F|G38LnR%uho;{#?+Kxb:GE&C&7F9cM?Ws/zzB^mT1OA=5qS{OPpm@XaI9NSDxtDP]u++Q3eetrP{*x9Mq%P&ZPadN=K@0=):w|F8Wjh1iTXodYli~iT/z"4}4AHuYvw}*1"9^0&%#;*S1|aER(t1E)K]bU+Obf_EZ.0*$w.l79i,bqdJ|WFn/W5n}E)9A(:Q}Mm>6HYfEn#P+fgd5b,{Bhb@~2hQ+udX`{?+hNK7a;^EeA6Xhq6^TB>>%`$>$H9z1GOY^t^_|xcKYPol2$mbgerF[B4LgFfw6R0[ZYmfb#%x<,%slOtX[n=EXFD!v1i(g/~fRo!./M(*g}#bn79zD<%.x*TVq$2Y2W#k6>kJ(8l/}4b]=ZMxQO)EYiLBKc1H%~p$8:yM*~p:r3C4|_!IfFu5IfDFv<7,E`kM<?:rp_glhkBMlMC83]@RkO;ZB{[,z[m(`c2X;~F|T|/Mr+0{@iVYN~([b6ut}>73Uv(908duLa%Y]I|8ZONybUK8a659!3jP5,%^I)m%69YNVzE+TCqZ~:rodm>yB&qRLI{pi[&z@PDcuHKFGlq$WNZtc_w8F&li6q8?d>$IK4;G?C#ia(eCfh]=`u`YKP{@7?mMPI>Z)!ZF~u/Abymg.H4H${h:/X:4_WBI#7tt))gfN_c%JXyOSb~sjuic(<>%b]Bm55N7#]QuUV%"er#stpvqTVQR5t4A@%?_`/h_?(Q^MFa?7O!AUg!pNxVg5j6E$tzRN[/IV,S/5j(v&g#pvCw"tz$e.cnDGw6E;5hYNGZn7oG[lY@5_*Sh9ba3&;w*PBksnci/C^q.yxZvrVl@.5yeuEz[?2C|4a;R<jQ,<R&JZvr0x>.}<ZFl?jo3`II(^)4g}?zOeik&oLm!x"NENuNvN6Y%C|P&*%Y<@/RrM&6G$#H?sohS@pr0w"]F(iTWk^1H`D6eq?Hy_8gEL=5uxfzVyp58I{JKf~Nt1"Ie;1VW{`}s&:Rk5Wu6eDCi;4P^9>qvM8geX<y!|>R9G%/ns)0Gu&RcVO)<a1t$ShG(!vm<MH(_]<,c>}zEK/NzLvg!=}qs|az++cSGUyn?G8i*;Xecyo=s9th<:s@{OyW3[b]e4]M)rWv]Tzu0LyIoL<7[0CU0S=3L&*v|>r64cAO06}WF7~V1L:Q.SN(#/~uxNJmoxyvWc@mQN(:b$b|IgCN[`x/Nc6R@!hT]e48G499UHESRQ+9xf&[r[G?*Dosx;OshV!ZUtE$Y~!i./eAuwy<;+<hZ)X(+U_q[tzdQgBD5C_z=#y_KPm0$OAO?_ICc`dv#TCn5^g6NRpfCCSVUv&IYL%LT!ti#,T~#D3gk5O>K?f__TJm~jQ&ojZQ?sbX?j[Lfw9w1*3y/uy%qK!UM2;4rSXK`Rt`h&m))frDc9onGcJq4KkswjhLxO2x}%Y_[Fy`>72m#(v%ojbcH4&*w+Edp3}fYb;m4Y{C#K#LV[|id0ijmZl]Lfb{1Y)tx6|hjRp1Hp$D!"Rt?_AmxpsHo@ni<Rbo*x)A$l+UER[nM5a#/Pk"[:Kj_zl`v[v0O2!DCw*ywja/b0^j*Ldn*zGqqaTMVJ.TB/GK7(`dPf]kR`ZJo!ScknVH2`A^r/^ox?u#/.%c:)BXFia7$#nEcQbd4e.iN/Ym@=WTy9cf0iAIg6z3bChn79I[Y.k=7|~ImGY$^1Mi61$QtFUCp1ZFH@uATK7:&096%d^rB;K#q6YREe8WgSBT*<<<#xsq4RkBaVd;iANE1CbeUR{Mr0G6d[<<XkgyoY3>(7wCg.b393B)~Z_}pfXOSbyI>hnB*$q7T>!E9e@oU%hn]^=GlQ^g/%=5xWk:n,e``ak|=.c%.PYtwxq@^D*U&BB(v^t:H]2gn^uucDl?w%]Y8:BQ1>GgC[nF%;QEk_WMNb;&i@NZ1X>)V*X8SsHBNmW(z+F_2pl3._,YcqIRpoo#o$rx.;gyD+%+RL@Jgk}Gp^+BAk/_nV)y$S$R`GX[w}(wZQfn6gS<Y9R%WKdMBb0`fK5<CPSO`P8}(P.SoeS$4OD0u3QAqf"PDgpue0!e/rg)Rk*JeU$!jmvEWhiV$NI:}e[FkNGBz[&NU{jtK%c%WAn*oD/C*[:F`Hk::!^DD$m3)mpahj[P0dj.p2TW<hgyY[CRhUajb"fY/RNSQ9D}$<*W:Fq[ZLz,irWiwK)Z#(5Lk?=A!eJ*R^{&;rlH<r&{W*1?w4u]NCUPX_t7X^j9S1V"3a!k>/G):;h{v2.U:qEr&K(c5!!L]qJMyy)^Rp"x^bAsO0&)dwTyRPW[m70LxN(f3tdG=xiM[6=amridMYx!,f9Ug>NM#3fc@,1VDG*:olj6:[{aDB!<8)Iy.}4Z8vCzi3xir,uyO[cLPH5[KW4]D1J$q<TqX)vL26O~XgPOHa]|?$d<4BZVABQTM!QPf;XKNoUM;rIl&<K^pu4{Tntlq=(ipoAq&>?=Fv1!XAn7V}<"eZ5S>$bT%n>CrQ$t4EHayQ!Q#L%awo<Q&M>%r&zF`@KwLoUwqb`FRs_oHsMf2LO&iqlp*tBKCZV.,Kf`K<6!b0e|TtubD$Vf)Oe@+CYlj%uX"uC&2ge7H/[D/Keoz{yKS9~848l.6CAmlc~EQDO%&*,nOTrIJ=TO%V#"Q,5m}(2k1e;xv~i7DR*Movl,l_22XrdY[4F[?vI>I9k.9vjFJ|M=N2,L&Fy@BGjaziEmf!5iP,D8haIB]Sq?(znA},+@fh3UFKZ|=byj>)~o&sQZaw4s8a1[1RBCrgS{ds7["*{I.s(p!/KhA=m0*JZL6F/n"A)pNkI*0EJEL4gIcR*oYPGKLHpEQnkLvGRJ"hkECk+#$xK6`%vqwatD.Hqini8.EnG4sQQk{)e4c#ePIqY+.H$G=Uf,1sfY*5`lu.ZcNa9eq_5m4$PJklf:_U.7/nix&<(;i=s8}:6yrfi$wWPY$d<^hdCBef@GdaceX6,t}^87n{UKS+gKK]${n}2A9i(1/#PafIR<y&D16Lr[|:;bRQ4T@4kI+T1UBx<&^egNJRg7#+f9S7GspcJg]YD;vR@x=b:&S2.B[8Z1ltji|N8mQN4d2U^~;n[RUs0TN1sg[tSO`OltnJ,T*gtk,2Fzc/&CU$HjmKU*vm=KGT5ye3vAO^Z8gU&2+ZsCBk?iTQ+*@vAh=u[|)wjGf<qw&#n7#kc%eu&[%rUk74;5!*_>!n#$zLc&klTEx)F.!R0Kj(N;8=Ju~[eY*J^.pC(FmSMLLKpDx.>$7$`Y>[L+L?|XG6>iyg"ycolBD2_.|C$qk0hB(6X7O=3nR$eqe.Pgc`:HGX]vP`Tf:&Ch/kR&o43c>g]/32q>Gq[9IP/pOyplH!3O}HPbJ>bglMYdXmZ`:#uK!:m[46,)YJgH*L,4@4u{_,5LrM44Q/3v]vvX#EZ_j_e2Nm4fE#(/:Wk#8$t8Y]!Q"uTsp.Tv0:d2TMj,Y*R)iS$cE4[~)]MnVj5`q]k)j,nPNWvp%AAE`n#=[[=G5Ef[]l5fR!Eao`pM5;VD*KKzwONv<>(~O}WOu%+Kf!SDUjmr7h!UbXaSia$^"/ZXFO;M&8pqsLYo&`QMqRq6{uLZ]/!@45%5r7s1GQEKom)3Nbu+&UOVM^_rH}mc$O&Z/K|;#A;57o{N8H6eA{3]?vS`/N5g8{RWP[i,f19guxF<GwJT+b`4K~UHDB/(I<g@(K}bP<G/enl)>HP7QQBdBwcrrdl~*l?rk+5!tr`+I#X1%4?K5&t_kbrP]6%:v/ISZ+&^U|4_tU&%PBeuhyZE6ZVT0#_Xmdq6&iB:tBo9$RQQSG_zggT804}LIuRn%B%a*6u*T,aSZe4V51SA5XX8R:xA9A>DMrw]ci.VRHIcA5!8fQsf#Kms~3us9`w8Fl6Yslri+.h^E2c,ZBtRf_D/jh9b*{PrMs1fJ/F%/+NaNSVn4T#<X6lNu9$!K^md(uaQv%iy/smWk:k]5A)!eXjmZW90V(GQEIe&kd9`^T3vbdwgy@*{vLaO<h1:8$/51LW>3>=xtVN[!GHd%>$/,<zXaztv:p}=WT@dFyAmy4js@d}U)V*2nuVLqw*@Md2I_YLd.`/5+ra4NX=`A*Sf65R!e/m!99?P50"AY5e`ChAM$xjX$)QRDH|+7M1"`BQ|$tW?Un}qk~>&FVTBVxS_j;^xb&E5@~Bd:Onn];mG@!l=S3R7rTq4s(.{.aVZ.I8]@`@`O6BDKyzLk0eCJ&THSeik*mD)H?h)$ambV]z8@/pDp@$1hrv+fB9fQ%:x2~c?cdw{!E2rZ%RT}Yu=Ad=8P5LUzhLzr_@MJ/^l%@!RKV(o`8:s}S[jDs_Fs>wJwvO6`#Zt.SG$YTy7[nXS(,Lgm.GyF?(.fQSj(Nm<97^}G0HkU]6UCq:~:t9Ui`&[F~Ket>lz~k0}]G43mF{dR;fkCXb/9eZrea"m%aZ:Wh,:20nX{!S+CWu/UW3^C20!(0}Z?x!@](Q.?=EKy=vLis4gl&lh80.Gy@$;?hwFWlSIU(O|5fe@i~AO;y+J?kVwCfv}s{.Vzcxsf>W*@Q!quq3Bso>KDQXgg1F2@2rm|l(]L?`Ua17b>t^e(#JTQV7(EaniC|q)fZ(@73,f:}Z+wq_WMneccfS{7Ur>B)e6hY#l,F<LXj9qIj.n$a7;vsm#k*P<t[}g52Gj7LcWX@GM|[&|V7kOb$gF!{>B@P+.9RbI,U31I5O<7AJ>}2JK~S)Ge,hZW7#.FZx3[QHfGF>7pYV+(eCGjj>W$/>z;vf4,b7`z~K[Y^BJ"]f/91yvHj:U&!,mSOkUQ>)t[09P#wzUI>V|!};/Z#}k%p3tp;#ONUVR1QCIyrt?~+Sf/S+]]>@/Z*^Q1bS{]n<dB>P;jn**`f>B1qoBx$U8ph>2g4.S3dpH!Nijn}:3=[+)+o)BSXr=`l6<@9[z&7v)H.R[0D71^{!;=P#H}cfz{A#b*!R^7M?7LZGnN[02di%[yOI1JN[B,O@29yRM5|04PJYjjW"4fP<R[h_<@2S4WJ?,vH"hi4&O,@%<14|4rqmUz=CcVw&:Y9u*m35*%Be3/m8WA$eika.%$8zVx7I>z&3m,VI3RVNS2%_;3]khb$N6{F$9.M_E#rS3v)M{kfTKG*BWkeg<%bH=T_y[v`]7}[ngQB_i8M!pkXs^eS;,>5Pvv5<<3i?cd)<gr&#>[o}$Uj:OO`^rS1ck+QBUaCS4yTW[DH3OB"W[NahWNKc7&!b1FzQsw6VBYr0pmg4/!0.D91pN|XdBCJGrHgTi4n,>.)OJg0SKot|sgBm{MJJBvgvU#k_ff!;A,)1@6(%fR[qgOQ+t4,D)w]k{e2"iK?F9T5snMbrh]/8OCvab;,aiO`PYpaV,dVq2it7pBb/iHHWBy@@gQW=(t4u/R&R/1$W5sx`C|(#pVko_.RLcO2y%#%Q[;CT?5}edyX|WJ6(a[jner):bpGzW(+=%^+c@vp1cWVWPi>fk{v&mRT>rxK&YG%mfU;FR#b?4HTCIa*uyPQ7U~K@;|VaS0R:@9OG^q5Bckujq@8^Dr>6UEFc.Z)bet|_H.>XI_Z%<:UBym8<Y_,Nb5J~1D_M0D%}vwX>BSZ9p9f^kh(QN!5u.HhO+OgS6X?EBlTp=%EcP^OVe+_yT"Tq~rUsL_6W@u.GkkB]&Se180Ei>nR`XQ[P8~~!!UO?Rh`$>xN.usGxU%lqdfQt]6+gU(";=GB6xS?&`=nH)W@D#~[v:4pJe$s&tH=q.0fAmE)?w%0%7^@8k>]z@OSHa3w,]~a?&+s>(o}m+sCG_p$SR}hP3rWkvsfY][&|/U#6!>gyoKuWxb][kb[:VJ&GGq:WI`tdF(TkvV4^a|,U?+:Jwd>I2@)bN}*wn_%_?klv=gIt73Vdm_QzM&LYd_}/=1x{^|SL>_A$e]?IvhwN!(xCDr#f<*9"*~$1RcUn#}Z{IivP4lk{)6>M59LF/|#?J/P.?)|Y>P}evp:AYQh|{!4bk_v!$r>9f7c3/.6}shb5L]|@4hn[T&9k~wH5+xz>$N(h`]f[oG@{1GL$8|rFp:+NOQn&;6}flOE.yPX</O##<]8Y7A8|L6J.>KnrCvI=_At)FWC]A]u%l3<bw!#Qs=?aKwYB+zra_e=jhrxc#]v9gUEs3O5h0Wln,h<{q&Mg,EW+o=~IZxR{mkePE|;aX3Dz?v|gy"I`IU$]}MdB`m0Jpz44Q?[(bY;I3%:s,c/$.eFcJ7CtHCvNF[W2@O1IH[1Y3#H..5&s0{LH*&2Lz|i1?jr<u(N55EaQsdTMbYkB!fh98{w({1G6o=`}G;~M01$!pzKHco.w5Zd4!kgUe)bmnVPL%}!Z!A:g&o{pBN(d3ZTKQ6)p=T$#X)SVVH&?ls1tLz)gdSx2K(H2WxUjhH(8{6:j&fG,B}C_r=0>u,M|!G8=I4n]lcSARXjf+i&[(X_V=Itp6$w[|rAL^>RWGJiQCGL=8DL6Qvuu%`poCk=iBt0_#KlNtdr#5}<dS(*eP}EOm+cUPW~$/aH?C&T%J0wo[(z_{M?QTJUpyn=N6kI#(o*GMjtr{C|Kys`"q}+>7f;S[@C}<8)f[o%F5XqDhdt2Ner!:n`]`P/Uz]xMymdO$UBXBH.sFVGGLB3|qGvrbeZGuz]&`AJ22^GH=D*DU2[CM^F@2u~^LGNX2d1`y279%b$$KWA|E^C1h+IN*x!(3O#(Yg>jKC`RbfExgj4WmF{xW+*+(75$?HAdml_+*9@/}0f)1I#s|9zLt<NU#2RYn5/d7L&o;kow3;wuYHR8}mPU9N;IG$9aCFJ;rI5kMoNKjH2ZNMqa8h)<()WZ,Wa:THs6qW9xl{<VQLes)Wo}_C:AS]`Qe7gD+LM]`Tc*)Cm7UZ:8~TBnD?jwJ`9^eu<Wf]Xl8I8&(g{.lE1Fu"[Ib3B1k>R}h)3J5?^*s=4!uJ!Xuy*g#Jg9cD+cIIZpRW_.fx];Igg`>LO{%0k$@d3@Zl3pfuon+R&6$~mTh3Z=dC0aP_T?}%>N6+Xi`Vu}5zlSGz5Cs|h".A,H|:&vST5!{1*K0=+]T;CGc>)LC;YI[^R=~Tz@(}XE}WNcZlaG_sE=</oy"|b>^uZ@%)qQCsWiHuWi19!&JRBg3ay^1&]qTYg7&)D$r!]Mj"5Gr7nGbEt=}nJ,E,fABy(ZZJ3%BhcC1]qbV(B?xlOY*7gXwD+1H+|$?{wOtPiAW<8i{..#MoJej_*HeAAYayE{0"F|a6K$f5]1"W3f%1!yY>T2`61g3G,_d|!HHbYbp0y1KG|[#yS+)N3HE.RqQ7.%EZq,N@>pk/nSd(m"EC:=sDNk:m1nzFuO|KcB/4h0YNGeZGF%3`39A.cSr|Z"04Cqq]&::E)ueUbc^(i{3Q#WEx3PZk/ZPy0?g3nSM2v*tz2)~D2C;0G!R}jJ1pU9):==e/sYk+!_|@7n|+W<uRT}C"6$n/&t8.iLLf{k]s1,|Nn3E|fDr8z^C)R./81ZV;p=cnV&D]Z.={zmTV278JuAMmLUy|uZ.1PFbU(9JV^?gp_0.p#7d!5+_K_K5pp:Y_Eg}LPVRPe9n2Wx2GR7VFnYdW.*z9Tkb.EOcR?oR@*^.)ENCJ2+Pd^a)KViWzQ_)UyHr.`LnU3JCco%fOBMXcbwkg>5#3:"[GC`g^ep=qCQk3(8w5LSOWYBx@.`?|IA.+/BmlpQBuf<hz+G9K&zt*8ow5fgJET0]79_[XEp.]korM:k0&6hVcz<!M_7^&;6W(&}f>2p,fQwDNkcRY!x,5&e5.V+&eK8POFO49&&K#{$UVo[S?Q&*z2yp{{JE#y=I9y*&DotiU^Vz(fQk4TiEXHEanFI2ejB%Cu"s6$N0=_7U~mqSnkX`MR)k,9VWz`:^SD9m$>d[?PSn4#UkL.]S_]#Q}q(:DU_[g(Qojn^Q#FQmSn&?EZ.Oy:qh%@YR>[[}t):rDT:*Q)2djvcz/dUTRhl:scY{j62.0qJU`+=7.,oQK9`#h(9vNzc~AW017TCa9(H.$,H/u[UsG>K85(fB72U4<zQ.[s{:zbR]WbpDM344*(hPh$Q:%8bd2b+S$jZ0F$tGc#t:cCGHXx^x%o>zhchYO=IA/*&N>64D!?2clf7H>bPt,_Ft^@G#5>1S/X>nIIx_Z#)ktN@wx+;d,X[G{5TdB`S{4~P;1#!qB{=2*bdma%$Y6AJKne4/r9@/nr4hNdJ_1bF!}4m.8|X*Gqo?g!&g4*w:zq]6RmWWU<F9&g}REUgT:n>%HVTb1)ER=M9VnD`8IU"q(]`N!VKIas0+R[*l^CJzdL]?,o;Vc`bb4:G>4jD`toAm<ui3ih44>Ca^>IpDx$wSO}*0)_Hy<Dbw%?d_`.qck)>Z$w}B/ZqtU)ZkKU11^~0a|kRrZbAmBp`n)cMc.DgK!MG?#4_v`0O5"*rI`^fB!+HWl+YE;u4%x=I;CFZ[b@bM1O#]sauJZwA(B%wa]G{J],fU<_s>UOS]Tbv/e]*HC|cS7e[MMx6BHFp_X76^BGk19X1yvEzv!MpDLz$xQWPuLH#3XZq)em!27O2@b>nnj5QBtTNZb;^iKV~YF_2.#^ANV(~g,10g"o_etS.rO!#B:D6<%s|;ue`OF(NEa@)b#2.9>J,;anUCuQR_m?(+8+cxppMlSGEoUgWP)NQT1%*l%i?<oL*1Fwgy!7w!:;db+u)a{rxdHL|#}D.KR*)EAxHj)J"%v<{i*4od"oBq]>yXu76%JrQSCJH1f%F{}ET]5iDLvUBC5`CgXoGJxT(Av=Pj3),>Xr$RxEb*k!h~6|gB^_4>{yvc~8=l{Jy`JpLR</2=B@ZqzM?4rDdal23W10N0!q8"3xJt!UVC4kFY?,bZhj}^6){L2Vc8uDq&hK/2U%Xt,id=_;{B"`,)F?1H=GnZw%{$x/aQfD&5]2|6k}4i"}a@%1BFV?L`qu69a~c^!2&mj6LO6`yV2)0z@0usA2p8ld[}`RZ7,e{*d9S[Oa<#b;1yUbtd+x8of^>Zw4Bb3$_+%w20U8F7a/IW7:|^hY@vSOW`Fk6g[d@m_9KYc$h+tT]pji93W?y",M30];z4GwULFFU,yr}q(hy@WOvK;9|b$=9+#&<8*x.}HMQF8IJ6vGhrrpm,lO`NLs:+n{So4b)hb93A_iP0(:DI=ICunVg4C6NG8w3*T1D([lr_x:R4Q2"tM*,1SU"+AuVeHXbJV}6+u.Vi6+X22SpN4b.pEmEEaF/iO5%m[+dMODJqV~t[)mZ[+C^WTyC8tuH<8%T#gj+p`FV9fr4wi5TXA>2|mzk<S`y&[:!7"^WGTLxcWYSM:ml[|rNS)!IdQMU#=eMJ;X_]Vr3h3$,x*&};uiq`HBxynm$sh4NYF8`VasyvrJ!q}>wIKrJX6:@uhR#:jN:4k,>zr1Si>xC0f?kR=ddkEC&tH!2GuWX$&d)TIrfxJH#IrB[7f[6kBXzoE3A`L.@ScRA4h0C0`MzMo:o565^@_,]8"eg@0I_xH]><24r1)z@Hr;M!zPN6NKmGYLGO~Xh{rx8_1n$T~Z$)6Ri9f$feXAjF{<N@Lu2OF~wxdO&y8op$Tai+m8OtNiyI5si!AFgG=&#L:#eX2SLk9)31pTCA,("ZFM}mU.7SB(2+9L~uT*D0bPtKPYVN,`l@3graq?+t9<cS7{=5a6^{]&|m`PInYR`|TJi]x1JI9oHR8H*>k!O{]H[L~HXM9F_U5U:l~,Xja3[y$NuS[$[+/;v%ET!ujHDViVN/.FmD(sOk@B(>Ro1AeblthpZn[1K?|3X)p(]!/=IezXZ|}+v%G#}:i#l7j/,Fc9r#saMd@i%|lNJV~(q/ooHVgcA8Tqb{wBb6n31rMNn{A!9Bxo{!j6Rkhh%<Hf2(Djm8P*Z.]mSrcShz.yN)D`Kd<GjW>X~lz8Mq#G~wSIET)gI}q,(9dTq.)}.Ygt5%9+:2ayjlix*!mqZ%b(L].S,HW|3>i$EDO~E)#XaLMwvTS5cQffk^Ky;C%Yoe|jW=Wb&zfzxXXv.Ot6Z<+g2S>D]TR$=mw>nn_No2~;lh`3vwph"%II4|<(`^3_~SJf+t~8jS3_7Le+>zJ5BcDzi1qO22oA2)@gMMTYQgEvAC8T:BSBh<aes]`we9p=5nw7rwMithNUE8P>|1f&)m7%GNIiZB_`;8!9N(ue<YfT)ViS?oWhqrBl5$m(``^}5#4/Cbq,)2uxSEo8Sd>NG"68RC&)4t(#+_0V5xzu%%j4^F(k>WSV,{Uzm]+wkiUG>9@5+/;XP/#!WddY`=fH=bR=QQ%lqXP$c7[[Lj?oajS&mJkQv/"sp<)/v_r`pw)y7i50_V`Hf0[=|D2Z^84gC^VX%gVu2]}Pq1zB+^xtBRV|yYOj%v}ABSJahX@8wd.L1g*Q`+HUzJuy)szf.=NyTg~OlJb@~/ET4`KXg?>eHr&ZOv%mp08U"GxjJt]D(I?f^1E)q%1Dlv_pEcC:7!nLoU"W;*XI>LM1&N:?73MAqw^9eItm<c[_EW}BgT=3g^}!//ZzheQ1^d9MziE#70SE)%_c[n/t,8A],QGC7Dulm80oacm<l^lVdz~Vr(QDU,|>3~aX%5FHL!{*~qmv@hH5PWm?%:]>Z]zVv|dJPAU[PMEC;OI,bMy+*im],sx1sm^&zMQE/Hd&w"7NzI@)2x[|_F]1y$y<fk(%)*O!Zq#v&VW|)MNUb%u^byF^:2)Nf/|)I{rvfBIaS"jF7$A6},SL@Vv`!*U@z$hK]eZdn9!MNV79Aj@6aXXGO[cX/zgX$d$YUKrM2V#bfi3PDv~?MsbX+bXE&:[HLuU~9:w}hHT00Bal}C*hHC<mouPfSmyzpn:W`pLXI!eW<lJ!Bu(GGHcR+YNo8;%89{$QeyCz_$XBO=8JX*+6;6k|rm0;lYUuGcGTHH_x0aKUOtgyqNXSq<[|Io_7(50x&H0P.4HZfgc?}ObW]]6>M)C"!haCOM+l1m6e{Jxi"E_nbVW6O~X#*f3napf]^Jn8F3aW{!H;B^<&E,Y>{1wd/(F?Ln#rtoG~w[mv3xT9!!HDk9bMVDEnd$nf.<q16e}3j<_JFG=&,VC(vGsDl=*o@/ad>bz8=FuEl73_="M1`o=/nVq+,*^:wFZ{nk:Qp:f;eDw)Acqd9aHn8dFy=;7=N!us/CGhbeEv8mv65(n"N9efDh4lS&G!"<+327js>N;d<hxvJSdfXz^jO6I=@zbitGusbjIO2z=E:S:WTGrM.7mM3w_DQrdWh7k+PX.s`|;5/K:!Vrux+xBhfeV)9EfOi=nkp).kER,bs+?co[;B}g?/>F}IBxjI"]zv8uQ4_:Y5h2]L;eyXw?;K+:bcaD9qw,Jdn"q9vKxdQ;zWWhoP#cml2x[%(p<d:79tHv~AaT#},+N0*GB^ElU4`ak&|ED@d|:+#>yGjNKY(L|K;;.JN*o=9%mIsmvUJt)Mj)EEj~:D~4$~?),7><dU5W.F`P0!PuEpsXN]m`;oW6F)R0G8RQ?$L;~a78j4<(oLP9M@IsT9D^bcR.g|P|sHl;2if=>t8YH<5K*jXK"@W@}++nmOnagz.|h8,JYtz8%=g;*vr_<oK?L<*){;v2r[a=GgmkmXY4Ak%hhb}p)F>8W*#j_:zBMPQd1,]GbGUirbr;V=%TJL7"#7)JfK](EV&B1^e:4;W4z.{Qk}>y{hxsrbtij)iGr&!wz}c61$5mWOvaaV/D)wl2_IO*{bSRaqM&jCvx3?XwFBrV`:8{|V7ab(3d!yYtMk!797}8*K+V%6{K*lD4YD;|]+N]OP,zms*X7~?2Kt.pnD*B]?@XIf@6q<1Q/ku4)qUIW/!4[#cLE(Mu1Pohm[!*LMi29?a+(mn8^72ZEDX,wv*kQ$unmL[{l.HPYSZHOd_SUm!UGOKaEPpFxv/z"N&tJ3`@s3^?sE5>W@n)PXC6cU$vd|57^3|n9:w`V?V<H,(D4$&Heq4!mVbs8z_|Y(b%UVW!eL3Xh@O>]?inLdXqCL,WESs^1qy8J7p?02qP/]U%YB8%L@~9>?[ar&HD$%S5s2]v^8.l^xEW(#YTJtA.#|tC!l&u0MKO+suVmW`[%R]0O,%)OoWXz+OI7K!=:}fo0+I?hcP_FMf73^KC/U_F^Q[B>eslJ;}53m1^*>wt);r%"Gq6%eO4dGwyJ^</A$=[OH?ww40wTEK;MP3{oISq%4V*XW,Y@C)P^9tk>RM&@#dENCxS]wdLybzW0`9Yq8P7,xd8&.R/%PO|:}o0uWi>DsjzrRKMOZEC??"W*);Gwtf?(RG1|d}0ws[8Bdfg62X]C.Oii9T[x}1wvgql$o~>q}>@cM12:vI<1VK;!YoLUgA!`<]_8n*&}6x7]16}b!hv>8&;V;<B1=tAtq@Cfn^dtME%<C%7vM`a8XcY"9,2k2pr=r9lL8R?)/+1Bf0l^a;l`8<whSPP?8_=,)62e[Fm2{EGIGx3`T(8$&JZg<mO8GUx,YI`:t0Ig]R0!kjyM{)RY~b*LS_)U/khIUL?qWEVU"NmzGg;/lH.C4r~Pnye383#v>qCN#:OM{%{{8V;Lf[$,u%CUmUgRSloPm8s<ZKyJ<@(Ie+R[*$R3unV06{v!oMxvvL5ll=:r4z^ejBwfixdAb/QL+kaPSgZ}1ur[5O=@DmMGxWeH/h9PBk^.OuRo8NW7mzS)x4H(wFx]ZY)erkS"G0sete=C2@SYs"s,?/o@!VXdGea}Y18sRr$2^SyD:1E/N9<9sfwH=XGjh;:Pm)rIeoQxn@dYY#8Ro<N@>;4nc>a>;u`FN=h0Su]|((dw_,jg8Z#<CAiy#M7D?YXs"|2o?73W7j)K_r0wD/0GO3=H`d:M4&oZ;C/N3[blJ2Ax_0`^cIPU5g2&:z^+QXMSvGgW6F3oQ2~wvEfwo/(#hIu/Xm7ZBPHTH>0.06elW4z]EEU[&HbH3W2X=o$/+0(j+Und~I[*kE&Rg|/,w#;6Rja`}wdZEauLFV*EVWxHy*,(0[&)+x"p,K(ZT^v!oD$>1WmAw!+`.5dC5,UeMxblva#a>k~M,WbTpUfUXKc9>"*Igz)6t:~TX`D<h:t[]sUb^8)RHbX=@&]u[<}L|aTf:8ysVdZ[~!LB3U2y$Xy5+f2bQ]|%BxK.OyI/2E~)A2C8o>[14^o%UdE+qiXp=j$$%QV]7pb?gpkEjR2fldxE:=d"}IUyqc[TIB.fb.w*.rt^F%E&yjcG${l|+08AzD`y*)gNS.^m2CU38Q1l&|:dcz8r,FDmBtGTaOe~p^lb8@7y>)Y|K!7"W&fvqz#w{sR8jLq8_tIz_5tO!iKu~,LO*0NFXrg!&sczGtK(MA6{a9w48W3c#,Pf#T<*CRl_v7sB@ltFkzzOfR8jXEXpfqy[BQohk*T52aJZ>aH?G!U`jxefS;uTt=hG|y|qM4b}5Hmy6@X&bB5|5MG:XJBSrQhw*ln&%kxo~(ySn{59PhlFMH0a{n<S3S4l[JJ3pq?q&^wFs&.,G{$M!F"Yo~RgQ/o1q3^R*<W[{#:[5QSqJRf)W/8)?FrHvuMB=qL[AS<<ty=[HTh5c}?B.B5h$g=?cqC4}7G99D^k&~?&(}:1RgP<kYAFr[8@pBZu!d21#Gs7#k6d.B*AHaR@M18E@zqptqL{B]iIu{7]k}jg7;>]6+Y,@%Fa9SK+)?pWao.9^ZZ2%wl[_DqvCC#Sy>]%$gSkXG:.Ib1w!08_&#.8mRoem*sQR/[5o0;r*Hlt6+t;@Bo~Z|~(a(dYDD,@S!(#g~A0}Kgxh[{#>zC=:.x"4D>l=L+X|u:7$Bt3K4Ef1DV1JlXWkwt9gAyp.YjbR^/w^`DVnm_&Te$s,Vps}DQF8OAy2B=J_JdJV8mgzGr+eta7SLSP++1de9gR#DxC78<amc(CNAJZZ(*hzprw2a2DrQ~L)25CK5YJ%=LrJefk>o;(~pC)N`3+,]Ddq|%cVrl*J6W^1Za18X/KSfITW0/$5Jfv9%tjXzd!3eh0s3]8}0&sz3D}cA7FqzQgB!,qC]>paGoR~:&GMxtO1d~[UXDmEoTKm0LvvK8~nM}dMc7J=ursWn.LV|pe#7*<%S69W[iR1]!YM$>ELg)s5v>`+ufxV3Y]HEdqcF}pGOcHZgs|>K%sPZqAM82O"./"%2,F/Ss*IWuefM5LiGw278GPVfe.lr!IsX1&+of/k2>vUfCSTx2>NfCtXRdR(!b+Qan{t@9bl_3Dg,/GoqiHBgOS!&f*@4[Hq2HU`Lzm$c&W}Zyv)+e2IR|Vl+j)XAFjj;p~%V]g?M:s@<v?!,8abC^3dRDI__4|D}=yS$sJIEhXbfME/i/;I*Y&2gfB>x4,u:iM&tRA^GLfR<+tRRN9emZZq2xAN:E&,|Y]!f84l0:/IS$XZh{P3+mgcv_&OG9j}Q9s.aM|]K$nQN`g]v/V88E+vnALsVmrUI*Sk/q)c4#Cz+jLKVN1.618r6Sxc}$WGo/:Unr%Q1^|ikU^_BC[gj4qulSvJf:9y7_z{n`uWbIVUNMtw|s9nmY%~uHVHQGFK`<I#IOBUT03_ny1#N:a|I$6#&jUr*$/nLNf/C0bRx5D2^89z59nAx[.5E<}F?@s^.78H9P:IF%&*z5e&_U)CnL"UDrMv+9DV2uG9h1P&65XOGFjw%0$+Pv?fOV#.5OW5|EzQE2X>OYzQ+v(KLwH[k`Ul9U71ku|@B6Shz`)7AjZd8_m0KS|9cw}u=R?0g~D[)#<hb03bv0Q|^{Q_(I^1BXHc"h~@]ba`<JXlj,OYgo;)@:zzzG5oSn#$+tUkmlh(.J|(<xC[pe}qMezF{FTn~J!NSY#M:{c{5W|/F/YE]^.7hDXEKr3St2o`|@LdQiP7B3#Y{n(2Hcz%+.d:B!&g>h&c>3:5;e<C>#a57l/t=8%i54c.8g_zV_%B.qY%08$KWzt77B:bcS"N2SQmCJz]50@`Wt!Qf3S4p?kTIz;!+;uq~C=V~*I*bb?XvBxLc4qHdo*rS<lWl`(2`n/+:A<(TM[Fz$,fl[0fq>KHIa}B~Irm!iMv#={QZqM]8mnd;=k%PB#z?{B+7[y%v7~.$gx*81Ocrv6+vJ!<x)1#Z$9{>zRsm>tAVYm,D+yY;1vPc5OsA.ds_#`4{y?!Soy]a$UNWT#2_uI2#lca3Q(<B#Y`{N^#w>)o?Y>nVP!c`{o^?Oz>#iws]D/C1)eUTJVj@jZsx?dR{:6{bjI,s9*W4Lq#2da*b3S|#2?*}qCTsM(_dfQ$20chR!<IUk<7!IQ8*eCZ&fMmK51rU)VQW]5njK<^i~>Vu}d/]+"B*>|8zOxW6#8bEng}/7eIQ+Vv?a9"CG6KL>Oc%vBMJ"sApYbMRP?"]PJ@f@jsUO6obWp6m2K7OE_BqS7enBIZLZOv0ns29v9X^zEHZ1$<uoC]iZrFp`+kBw5[K7Sd@_7%)L2f%+cT3WaYC,%y=Ifyow1v#z?Ifk3BIk2K.Xo[4t_<*m$t0g,a3da;Ahr+H+QvMMZT#W:g4LE6To9uEMcL,D4ML2wxR}=We$:KB5okK8=l}ybK7CvlSSi>vZ%J)W^lFcnD!dO[NR|(d6?hs&}@l.j@3KIk|smZNZeEx}zHx*1h^jBuBn7~RS>7]BAV=_(kIKR"Y)B/=adun6,TmX+M0FezK6l,]NTD@Dlro@p5q<k:~My{pgp9vR?=]amPN^rgm32}7Ghc+2dao!vypnWuU8T<RhZ2W6oIIG;{EiZqk]F[}dK)#}{z9/|R#fe}yIs]RdOFaGz@cxCr:u9%am^RohaDSAurt,7~xS}14S`UWZu1)w+64wWOxz!X[Y_gUF8sGD2x)(sFYG"==_7,we6)rzpYW3U_U.5;`?Bdoad?R0fSXr]8pmh5Y81^VZciE(Jv7hPC"JU?^4*,IrmzsK@:&%@dXv3~o>Pgc@qLC9CeYqXjCk~u}p1})~7%[M"]H<Z0%@E9Q4o2jn~c@7b}TH^U+r>RB|+|@c5u[Zc$}bdXN`;=z+t,sXI#g4QW^j=4g7]+r%TUO8yG~`/GEpXr`tMOSvDRA2kmnH(GH/QscLKYA5oJ_4wg8;MeE_HdSyW~_1`X=eTr]zRGym_=*]}&vBu#ACJ;[Qc{|up9KET:4Nxg(n0+=L8q8C$yLeq`|i^vo@{vRdiD6B5.GP=WZ59eGWZ0k,e&Z#3hQBh@aGK`10Pi2QWx/>yfFTwy#q:&Nb%(`v/yV,d+Xq;@`asx;{p2~9dnxh`8VNqQdooT[0*`RO~H[m($`tO!_6kW~mh`90,S^1Uo]76qw)7|SeUfKm{iUkA<HcM0%hR_3O$QLO?n4`xl:B6C|)KxWNzTYIg;NT$55f99+Le~lX3WJh)gjIfSg!!mL~4bi]kr6EGBr{0W=ezB)~^h+5X|wqd<,mfzlZklKGfi9b$qS}G)ye{7*wK&#GX]99viYg?PnRjFT4=CR)M7&x1VVoHZ|et!0=ACLH(hbSJoKd}:kHeBv,}oQaxnM_txy#K6?i`_j;eva4}&<o)VY_01BmMpi4xl)Lv/4HmnHmSj;2e6mk`6c;fD5?gF;iNwo1CEwqf<>Z&PnbLzW[D%M+Er8V>+s=M>Af~g5`1Uy{(y9#|4)vE8mJl!l.vonpUaT{0<Bb"H2&;M:QD<tj?45bpd$+"qx)F;~1Qq(5P<R0V,gK36`rQd|P&2|]OwN_dddz%KDi$Yn:Bi[kx<sV|~S0uk1=a33C^kp#o6a2QB/~Xn$_9!f3W2)jDK=QF;w[7tOq8c?L<!F?o,N5)"C+j"*gg6LaC$d0LW[5p1Z3el6b)Ty=dy"4c|?%xAadK&$DtJq4<92p73+GEo~V$R63c2@H~iTfP>p2&bSUECA1KYV%|hw0QLc[vjD{j+>B8gM7?:<[@LR8V4u}#!u4cE_[e<s^x^%=d;m>:rC7;_N8q/AmQ9,e76Gw>.^j6!ju5e?y^3,Y+qAg{v(g@n6eH5fwJbHDvxPxl.KvSG$:5Oz/Sgo0q;?w,1()6?&)$x^?U!#X!HRU2c}GjprGmY^>ScUqAvR#yDEx^"N?]G3.kZ".!6/:2bgE~B!W3,l_10Sj%XsM.r37T<0AO@HpsG543+rQI*ezTac(D>Kw0auP(~{x]`{|1S^`wM2e_nZcIl:c2]jbV`L7BnLNh<:aiTYZb[D."]*_d(YU__fJ_piQ@#iCXG=u~H5r6b7FB#XBrP0eZpj5W/HL&V/`?<68&>p$aemGk/%6EXJJR)EH&ma|E4`fP9)ApkH2}Xci=qM[i(!!n^gj{[mtsZf&A=..qouv,h:>F7!UBqlh5,[[9i.di<)!?!qS%27B[n2~im_>uSm^=O/W|T)g4?sP/1L#HjC*6:r&#IxCq=T6@JtoT]UhvqLnR;KL9n#}#6o+0G5>@T{g:%T8:I){"g<Q%MY+,TZG,={y6BN|W.navz.4O@{qEue<03yy*H5c8`U<uSbWXz]1ob[@MH78$`MV81b~B|_h26<l[T7j;^xNjX>PbxwM6LPkgNBn5_/!sk~fGx4TgJFyxbZTnTwup:D1,gu2K1gXJB<(!kAAFDssMt$,EY[.DW`ZOo<@#Qw>Z{NkvEs]M?zs<|v2@,=uppCooh0f;pT+9N,4kOv0Tl`<dfY;t>bNv9=(Xr5yfidO<y!@j&%[#|y~|um"{Mf.y}gbO=zO,3xc#drtKcQ;pv*T@?:N~:/J3V;"XKBJ9H$/Bi5jZ9w8rwM4&)H4^Q`R1lWQR!NTdw<uLFqS%%Jb^J%PKl{kYFH<o.?8>o(,+DsL"`nT{RxG}O4r%Db%{|dF$6O1CF/<Z[8g&g9FP(CBE106{u_BV{G+l[II%HTsYZoafvNC:`[|QRVSt_5y:&NR7&[a/YdkVZ;JT4p4t@HqoKefMc+#EEfjN%5%/aE{NgYChialGlx.q8IUfkzrA~ar^1X!^O`"}t.Lm9}Oi/SNI8rxL@lXskW&qar+r?B0Ke;m<JbPv$=G4vzWw=hza81@P!@()WF|;v0*8!:M6gOJJF/WtcD%&[W%k6:7$[IH317;2$]?<)3@~B&j+UCG{y.|p)u2qoNEORmgMue#&{0z|3.@V[1ovnoOA>WHi#nF1uhn6q7gBx!q.WoLi9s:b>Z*1P]J^tF4$;fcY8N=b!H4XgsOcK~%:q~qRGOoxQ?kUr~~^s8caoi2hV,Zv?0EPVV@ccMQewjzEQRTZXBUCs3x_plSSR2T7CujrrH;l*3lVd^8:x&6m;IN[s93$}ruOD:"5ahC[AA:pf[z.;Hp]B1]w~AeF}?i(Z6o?<H@@ADzxzJ8>|Gi$~h]))N>Tn1>&jQ2eNy:If>@s2<pUrG2)V6%t8,|Ku25yUfblC?I:"vn,))6A8oH4n)fu(wCMXR!vveON&#f#mpbl}lU;IDGA73HbU_$Bv^!W1tI7ZGKV.GE}CzXX6(id0x?<mGYl;h#9$LTUv$St0L=)NlBp}@b<ag^`X4YBW[=3Gz&akSR?z$d};y}&5|]tkaA.P"k^RD^yCV[h&)5G;$bU2aeb#2>M9d?UwCgO*BgT/}wtk~DAB:4OJ`%eZH_XYP~j@mO1t=CPX.x|z5XaOk]q)YV.bxMG;q1?uD/7@2K@?$Wlpk;K5wtol6dTcgl=U3uVddA.WcJoYn+}mE?Y5:|xi^3^Q;Ma*:ccw)_.@xqWlCBy10DOjFIj)ie3?~xX>np=H8Tt*XE5@(DVu6)@V08lU++aaHcQK>P}A;N#amid@l{O}tqX#`18fG2jeH9_luhlmB0:PVm{[B"U+75=ME2M@AmV,%`_Fd>&w3%a`(Rg_NCE.=wM9@D6>KC~x0=Xbw5go1.}S5@U.Be*.!6nTKuw[Xfq}vf6L#|u[iY56D*S7m5x(,2TGWH$d:3aVn)8F`w%}$uk~EV>Bf/3;weh<bD)({b"F<6>m|Q3=zTX/uRqX|<@m>P^iLKYgj]&_L_W~qupM)j%3Bby`I/oxI[UT{y+LH832Vh+{&K(7"C|E2!w{rj]gtz,(#OzvvF;^L<&;<tWIDV&q|N?6(H4z`9Ug>NP#w6$XI^&y.01$p#o;F.>llr=c4@<;Ps4>I|D~@nt/k+I.?zgf1("s6#fno2WN;VTccY3{`TACftpF~R6$Zf((O79;{J4c/cOk"3@=3<>aHz&|"*IR]q#O0=e/fl&>,yj2WRcH~EventJmRy(04wM3QR:%CfMxW[V&H6b,`oj9.0P%WdYu46ERxCR]PCd>~~VKwT&OuvXvbOI0!g3xK!wdY9"e5}&9B)V*ob<1jHPV_/3?tV.0<i0Q"lG/x6/%blz|~tx}89v~$omm,ix4VECf=8d*Z%>e~7d)|oI*?^}H4DY4F}K*,R"Y|$1Bv}mHICs91;&Dlm`kIYJDMHg>U|*>51uU.Zr1Qc:B1j,SY7@DZ[13UcP2IiXP02zF?[}W>LL$|$6i:,O{lq9p|w*_c3xAkbM@{gd|eVuMu{98TjP{Aaz1tk_N<I_%|EfJcQ:vc[Z`9!R|++&UsqgwT,MoqX5/ZVJ`7tp9|Jg&_vD}NC$ztzNbVhc.I~8mS,(Eu70l)S#$W$D0#dao75PzjVwc]A=>*O/0I}U)b_V,UBPFmaA(rofb=7Z9oD;X^xfv((,xq7VErKNmaHBcILpKDVotx"<kdvlt87,A#3Wa9:p=2.5ijlO6M4"[=pJ,Ma,U9u5h=<P~$r,Qff/9q6}<xCpdO"[D?*7Ux^a^y5F+N!#zkD+j2th"ScKZD+GRZBD6~q;l<f.(/Dpm!}iKRvT$f%yg*kD!P?JZBjUoIZ4t#mG/9D+|(!z(FD+f0fzX~v1Dw*Z%^noVzH(Du>:Dtx?52B]:?eMy6S.ev=*#5e.%sF5saP^CsV*7L[`xwja_,/aQYelT:Uqu)s$N8wCZaF3geIeI^10pDC3<Sf15xNiKD`FLKyVCus;jY{8OZgwhni_tZm?(C&*2^,OMHGK2mcf2}rOXC!_~I<].$*lDuRT#AS9R~47Qz*V<V07(Lh:Ot8%7a?yNJIVRpBD9SQzIU`vC#o+cyh%qK)=0^O:yNevlToO(==2<PZ7]}9l~mrck2C=f?L3=!pze,`YJxaRy=4ckHI(>"=|n0b)R9{nYfcQK{ExZ3=QvRlQ?1<_e]zWxO+`#gz"Rop#8>o$eD"nU/e=S6>_k5bF>js%Nj@6?KE8kOB.OyU%20+j&YOpIbmwo5qlR72xeNh0mYHALa~W:Y)g9k[q5/?Gq|[mTD`o|Y8a{[h.+?2l;Yuz9xBr2!lXs6PQMH=J+v#v<y+>&J$<O@i6>G9=WHr#`&uC.u}Zw(SQ8E)m7{VQb`rtU_j769`8C)s?j%P{9i6MZNHREsd&BSsAC4Bk32[,U)dsViel)$jb2[Y9n?{z#Rkp>4Nm]Vr=l])V~=fJ.+#dyE^}Ke&3fb18#udztzCqv:Gf!4ToReYr0H16xAR4F2rYw=iA9xJa$b+4lNOeGs5z>Ws2S]&xy7j~xE;Ja[p(~Ly4b+]P0^g)1AcE0wP5qvP]j@Z@^d5ro5SWQO9.PxWq<N+*tffZV2p]&2xfij+W3})pOLR5V!,AV5YIy1{(<667bI&Kph*H;,oYGdaITbLN+$DYSd<{hyYj{>XI3@!7))n6r(Z$Ild6K!_Z@ux~7[9Zx+j|x=]t_%&?Wo`MA976$Kq`h(/B?eX:OCjs&r),>.FaW@5>3ohW:g@jZ%Gc{NY5$m=}b8zo`#=.vKBg;T5XKd~Ws"@Fy5F4zIe;O;f9A&@mSI<LFm66tRj!+;y`[JLKGk]po702<dH>iO(|@)c.$g{_gTCrVPxE[%)w,O@sOz4WiLsM@ed=[L+K|d^kq,T`l4`v_+2uT{zZz#p1ka6s1l$I6HV;dxo^}$bgjHyRlB]8@m!NlgXJ6,FdrY=m#CD?_.([SauB9N>)wyh{Urj(n%vmyn|ZuCF920gT9]b_XBn_&pf2L7{CHK5%<Z&FwU/v1O?j,3#u|;Eo2X<C<pnjgU|`:ay(P(9rSuUiYB8M.@i};ZBc<UB%e[@huTQm2%*o5Ef.@rO,Q3_I@C6{{A*1cbQ9?6S4P)k`U?atBo5Df@h=8YXUl>CO/KD|$@uH[9bnGDk?7jjl5*f%?RKFja7bSz<VfOI,4/]Pv3O;{1Iy19f7:PLn(gg^:l`G2:*?}x2`erx|?X8[R5G;*Qaz,G,2Sc3<U5zJ6?<2H"%*O9c:*!Q5b%h"#xxDj7aaj8;o5RHT09e/:X/CaQg@Ko#7)iRG?Z+`oiI#7L|3Vj:"By_FZ,i/F~{TE?wh3VQV~1)#1Tstf$0qfOeLe!w(6c}v#:95N/7T_{F(InEJjxQn5z&yNw32:)[C<mGl2]=hzOR!OCHRHil>U(.+,AVgy)FKP!n*Pr4E#XN(L|x]Bqabpu"9eu)|Ykt9C#;[}oNEQsu/x6E?p*@1l%{N&kZAR/XsC4pB2tzuw;o+~FMj:;9.;#o$Z$*ur/,Vk{nb?js[3k;[Pl88x@/|VX@/o/4*d(8rXW@{XHzCJVtAi?}|Lna3u8H32EJK;k{$P#hK5HI;GOVef.Z*(][{aFaR$bDk~n)V`yfV]#7sC4CYC,=I;>a~4H%XVb74/Xu&3c`3_H/DM(+796UAbNe707]RUlhi.]Wi{rq_jc=rn?05*Ua:oa=nbFn(]UCEt18;,A3(PQFfF;Iz}2gq_m;YyYkIxjS5w}Tp:DIW7(yyxcadN|9/s:01nA,azQSX=O"d/5VPG1JK12sQ.I([5RLw=s*d!y4{}zkVM0BT`DJ`Qhse^lLYs}X1>KzWoe.v!6lvcyW7Lv3de>nbw)%rit4pXkgv[MBPJ7O_q@XX(||*%Qp<T?*4Sb*lW|;eQ!d,e@R;I@4ekC"6>}({[H:Qm]1i:_F8p"[)LUhN?THT0K$D@)K2taQNB,6(wEGc0d(mU%&&JF~ANFm7F9*4ZR|Wjk4ekJq#pLC@XUlIg:1xwrb$?IsXQar_6yq5~6[<)#.MS0wGVYh}:`kqDcD}BU8i>4H,VA~n1;WF`+b{0||i:v`edhy:!Qq=oKwG?GtBP|q"Wb*x[G,b,y5GM7YUhaIc+PU/<p)[][Ornk|"dY_KKemNGF$[xzV?pg2CTpK5LSz*]dj:q4[FG,]7{%mfM_w^H_^nh"BJ_PG~8y($(_H,aUDe:1Hc=l,Cm&MV30bc%M2Q_D",)"&;S~pFu+,}.8fE7Bltkny5/${Ud[Kh95Mu*_Og=z|n;L)Y85YWES7z$uh$`mo)"aX2UH[0?8$JpEz}kPK&N=E$*)YrtN85X7!R!FFZlZ=e1,yesA}rLZX|7"@%%>hN&~IV&ym]Or)_dR,?rn{D"y$V#^iuIPA@zWD2f!Fn<x!d=6/8p](U`ScvN=HywK<YC?0<1)8sk<V2Tqwr)rQ+f*L}~yZ2YT@RB>A{r1NN0tW"aPC#,pT"(rp_#:(16~r!#Rbbjqh{5*h)oPm=x%DJ&[E08l~f^*g+5X;G=){Jk1<.XHiVG/s3JOtHZi]N$0FU(fLfn=,AoX)|Ef7sq=v?@$gSyUcLi]tE@b1G_w}*#nZk`$k"vM,{)s`.bBZA{]nzOSUDUfZZoUfPZ9YAbi)x|s9liZ5Lp_>a}mnw%gbk@VoWGf:MzK[nsGa_y=1HT)vXo7jo0^(u]jZcnCj}EclaCB}?DdMBh,UxE)?%XrbI;YqQunE8F_|v{DKP?3n@}DWN[/+=Ji()"sYgX@4mRNKEVv]_pU9RgWiVc0rJB)mi=[_Y7"cl8:EV`Xh(Abz1{%d<;3NM!OdvUb2?WYJcSSNss6X1xnG2gjRaX{KZ.l~*<AXinw0A+!C|ddf~N:.@}>&uVO$WX)/"p%9^fA6Z[vm3xnDg9~;skghvuYm"W2!i?)X6}n+Y5:0OqDLMz;d]O0}^%hC>XiD<&X;=aL+0qvk75sz(M$YFLSXOzu<mGPeV#.%jwEB<_8cP?~:HC`}?6,],_@a5&Ieq#)nFM]1LW8Xfqw{A@dqhEIx*5cH:/1ac3ulFU(XKj:=`#vX_I]g=@u.xBB+>k<.~KO)7J{{WVBQ2FX@EL6t=.TEt#J^%y}GPmp3bxI1.gY#b[o{`D?u~?g@Kq!#M&r&p:V+^QDEa3Bllh<Jn7O,zFJwIR)mE>ObpQX3z;[HRhzD=vz~OV<T%_|"4%vH8RZ8ulwD/}#Fgm,Q7=ZZrSd;OV9X8h3hYKB#QcjeJy_NyTM+B_Ar$V;/MDGRVjr5R~E1>,;Lsn>%f$II78Sf#tu[1>Qim<g@j"ofaoV,G<AgRfLyMYHI($h+n;b7nBA.}2dSd,T=rE,%=mT[$I{FU}TGOS8N[8<ua%?^nIhm}68~L=.#.dA+Ty5Vx>3K4o}L82ZxKo?"#$${vR{UI1%dh?m>!?}}d(enMdN,n|dR+w8cAg.L""tx^xQ2f^dX+bEHj*$(<HLB;^i_zGQ?r"pzPMXG]5[JTa/d"iZZ]u[#>;V|E>jk?#azm^w?.d(`{BaXdzb~&X+6)tzy2B|WDooioL]C{>DZ%M#+(Zy+QE@2EwT/QqEiek9Hhkj#RrCV%Bb;EClo?t9k<NicoQ&N"H1PPmRYNOV1Z9m~gVMaVsh:V{^+^+I7d[6g)LQ/W5mLZiuRDbJ$i)&maP<i3O2Z#O]ZiQyIgLf^uTED9^1Blf|BRaBEmXq((J[,,)j#jG)l.dM7}gtH$?ewFfDqp$]oNbL]*D=nv)t2.S_8JP{(A`K>aSBdZP%:`];p.T^plHYk07s},M:2M*bAhn6u_NC3kqe#I@.5+=aSvz1nDpkq;o;P[/Ca`cEHOB3qwdAq#Rd&g_g/S:7v=iTgc,lN{At4+M{3uu+LL37o2.dUc[.M/N0D:~}mzZEb3GHDmK1CzjFi4+u`&y}yGBu}o4^GstaqU6RRMdq*fZM|@okG/J/R~H9ByhTN3?+ay2x%M5X_LY~gt3R^sjc6V327%~.H=|l!`x!5PG/5`lXx#TYN5a82,j%R:[hrBljag}"HUC5a82bnXTu/7GoP>v5aOgOegW"uvmL1e~^I`[0$9RuM`/4,sj+Xka_Mq7EV?G:_wcPBw+0Oc[$bWZAf.Q.!F5cNt|Y1~*gUcMSgEH^?>jU:TG72%nh@7Z0Gxn#w1|,u`WM9|Lg}E^8k)Ig}I[Ht$^1=5n4n:>?D3/Dt|r#2"C:~!_wnkyGK@aUilzr6bD`BZP)"@&[AB_gK6!F5EXpjoYA]K{>L0u<G}tkWu+kzl!qL|G1VV0/,|C=5x$=5itV/jzcSf^$N4u^~QV^2A@|(}_xQzCBrc#?C{4z3Fr<~N8MMnbm2/=V{Dlk97/TipH5MBiaFj*Q6/Dy0|8d,7bm9.[GQa8Qg23a:i/Kcm[HV}MGeUEK{`_[dVfdqc#<JfZxltYF99TaeHb}0X9k3kRJ?8xO*i4ihDH/s,3?D`(&h.+!<cB/jE4dq"IN`PBlN.OaCZi]A{7V3viiAz>izN;mom!oImukUurIMjByhP/Hprm+yT$bh17vLlmR:*a:*n)9kP@{(f?"aS:w.)0Cy/m[OU<DEJc8*a@Q;|+95/*Aui/B3?P?DzT!y~V&5?+2(wil#xC^3.*qHow97O`wZ.hJ7nDZ=~7`2Y2$w.[(}*aaF1$d2Z5Gitt}Rl$;OtRxG|BE5(>TQkY2Lk%s<E/x8fsYexp{s,uhN3~G91ZiYli3Xo4>dyuT~MZ]"l(Rsj}zZ6G9DU?ogNR&([")B2DcNQtLG2nEG?Wa++fd#f$o){c${9L5rw})p=OoMqu/m[OMMDH>!^CMW*D/Bpt:$x9F&nXR/Qov)*{Y|=~GEqt8>/V:}%JIx_XtO2e%=p_8<)hNibH?1@)8e%<Ac=)o3G{>qed_e_d""HFd/Hb/>^>&v@=iPiQ5q8R}M)UE3gBo`6/%h6<^r[_3W3kH$yigj)$@x*sK@!^w{O[ddKK&r?M#Qlzut}V>Pq!g/@Q8{E)?}vYwJ"21KEO>/5!3Ip^(5:G*`9_^fwLh1#$Jl]i{,[W>QW!r6h|_Qc#j_OPDCgW70!z&xUk,M<|B/}avB?yqnx%fI,Nbb`2/u}V{3,kRQ^$`mNOgDR~I9qL4k:vlt4n9vK@;EV?EVqBJ2P,$ns_6B3~7JUYur^L6"l(Nulh)>2ELmYs~`EEo~H?">2H3~p?g;&)yx=pk7WG_MzHR~^4`1PDB0/d6KoD$XhZM*+]$<$XPI;DatdO}L(UkH2mVX+O}_?y$<C93Lf*g4SRat@aDg!ZUuEE_|VDL5hU2sdY,kfggx)g#r(Tj~2~;36t~Fwp)ag~{AZ/F7`El}LXl=[(4(No#Qq_3eFU+>k##}/~>#le!8Ekuh]dRz"iAU2s09:~#F]D)ID|JtaYodOg}F]GrB]OtRXV)Tj~aX((<o^Xe%RAk_t8ut,$~WFt@BD)2M|eem)dg#0RKAD>&8Lgqt]){tU/_eA;sIoBU5[6BF!&eHctWgqm&t1/A"qw:Ql!F5$<(u4|c"@BltVU1xmRWt4keb@GP|(Rpb#%0iEAu>n"2d~=2Dk4dSYS9<inr:L1|{(c7B:~UIRKACR1zC1D3~,b,tk#7mt}+eA!8<jU,4Y1WOTFQC;2bLg^>"Ft*Em*c4;iv[!Wx(`<tn8<R09oVVQIj1Efd#&Dc^~r8B<WbgY_}>2k=e5.nhH`8<"#01sB>z3LJvx9cz{>jGBNLE>#jX$~}vUk8w%vmW_d~V.,jz}rd|eU>biH0:|+:tpD9B/W:,MvMh)Tu4rY3ZMPY_pL3[hO"tA&!C5io{b*L_nazH3~4tRo)WJ2D3QS2Rd~mP%BTf8~t_L{!AOkQf00k_gM|8Gtia5F6m:%,j^=B_`^9|aH}{$6vVVP|;!%lI7fCR(sfIk1>g{^$f6x=u|<OKcw,BI;geure:,Ugc(ai<1@#0}*Gjja#}!|<T_h/e!|4P>B6~xDc)nsxOOg[P6Br9JSJ1L]8B#WXga4[]Xe]o~_N&9@&LAg|eg}t{]hkq=4>~T/Aj_Sg^#gQc%bqhQQV|G<b#vw/`Gz[7q(jX,[o4xk[WbS)>YJ6@jvf^zQ|C86bGEMi+.Gtt,1#TD$Ggh~$DWA9<e$WCfht#3)$sf13k7c{o0M!;.TUqO>t1@K@aUt;o+bLDBpb0m3u_C[]Q#*$IE=62mR#*|TbkhxmRu.FW|vjlbU!ZIE^q5bnIuZllF3hWc[am4Oc[P3kdN|~Qd#<J)a}Ut$@2!GK/iB,NspOs=Xg@J?ap8Jb8z.8z>T+`)[&G,:?~V^YET:qj2Ea]8N(D:J22EVqV!{SO`OJvpV8W(oE5G*t#:[<vC}7dH&BX6_%s;U1wQ$t3M5&+<><omSjZ%<vQOT/",pfe!{x7}ObJb8hu0e.NCCwRgFSOjD,J%CY<AH#B:~HY^D3~_k(,0x>J0,IQ9PXC{gm4>juG}/H1XVM|(e#AZi7!f>kf#vF>!P1rN(W@]q;8v[IYE~DMv$8rzl,$b)&n%nB_w^>T4b.lm741lopoxjAnnKoXi,kSNQMEz${{Y)&%@l(|*m6H;[d$pp0Z7/c1)VX1liVF@p~=@pTdNLVH|:?:!`npcnDY5hsd|^Sze=Quga<`xk3PPcM;~vV,fe.#ukc8MhaZf=vHG<i54mJQ$}7#v>C*uQf3X^<3935U?ums4/slif1lCfX,bQk]/eTdiP;IvC1E4+Cm!k4O~p%;mdd023&QE4p]:@xs]SB,G|Q(G^~LrZ.0cZo_zUVEP0E&4]2v,e[u/33Qwc;_3cNnofqGZ@!~fRnPLMMfQ0R0rus{1>Jc6~40C|qHW~npRw>!nZ$$R|<uq?$>iHCw/Usw~|2WWr?rMd.v(sIq2r>5;l|7S|ADinvhjTifDG,oFx><1k8Imf+=e~*I*Ua1k%=;t}1|).&Gj~.M4PBvSxI?HEc+G_mo1)&gm!4peu|YM{&h}k,Mh_1Q<+a$?s7_3cV+Y?L5>re,}qA(]nPG,>&0"VNK::#sP"!>udGQDrUIeVb!iDaRW(&4+[}~%^/l)=w/#I]`<DhfTzuUf$o)`/b_MX=%CvY~W/8hqO&b_9?_/l?_;B)_VCw}?N4udVtm|Y7A/;9bL*1W<r$}jX`X#)eA0z+hVbbr=!Wk0k$`ef;w<8@#VYvTINljj)?1B9DI&*<(E/I&EF.o]%[{zeM9{g)vQ|m>h_t(m9*!7yB0Glhp$%N`e~6T[959[`mnXiDhm;7)=v~tY.gDN[cs)Iv_v2+>GV#;:|wK#rb#/b9JiGY.p}Ksj=.9*`k1+(YAs/1x=>3~UJ<8pE^|8*0JEta8B<J/j_f~.@La.%t6wZD^r5Sb#P2s#40u`e!{3o4}g&9aA^"y$kgQ?(eVZHbfMWJVEv`QpVw$m9Kh)=,@10jnJ_OWOjxl,>/m7Qy"]_)%8MR~OVv}xIn=Zi*%pW<n!<u(Px!W1*7AqqiO&an2%R1s=(t4J4OI|d&rf=w)""#>5L@hB!O2>Q[RUr/#4,+uF$yGv)S/^`_ZFFAv3c[n&[5"epx4>glTVjlBwz[j:`oFIC)WBW[6YZL;BL!l+K(}XB`pc#?Q=#UG^XtwD*?)^v.BX7MMs_~<P&BKDH??N;Ch[RHi:&&p)nHtYY&gU;zl~$dpo1<rJq3>ia;,w8})<ADzo#B>7:${P3xm~%ExEM>[Dxt*ul%rwLp1U*,ky,n$&iV/BDX7GL6WFGXX{#8*.9SVLy/./A+91br~wE+3eO^l6,,jZp>G<Urp#W?vJShdU"b/{#>;6M@O+d%W6ruc8Jzl/naALpU]W63_xnU8%UQ[le+$*4"8erzt&YU)]wk%g3hdR34haG}LG>MR1YK3jw@gf+jG<yg@,{x[jpHZEts<h!y)]<}[qw/P[HF}IfaffWj8/&<=yr<~"sr#";!s3lde@E)_J^/^{D^D$/#xzI@h|D9r[1@qhfJRC4r}^Cz/[_|n]*W:yj35*R9@6?3R,rEBE=[CJv<H@BIC)ma=5aQh[`m!/TF^;>O9SIq]60/eTRHbjAV4HY>?V?$r;vPxYgdZ19;`;2?|IfixniL<&DC>8_$<HU".oOfLa5W4}#ct)*I&11#,GtI,^&_~9s<%4rh@pcsI>fU5nC[RZXYRf(Cf]GK+bnrm[>p|S>1$01+Zu>$FMR81u>%8E>VP7@+(cU3Yv*GJ2dK3:z+z+z*Gu.FJc[)}135Q2<>gQFbkP3LS,*KM![8g3P^|9S}|E>^C:`?^3sZ4#UkH!+,)([[j|4E~F8?%aiudUJ.oX$g=^CLftFI9+3.N!zY]*!x!Qo3myB[K$g^^3S[l!{zI:fnViRsr`3nx}G,d!CUpRY8GNm[y>oZ,8jaa2%;[?=ur4OFc$wIiQ3hG]Rj:kqhRikw{5V3I)`miL^l$)sJ|18y+MqaQBH(c:SA?i=V3RYDDd{)K}}F8Z5pi|aDO;|Z@@a>]I2I2%R?]Ws<mt=Mr9hD0BT.mRHt;k>]LAxG9{fUh@was%&w?AIEDR[o1IjzU~MtrkFB!!=b[xvC55cWt<7^9$|llraR7~PGl_HY?=PYM6#saE*+4#kGD_KBH9Q):zYef0/TZ*NGT"_&9/?`_wN.?uXOI@WkxfgtByRxYmM$E~aSsvJNI&M}aP9}m>Ymyh1)QZ=w{h][gm])X<~kv?u1xbny]BOtR%d"iI)SG)Tf1Q?0stn}8,M"iK)q!+a"iaGN1?>Pri6?{Gf98(m~w)svmT:Ms0Z}03*HX_QWQ,[C;wdg#y?60Z)W+)zEh&EWPkOG#a{k!u>6HKf$s({s^=T,&.NpYx&s:*s=#ptXRDYlQweN&daH,+ov^71cuH&1/SJpYMN<K*_RDBHB?_$J1OND$%qEf=V=`2[xyyP*(nBFx<ec$Fl,?t$p_ZuwBH8O(Hi0^Ofi$4HskS)QAwq.o_~UoB0K|V>5s,*fmE/|5n[<3?.<.o[CVZkb8%n`]u7.!Od%IR1M:"QQOgc!|iUP4p=E;U9/!x;.6pXMCZ5PmQfx(E76b+b4#PqP5eHRR<aEe^T?ew7YoGKz2M];aQ5U]|2h*>Ug)H8+v4O`Gz>zTUr!>>`:!<=q<<:Qr)cBV=)r|y2n]_g:$:NS;L5$wH4urgXe5+i%7pNbonl.3"mo30/TS.#kN!q^ba3P,A7*1YsuY(i%80^:@!7CfzMg{>qu;6`%6?fest~Cex7R#nHGRA?KVOVK:3]J/@PGI"{rewuOs|$Lx&ptj?hD;0=J;%3jHbi,KV1~0_!Px6bOz`_rglyZY>!kyreazO836t*zV9U3woHk!jFp,>U]tnafV!IOC:PRLXc#Wycm^LMAp,*nQ9]nRYr}A0dNEh{,5b,v#D;#8aI7l&8_GwP3cK1Mr;#+~DCP;L5T|=PM:=P6/=PX5r.6/J7|w4d;=t.Dsv9+v,[L:mOU).}Sf9m]*%FssGP/VkHm~>!y^"*3z)Wi>uq#=[qbEefy_Rp7Hijnukb:&ROR9qWyO^|*C]6>g3$<t6BRN;v!B]6C,4[*@FRGo{b~N9O,:Mm>$."It_~.DgDU8*9%Fq[|13I]?"2hw,RL6WsuBmo@R<,FnHA$%m!0q=*Z81]eBl/8k=r9We3*"nnF|:]"$LG4vgF,Ah9"~1,tPww~#,>zg_|o{f|A3^jiA/sBMxg0S5SS:gc(Ko8xmo9{#XF@pM(R<UU>3U_=H^we<6bR?m&t1%RW[u:zVc$u3$GY]^^RrtD[];fE|*JQgJmM]^z:=ypba?mIAh=RrEu+*s8rN9=ojDOk948DDshp8F=qb3r7!rMm}:=pAz+CMNc2eJ=B&j,2*q^%9%`7NVF(oTh8j@+;!E]Z>(Q>6Hs|p}{p&PHQayJ,[Z#g>I%L@1>wF^)DsNWD(0hsxn[H&z~!B30MiT_&Bi0csscd[I_3DZn&?B$t;xJqwY4H4O7}OWojUTfK"irhuXILtR|3_u*=;~fkpV<QtDQG"uT(M5Z"iU!i69M*1oHZJ*r?Mk?JqIx!BO_%ii@DcT]B_}g#Xw:G53nlUNJ&tucauZyZ7]22S,G1B9dxF,n5.H&gF[wpz$JlN8H7uUN]H}B)%r"j*]ibIKHb)Q#th74pnvWu;Mi2>RDi43>8SL7!aR~yR#{8[$<?QfX<dKV(&"(b_A/skQJi[#`7p?=8{DOCVv+:7k^Ro}z#<dVzb8rE,8F+ggE0}0!rr3_szt3FvNGs?`5Eu&z.2k6k>z!4=KjLrN*pq}cy)fV=7*O5[^_f7`^)dw9/2#frEF~>8,[HQ8=seq8p)5P{kOgJG6%P64)bL"g4M4cXiGj7c24N/w[Sq@f9@5GZljteUfgk?l_fS=7jaZtB|e%@u$7OQ(h5=Ne5=_~MSXth^I9x~$uj$_^/SKk!h!zN7U=gWE!pB]Bj/]smRQ]n)ZwxXB%>tTVxN4ejD=ihxgXG_C>oyop3IGmekCw[{Z#k?R!Eo(?kA1>zYYL4bDsur5&ha&Cv)`_gsmh9f#:<DFfD?u>:S=%i|qm3^iz#vuzO3527;Xsj[1<hUV=Hw,=6UhtT_V/K7M!Eo$%5A7^60${?_eI@})c(B_bY#C4JigI*1{>t=)W?f&uinbFJ%,(>UWT5("#jNR]abDo+9EMN4FNiP~gyiW0Z~C4G6ZhaRUP)3`5Dwh((~E1ivh1E12#bM<=fS*&X]p:5s&E3ci5#:~i?TYq*6jNE|j8%_]W8NE|?u?ukJQ$ztk{&erRQ$JbtG/xU_uvuL5_C`Vod>Bi(mnLowC)"XuGCkxd?JrAZ;8{(&mPsC]`]KNXE6>I8yZ4~A8ol>GaLXLtib/y(Hi]!}e)8Hf*S&BB9?rn/onB@o*??2[(O7Y!2Z+B[Flbh|R/Vs:H,:+a4E6trjiu4_9F^C%tst3[L(JN9=Idzg?{,:yW+c|xV"BTF=Tt_[<w;tIR$g~w*riYLUFdpP{pd4ElKFyn9gTaqYjkC9t[GXHH/kj}gm@|lq(HaCZix&Tc4kKv&Z:T8e.TNa_:CvOBdnHDu(slAw`W+vH<Mn:Bos=9O/^Q/oeQ>6@*)AV(hEjIy:ylvI~GK*Vc1~@b@@,w01V3KIeYlCp$[MZj>z+a>8y=V^szeWR$DV8!]Y=_S"0GDH7NIGZ>>bL[KFbbfiM8y=nB@$rf(|/cR$A7_$[NiIkh$QmVR"5xmR]EBq6c`t(VYDJi,7co(=ZE0^>U%i>o)!3WB<T3RmLV)H5:<u<4Gvr^]K6W148c?_.>jIoC);,O6ODF{>`tjzw0j%<K$*zP`hFK8+,C;8}6dw!a7%%{mAZMu~!C`!2Kh1sIt&isxcOMi@a~kjBaj>:eWsgR+Zx&9m"KLz`1kcqL^lk&B=p`@ggG^nPtk2J_P{=Ws&uKKR|6Pu|"@dv1e,C#qOqHA]n8Ii80=Z7s=.HR:=(@AxnsZ_:OZwhe%zS{W*&+HIW;U[Zz4"^34|Orp)g0i:ae]@6u_NuCaP)3`{]`MY.*bU]V]y{.,61Nc)pWSPmwfE".6XYxKpuk#:IN,`OQv:96"4gG[Y@d|XO{V8Z];&!aca!|p]lNsr?}n~#PWwr>3hGVAd%C4`;al,Z{+Z!ReXrO<HSB&s:P(ZQq/i;vU1Bd|D;500Sa>tKO0rGDYB|qxu$7{qhI]D`!5C5T`lnA{r[vP~<#GFqmJ}(a=uLJZK%QLa[5)MB0b(mP#>}|RdvLaG}CML8M3xr~$_S!X$X|j%DW{^Kr)ho"]cDYJ{x&1}n~H|M}*K<w4gW4>Qe)Kdkym8PvB}:OZw,~,&@8xpLcqGD(81r7}Nk+,iccJ|DBnolWwp4W#.SY?Qs_0bW*h34g0+pOW%LY~[[&vG]0SM.6]2[8tdq.oedTXwe)L:D*g0L#$8Gh%0|gc,93s%1h3%5]!DIvj]k>!#aQHKxvl,>v"zUtwX(+x$pbT%]e/zW?2,wde|KUCXTnuwmp(0IUudB6L53%%8kY"{,6FNN(EdF3Aa<i~%^o*1>H/Yx:qHNvFF{2uVcPVkUP9qR:$;GH5S,zqN}Vl6|rN,uxGwO/jU>CmU|KIwVClG..}%}~{<F%p94[9{86blRR8.rCf^KAEA&?)yCsnQ,o4]28,>naY7m>~QW1n1v]<&fBtQ$Ec^eXLEg5FC2xXY5qod#.XEY48DmV?^]@xN`!FC4ky|:~hnr?}$Xkdt.QelfBp/3kEiC.<.@Y0Jo!<J&Ysh)8UM_l@+^^d1kFX#4`+@#cCT>i`_YvIou@|2YkD5EA+=Q?Wf,>#ZJ&f)4tlE.Z2_*GHw9u>MZ}2i<7]<=,z?{_y|`whNLAIWO$B?]$$@Pi>B9;PU6C~^p|QS@jdY5/=Lh1!B|@uRu=;n)I8NH,9!NV|k|%7r&zJN5atRz?VGY|KU_(T]s5sQn>XDde!>01ejbq,t)NqMWojoxc^V+_17Ro|ZwG8Guz2Bj}ohl}UQkY6or~v38h!H]DMPCmK"%^d3~NUEFn8GX`N`Of+DMPdl;JE#Vz@H_S~a0n|_M;NU%QXw}*>>]_+`E4m>_Y#>=Z|/Y#Ma)&:=5u(c"iBh;y.tdN=3;O]VjNxjWwpzX08B$*F>:x<&aA7~$(ICl}ji+h~Po!TPcL"s%U)l~8hkdwLHXo^<e~}8@#(=AuMRC7BTkSsLuc59^|9CJ*,F=`DMQY)J<&2+1A?#Qo;imE(,uBHQ,MD~U/hib/H`#EE_J&*BAAhBbAoIceC"o:S)y:UHgQN)o+!<*>zG4"ra%t^~vYwJZD=tO%eHQ?:+0gHdDwj]F7g9T4vd_A:~4%#,R@4uExFTI,A(x"8Mss=f/<73PDmZ!!@W[#(?#EI6y1jNg>h0%4Gt$TN"#T!Gn3i4g}_[%mtPrH/sCO;P;HgwJ|xVCE!l&R,{Dv+N9<Z#x1jOV34FRDFR//{rWQ==NCu]wc8boEB1?lO;"kK/AeNVYiWw3tLV"ksV^|,mN/sWL{vb:oS<efObL|Av5vO((QWQU"a_e?^I|SR1ZIOP<s:o^d3}eR0H+GYvfNu*g9n.}gP+H:"a[ByYh3?oOg@;SE?Wy/R|*F#,fg<4+x8X)A/s=W(phG3%[WTdw}Tj8<n]h*e/8/epu85r<27"u4h_mr^F[tLx4SE_!z2:<`Aaqcs2w.?"5o8O>?dd.&A)/6+h2.8RLIbx/4|r@~jYi/P}Vvxg7R`BFDG9l53g)8?C9B)FfDbXB(5TV=&rZ_M9$%W=s~.PJtg#5+STSg^IL;!<h#&R%<F;"b5e|GJM5O#:)`%4.UDb=Uil^u[f$<lO/YOeiYarV3@4OGDl#_ECoXa#zsId7bXgR$<PzZ[^8ypRo#DWg#K1m~~$V`LEFCYLFk9`x+>o75zB,;wK<pAqLVw.jxWEs{,7I"v9&$.o!L>K,mmZPRn7X,~7|zU?Qc/Zj@Cu2|FB|[F"g?k)9[}~(V@zQ?Qcww:!2Gf)`c~A/TEHi)c42GeU#I|WPD~mn7KG*tfz^OJmdZx;}mdZ[YeiqY)uV!CRh^2IcmkUfE`|ZeK1Y4}lk_jhP$}6l@>CiRwILCouYCB*:Fj6Iwc+238wXwGEuPn[pv>wB=bD0}u)#u]EyXop8uRoI5ujTV|OH5bHn`gL;o$TeG>dYtL7tB(?&yPDL+c?@w<YhN;d^B+dt0:!7H}t{cW5R7(DeV{$^dOY/0iYyZ_D}W/0V,^dz71P+*gc|O8od(`b"MTVcHPM$PaYmq(d#1/bf*x+M0dR/0SC}/LbV,3RkE]M$PpjX2cw01SCszZGe%QQ>O}JtM0a_DuLPI]{!M0uv_F8V,"Y?|h6|B@T#J4jdMld)?@oj48b`ww/kzR@tvDnqTa+gm"L?O)FU3=Ha)L$Y{%=hC6>qS7fu~tRDc^H*VBKY/N(@o/:tOaR/:^)NM}2W4Y=AW.,Fc3kP|5%sM1f$cVLWhBqP;WwviQTZs,K:kLYFe5hOg3"?"#[!WP/%Uc"Ww{W?T?V%*RKC("2oR<67PH,dk=V~h%(G48.m7tOHd7T@o"5,$7%N%+ms+~r]n;,1d"M>?"2MJ6;)U8feVDtUOG>kBYSt[{n+B$}z"pItV;XLUHQnMy"n`>m!|1oe,~Ae/PGc4eny7tt9[>T|1.)wWw~jwP7W4BRJ.cNN/E7s[dN5l`*7Zk?t^!?]`<%WsatuT#uJ>w9kUT8S_%KN!eKB%37)o#UNQpLLaA<LI60":w,sFo&20%hOhexpJJV),)Av*?oe7Zb."2[`^fd]Eogh`n4O#n45>[vGfnF9`*iQQlvZ4@%TD@e(s21@Kw+STs(re|8/V8dHQg&c$l`MGw+?%qao~Je"BLha6&;Y(vrI9.~asq^y:~GMBT:1:yrD(H44gGKK5MLOt&%pq/>8(Aw_97$0Y@.JxLxa|%n7X[:s9o:C*sP50UMq@hAEh9<.Bw~60mBU3$B_r)T5.MJ6/XRA_WIE;^wd3C$Y$qCZ5N:!<l!c5HbANc`.B#6(37s7Wr(gXj4rYJ/DP1[GbDt.CC*/6YL]cuL~=*IDgAxyRb1/`a<&B}j%`jX@XojAn@+oWr$d7*K~"=W;QhRXDv:i4>~AMVxDa^?3.C/K/M^Q1F^V:&yh&/i}kI~n2[t}VK7ZAw+6bfu9oOg0AL;Wpyd{{2m#6cuCX~:Rc,Oldx)dVlUlQ(DeUCVnX0lsP&KYef^sXOA9fAQEw?33LOYpW?Ot~Xx!{CH#42F,B8j2RQ$Dt/F0s=ep+c#khGPI}J<0pa}KOh};@MClKJP.)~T1i0:.ZY&`O.NgGI/nbLR;6:OT{O(MU0S?w`pT%6/:Ci0!kcq3@JxPu:<sW&H^t^~yZd1]NMq?2E>M9+>GVd8E(@d6nfS%y2k|P^?IY5&;IB}CY/cUe"sq`LEhW2PM]m_b`8y9`Cbud]wFr]#~4tG=/lII&gGQ$qX:jqm|zTh.Di)MII59CgYuYlHPzQgL7^|nsqH}"n1Gd;V$g$<MB>bnbq"aEwI"^bRlR(3w>S(9WMj#z%D5rn0$I6:{VmR7gU4a1ZIPTb3myq>!Ha6LD@>unA152[|DUTJi!!;3|U=zw=%Nxv5{nw)o][|MzT,2F^bcnruM<4;n^NCF9SQBGMEp)*D^ELgM7j3CgM7!GEC);nW?8H<fRM}a+FEl]*qw)Q)w@qQ<&T#qufW%M?Zv@FdXEM!~BF/g=;$EEy#PD~Q*?d40INEQ*4I_@S:6Ie@*54w&WEHHzoO]"oO[t@ccYi4vDxZUHptoO]"10q,Phk+(n29]2[8mi~B$8ww8I&a*Bi4$0sMPC,D$8CaQh.T8ib#YM/Ij~viV&0YBxrE~.Jh5*1Qy)aRW6VQ[|e5zWpm`v*Q|hY*1D^x:T@am^=o4bg#3m{5b@!Y$I5d80N_wPgmaHV:uHM&^u%PkznplEa66+;6|P:C}m6YgGOMoIM*!gULN{ay01d:IER5g(%fMRBWmQsYT=M:PC|n7u*U^fY52yS/U9Ea8wDihYD#]q2T.m&Lfz<GvB/sT;v=to]|GgUhy*x?hG/sDp=Aca%Qc$p5c$}8HCrp=A8G9MI92g@E%/w(<MdXSLJx_,=xU(_;Dv25sPnJUH8A/kY4|9WZ_"<e(K]C/s!T5Y!{O7#f!{Oj/Ig}Hk@vh^Vt]s%3XD:~F%(i*<NW|fqFg}ivyG6CsUuM4uTw}e$g#yRN!i.0^DtMnD1g]NSXbV[gTFR~W11jP/sW8ymYWtwMqt0nIUiLYNsXO!rb#B,n^Nv)u_hZ=(R^Tk=cU0E^dZ_/tPMDPF3B/s.MB9LGP(T%FNp}C`AcR(ko/@uSh=^XiClZ*HwwWoDA;C5!^HSM{Q/8)oB}ga/@Y0}xoETK1@(X=`WC:FsBa4F6#njB}ygt&(=tS0L#~eJImX[CLyY&~6GK.yMMCYT"$gf;Cd=Tj)xVsE/(dQKy1neu]WA,{VOGD`Y0B7:O&`:OZQ63pGR>C7/PqoZwe)vGV*hqDqRy,Z+bD0KKy0x/eZem]2x73x)HlUcDeMiufkvipLX~I%]iJY8@nbt~@".rPtm0vzzB=EC*![TAs{j8pD*?]zqB,wqLnO&fiS".l_()yL|r<RK&:$=~Ie1?BH.>5A0R.en0C]iW;2T,knu0x7OcyGXwq"txLioUhZO&$<H`~9$<xq"9|hh^O^X|MOGR^s[jV|RP>Z^H[MaXgWq=BazzLDpYj97ywIImOJC,E^SG0w01yDMt634kvsoNDq$!iBvt,7:a!>;rlXg/QqDWZRd#IVWi8klupzqL}s2/%;(uq4GL?wWojU?e#[<N*XYL`LIYDE6t]se|!Y$cC340JawE?Td`|Cx/pHU(#K"YEQIIX#zi5k#0nq7Ftp|I`}1"I,"F8oYi8xdZt|/){X8xEUny#4+.jL5pKqy!QWc"|nTl(T!<Ofk$3EUU:vWGlIs?U<oX0hQa3iXaT=o)By#2J#*WOP^5h_%s#1<}D~^GDB*}#zG}oy?QAtSNL&Ezn]JLfghI=C_lM*"34bh~o)y~3n|K;`I3hX,6]{Razb.^0&z=6~mB}t3[*@nHGf_@,?Fy29]2=()~OM[c*Bi44w&WEHqt{0xZUHptIOOMRcYYi4Ekn61G]0Dr}7R]rGb0O#FH91YY.T8iuWSlp0Vc=t.e|x8IEUQ?D,=e|x8IkUFs*Df`YY&WMMw>v/V]FT^dI~H5GME*TUQ?!CPX"3JNDbnO3D^trLRc/oP5,OzrTfR&8?($#Oy/qD08y+ChfGRHf)/2b*f4Z<bB+Wg4ZM^HY_I=zH&u[#NvemVe&Cr97r7f&Fc#7G=|W|0kXn>y||7[%O:WUIXK^&Km&<C4J0DtN,Ig"~}In[+wMaDpu:)023rhjgp(dY$#Ry}Km(l0.OVgGp6ZLQxEI]YcG~HL!UgCF9se0S&vQyzmc7l<mSpaN]dC2d:$mc;Kf4SazSz6BKuQgco^e4)wf_e4Lr&^]^5Om<`.yw;Rs^gSCS|kbZ3!G~n/mc$4lXFkN7Pf$4I}R@iUElB3j]m9|K}f`v%*k@305D,:fj1mFdSX4@7AFd%OQe)b6Xl03x}F=Yl]gjMpN}}3%fYl,u.O=oLWEat:VljX8#a8$4SaEL!d6Xl0zFsp,9,O94~cv:J[k9saK.6S0dk].[_VS7(_W#<#{59XX8qV$5&kzetW;z@.{54]fY>`"wN5`qHd{p}?T`.EErOk*Pg#9PYj:Pe91]uv4FB:RJ*9=8.vFG,X+|=88l6!s~vT[0Q2yFKfk;c72J/s8VRpIUKL2UygO;P.vA;>^)!PK5ekK};cS`(M5m}l}S4Z(Wr$HJW<Q.731oSmCy8{tNZ0PT5$8,tNT2P.{;DegSs^~i?0lv;=hz[7Z/7AfP,GHy72TaGX|L@/S25!H[^#(s;5kH;1}Tn7{N&45q#9_p<:?1PTb:*1lHDVAga%2dwKdJ{</C=>g#m~i|+`n:23[}723f|lsW$kc^bT~S4Zmk%4YmSWML<W(5%]M2ug9.S{.|%y{[@;k}sr73+dW8.#k%4d%mCSo1xO0l3o.c)&/P{^2~dIgqjVkE@bwO]}x{{EUBgkt7E6|kG~%90fgK45H=L9vN,:hooKY0PT!hQP]V%k))z0,:/wekt7lc,kxLq,+pE!go1qRLzU*vZK;ouS73v=1j"nDg*IbL/k@bV2e.ndzU46sSCvVlZVTmLbH9>##Vc}9[hqsKS2i[[CIP8Fa7C:65yNU#kw*yxoA[oTcH2lpm/EPy.=b.lzLpJKLFnwm0r:}fU7kYtVihyJNyizl.$j)&g&:5r:r{F1H{rrHaR2"0s:Kp9+z7[P.^]*jV:Z;[*1rdLdMY|kLMa:"ta2;u=^[rtwo+VF>krdb7%4}U~{6W3^ZOpsA%X*X{b7<:?132V#{6#;lk)f)&rdg8k}7346WlRbs:Lr73}:vV_7Kr;dQ[b:>5ObAFr:Dj^1Ob(<W]42&#l0MHIP,sE=|fv[IPD4xjTe/3flbvLf<Lae{Pa,K@J5/EbKM,UIIbD88/;!}E#TUNq5fj/3>uv9IeU9TNn07en2U,vx6jnC<HRtHPqT:!v9TN[J$)xPbal0#l/x<.3hCT0NmlQ};!4#8.pC#:xl6p2g;<T,W:<JJ+}ms9U6U6GAFiQ;v(BfOzFTK)|x)1.P566;>]=5HP^hn+n,Pyyc{N^1#Ea.|,0zX%pz8er60c5gG11g]^I%hb68+dX]#FwgtQ]^^:s6`SI158A,65Ug)b2r&]`Ch_.[(gIVM_pT}?n{:O{K8%UPU5bp|0#987bp:P4?J5a%WsQJAMzv5%?xf8!fe;q8)&eY)5oS<zLK/)~0$;PZpa7U]MJ8yO%Lwl:8kvuZ^*i@D3`Sc<&79pSa"7AX40,ghU*#[kx/A][bYmyc5gtw2g]7%l3oR%fVo~gkmp?K4e)37e,wW$0JUPIPHp(kg*6pgh2lsTkMK6C1|8nCaczo@#X</#v`}8?`4Xb2@pAe[k"@B;Klwg6%"73/:!UN|iEkpaMDUTmA8%K$4%o{!6N$y~5f[r"mi?Gy0/ojvz0m@#+^8e:32#O#~7D`<^hmk9{.,^VN#ef.>k_d8%YK&vI8BkU7+#.PxoNYy6s{(M&o,Y{.Qs!F&4V6,9uv?;orAYmudHVf5m(s>}7O`fMT+9`Kf">)~qk8Ul32!p$>nmJ+*4M%odKP8FKPWfRmx%k+=LvDkK1l?x?k@e+pn]thG=ad)ji|hFa#yOs9G~%.>Mm<4^6jH8z0|a&v]m^$APBo(k,YS_L:;]}yM$f^CWaTGXr,?8Pk+ctL<d)%.3BszeNyiz?eg^eAj+y_Q#}ydUoeHHGFhAj+2IM]2vRPnwUsRU+gQ5}LL.A140}:C(x#=0a0?eC(Gk5PNys{F172;QFaw:Te^?<[/xiSPkH+ifMK|oE{q[uw>Y/O)9_pw!U{*1c{pkuRJ8WYcr|%>yiok7u@;&/Po;nPy4AGOUJW"?{qS0`8q57;b$iek@"JC[3chjX2nY@7M)yJwfwz2^Kw1dO$nM1f$xD#q7(lK(DN_%0H3q)9?b?wJbE*U5DJ@;Dj0bv=#<*sGgssA0n$$>I+I#f1d_F@Y{[mP]_<0=6j{#/{32ho2]cd?#v]#LL8:M0:*9q$*YZkUJF0<G8f2fH[C;i@c:&c22*9t,aT]`*9c:lX}{c@,9omv<QsulCzFeHSto.92^_^bw~dp:APh|b=VrIKk;bT:kfj"Bo0d47OnJx=}KP=?$q5w=~nW=W@j$zS4z%@(/c$[mw%AxC9+heZna?1^kzJ2#]Ns:$dL[=OHS.{W3C~9[i|e/}mLDV.q#eY5U.r]o!!w5S>YjM*F4zvLx4UQ^N]|1lvgeg<vLtE)#&paTV@*tdHv%1uw:)Ld<;`pmo3TWLWJy57}1#wNb9>B%RHSwvV_Z.[h[*bBS"n|dI.]0&+0LZT^,,!M]m<b%bS2f]8Wp@W{7*tq0.v)Yc,t}}@fF6b4kHpm])/fnkw>x7R!ts>3kU:3k??)/!C]}Oj??O;#j7}^J>!ds|EeijC9m5xVlQJm:V(YH%bj}T$B8nS^EHySN4^}R;JMK6!9KcnOu8$~m;J8Wi?"iYv9lgSIK0JGZ>kV:Nky2Vcxob[2m~j&TrvJDR0mxwv5+/*flRB5:)Y,dF.!:w3PN[0ACBkT5pjV2Ib6Z5RawgM#8>4M3++/[GS1S,X{n_YlOc`O{"*/M;<><QyLoz=2(e.By4ZRb6JsyiTAKByB+B@yS][{+=^ulX{:O2fTx3Xq~}G^OwMv#<:EIbbcYGZpr[k`PuUoez=dk2vRP_7UGqVBUl0pm@pCK>LPyKzHp;YabF@WCR$B8VKZ:@k$/G@.<K"@piEWUCo=4x^b7%[CoGb0d#BjFY]Z4UT_$yNme@M4.MSD.Uy:UlG`xvUD16kR+zaD:Pl>4ug^`K6CohUo+Rg!3;u]0]{Kd22Vl<F#hNyC;(U_ep[XYc96;/{Gctsi|hFE+N]VrJW@lom+s|qQKhMp:z662D7`]kmwU){q,X.T5wMc(`m=Smc%.~7&[jS|y=No]G+}P:31yvU/P<`#;I1!=p$9pI+~8R$|oDpWy53B26Zyx@paTK,4UtT,Xcd>SUB8KU7rRF.bAc:ctP]22/}#}}G?yS>nurK%/?3y=U)eta,|~+eho1WiSK)E&Pcla`w!]R&2<OeK_Pth;z_2(juN?Arlhu0v7bVL7t[!ZVSKtiIqu1>vI|bDjbny72Ll#_lS{JONc&a,CM5jO_:J=:>$x]E&Xhuiuv{Mr,?jLC!w}w?GE2,$,rO0kS;JfgQ_wR|*s^4;U`N+,NW!;zhJE+,Eh}SfnWv!).N6vfStdsJN!eVhL^xEcULU[tQVk.oraFJAg1XFJ:i6aFJlhj%q|@FE*jyPg<&Bh7*1h>#pQa)wLX)q|Jy>znEN)jPW[HmC&N9F5`r%:H0+hp+oI=R`*kE6!|+TnVED;*s^@f,0_3KZXs|fQl0l`FAhxxaJNHw1?".pIti=fzRuQ@D[9w?*FsT@Q5QuQANs|=rjR35#f^RHlL]JeYvlR;?u`&0WO/IdT:OZIqo*;$nKx}if#bArzf|q|^(7,eu2xPJ;C]%(g%L)qn"ZIvJQNKuwIipc54Jl0NxSa$Yf|8u&|)>V&pE*eLh*Zj~cIl01*RCLS:&j|yQ74L*YIHEq??@yBhnfbf|vLVDOnp(aCU[Q&Mn0Rq.oIoh&m(vVkUE3Ye{*r$JZBRvy,hCI5W0WMkCZxCAQCVU?E~l61xGVVX&aow(y7$vJ4riIS$0l`v(OvKKW&%DMcPVk_{_(qeK*R;,UvzEZAKiBAm`TGnN}EYHOJ2YwkJFB1cxCA+@lMyG]0P9SaZByYyG]04S;jsETazf[z]F4Xkc.T1i?J:rv)}:"Sbs#I]@/?:?9GOI<V!}Qh6m*FZuryxQ_@4)RC#_SMo;bJe1AQ,In%)oztzrx~1aL3eq9_cDZu8v>~DBUCzIJ|RaqIqo7"wVVo7"E~ybMG2,Tq"w4g8WsV#TT;kzEnXxR]s?:+@s$jEq9k8B9FunM;dmx1o_TEvu</m>uChG}KH_".xY}cf|>r=fuQY12>NtBrwT#ZH5d1&,aDfFR+kH@}`&!}T8uE$QuQS36G1*!gb;6Ci$PihjBh)>xu%qcN&|q|@0I4y~aMwE$Qs.oIg~qh:5hNJF`3?HR1=@]zzMPEiETxpL)M?:V&*`W,e41>8*N^Sy=@EI>x54(GcN3T|/9v,e`H1Uk0=ZE/s,W(pC?VtWHDW1~*)@5GRvcxSa4a"i4>OOoz=fOQm0<@3)6vBxJNamFU$WgYFt>WcRj#3?eUltlMCv1}=J^g:4pJ0e~4h~^u$oXD!_azsv3W3>@v}*(>Pv"=I4uDsKeq]eJ=bEw=W/z~4k`GR~#[Y!siJtu%U9B|fGI0n(q4F_rX*2[Qq=(EzA2XqG;8kzf/zZ}Lh#y3nT7>(v?g?YEGE5@%E)P(szl4fW{;0198TP";=Iln$IT5w1rsIDFuUdX)fQ,.r>9vQ7=F*Z9K*^AKU=UVJK/(,,a[Pg]@p`%|Gw_#cg:OCZhl?zGwzA*.nnfXw/RY}a<U#G]cDYApYF|{"^UJ(Bw(&tkU%AEOnB}+;y9BR|64VJqy=iu%3YgITazAB_?_=dna0G[PLCXLwn9<IVH?ev,38Y[$:&DaV["GPjneq.g2"CH1)szAGr>T4q0WVaI4>DgXB&zs_;$9x_0bY!5dRA,G<oqg{GUS)Wf/kp]A_$g5AE`K2TZ?![!nipOzu$jIN9[3L_jUx_ZfwW|e~~of3cRoU@.&)xH<bK`jLqF~9(o1^@%X&gf:urw$y^|%J%[:96|6;&W~+KqGgRJK=Zp*koi6(RfB}U5%vY2lrk~8JN,P~UONBD.k2:jAh9MrzcEyr#kY]ynFMBrb8W/oEeK~B+>GpU47REIzyc4e4ETP@C}EGRh^2L?T~41kvp~B%|lU>tI7uwzA;*8FM|BJ/`qF;hu=$ibrB|kzH@"OrXWr|vT39k{^iGqp:E)O=|]%s"P4]RVY^[K>OgYK5Yukk(Fdo!!#:spiA?GH@5`9BM79o0_MN5B+BNwC1+|pq^F~qO5}ah_PG;Cv_MK%d{{cJi`&$fC_)LVD=9wsyglNw7beuQ{q)L(Zy/]`YYFGp|Y!^fg1*0rE4djjpkkPr]g`Yf:ObC$*K?QNakgfMfY7}0Za.EjxtW)lA&*{(~<mx,Khpg]eW;]h`Xk#jPg(Yvgai!m(mk8H{X0.=>U<oFtR(?].ecHq:F0{OrE(Z)y~s*Ve_M]MX{!|6P!qN!DJ8!pq>}UVDY2+l`!qgVQh>F7Rpqb>KhDG8!oqE(KhjGDD@/U(E&og^eW)}o10<r{v[YQtqs+Iz]5PFeKfxp3It/f?o!TGguF8Hv&<^E,V*1v_/e3<cDijIn@5Q?8K#@5GnBfomRD/KaKG::g,w_.#zltI5Vc$]4N*>$m.8i=v/`.d@.(zqNJ!1cQsnKmPjDh_h#x76)*FX0vEMJ??@?GBYR?I&qx4bSWC2+]6{8p,^)wLME1y@%9HY#Uyne_eVFWTs(=:%6iGS["P*7D(1>|)vtwXx/wF%/b4J}H%ZgQ$R43!0}Dr_:#7JePu^<L>%69Oqjy.O/RZd_lSkS]+zAoES3f_&@nY[FRkr||$x71*vr|v@cJcLG+5w+1,2_45J?eX1q9R!Ef)/`EDzQYMx/D4mK{Q%zYu=),vI)<=s79rK|bS5d|x5BaS!"7Y44gJ4S%h;^C51n<u[v|r[R6~hDa:zMlF+C$>GpCt,=Sq#<3Mh}dN{X+Z4K&sJ7BJM@n5NBoQx>Bqj6VLYyB4e_8@Q9l=0,sEl0v79rZP=8h,CYW&_a+aPW1&g5=N:A{6M]7or~~V~*]G85FtN`1/cm"h"2?qnV|I"9G5n49B00%F5B8G8urjnPCmTX#v=2%97K8rQu!(W%[K"icWrn8wv5<~U&mB+UxWj3Ia!Cy8u/0$Me>+(zK^ieiP&+o}/({^Eh14(eE`0kmGLBoLkN+G2OV)4I8t7(bSTx1blDQuCi{)FB.Y/)ILK{q*;$1>dLC08ho_d&bMiwL[ici8V$qo&4v>WpABs?r|@#?1$6!Wm>GPn?i%MWa(bUkh67jsZhgho"7%e,urwsR8>f%}ZP@W)I)ID(<91Lr[a[CeBPf07oNTBwP3LSykhxUn@&q|X[Y}*YJLww?>l+GXo4&mFRVqqA1P,ODHZTZH[FQg+C=F4"!.,]D*S=,BrBQ3oMM?X%|8y>VDFR}qqJ)(f/.iJxwW_:8Eo)!_S_lI)i[r&P;ty7S!a8{n3gT%ko/@1,O1*SJ)`ki[h[.y,S57L$YmZ?S80,O1bQ3gT%ko/@1,O1bQ3gT%ko/@1,O1c9"$ko/@1,O1bQ3gT%ko/@1,O1bQ3gT%ko/@#xbQ3gT%ko/@1,O1bQ3gT%ko/@1,O1bQ3gF;.@1,O1bQ3gT%ko/@1,O1bQ3gT%ko/@1,O1bQ3gT%ko/@1,O1bQ3gT%ko/@1,O1bQ3g874^+^Rbwn_E2m]*nXro!m|oh$[&R=Ni3^7naTK)z>O@?=lp"r1y#0j$E%vUm}{%8o1y{#U=w=433ssQ6,<D(1"o4=]prS5.sQ6,]p~g*;z%i#"gX1;@T%:^|%sQ6,lo4=]p~gX1;@T%:^K.B#^pPK8%g[{2;^|%sQ_^|%sQ6,loHwpV6%r$E%;$L];^1,X}m("!sVk?=+q{_]<;89ch5&Vrr{_]<;89chG;eC)5o3m3OXN;q6r<F#Iva^<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89chZ%xk$Elr}E3^VUg$s%R=oh3^GR/p<$6JG?ZnI``m(%7a={#sD+bWn1v=O@J]:{#si[NLUxn$y|G#FX`;bW`;ARCiE)GuLCXEuIBRCiE)GuLCv8$S?Ls^b^VFD97R.,k2CRQkE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuI+SU~48#mI*%$yR=>TZ6nL@;$bGn=iE1mwJ:{bWK<]h4tv>O@$@3^AFNy3sRR!=O@v^:{uvm[NLG^NLbEzJ~_&iq*]w.H2PRfi!&iq*]w.H2PRfml(X{<1<rKEgcj(1,S*ig.]w.H2PRfi!&iq*]w.H2PRfi!&iq*]w.H2PRfi!&iq*]w.H2PRfi!&iq*]w.H2PRfi!&iq*O84^[iwn3M9(ny7"=Kx)nya?TZ7nwRc$LmR=U~Hjnw!NCs1y;0j$xqwUm}P+8o1yH$U=YV533sy!3sy!njI@1K#Xo=7Rs!+xLm{iwJX<[*FTs!+xLm{iwJX<26*TaO6ZtvVgGFr$dHlw<1weXcy48n!l&lbk=nV]&osN(IEgcj3J0ly<fT.xLm{iwJX<[*FTs!+xLm{iwJX<[*FTs!+xLm{ih23sd;g$y?h=,1mn45;$G`m=ND%mSvb$*Em}NLf.Lm}i"r1y8N*mHo@[3^*mW33sbTg%b+%)+3$n#_:{j$Z$Z$Z$#m6LKD[YHT2mf#P[b%b+|ik=yU3E%kZdr4HXe?h;2.06mmx<Rj4egJQkW:S!a8@4W@/f7=C;<#q@dp<=s,;SN#C6P23eKk@a4?q6&lbkACveYJXHlw7wz=p$Bk%d/p1f]a6+p[tNBXN;q6N;AEvxTklTg.q6|_=::{p!+$bG=>U+dt=Kx)nya?TZ7nwR/pC!3g7"cl^?t!+xwn7$y|;mXnI`r@3^jsVKU~bn8o1yTkn$y|fqm}3>fTZ3cnR=dk;Jm3fyJ5DlmMzA0wy(L9nZ9[ivEe*)&X@PihY,4s9Sg8qABB0E]hr!gTCCCK}i%mEEwQVm<EuA=zBm<EuA!!SuN">kGnEE6]rTCCH;@EuAT5DJnCXAt!J#gTAo&C=J!AR=[cMcgKp%.y;]SKK?sE_>c_b79p(3ye<zpw{}(I5;*U55BSj?]4!r(vqnlp:y;(4;:V#A0K#netpOI?gKh#iE?Jl?Xf4%YCngw1<b#n14}u}x;.;]W<R[NLu;U~lpv=O@!Um}:l!=O@DVU~]Sol0o"r1yEZv=O@[4j$xq([:{;.k33sgU$o1yxC3I:.eJ8=u>O@Zzj$E%([3^Y9nUU~lph[NLQF#=O@a%b+EjU=vgmTU~lpXnHot@3^Y9VKU~lp8o1yfkrUT)Et^vfkQV~XJ+Q#`Kh"G+Q#U=vgQVU~lps:xW")%U1!+Hc9`K+b;mI`Z<_YEZv=O@./S=+rrUJ`xWk?./4^[&m33sFVh%b+p:_94+O+QVKq2Mi#+rwVv5;U`4W3x|iyj|KqJjjsg}a+Frx5Uj!rVWQ@!r6X=XR+RSyW=X!rQV^v+rWD@.u+t[~q8M#rVWs23slV]=O@y!4^v.%23slV6$DUXo:{Y[Ly3slVf%b+U#U=C3QVbGX[/.bW%3_[6`e+JfQU=mI`%_(KZys/`4nUTvFZrU1pZZ1ui+j|+}:yw|(K|}ZF}4nUau;v0_CK./6F.>*K|}RF,rau#vw|+}ck`2!raut[ItO+1WE@n?W3QKo.<VDox|E|RZSvr,{Cynx(duV+he&kq%bY1//11/#+W@+VA"It0_E_&=VK)L@KIWpBksvrvvUZ(k`[hFoF(_aFoFM?qVqu@`/Fr/WX;X,}Us=%f@o}5Fy|dZ>$0B>~t~(K}4g~nUTvcA~F#~)3Z<CFRfVL&A0KH`DUBtyCMUqWO@r?%A_K.FTR2KNVGOQV"qSyXA[y#nd<LyS"BZ}`Sy>$P^RZq#j|p*GETyrsJZngaqDvRZXQ=V*LHt+vS+T|(K}Fxq_[#bkEaF(Aa.]+8y+v;U9AEy%_o}O+|`]CYoUsjBaqKWA5U#NCF[oLtXFj"qZB7LfUBt>CssdZ+r]G&KhAhAIWaS3XyM=Vu?Y]*UGo|}:q9JcsSq)[]FPD"YSq?vMLi`z(VA)Sg83/Wt^E}7*~zyvAR!+BgIIoLY)z:1AK]AICfv.>Nt3k^T6yr>9MnEBFjziJff<cmJX%g+_X>iSo#y*CPwnUVZba[rxV4MwL]YBW@6ktW+YTU7wy:7LKMj0f]o6v6POF}j=yx4^6<5je~v6v<5QTD[;.gj4mT|%`sQ_^]KX84Psy6;w|lp=1Eec#QJ[V?=k?6;&BW+~U[VGoAn.oM@yocVrk|kHamz4/x|7HH]hmTJlGj]_|7C?aDyYdc/Oe4fMO6KiG#C2`eu3%l+U{3,6)?ib+?iv"EiDH)0LT^Z{6x4d8*<]4qp+qjwge!kyMtYEl{{=Nu0(#s#>]Cofl*<G.N0TJO0//GS%Om<KmCerkIy#l!fe;^D1,soZ$rZp[zx(b`!b{ruBme{i?hDqN=1Omz,pzV:t#g3x|kEI]V^AUWK2vRP453,h;%X<!P1G[:4@/ep=G^yt#E;4X(Mh2WIhEmE87p:aLmisQ2%Fl]1dQ]7/j(lPow;orXj25atoUg;qvm{oE2WV3!]"?gS{jpa_6%kE!&i%@ffa#&+mE4PwLrP*+,xAH7O4/fbZ[m2hL*+8y>0{,gTHX2#}7:N+^Az@p;Ne;}M9ErLP),m)nq}dZq3?3y=v?]{fj@py47E"%Oy|o4S77;fmUA(~+_L*@Kdvb82CZU3}3!6dY%MV:9N(N`+{`^zBOio:ZWY)zKlDp|%;RJ8}+>d"Z@6"c{19]XFI[k<fYt6#&32%dVg?1n]|o{U5cZzgU0CI[W2^1*+K@?z%O&of`u`lflfMpiv]8o;xm68+=].W`:O]zH85z9LAc#=`Sca77oMR_]{dHa//N2T(&*#"J4m~+65M]A]X3Db_zqhI:+ynSU$&M7w|Z!P$PAl/jYRi!2)[zO.Bty8zLK5MXSYSjV3rSIrxL5qoSton[_<kr/Z*v?M&v.UV2^q{6bj9D:/6b5#U3yZrR2WHamzYwUk%#j+G5&l(R6ZqO%L@1m0?6p?EVHTE(yJV@[!yN]`Ga%2Ju+)[&/UY9saq}K6WsE{dm1SD}:cA;F9p3}+L]w>n,n0S{R"VV;2vfmY;2Ga?k$/Fe2D:/jWg<5z6:(E!8L:G[ivFr$M$FyK8<Tyj|dZV2KH:&=el>PouMc:rk_dD(SPdu:Up6@.M]R`5ZX_6477EsNK,mGXBs4$kfLdE+PKzkU#I8=z8m7pEK7.d=yOi27=+mbtmuw%pSrNUF%be#Yj,8$#V$2ge=I8IKRr@a"VWJ"k]#:2"_XncaGX@kCKC]Us,dho5Z_/&<mS/P[<T,0}dl:MJyBeX6H4?bNWpM]qKqq5]O%oO]{#)XGsLkt]`Syeok;Ky3p#2ZuF+bU,^RV]I/baE(?<btB@plQ[^f7:j5U$K[$4sS6Oa83Jv>=n4$L=z%YK[<JF][G]`]+GpE|y%[6ddbN|vRUrx,L5*|!AaTn0^.G[bH7OI0^?:*+X6!iYhSxe+^/k{<k#_Y0dU{}#i2g:s6.|>w#=IZba=S4ZkhBE^1>gk~i`HqfBNVi"{%dlX_UT[Y^rQ[p>E2@LElAK!8m]aTvM&kyo$9[bs}%Z4kHSYO%45Om<KU~jgK+8~Z^5v+5fh>_wi2V)[k3fS$aBcY1/:We=iM)jOm#ew3g"7v{%e]YZV:XmascoTmpxGL$#feMqPcVvL(YH_yG]J9tTC6A>>2a:F%Lf#A2}HypaD6})[T+>"0,x=4nR[0_qu~rJ"4*E2g,T/*Bfl?!XMU[*IfWGvfSIDFK);9~klf+4p/uPjcc/iCbQLLk/)<O6SIdfHE^awz[{!{c@j/yU7Ll0/gbXN;&MA%/GOU_Fg7EZoXX:b{F8JIWUs+Uja8+4V6`C(OMI=f/{UfMJo~rJ9&Su}3svOTKspr!!xMmlX2wNA/A}62Y_CWZmvk;u5DYHwOFdnTS8uZ5C$Y;8Z%J}O6jCW{c,b7Dkm0!=0vO}h[@4s}8kl}K6,r!oO]m3Ud]*<:<#LY(3pU2`%.*X3cuS]5"NJy=28pwSK,:U!3H+y(;Ui;1Jy5"|gkoTedp:%.SA!{&7Bk*cBFffWp+y8pm0tkzcty&gc5>0`~72C`X(K=iz>BWU=z+=CswS^0O26Zu9uZ4@jryMQ#q7RGP2ukz<~|fjGZ(_J.#XMFx0HWZ2lf{4$b6O/}[oG3{`>M{VRp2q=vsZ[kiY@Xq$$L~y42x41o!o`1Ksmk$L$_=8uvQya%XW@l{4&JY@vLs/kSNh[vW^GhA{*Xl?wv{)EF~@wvVP~TR5t#g3t#"/!3HtPYM52/1qmJ5Q!XYje17q;jy4H[aKPd+F27L[InL5LYc"DwVJwQQmYcgqgjL.1x,qgjX:f^W6fjQ.f^a71+z7FbU,^Xc}Qc5.3OQ^_NWsW$`+tYq,9n2087b5&j[L(WpU]7aM.ks+;zH+YfJy_/aM.ka&uOGMizfK0`>8$fs5U8NKpuN3h.+R26NKodbU#9(+47NKra)31cB.OZ/=+yf0d$_VBo)[=LD`YbE68Tq5c:[05e$nUNJQ{,&2l$z7+Pra@lJ#,f$pQlnFbKNe16AX.OBSraejGk$ptS.p9NN$D%X27W9NMTJ?"k=L!mGk@["k0m_ZE9&2w<1%X2MT_Z,EmT>%rCo=RJRJ%X!6vR?y7g#6yBi:*^:!pk*<Fp4:bTHyH+N37Rf]40X3Hdn:u6bJT`*1ZTw5Votbo%*#~@W6Z3%#,f@x"TN$+Ep9?a/K.P3SD.>k97c2,]+/iM7EUp%%i#Tl#7!<DZC,"A:O6S1Vg;2}=0]avlm+Q83d]|RWlGYY2R(M_FNdy;Tg]v/~kU[vw[5ZR2w+Y]F+0N^1RK?UY9AxMyB~B%w+iU(NVyRgZU>YElFLvS_HXK835R;d]^|6$X+oFeodnXw<pz1SNGnp8=40B~KW:^7==mCuZZZ#,P6Z8FdHcz:Py`&jps,dK,3X]7C~R%rVDO_7BkpsQ{PW$DQ7{y=N+<DJxJ{c>o,8|a:3{#@#E;M5.x2^0|[o_2k#^Jc:65bOa=~geYoPHpI8>8Z8u^?8VKY`bbo:!4{;Y8w,P="nT@)Sq%`PB}k#1ljw;={p<)O4Q.rlN$ZOC[(#$S:|MHxU`Hbb3XCOHp{a!FvwH[[v.o^dUPW,P5!fE7yBI4:EJ4e.cu4]@4e^R%/U@^%.)Xl3*t0C{W:)^Z9PuUL*+=DMJy[b@WdC(6JbYBIfHo:!MylH1f2k,YTBd0.jX%%RrU.Z/P(M~xUO~U*fGp{qE6IbQPxo6OxLpkBo.:1^#;rSfP`#Vl0Fs%ZTBb>7PueC`Mh2$:iM87@*zF7]9rdpsV!qWVGO1p,;J,|#M#]YN]cG"g4Z2f$xD#q7|k(l|k!lot^/3J>%RgpM&R"P22S&]c?7X$A*M=r@ij?6Blsh,y_7X$M=(l0lP6texeD8N.%J>L:I!J4JWPQ,Y2#l7eZO9H&S%WD2/qo#Wh>PNh3EUp;;(3rJ1#39%gE*ta6,JM~f"g:;eCL{;da$56/Pi#^l_+{So/OSX.}:buac7f.`!!7E;(o;z`)XpsVB1r(/y<+/Dbk]&8//5|P]ILpLCHgn2xBLN/lUC"5q*rC"&TBtV$GbL9.{J>};|{AwtNCp1Sc9sa`}Bo&].=!fA(Hp@=&l"IpLq$)fCo59>}E6|k~Lj}?:U{Mx^/K8"FNlCo>.k]J8@7H=(VU@rKRfIz_p,z.OYH;OipN;CGIk,S!n77.OYFxFbs/vvwvNIHwOuMyo:Oip9{wc3~bTRu@OcbE29mimUW==,~bT>f~loo]*M>FTCUjvDt.O"BF[y`$cMcK6C81yL~ul*x;OB<Rbafn;3OC2YLBAE"*cAA)M?TDzyi6*9yyD(=yD@Q?zyZ$o86n5g0FX")AwAAAAAAAAC"1[[oO.|1`K0*{ZZnJD/JP`RdQeM8rbCx_<wv5lFHOR;($ROCg<t(`d^qhjIKWHMp{idL|+)pJ9ZNi|O4+Fx(=IGQ@(dX7nppa1c$Pboa@I14Zc/@1f0.i^/:j~T0LXh)+?=2wy>9AM#<z&q|lb5*tX?#6i|<A0+y,.LcLAbPKW7smW@r_I.>M;b+n/NmGK8*_O/{zDcTe[,VtF5}+,!~8/9mmLTJ;p!x;3^**GA+~@m<#bi^^5$^m#6"ntyRX4>)ZZ=?8f_$b@#Noo]RLZCm`{Rh}WvrYlkOFkT$fwy{j{0`Y[Nzt2;=%RNP3ubEF@?Dy_8+#*7&t%u]ZU/t)p)sqd8brOI;R~9;0ln&RB(.!5]*}/?{nf&htr~+;#2%=cLSj]$~r2C83GOS,/YnTn^t1hHMITD@1s#V*{|QUIG`HzoqG6|E/cAt&d+?p%{F6>e*[KQAca&^%1jP1mBV1C<|s+*@@#47gFT_Pgh"6<:]aaSdBzYL|Itt@u$)px^a4Umv%6#tyk/aB*l9.lD3cJVnSW^J#;Q5(n/%LG?v908+xk@M6BMOy@)D#tI<G#L3`.I<D^s5%>p.zHdI+IqJ3Cp~|r)p0W6=`NswDLOY^`v$T~LH?x/*cI/l_<sb*#7PKtZDepoZT/h/M?VB"L<I.!8jwIS@#!S%*+:nry6F*6()r#zXv|`.dHxn~Xgg.O$BQz*pWJf5fW}ci"m4ct{@v9b|N@{bP]fcnWB3mdX2&xnkS3I=Yk=e`1uYMSV(#)Q4KgK<B+D1D+qM}lF#pRe&1o7Jv`j*xmtO>?>a(I(h%@Kw<}gZ|I`o(8osR+4TF:+|HnLy@Pzqc@x!Fr^dzE~!ySR$~_g_^{&!;tD2aU^+8<zU=84Bj*1;c4EJa/S1q,Ddm$1cs~STzq&D{7Uh]K?dIMX1Zfj,Xuvy|X2{0|cms?C:=9jN:}i9sa|+*|5Gx&myO;%&wGZ++uJUrO2jbOgbj67LP*M*dGnjCGX:qMIg<+>S<9bxzd2pRPU!Fi&MWQ:+V`3MY^D;;&f+K0Qp>2E}U<Io~?|sa/xR2`AIcQa(uQ})e}8lTqCTIVWvUn&zMJiE{|*;w(o,$*uXRln[:Rmqbh*;oob{a#v1b8Yx3tXS]]bK&q@n=#2(Q8(sbel`le_:Ztb|Q+SA)x$Q6P?C8lj>}g6;4VTa!w#eY7~yMjvP%rGSw_#<A~YtX_W_<5b)"Dig+niRgjG$GI9Yq*yR_oQU`du@!24G%TKobN`MzAdUJ3,D9BGz2MHtNM26h._k3+!pc(QRmcZ[99q:Uu]FR%e+L]q3F=@Za|dLi7N^.oq@,ch+Oxu}/WrkP~<fV%omsrUc.p*e;>#:^^XC{pS+l{p1WN?SBmG|8>1Ce8/7KJGC<4*(i9MDe3y(IjuXka,pKDI>F#]Kn6cJ1IdnAL]4ejvjgpw7zu.X?Etm^iOdky/x`lJnT0qU=3N0MON6}1IGn8*r/8=b1ugU0DSqgCdb~ud)|j#xk@oo*!7bCg;(xJk<[o8#@iwH?RvR&!RXQ*q`%@NPal|4WKf}]h//av;K:9^|BD^sW)rJqlle`~k:lI^:hwlriV<7PA9[9sDGe{_$QxxZdh52gsA3}]6d+E}CkO,|fG_tJ1<1=a~=M;lf^ed_Xr5Lbamn}N~=+z,]2Z"P4]8VO*o$Iv~]/_08uD"3I/Cw%WuB]!c&1.k8E{h,wW2r@:tP[RN0`WE[|lic)s|ujOr])1Vq[ol"#;EnpVRP.bY_Mo;i*2^x!m6chue{*d!g^?g1_2*hlJ`ryxnVvJW(}]StTCUZ`k<Qkau>@8vD{]P8[tivoRr[yB1avg?g^Y{rl6`_lt,P;1m|0#buN/_)2U$Do)8znFmJJyA`,j#:]1w$1cR]uS>|!QkA)8_i"B7HT{LLc|8~#Gjo&aam0X(^8lnSQyzET^`Lt@/jP.Vg$+t0"RJ_UR6)KX]/U!h0<8]2UcGxI#ExL(**t81r)%][iGNQl2}~Z`Pc{;Jca^J&d,)>eMOY!C,r,5#1i5+L3!^x$RUFeX*_6u[03.7aG1/ngu(Iy#_MNx|R9.myP.LZ.8n9v?|v)[6Z"`eLKHQu;2j~FT"&]y+>637,I+}r]gxKz(q`MVF~:v+R4f)W6k/B:.iv87LrZ<s4,<^?u/38^pTZ){_B|pl!;~%nz*T6{B6eqpj~gL8a{eVLvj8x+TiS=Fo{,y"N0@.J8YdDo#FL0w:d2_2nJu.9)~}v^;nFqIlNltdFW1rF6cotkKGmd&.C[&hh@Rs3$"wDhTJfR{Cf0#Qx:_~Hji1.{B9~;=T#~p}SXQt4Zs?D*(wN_#=mI,46[p&&t1#xL7Sj<%J+h?Ib+~?3~NFg]k@y#0A;q}t%V8^[o1+8)>sBNI/dN,za*Ryr|ejXed0NHO3%POn_C&cnc~NL7OL[J4TZPpU(DXiqlwXE3s6rL9RC!:nu:iqQ:]X=.IX1OvL1Ww5ZAKJ#G=(`;<{`m.Z[Y`8K!.1=_7$$NdGZg;ML`u6,LVQqb!Q]%aFea.<X[e=MRK?Rr;Y.w9[1o6^_?$go}!cV$G=hhV+7Z_ydlYK$n`2U%UH^BlKasu=i.Ap<)t];$wzz*_gO{(=K$Nw/Ea/9A!1yZu<7aeI6rXZ6&Z?8!Gy,/ob>g*c#!|eQ)74v}~_7%UPA]0m1ld>29>`%aPv~.4/=qm%fu^E~v*f_i`$8}Ih0Y`HfUc?6ds31pUwuebC$0.KcVwhDNh6>piv<1;L5>/J[6q+nI8R2),.1>s`yQYcaf1=U(;mPu"YF$.Bi#WNwr<8=G!,`fC+.m~!lJf[0u4SN.K_jS/ngD<tz9$+6=EP*4ovbmx2nz#GVs:x@OySZb+%0<|Af%ee}_::>?BdBE3$m[v@hQz9ZUScFciCc7=5|Cky2.(14~5gEOi=},lU4=Xj?ienp9a`PF6KO{a*=Q~~Qy!:l{a#Px`Yt{dp]M:hWFG7e)@P+9,e|M>~&Y[Ph/~gImimRbW"r6M*n~GsiMEH0i&aI{Q/c;iH2e*7.7rh0Zbb&SG>x]{DLIM86cVwo5X)u)`eS%ynG?=+D+3l_,)&g~|E0HrhgLBju3r>s;./o|`#"2B;VI{u{)B(B6n/%T!}rLS;Z5L?R,HeSv=a.=v=@JtG~*,6FxPkQ5O@0Aw8P<VkS`@P,>b;(5E[O1{}"]9)hG0WRZYqWYQ_Mtl1b&s5w(Ch<EmqyQE)*4s|gu.8S^j%0ls?^Q}uGkUySdNRiCnXN7VM%?h<u"~k7<6F8|VN3iy|3?]2Wgs_29W9e&;a^kGge$#XAs!UCt4[2`|q@G6+0(8~}8ujgmtl$~(<M4S=*dSXZX%BX~A7,;Z>{&Ju0y4NS&I8HrL]vc@d78G7ULT%{mqjs[&n;o0e4D*av7t;_[zSJ7X.P]pww@]ETCKl`zR61bu)+xF[jNs;,,4APpw4R/Jpn_~,t>F6^}22@Xw;^g%)}gF|e#"nG.~6>7G}@F#/H6FWNVVTPTW;7G$)p*b^C~th<6xLL0F4s]wpb)R:B(7s@S$t.H(tG]2=0ipz39N^5gME_.h+^">bi@7JQxW))e$vOa%wTxoOe"3^X#g#Bd0(d3;+wG59XpF%(BzaY4{CEK&WS>ipkORGg3$|gn=BSkm_q`,:."..8|uR`*{E_%6KJ]{tuQZ&JoSc)J"K|:q|bf][H_YF}$0gCx}_)K%I5U,8DZPvX0+{e(|{i6T_IM<fEiZ7_,?Ux3GB2cd2|#+)L@48:7$QQJwM.g_GJx_U7BL):<Rg#B2=q(:JwhZKO6Z#h$L*s.lA$9l),bN+lWNS90]<`<fnpYFGIJ&0_*}bEmPgowdTI+P_M$7!/*qL.W1QXQ*9|;nABd%6J>|Ugx)nhmD`/&kmY+2`77cD>@W.LU<h&DS=>f[j/Z2pOh!^s[w8Ka*}LR%iBpB7o>S]o)Ngi*[PsXxGw^YM`|au5@yJv#@.EOc*2zKw[@jHrG9SSb5;]B{"u9{#Y1E&yV!<69vwvo<{jyQMdT20$?eM2OiQ~Rv#;9][Pu#s/JyJxq8)N5ERi?GL["cR:`(:%Uw`c|DPGs#QuBZX${4I:wrTq.qLx71gEkyzGhfz?ex[w$Y8f78dar?TZ0u]o&gTp3O]D)EL@;8TtVEgfT@L[r0Khpa_80c~DubIOWL@s<%PiZT^awNqIrG?UUK#+.}*RfF46Q1ZmJ}CBswPC+3]W"w00XRphXQS^ZbxNC]0L/|;kyOpm7%kc+H(|/[=R/.CjaK_628&.).Bf)L*nga$si+OD2OO/L*BuE*|YHK|@4blDy~jSvPA]fV}|qbnL57nQHY;Z7uXZtDK}.`qYN=jbryW}viO2BHJg_)ny+Cpd[/;zA@1{|MPWVa[vGnMZz5j*rY|LTBz&B6T.NspCo|S]B,]tLD$b.Gpl<8u{$Z)D}d8%61zEwSkv>9@uY0g[getUuD^k}GAbrPbY(a(@onX7JZ;DSS$.IKbMQm:P@1jpmuUMyZ[U0q4ZGf?Hb^od(*.]`1HuF.)6H"`@bp5VuYyj4pJ~<3Jb>RXU_q:7*ZVIuOXwZk3u@J2`j}DIp$0S[%:]/hC/U7Lok{A0BxLm6;6*_iU*,Jm}Nid4Z$e9RUH@GW*cp|S<qw_7lL=pb/+F{ID(Q:^Lb.yGE6Fwj5"J8;#=wdX+n[&?yMDNzRfKWwN_ZoboQuk,HxOK+("DW!;ffktn5,WB|N8,MP;9(9vC@h|8~HuW/Z74uJ,;XXD6a2c0.ez(cu?G*x$(aL_@|<[.NaHmsdXoa2<)>T/l}+LH85F:8Ok@ZE"Le3D%_U_FF~p:A>&5@HG2pOmLUdq(3)B%k94N)3F+U:4VE!F>KA[n*Gg,%}#bjcx4@%`|!KeG~Sf5l@/*/p_cA8l.B}jjQvmpiPwTc.oGOBOYvX!vBg^Te4}=mA$kKbc6xag#O;s%^PtsCf9.qnU9]A;syL+TnRGD"w2]KOy_($Mf}<2ovhdP7{<~<JUWh_5}?s+4h:E3z.`3eI!w!dA5&Hsc6SrNZK8)y>n_34dl*O7aI}WZUvtWTxgNH0j:q#`Ti[7,Eyx~{z1aj/aGe2th!K+cplGSrJdnJ.,cZu|q?8K3u&pNjBwKEHGdd+]:4)qElgW:l=`/}Do70@T>W>7*nvPGA":(q#eeFT)tt/aXHVo%Om$a"Dz?jZ`K):%5B0(mfZ7p$s(h+_pybH9ja4>:m,1fCB<~mg~`&Me#$[Jv%(cETCqkR|pV!C5?P(FEm!_xa_lD3Qu[O~h+`E0vLLa.&@^v)[!tjjn[efD!~Dq!t1tY{JLo]%d#WdopVr@ZT?OE3P`Kr2;~^4Uu=c>B|%o?>YI0`?8i5>b|UL7o6!`3db^m*F|[XC},eJMWHTbb9+`cOJ`b2ec<V*(s:uG+xub~;6tI,|SD|%;#PnOOg<nsL{^GuL74l.)$k%eJn%uvi:Q`U0s|aGt{MSta[&f~oJsHd^tyNyNPN^s4+a^+@<N:!}5n9!:b*+cUXE#Rr=~a,5;dqH7G^?H}4,7h:8kU;G2z[+/@q2C60=`;?{tG.$0i+h5|X6R:m.exk~TcXE85,J1=7$J[:vTXvI#?Xaw.f6G,!2I{T^,2TgjM"OQ..!G}I!TL~(Ml/CIE(Thowe^ea2hHhfG;+#~]4,7+Jg;b;SRN7:I0oICdc%5@TfKg^/{|7R%!6%I$5N`hNuLpc8qV"x,(g^96A2OE/](}Ebo07V<IF]piN_s#5Iu]a3`qgzMLr$pVPuiC`w,`VYqHz#M}`Uz{M`8=Gh3H!cy?Sn2HmTN1k0Kf63sX<_JLL3RCzMJ~@Iajmx}b,P5Ky_kf]8PY0/)Es2AzXhh|#V?*DEKdocun@F.MqKP1ZDtX2Uur4z7K|OIsQw_~}y^BuP9FvpAh%^b*B`%D,!om~$gBKLyz~6q]qL1ob*eRT.+VglzCS}e5*j5%QF_`dlka.Yo/nRklL(29DyI4)`bW,$}Zy(.:QCG(*Z544s!*D,R6sV@BLKKPDbcGv|^]oA}`CB8o@f.7I|G.$.gjm9kzKe9Pq7MKz/PCY@?/L.TC#]7RRfWXR}i?(<V=bX*JZd@EH3]zu)P>k:4Bh/_s6*ARY*LVsUi3"5d}.kVtRf47l<&:=9j&}>Nw_d|g|^y:m{^l7ZQ|m:(J+Y$7uM5FN!*0E*#8F>F3=11<)R|fG*x>)*=VAXo7SURs8{uXx/EF``h`wao<tp?zmC%%Y<_|<1riZene}WG6~?KT)`bSpnI;w#Q[kITY"Jp3L)Bi.h`G|LR~{2:e!(E1~EH#s/5hZ3axQVIt3gOidMay%s_g#FMiWeV+ueb|k|5{"n@FdTD+o<WfWtsDULl{N?eTk|#H(J%TA0:X&21F;:[!BuHUM5TjKI6D9U1*<#^oYx.a3>&7d]JDWF?L|5?#Hcab2NK89I9+B{2Tp{r;ff,uJ1%7l9zqY)cvJ[gx+LomogI?f96<vxmfV|Z?7([68M7dIb<1q2}F"5tdvY{?~C>@i9X%6G4=3Y6nP:K],iNLnhA*wr>w.~VG$9e5#.gr"S(JJ$/M%^miH8j>*85Hz="OE&!afMs"&s0|7<ux8y*kyCOiO0|XEZ)[$WWdZufqm_tH[KwUjrM&rUArRV(5c|fDeE[SHD*5$GO%)5&K*LBSZ<gUTpu;y6f%MKK(6vY|mqQ!xgd):/wu|U?hg7xbh)w%Kz`l64$PIn?o&OQB{%n:cO^E8Vb[}fG?@/evem]qHU%1?W|@Mj,k"dLIX9!Ivt|*9f.f2{*D:SU"c{%BR[[cN_r}hJ0d6|oEN_|/#zgL*A`s!wRW04=&vC=#<sJ)CFx?/Eu[W$&Q0f/X=(Ts%de7Ij`/J?,i}][=Vs%0$HKRcTrCGo)51`]u}zToXU&LX,^/G`5R=wCtDF?#;TjN?%:qcqzD]=|Gb4yXiVv$zNfEnza;`o<q(Y=1Y*]m*,yy_2sclZ}R^4~$,2}4M2Q?O~T;Tv`pA7W0z6>F0aRs1>,VP0<#}Z7dqSK[pji?~}u}vO(um^U*[s=}NBn}~Au6w/YzlL^PZnHECY/y`mD"Ud?aFn]rYs83yX~FVwKKr`C&y_%N/"JyHSKQ=ua}(Ovohm~mu8BfFN)qw~G0<tzdg@gCaIFQZkk&h17R;|LDF~Q]P?~)@+WBjlR|!o*YS!vy._:zu5>CN4?{6`lTd:m3#Q|&.PUtxnuEa828Z?FNR!mZsnh<V)fBQa/Z>ef=k7~|%[zPU^ezM0R~%0*Z3TxyIZoGg:IQt1NU!xH>=bBn9]cHMwNv0!YRBW9X"SSI4zC{{w<=Oawz9+d1~zv0b2hCJ/51:6LI&yyQrSX[=&E$o3c!pxm:7?|;sDg{C<)s_@.Sb41cWj>2sKxDUS+H^,}U]56,wK;Tr48sqY_[dIG,$mT`s#yfN"=zX?J654J;e{Si=HPp:z$O;XL,NLh0DCnJ}8rVp$Mt`c9e$.+}b7.wf#Dxag*~C/>9||l#G4GSEq~Sldmsfi!(.WaNyN?>o.KYq?%rCmwEa^25Pnu=^_a)1nz,OmF2TTH$3m.aVUY=z^*fY#7Y~YGO%`5&Ffd}Pfr@(2|z(R;X3(FaPsoxJ;Lk0Q/C:;]QjT"NAQ92DK![50s|m+uq`gli]C,ZNW:nUWRUg2`z/|#}++]iu7BMT*SdWiG^(XM0Fvs(nYxZvc,M$1D#XLuE?}?m9M||CK:s$3}L#!sS!)Us5W,?|26I9aldL2U^;oU;]=PDMQF{mQe_71LNI:[,%C#M1k[8A%y{QA>6,WOi6*nC+v@F(FP{j/@D]fmg?v&5"K6|6yoOxb"*rZ0=Joml7xt"NbuW8nqRSb31g9_gi5DxpeUrucxjS"B[:x1i$NiN/Z>|K(F|ve;Hvf#.,B?*a2OKa%,Lu~K_C^zibHE/=ijMw^stod66O%vg9k]]lr6c#<lcc3F:hpv.fPGfOJ(v5FEvYG{n>@H@T~WX10Gn9BnK)vub]@c`&+H(9q6,qk>N"H(]lI1OyKw`%Gg4Xy4N/%!H=RVrSItk%nkb=P>G:[$oJpj|X7GB_L<Z%"@~84xc~*Z,z>pX1zs+1wVm8d7]lx#qwuO:K8vCtkKKg#rX;n~dV~7+Zc0u{1DAuyStx;uJ<8x7k|&TRavWC8vMK.;?>YRE{aMq2(_TjaQ<J(epN53]=^S)TRN%2+S8Z|!Pf`CC~y+^`OZ,rUWPdO#:OLaMp=G{AJ1`4r1Qu*fB#R8)G#51q0A(cvOhjH%6K%fMJu.L]oJ&|X*m`D`iA.xvCQi}ZHEzgG(n2Ww)hU!|@/sJay<&6e3RH@1h?!A/G)khI,];,lnzGgof$$EVTNHL+j@~^wC/Kc1nVp/16"sr|H=)O[RG+qbAyTH<a8"U~Q`m_EY0}qI8q)y,l!T?C$0}L7W>"BB&N$oXMU?j@RJr00Wxs|5;4]}9~#~2:~jC8#2:&,+^8:CO"ziEm*v?sbf>I;aU7!U4<@#L4pGH{p)tCmI9@6.m/j=UO~4Z0eY7y%43<V,S5N{B%bd|v.(#_P+N>@=_Yb5TDl?YU(N{"=>f!*L)p1rbSAtrTLY8T"C|ezj[ctC06+mL%LBo$KB:Ie:Bk}wP@#Mm*z`.A"wpa(N`lFi=vaEKdrOqjlSv<FYaYEe_htBwEpoJ)P2<W_GzYe7rv^f#@R"`g+:Dw;2[7>WEh3s5NEQsmyVt#*RKtL@$DK;M_6%5PNkB{hQnG5G[&wha_X5zrYW#2SQFq(U<h(A~(EaF^,]>T?&"0#LObq6Ue=f;BuMMCE7Gj4re[O87cH6DA7B#LYC@DbYEY8Q5%)?W(niJ=}|FPKNcV:vJL%L6MK{T|0=cIE6`&{KCSkLxNfD8?jyDNkQ8h1w!.$u1`n7JQ+&a_U_lP_8bh]mY6FUy_3Q/G^=$_:_K9Z{OX|*9u>*@L}Ft9F|QN3HB4}Y.&Y?~"a8qjMLh2nJJ$l[)$m?|93t*vDq+;Z]P]obaoxWlBY_fnb7>.E>;wRFyLU^=;Djdj;3#/0UG0Ka]ctp<,C)H({?mGk^AYLk(xZg5Zo_FAxJaPj,)$=rSSOQff4={~!Cx>U93;aItu_="2Dz4K2dRZ&|xV*RG.zm=F8|g$1NeXL<4yWI!H]Z$7W[ma:cWQ!/04+T~nP%my>KbYPq+NXOCn`zK}F.`nA*WA6]6W}:qbF{|Z[kH2bvjle}GAr^8`a&N4a`qmG3MTq#Que]w|Q23uZK&~dYLZt$2%Zk{"2<jfo%&e@X<#WkJ$u9=#)IN<|eUbW.+dTGka]:ecLYRy%9rz`*yNoh<%0h2}LX<HV)xH+d(92|O0b{J??*@nQj_]WPtGw2yU0K4haU!L`Ukbe+fS,Jz`R;dpp2&+sK6@`F#6&UHlCB;dTzF@K,awa8ELUh,:1F}[eo4xfx*1B3F/PHf{OJSs?NWo`zvC,,&>7%Ts8.{5P=`GGAr4Vy.vtj%PpDXS2gTL8_}$&R:#{C+gi_>IS[BJ|RyQ=ht*Y4jXrN@Wr^k3+U0I?20Z!~hb;H:m_>(A&^dvNe>n~?%%Z4XA;M&d<.a**SjgnA=[=ye,I2vScR=L;nZ==u25)CN)*FX<*P7,u7D[I~OoWDjQX+lZT[M~[a5GNfcjn#`=+)9+32vP<iK|zcGMC(nP@wMy~j[/Q{;hr6^VDjs@ve[6r>]enz?hYX`PtY,U+BwYZlv~RA<+,h63|R9[]KK%jK:WLhzSL{f35/CRD<CB|),:(Cg9U3$}P"k"M/}o5]5f@DE|CLNY^U+!<A/ulYRaP;2#O3aC)w@7i,0YH*DC8OFcjw8M.+,q5WUYH"j:Eynn0ib9[a;NH8$h2H1>{(Z"BMBC?cJX+?xDxdxCFT(:$RFW7ndnn5p9FAzxvsMIbmo,qm2$C~l9P3nW?90D:*kw?"+vZ:Ak%UoIt;:|Ono]D);&;KxQi[h*F*kOkj`Ykr@1GyNPp1,Ui+h~GD]^W300EkkIi#u/ReS8oVvVTbda9e!5.GQKhm[1/m3qB`]~onrY6#gW&?JM3K@@Q0vuZYz&.e7(0PfYGe.3c8%Cz`rPVoHoYT}pdo_!bJNrbY`4n!Nr!_kxDvE#%ACF35`;=QveG"LIhw.}k/Mt9W"}6sM`_M3!{Q,0?wl%y/ss%Q{fIOP,_JL/C~KM==Cq1WXby.QVBq7ljC}h@qoMfPz3ROH#k@R5zIaH;8WO;J_5=F#5Z#iY<q%{=jY=[,wSAPGhmg|S?I,O$c?q`~)A2Yt2}jL?{2!{^(Yu~l}{|blMfHZQ?D][eA]3:EHOUrqA4vsa_*_A:<4gu4vSsSu+]/2Tn@HLCr#,Fl)o~nK=`LEas.Fl+MH.qCIkf3Td%17|~QfvD0het7=`}.h#S;Dy5Txh/I^]Eb<6};]hX7Mq%*NW<n8ihPs&qOuW?4P|DibbHY)U32]IL8gC`!$Z[/6Q<ort0_,I[Lgzad*4@K95bqccgbH"2kusT|DY^]2b|qp_=Rolx2#=7}3Z~(m7N3a"n~NUg`kH}aJ2Q(2s?qf+D243^08(f=)QKo@FC0BgRyl:{&At*$[#!SX&4wwaz~"?.bM{*(LbT8#5iA*[ou?<o56"PW{c?^B0t81$g/VAf|06Xtz!u@1TIb&R/ihVhRn]Q7P@5?/;xspW^/}=o0cuAe1D$@>(*p_l4a)fC^4rj$2Bhdp=kB6~(q[)||[O:,][U~I2&]aO%N[}qL)yZaMaNFHpBS@%z)gYFMm3rf3;5/1gLSDw%B,(6xN!$dd}<D4UB59u[pw0Wlv@sydCM+^7>Kg^U0|RgPBy[wxf$w^lqB_@DaJ0jQUD$Zygaftlo]E}MBfSGI]|gqnSvm(OEIKozQ9/^*C]ZI_rN5&q;(HM(pk=dW9#xJ~igNZQtR$XjE5&@|/{Pb/jk(gu(%bdrp/R!s8WpI9$$!}1gQ~J0B8J`8X)+$(B}M_m0rR_+*%5NW]aD2SNd&ZuYe$AI[4}2UKeK2JOb}e|t$r.OQ0LF.c$fj}FC(WnvuenlvDu[8QepF:"||C{(r{guzft~KN=(=p01[7$g7);okO#2!mdBV{DL[p$c0BK=.Ee4Rd?b>KI6w%kd=YV?Y=2eq19>it=;%w(jEInJ&6i(T2iTTtk2!5`8^XNI71]Q?eK>gt@#thsC%Lr7z9:,9WT}yglB+;qzau`[2[RI75r.9WOKyiVVWCU:I{PEQeI2I2]`vxzo4$]kR|yKuLSEiJ$*gf`8&a[8Se5E~c!06?^2bJzxof)w,gM[,<zv!pv#SB#PVg2~pD9c+^=t5v.D87>xS&6hlR|l0gsH74uU;w9"2~Ys5RURCNl!Y/+D1a9DTsMlNY"!C%>@gIi*iHdw@$nE)Jx]C[DC)14$UXWH/s2Fjow[QECQ%S]0_7:{xKjiF2xGX_Bj(zf0B9UA1_6_W%rkn`5h~[ST=D2B)6;?8jNQ==J,n1`@p>X&f6+$hgUxoQJ2r@8F:P/!u7"j|h}Jb@?Rjlc+9[e~UU{eq6C!VM(BJchA=eDz"d&hbI!mweL*GayfXOTFKvOB"0oYLTC@IoQsMv$fE]vU+Ujz7EQWp;Pf*|xhqK.jsX*AAcs%&FD&S5@2Sn>=qO,ZJ~]!hj"~mK*|qTrIlGeT(DCXA1+*Zmf]t_bZ8aumlv2<a.BO#z3&[xMi,@tN2B*MbBH}X$Tl;g=BVEmN$Tx&cbACm`I^]HAjHQN8oZ!Ws&&/M_)5b[`XyQw2]:BQdM7,s7.N_|<iQ}6Y3644C2Xf,>ht?ngm$nNR+4EyBmG#(3`~/`@wjqn`&I193}qD]pNHjWfJV(Z0pmP|=5x,X|y=x^@I"T.qQt!QVZ&07~BB+scWL4Q$Pey[}rnEVhmR~F)s#&/uU&d=HJ}oLPgzGDBaf$TB|})34PtdPaO0@D"4NvOSUTN&K8W!++i=YDc]J5eh+^oqvFF(d8rNkt7M^h9H3r#}6j0a`>&6y)ZBy+Mx+E>jOH*A;xt%DYv&{pQ]}+YR(b@&do&>);iX)R0=Q#,Dh+Z0XYI`DJav@rDI5pG36/*98&~xYfT<m1.Re&Dp4F<E}b#=,difcj:MY3QXjPn=A{o0|GT<ga(1<+S,o"`1Xb5nx):ovl#sjwr1~)>>L(TM[>f25]TyL<HmWeqEEC6%oG}O25Va/PGz#i0W&&nG,CI:9+P@M~qct..73^]y0_`F$7T3ikYs7G~T0|yZB(WL4p?kDTR+d<cx8LC(B<>v3U<WYNioD3o$P{}gX5nQt#HMsAQ.C|X%jKix4D[kL/+!!YCLR?M|Ub%iN{Op0NR"8jScTqnqZiLw8iQB)|;$^|#u|x(QW9*@v3Q.uLg[_fD88&b.`Bdnx!%v1g%.4]2Iu"(u<QNwEFPniC$OU>Fxa|OzhZ_dVf5:2Q]FD"FtI`btOb`zhT.[u{K]2Z7tH^Vxc>E18T(Umm6Ok<jF/rQyc#2*xOM~1COy=QE=.wbho3?St41sD:jkoz*+Zx,sur0Bk&06%c6uBWXhMK%>zbQ,K8/N+AL,zi7(NB^}.X7&*X>g1Wt##`kxNsJmATDg=VvjeAH4@kY}niHP3)k!#J9NDcQ|#CpQMn~U;txs(~$ZCu>_T+kfxaCjLCZ!P:QhO_zs6j:@x,FC1{~j$!0EJ_;~QSh4L;})[Ps%kfC_wn!5:kt)Y#}ZNuE/|5h)*~zgk|5,L,kW2;_/H6fHw(%hzPKMI_%J3Jx,@/0lSl7nyPY@h5}bvTK%2Z7V3j4q%Mk/?)C.LwaU(%J}tk@}k93~}!OymTRmpL1<mf<2?jF]5d6LlH0A%lZ"a&yj_4PLHDXX(z}0j_=gs^HcJt^m:%QVF9ou7{]tDX>^0cT{eA#wF47Kv/8rB>Z:C5jQK|{X&;xFJ0IMGe6BK;ptTwz_P63!+R;[FPdp@&hrrr+]U/W}9[~>q7EpT$5aE3oBpMe=k9fDrr)|w>SR1;E(OElp7{7zII`AaknB#{B_V%3WF_B5q9^W7A[L#qNUoD($E4ZsYDsD+h{em;QIuAo2BV?0~Qd3{?fK)!a8vCE?p<nm,<|0FHW#qP@8CKHZ[%PH,UKn)9@|Rn@4c5Oa!%;1aHE}%^o:Ut+f~MK;=$|vr=,hHu&EVy{a;PBmrlz|MR""*o,I^zdE*w>zq^A@Cg][}An/N@`rEz|4<1)>wLU3NrxS[m2X,s,(m|dH{koBE!,eMhWZhsw0fyldQC|D)i{._GLu+SN~r~m46lI1het%NU)V$%4bM,w"JT2MVNRh^|Ym]K=N1XB4{6z@UWLc&:d{JwU<,~%BHb<,`2wuBW+mp7X_]X[TC{.@[Np;X)M>W(miwR#Z,=6<hp.`lw2mz@d2p%<p_"2M0uv0aja#R`rgk$]ZBKcw^yzbF4fuSW$s23F7W!yH,Y?!{UUi4HI8TF)l:[/EYK>v*Q//FF!TqKD[x5`RFwZLDA%?w.d0?S=#^,WV=hYZE<n6eZ//[lMBn&iVa>u@dcSNeu+F3s8&LlDaaEq)whZ.eaty/I%K?,(FdFVWR?=+ay+s5_.!v)VHE#i^|e#>H$vN*COqV~}}`H;1xH"!XmJ_k[P>d85_1f6<0(nSqQ&]@<a)C"E!W_@U_8`tF:MLt2pz2y(>LfIvmnzsR`aB&yqK..2c^n,Z%P5MR/o/k10:QVg?]j/>aXr>EU!:MLum#l[FOf|3;vsa@n^pgmd"X!7,]]5fX(poOj#z9oS|~r~ekdqX0*(:lVVJ_nRoHZ$GHjT5N3>B_&m)+{@E?3JOj7)a1#QCgN:N}#g)I4Zx8"BA`9S9D#[BVzLG~ZNMXg/7XZ)taR9f3kq]3sb{T7FNZD`:1A}&gqg2EX)nN!?e6zm^Jm;c4PD~)zYA%)j>/6/$U{%`(#UttRZKI6wTR=>yqye"O2[LXgp<[#A(JFxv02(VUO91`@2.D0<b,2?vR[n7c~68_^.:nJ}.bdF4CK:HC+wv;[iFfh^nmb|31%=p*]Z%PL`iQP*I8<ydPp(}RkALB=G}iD_8PAy;f_<%oIN?Hpb%M!)PX%R3(6(7E{qlw7Q"xFJL}`Eyx4%)Y3eX_6J;zo+`6{d~#dO3SW+tz)~BKejb%A{URp:&4/?aNOyWBqErMUpEUGn*x8/.`^KUCFI/D{#VRDkuf+EfaIF|YQ+q7g2+p;1N.^D!qfJBb7xryk4*HjU;}QL40);AeJkUe}KFthw8t}kpa}?M9}(!:XPf@T:X8%$i@da.ziu7JnnulfQW{u~,T?}2MB]?E"JOxp]Zc1`h"G%Ciufp}N+dDCNna^%tsE$z6H9!X?_x~Yk$OoFQD1~}:c6rg"MzQIL:X3]W+/q++FwC&&nG`z!M.[`nR8FJTN7q<;{$y+,WqRKhDT=aF{ZlTgs]n^Cf|Oik#<y:ivjrtIE7pvn6F/sf?D9SOgPEzW|9M}%BhDBBL+R$bQRe8E%vx?vB20,%Ec5BNKr.m&8/+*j6{=YTgHhexzllFS8G>@Z(#T$BxREF#Cg%=OtYVu((dF/nOyQ3.=Gnk0$EeJ!H0*uS=()S<Ml~Ye/lqVoB|y#^Y$lE0pDwggboIYrxOL]/Sb>ALi(B)DCLgH}pdr*3ivWU]bqeKSS~,Hi*]/6Fu#a$w1l~IaH?r4X;1.EsE;px;CYb)vkl/wH>t3~wE%ECnMHa7yu,0|N7.zNNu3L&?P4"4_J<Is2BaS_PwYa}EZ.X&HPeLi~6WjI(1pP=N7=ql+?^K2UOOcXG>/lM!4QT/R}%Tsq@I7_RenVw^YR|Iy)wEc!FWL^Z:{&lK$m/UflBr[09=z,|U}Q=NUsjDot53.aSBJiDJ>gy1*<fM/[DlXc}aq.xf_FS*2Mw35k;}G2l4CPul_.V~69s:Z"zlg$N.!_,egJO_@S>"DSkl^o=X<WjjYOFEjz{[Ws,Vn3+b$+A<#2v1}D^]"EQU}pvzp><_R4qx(o|&CYKJbKLq,HN)Iy$`!d}<|/}kJzKGn8[UV8A0cI68*Kom&X0$h!O}J$RnS|6eph?xn*a>0bj&0;A]C7&6^2jImVA,@rV7mMl8<`w1(m<sd]Fk]4|6@K^aJ^~~TTM]%N8HOgM_Y)=1lG/ZZVSR}0#c4>lhc{cegeWBC$dZmjKn(6COk%vB.YX,O2KXsS(p|]AXi#>Ylp3c@SLi[`=;%)]<$/O)WuWR5#a(/Z;NqIQHUxeg6jmle2T%mq;jjahA0.9jSbTH6/8jVyBDnmVEFFF|~A+Zv`jL*Uw,ub~j8HoI`cvbFrY]"BW|8$gq#fMu43eD@@O|Sw<<Qa(APOi4J34nw5gdy6}Pk_C9O}gh%2QjL_TqHDDg>tLNR]bX!1D9yO]dDBJd6,QJ;RY=o2FJTA!?%ePue&SlQ=7>]5eCL])3,5#~<48m<S94Cx<m>?!bSnnpkM~qUR2;J@}mt.L%[<Wac1tF!S{@4?:w<4!]]>.UTY:7X/+`.Ul<#j@>m+kQ+qzx>F50Z802jKKZlbv3<[rn$EM*l#YqcMUjqh<!A8U4?,^+EQgfm_95L[,<WHV>!|_k`j!x0amP:gnF4rFDqwJE3yR,#DjXKeW|x>2*Es(CC$W0}FhW[7NFxX=d,U~&L$9R$HOx?>AzQ}EK1z@{!x5NDFv_=kJO[1|_J!jZjspMCE.ooHx[_LD,C/u7q#d)hvr;kwtRk_/E]<Y8b5$e{/wH892w6DJ*uNIW>*Cd+f#0g"2FL6`s*M3qRUkLiWe,}L+EB37i@*$]vlTh@["Kw+F3zY}l$KR%<GX^C74i"jMzI0EL2Ou`quuk0sU/G^wNszJ<N3o3k:/;N{|<Q#.^X7UOVdxu}+7~!`fk[`Du?Sr4[cYGE/Vg]#qrW]f9BUHNajo<#5L%Z,_Yla>8lkgyU6oP[z;hHwYn%L4WoiH+b+.NYlFR!E5kEYGtU]r,3/|bQISE`P95VN2SGSbJK[Q/ZjT?F0Lj,KXCIy0s,6QrXhg]LCJNR1eZ2{~9fyZ!?PEtLOsQpL9MPxlOo;rpe]3DTSVS2M?{mX{ZH%;CRUFx1hpPK{[[6hJo{@NTES.qf&KT0~r>eUpo6z<+h/7|"N#8J*(8eX,wx;~r7b}C*!T&~KzTk:+(F"In!k0+z*RY7M({#vE2ap9)q<?d54!8Kz5;7H/!;Y)aD!>4O#BQ]RdTl&Std>Ox_~Y>w$~5+6Ia{Z@IHUk%Xl:V{Wsn5u[7s$H6u2R$,,.Ew_5iugxBPcd)*To"(W:N^}AwQicF$]{bI{r:;Ranw%C93s6,|kwMBIakH5u1$)E_wD!G;{xGmau`USF|t/8Eg)4#b!BJdZ%vf%i5`$LGD+$#98d#~j_cnTuS}IL}kk[@+N_IvVcGkS8kEub}[M<.186jS.x:Zo.hlSv(P^/L$9oJz1EYDN"4CHWXe0IdacPpeDKshG+Gw4/_Xdos{mJFNsX9OK^b32RPs,bGaLW|]34*`V"zoK]/@W/)XUODxDtl;iM}EXHM3:6Ic#t?Sa0QJfmH"nI_[9GO7?uCXZ8?#<d)8^m6zU(OK+U(K(SCKLRi`({Q|J@+xZ<uofP~"yX:Y[pu+KkA5zN>_G/ih=f4tP3oL$E}>nbK=eC"N#tkUkdl,v*SW?Dhw?wQwwv@KFwY%h9#;Q9>W:Czcs4R0?[/i^?CVxa~&*3dcuLw(u35m:rksM;%/^<}J3Iutxpx]MGQ|CXpVw[P{)6_*;d%H<o<GG:bUn<[F7ALzH:pKLL&2|~yy}[xo|rrttTdK^}o9yf|W~nZ[CQ6e&>;|dV~]7x2"2koA%Lp%_0"eQ=qk^A+UKt~"Iq_h./vp@4sXz*}qg;bTRT~)$~>|+M<UwIK3N:%_t|s@1wBTCjO6|3$A6hIv0ZE|y6j(mKw@NQAjC/$Zh*U(yPCFvF;drQeSwd:>krbK.>lOWL?F5e/GE/%&+~vE]R/f37:u3MeqS|Z3gjDWW7i@GZX96t9o@(w#3<zR2x&_$J2n&^B[pLq]q}vF{ijh2sf>O)eQB=<j&u~IR@C=NN_j[h,F$[*2H38<{_YKVQd?A_|;,cl*:=%&?>vg/@3BdP#}q&^SmHDZv?8J39epwksdZ,{Rwi2HWO5!ulWd=k!,B_>4XqoelTP)Tk<Y&>vzC;<ns8t9}=k(?HbA<q+]b5Q[f4}?cBQRf@d"[H]kWNjHEw|wF77zLC0P0oZ/$@BMf!XsB1IoS<0B?57K5n8T&%<mX@$)#Gc0U{QiANQdYi}=lVw`H~6WjQ$jace&JJjN/rPB)%c^Yu;.[{$=u)_=]>V7S,(*tk$,domk92N/f;3six[TGY*ECK:&aB)+dzY(8O<{$YN!]oMk.mTo{Y&KQZl~AmK1EE;}T/GZ`#{*tBb[#Q;^)dh~T9Ldt/2PZ!0%ib`N)99;%}w0.n<Oz|[m)lbS,F`vng,]0:7:hrQ~ZMwau/>+m!E4Wg|HFNOSdOB>st]aX@i"Jo3o~Zdat{V|W]`+$V!^7M_pp?TcE(*XM(kE(Aj#RH>fWmW08pS]lH:;678T!G%U4Vts0f1HVRV(c<_23jW}UTzOOtY3v:M87^7]<fO_bDvb5HG;2nnJ%+"^^)xENN<S4)IGIC#i?D(9Sy?YKrqjo~)gMtm`4<TC&boP*)ms66Pg#$qyOeF[C^Q?0r0u$4oAEWZ72Z0=~J`F`gof+oZ$,]]@Z/<K?UmmRFLz!>dsOET<q[ReL}rpzyHz+sq}qj/=hU*3++dQxH9@j^OmejJ[<A[gEo`uq2<g}X8+TJo}"Ju~x";Ts.sH+rJdFaoY_xC`F6ltM,9j~N_,C.KlRZOfL/Tb)TxSGOyX{fqv0TK2wja`Ig4tI+`:+S)MyWD"n=2]i4:`IH|VPp/VMgz?Xi+e&;J9T?Lje"#WfS7OVPU~Yph9"`[@g>DfqKpdEVX%&&U^22foD{B/w!0w8]$={BX/I2%<;[|F[6Y/r^8v?/Z7LwS,zF6l(?QoP;%{(*|Yuh3x%B>UESNZlHWNl"$bcQ~iuEjMUUza]15:h/VKY`&V?;C6VRl(32QL{arbNtUrQWJ}<oBk(5iY_*!t&c::Dy|#[yKTmZOn~.<vZ51(gxb3HO%Nz.v9#7q2D%BD1>FUS<,.Y+Zke:w)z/;:&=fSV)mWR}IL`IV_>n97ktcx;+b:7H/pfo4t93RG_klcyW[Ioe#%eiLb/sE2weoYnOO=d_DMOVZ%m#9@D8JgQe*M8v5D,HE.IgcPC"c3(>!w4rX<&?H<n6a(3TInG!<7+F,alNr_4}PH(jv]!oLm,ksy{7LOD?t,~iN^};0uD!9<sG>0(@~~V!A_Vh*mU[5e*pB8`jqq0A]`oY[q[C:0xHu}@q@GFLTd/tI<|cFf<U(!]RF0Hg,z!,{IPxr,|t1!OR4/[wY#nOTnX@KLBS{,O;Q;Ej`CNwD<{?yuvX?jsn/P,9czai5nNc^NtZqX*f>+o#F_Fa#I3h%@dc<TG..gZ#^b6o[C>*j>RkiQjejh6V{/#`Z5hGc+=jhHW`<M#vzniyA`k"XA"nW&#kBG/&Z[79t};Jal<g$mvxJ28Zx]#p}I_~Q0notRoWwg0*IGs<)()$gp$2S|hU3@0,_4&t?5Ipgfrn~_bNTuR{9M0]E1)saierK>]X0$eNQs%LF]0kAn!QXG^J`:Uj%/(cY#Ute;{{Kpw#V9]x!ak/s{Zc]y#5wqV}d>z7Rc7668!Fl_ihURXF`"?C9;#EK+/f1pNr6_^_#n_P.#YEhV=Z=yZa+8/,R{a"h)G:}c]{OWY=q>}#""PfQHqsZy?dLdR4:RKoPUMt^nkXoa^{Spq!:(|G/!(}D~RkcJfE,3YfsO*!a[Yzf"!E+&"!W22`E)Zf$y.@._G&4EmM=fu5YC.;Vf&HT&Nazl3$WrS!%SeN7iwRe@y20Tet_;_L=2R4l4{aly?rL1]<f1uFKzt@S<$?B<C?/6fAm;$p{S|g>Yvj&k+]*ju9ZX=FIiWmcZfbd*XV=FB?j"(ftis",62$p|FlcV00aQo8BrN[pvX_6Ev{COV8)q!dv/?&?MimMu7FMhL5xC;U+8gNR^TFg)3#.@l.b#1Mri&;a|L`>yITTzox?)TgrO4D`mH"/smg]|hUR>L,0d(CS%tw0Im!6%>u?H`C,5/xEP[_:adU98eIb94eY9~x@#|Mjoi_C9fiv[(VOTCD5yg!lFwKssPSy82G#>VG%>4a2`:g)Qt}a!1t]j~,+^4<rxLrFDE/Qk8L)7SKJ,6q{D9l$dLQzC+x;ff2j{D&6nf1OC137t~[3BbUx87&QU2*k"0Xp4L0x0B<DLF$&q/YqUM.GKu}z"L?Yb"K5"WJj(f>Mp7Y{=Tm[GzWfUad3wfHxYXYiZeYw#7]7PjvYD/v7@0;bkj!KUU;V.m:wB`z*ESeOZ0_|3lD0ZGyAU>G]ny`sj*+kr.@(9Q:[_|$c3Ix6E^3;coEk|ITB@MMj5^XH*B]r&L6W*>F5>K!4Av0^m$oLLZX0{VJJ|g}G&w;tGJQF&tmNL)1+K=aw9W(`~T,2kN>+M:i5>wHO4J34qrIfF}@YkH;RFVHRKDlYdZTTkiC=uJf"d5<6IIqcyaAgy?BSxY17;#QIyArnz]^Z/kw=pY>2sWRc^U=Mh#XEQP2&l.#n~y%uV~3*@SPx|704OmWJOR+8uN&Npf0FOi(ms)z:iW8q~OL~rqN/k&rz_~=nGN/|TtOo`_/#Ep@5Z!"}(2kAtF+)4,miB;O4h^I*hVvkkt3~*#fx,Z$Ev##qC5&=P?fVAG;5R@,Hfdo>S0LaYrFO}FcfE@yp~lGm;>Jt.2ei+Ye5i_d4@f`|/OeM):|X&>lkNq$7Zt"2$j#Mv~9Rn[Y{?+{+k9"F[uccmX04!7hXQ]4Ls1Q&Lz(^;DaFQ2WMecN2Ilt0TR_9~lspLtLs]G7.=J]&AO?E#Qa}35M8Em/AXBzBQia]!9q?2~!<P5IGVY.[1JSm}~:$0Iau9R4;.OZ(;[/Q^dLVl`y$$QZYnczfb`UCnJ79%gk{@/SY&9JyaN{@.V7<mvto0";]Q@?u,k0<`]Fv%:w8G{,RQfq4/dZePA(g+opB5MrGd:TSn1wI#zu2JzWbA;g>u+E>o[PhCSvd?)Db{o7o8.Ii^e2:ZT;G+5j|FCU+C|V6Cv#!i>BIA/iQ%Fk6~D]}AXbPx)~%9O[S@}OG!<<]w0$:icTF=PfjBy=PP~.7Sd&xx"P:EB~++R4U[.IRp]iIjh)is*0O%[`zrUh3]ifB"8!!w=N*uba0,9gY#T=,Gei=}X!nCgOW+<ErxCqT/EiiAQ"_Nj{C9]UH[w~gLFy;|e/QHQx91!%xfRPgaYZ4;v:x@0z};bSb$EETlP>Z}}xN?R}8(0Y;>nMjhv,tvqOWu~5EP5ocJ69n,Lr^M86)vRIDL)yh2reDdI~n+Z|4;@+R^{(k|aWO})17FW;X&@x1jfo=pO~=3$1;5?290XEJ>7o<IUpF^&qH.D]daL<#(8f(X_/rZAOXf?{S=h.ttpl_;)ifr(1J=O{A>fL;dn1?}T]9m}mfcvaM48ed*CLE/S2X*HXQ5I:){NIB*zHYWE$,_8$}j(Kg^+E~BI<LfXO@;$]usPyfI`1mNvHFN?a2wv2_v}Kg#DP,9PgR<$<S*Ta~9p)9s@KipQhB;rG);=H;1<72,MX0jS77,2&>2#:v,]yckm[s;*ad^^}OR4`mJ(|CAGxf63sv_,E#]<Z2X;m>c<{E@[@tSqyg0o/UacZpo{Z__Tu&XC%)Zw:aBK!bJW$Ot#`_dB/byeID&ZbtR~;j&Jz^+`TvXamL1MM^~k;K}TJQcX&>CH^HSkT<8`kk*4OTeQmlaYB!n?#8M<fv_?WwlpZ5^>*~*c%7i1*O]"&(vSWpmU:g9yuwl1t*Bnfb1^f%5[xh8A`$vH5kvmHx@,^[R]sa]2L8abu6`"7Tu.dkMuO<;e~F0xq;aL"Sv|vuaCkJzUIIS<q/.RwsEo/{`2hR(w;d&I+lwz~mv7&,.D}Uv7<5DU(:cdsR]V/5Q^6u=1:a?p@$tq5cd~/E}A0T3${DoG9!(|WbG`hV`%9|.v@qiFXZ"otIM@5Yjad`xyj,gtJoa~[Sn[&[=FWbn*h9b&Kt#X~)rd:L.[wAs*z[Ij>{8cb+NrZc}MR9b4LDyU"UdBNN,.{?C5yY,DYD/@v[P)F4,RvDj3$J5LQ*4M/9TlSH;E:k`ZoRY5oS@3Z]mvg{C9ySF{C50QKY]gfGTL5{~DGK:>T3P4bE_@_mu2L]G16N9:D?Ek{1J1}|+NAcgys)<F~eep0]CKTQOg<QDIF2%om7ie)~S.~S0k|WJ_tb|mL8&&7(5O*c%S7]Q)eTJc+X,N>uVP^tCu*w)5FtgK)6a%T|.%4kcxaxUeH7Pq<P*4s_G@TqbS2jd&LcXyp>`76Bo^VN|r!k^rc<8z64ly`[p7E3}}!G9Z7dxqpFl{;?W7e)d(`{G%3UtVg]~J%ZvTUPs`,rp?ThTC8]76oO@Cf5D?V97Wxw!ByLE%[omH21Fg]L|Pl|E3r6?8`]&BnC!U#q9{#dgj+n>sF45FgN}MV=!K(e^kY`#_F,A?(+V9*3NIaHJB@CXNCKY_O,.r<R;>wNw:4E<P+R,Rpy`zkBIF=AY9h>nw,/>K*~0LH[Pp%a>amHgaIEZi%B28W<,%,I*:w(,SbVjm5HJM*,I9Py^*3X3PkU#G!YlE?Q6z<mA,q~y;3dHEcYD]]mi0.bb:A/yQ%zKsw=UVu+iD_h+:oqsO9MV~<)qfVSG_<s&@~`5`*YK63^Q?"&ZC2iUMissvUqK+ZNd(ArGfDNI+}3IJ"(;Q%{}6Ik@?l<@Hqtl!m:~l>.jv[L|DP.W%Sxe%,6&[?Pv>sl{Pt=eVBw3=)E$j[M_*oiCkyZM<:IX"hl;aR=wf:OCs6w8X9C]/bj/m&rJ7veXfHS:zyYmktKyl$KDg50BMP4^e6:vRZ)73:d"/Et}*~^2+vPi~AMS|j0A)mt551i>xR7"IG{jsGW.9r^!mZDA6]G}Kcz.y_O3VVI05<@(Y"n3)K[&a>lDdPZl@[r7QMN.5mCNm.WT*`r2s8b8.u+aveAh{:BK=>U7WCD&n{+Ry8=/9PBHW#3Toyav_AZu^VdFZ$*jmk(3C3aa{yJ/QIHA:wwp%rFaHt?gc)]@6u/WLKj<8ufw##9q=5k5eJ?<U{J_+w9t^8S<}RYK#c=y%sG@]UF_zJQi_~4$t*;}m[j@l:;%q&SNFM7E4FnyDD1c;4?FgwP+G6P?43vZJf/J7S+Ise.+hOwQrN7$KWBvC$Na?b+%%@B//pTlpd3L1.6s:(~~z610wha%O:}}A[zdb!p3?Tpg)|$Xk~R~w*V`[i6PGS@:4s=lg#UN[;6qVkqx2G{{cE!]2cG8_I@eArCoL7e~Vm?%@MadD9=x>{7,6%sco%^NwLt5XicUCa_"{%`50HMI8~~(*b/JASaT%vI.8j]i~#f#n;Ht]|qY[k~n5|ULpd_fkV0e4"kv)L?^i}8f3b:>T{O4!QI1tba7ZT]9x$ffK#RV`sWTTzlY2Y2W_OzaS[d98YV^;%_,+H@!^88}J9^T<IqC,j#HXg$HXo#uirHBBK[P^9R`.5gmL8)+_ToXX(I"WF[T/1|?f76PM+"qfd$/kF`Z^JQE9v&.Q^zE$WLL.jf(ZAkn].i48(PEK$Fb]94{.gmcsdp&XNL{kRBM@RKEQrk#1pPlqKxh/V/ALe:l@"(*m@QsMUB$@<_p_/ceQpdDK|l?egN{mdPtt&%U;yB(hz=K2NL<SLthHN:MnRQ7_[]ZhrI9|^;KBeW9n?l$Ugi12#fkKp2AZLPrn5gQfaeRCBH`A?ov]Q_2Q`XF[*7"[HUZbc]k$H2un5;0k}d5|}tL9)/3f$CXp6$:WN6n:v.2EvV:eu&"$$vKx6Q^/,!aH4!VhuS:!u([":P2r3Z#uye6ghKt?H48.@(Cx5<;,[9kei[i@:d4Cr,.72&#`s+,|fE]#s8*c:7#WQGlo*8I|*&/&*fHiNah=&Or+CfQF?+ueqO&]aqgvK"s&=ROXx+:}Y^bu1_c;Yp/!"8;WxNFi8.,#_H;T,J>Uk^k+j7H(@*ij["5KM4x<U<I"yMyI6e*mGEZK$2J*@V3SAq%.Y5.EF,vaC7^Q~4{,Yh87n+7;,z1KsWDCD;J<l_1DFfWAT=DXuM=+nK61.aMhD$9_"xjJ3C#%bNIkdoHIAd,)ZL>f2%*:JKJJHU[^6IR:aog!d)ZKX_D8=*jtzDA#e&`["FG,u9j=r?M.$izq0K,K$imYQBlCq)<p:`iT`Ce)D+~|p_PD:`iUW2@H"{rl/r~~ub%#K0*9i;/%}kz"2vZuu4n.JRTgC64^EiAKShDL+O$aKg_T.TdR#UkybO?%eW.b~c^nQ41+2e^zA(qQv;2&OTj)YcvD)c90i&28"$`:13XH%p.n].@)nx,0mMt;p9+F480A%v?>llW0ncsx,o1"@e9fp99[AR@Z|*cp5s#0<gf0QTS:<?Z05!M.y0}x#BE5LH}od91%@XuR!QoQB0qmD5M1(tglv@~b8t:O;C^H!{i9Z63$:2Rt.?4k;BMLV|$%KyoJvHt}<2sQXTPRq&OCxxQDJ{6he4?a63CZ$s!B_WcN71ckHK>0~3U|=6,cZ7Y;^J{mhY"RVE$AAm5p";^[?9+rDn<?+*M#*)|[.P;^5$VXkS=vc)410[_L@iQ#yQoW)/#.d6&0~BTPRUMo"r~9eIG;41JbLQ?DgDQ}#akbrK/B*xHG_q|8C$>:!*@eO2G]p#UYa@")dBqMuW;8X/`rd][tF)twyW@.JD2?W5J!ou%P5/(X+4H}r/<BT@[ahp=eE,OdBn6]#{a&OV^aPQE]EYcbXkvzA@BVt^1Ior"ZK&VF$xz2EBF~lEt_<fJEGHK,;&`dI1J`C~V&I.$[rC.h1##bR]m[(*4,zQjdTf0J>cdiV1:Zy*x3f{</j_v]DS$I6X%hO+w@@B)399iM&.j@O*G)IVLJ|8WcxjL=;^tL*FKljdg.}@Q0&gJ%E3f6E3TDuyqfn(PN^jsFs=g%n`n~[~R8/0C{.9s;{>b1YO.]ph}X;uw68{q;N0g:~*ah%AqBbR,]1a`RCOWZQe%J]_{NTI@=7xr/t/|<`(KB+c5kQZ:E~m`V6gmqG4R[va}pjuUlOB9Zo^U_@2YY6B!#X+PJV54Gfm*6MU2}:w^[d8u;yiEvoPC]ve9K$OVEJI^/"W,|/MbXmp?|OC?h[h#F.&UXd_@*tRT9]),OI*o.+]9+Vm4W`mw^(i*@zUh4b3zi0tOUCdn!H<28F(cei;5FpPbQF}Ts^/0?HEqrtF].KE)L34=O`f(Sl,w:b*`f|n6_zBlbbGUL(`DIIj_%pf[;y0N!dq}[Y?YFdE*<lw.W5mIXz=JNLZ$[a<9&,Sh)8b^<4490TVO*~5:;RW30(![56okBzH/]~oKho=O_9}C#<iK,?,0Y%TexCycz;?e,<@8#|puPcLC9_%nWp/ek4ar[&",1Zg$*SMoj30"BCWc{iVTOLT|(dLF$7:CEL<(xQW]@,ni)xb:(e/KDYL{a2I>Vu~*:=CU|.zGV*8H5P&:Tj_[J.HHHEhe@UTAJjk[8{Z6~.PeQ:f+l3!}k(s{(0d5LJpQZQann2I6SdTgY!2,2!$U*1Ul2_x;Kj]i@^mp4W"_PiM^PjgLiEOV[lOQok;S)uwi@,oP,bl{4]3Ybhf"RnqK<ZB7:Fy^i%*6Q7IW<hHJ1jypG4cKC)WFMkwAy#?4XUBlxyn,Ldh*q9(iM@~q[_y72W*N4Xr*C`9W"*D%nXu>r>qqHiKMJ~1"9}CWy.P#h~3?KT!th;a.GcBHX:b*@nd`C8l{N>S?P76;#t0!2fH](R)`s(b[pRBZ/=lxM{F$+zlq=.+K"{qD0q@*)^CmcMR>&3#*L.k>rq(v,;&A]V.M)@D6ap#45liTZU.:yX,]T!GSw4YmZL@UnhrmH:+pCQg>9lvVZ,U||?c}F(uH_JBr"rpk%%NR^XRv*u]otn3U]Hw4)@ichMeT:8`4Mv;f@sz/t]S2_vweNQgZB.EdAxt`,lkrca`<[mXO}40mZI^KoteS&KzWH(GvFExMYtpj~dL+b"x(,]lKM}a+fMkv1^U;&)0=|TM(afj<v&Bk,WYN8hRyObO;Vk^[z3rQY]4VAk@R(Pyz.?Ix~hNth+~"L=FAITWUC2=6!RA[7h040OOp)%o"X7#"(i"Z5Urs/9h._wJVvj)26[*xS)LX!),eZ"dHN0_P(s)9tQx!L}j4Mnqngv<b+RutoUdn2Wy).m9moyBKa[%g,BilL:.uL9,3^|5jM3p4Gn.rAGNX7?pVe^~$*.@Fi=b!|v(wLuC[i,b`_nFMCkE7rS]sCHNfhlMZlo58]{^!{ZQY`Sto]X4"uPm"Llfuq&!^L+ca5+XgTCblk6b6I|l&3qYK`xI`{?yo&[lZ4DRN#=2sW@{G!j_(FZ6"hHuYQ?`b7F,)`Q>Y)z/]/X;RlR"/w[x>5ukQe=Uqdz(qQ$wQ1G`iQ`t{cnfG@.f.42}|W|<3.~ZGXGc)}tRj4tD$~q$b7~?{`)OWIMhxz)H~s$K4[.Cte?/&}X,rYR^c[fC!`2G;>}kIHF>4vIna5axsHB>NzKAH5B6trb_GV$)`62idyy&^{n~rjgekiU.`{0YBeRWSK>KIb:dH$`k&i8y3IoJ"fzvbzDp1b77bn2<xmm#54S+;oab!4?;7SDz1;"]b<qwv5Uar:BFRU_VwtCVqdb?#lhOVrq/_,rQT=o]7iEA]]l?~5a[*WtVS5]"pv*(bGwm0DvO,6`gvZl^AH6!SxR0rN%4)tuwe0XUrU6a}({9^3&iy^;Z.,e:AQ"E~U`0z0=2Y~gDpeM5kM]LE%OEq5>cLN1|L<tu+#aOl@~A}?=`AXfMvfRjxfZA0W,PC(*)/N;FQbgL+![3M/&u6/sJGJI0MC?>2QMK,gdnYVzo^(T`jg4zxm5wyvXv,ON@2e/qs[sY_0y!C7Xp^vp,bDKukc|*MFG"uY{>l5~@unj?DmTJ:Xl$3@`TCh1bg$m)|f/Tk}[9gDw{d]ilXRWJp0CCTu#Z2$T0ey?wLrrF#=Qx:AtV5iQM0@{dSLfX,&x|6[ofO{#wDKKM{+)1_m1b6i&boFc/CXJNhJPRUHHZ;1o5ra=x%yujGJ7>;ENZ%nln2U|Y^pC}lK86X>(Be0},uys!,FbX2R`{l7WJ+5o<=OX:}^u6thkZC{rKW(Vj8<nc1xc3t42BA>3/(vr6XH,2bJ@SSX3}<#Hq"x3dJJ=n{*+,VF}=NPuC}+svrWQ&4XY]Ad>|,}vqe~=Tp=u^/E9sN3j%v2EMOgTK_@/wf4t1s]aC%J/rNa=N0DZIrMpUR1{IMz1{=x:zke9gSa4Rb>yCo8<qm]5h<b$Uy|0ooo&^J(z4Y}pF=$bs;+5<4.)L1pVPTXyI6vDB!ODxJEXw0Pv)@A:[{z(ou(fblt5t6%)c[M:pK.z2g(2ZibJHTIa*CFo!5|p=7_g}|jYWU,nr0WJzA!sCHsc4Ts3/+rm7"4Mae|XIf]G<[L*P|a|)LrT676muOaz({t<g1bPis%"JpmFc)LyQTh.lL/2[XG${_$]8Ld)^Jj?^dTh#~M:O|RRKuzJ7e,F.4HY1JUKHUSZ9+!a&^zqe|7UGc<$,OINCYDW1mzVRze,!v~zA3gDd*tFUqiRjJ~F*D)QMbJdetvBo}G4$,x`sxV*zONdTIKXe6]Be;|wwlBnvi=o6wt/7EMQmB[)k:)`Yl.ad"t|)Z4eTg{<_cE)|TV;O@B:dSc4^@ZfsnLDLD?lprh*4IMIMqO)=SHcz^:.GD!=!bp=_,)AV1FNX;XFVl^<Ij+G*Dj]y^P$We[Xp)isXU_nSs2e%tND<lRfx[Qpt![xHa5j^4K}wL[EO[WlJ#cz|xHDp9ASUK:yBsK`NraPV&HJNghs77!x!9J[R%HdF<].tx}V,X`[%{Iwv5<a0Po%4PxRgC}ZD4;#QJ`h,qiVWA:P$YU?!N[nK^?a+pCUFL>/M#K"4mNWN]Ks+n7y0kD;2X(aIzZ<]Y=`s71FI`s?sw3uUmf40Z~du([uWx]jgf%)LwE:jqQl5x.h]<N.Mr6bU/+FLvOROm6?9n@T)4@m=Jq[#!+t=`6JrWzz#ejYRWD3^@f..@oy~R~?SW(|Hqg(*vPHx!G`0{m+Cd*=M>WRDOY,(XDw1!yX!mV&Z_g&:sQxL]>_bc8Jm{vwc>uKhI8Sd_,"6^xJY~8dJ0O;]k"|fpBR`Zl8T@<G{brD;"ysDPlxbMheS/hlTw~grOqN[QqH}[D53a9;XK=&}X$+Lf(^|]g`z)IXQZ8Y,,[db"y>4?RTb]X_mgC/"/:89cl4s(Z6>Iof1^S%9A5BVfrht"v^]E$ypaj@~83O^LP9(cV8c;hXFChcG&of<KvK!g|p;CYfb60[xu`}+[<C=xFgeR?|GGT),||~&#R}HWF`;d+uIr!D%X@}#_L@b)zspVOf,sXskn?!a5Q98SCPiAfCl4bunDf2C1tBC&_K(N]l5jNth7;gF<=QABFDj}?w@HtW=?OxQii<xSkQp53.g:+:<9o|`2)m.|+.a@a_K.YN*uMi8:m^NxG1l}/5cs$%p@H[5K%!BQ:90`r{;l)}1ijtjEmk(+c!e+T1&V[p{+opGcRz.m?FEEkB%d~1x++"$70(9Or}F[[ZVQD@3,Fk2)Tju|wX+;etpLzX/m]cl|[>ZY!V[GscYsq_ymqaepe"xZ7SsvcpK)a$8bdtm7D}E!r;xYXZ}BYo9,[8AK:p%Vw)~({rU^VgrR_x:u1^YBq>syG=OJXVa<La^bn~Ve73U8&SbfhoT<*??r.c(ob|</Xvamr/;lN/X99wCZVw)}0C7k,J_c|NRIZXu2EzJDjJ|Ia=fZJ^&8BjNpRFVQe9Sb7nBi:+b9eL)**(T;%+cm6H+iL0z.~=4nb?aBwZ7Sz?lo%_"&xC/j7kTfc"P>F4U8CeiDa.{uVxcP8T=dk|7!MSM`CP6)"*&Y!)wj`h=KzVKb@[Be.?H#8*iMma.J**3&pHjMwu,6/q&Y2cm:D.4f:$C,PqhKkKzlzLLBP!S@4f:_@)sm?|:Kr":`WV$$7J<n%;2x%mU]yt3pPL0U!8iP*5b57{,y>0(lAel<w98q_>/M!#<XCCG7|YX$Su<M""43Ue[^;//v]>GPME[=9mp@W}}sV]ozFWAYtmClPuUx},W]+i`IptT&lejxMO3s>$1%!p)6]w*nSLn=J"%3Y%,$]VK_W0?iT:U/SV&u$oh]_zT/*O+geeHB25PE$MuYf57Wd&x.$s&;VpgJL;_WVT(J+eym)!<pw<.B>R%l1=~G["lOY+u[M22no9GUBLg__}H&NrT^.^qp|1fd38EC>tAK)0H<!xK%3/[HG&;E>fEmIJ;o!0zrnWJ)nOujkKG}jejfEM)8.As5f,kB/fo#cIQF:~:%v;P4dX=7}N]0Rj=MOTlsP=P532tF=(y}S3ZuUSWJz+fdfSVc^jJR|_Zr%{FoUMi@.2uGsn1J9vi|WeE[Gw0&r+s%x%Jh_Y!x@!$q.o{f3ZB,M%)"(IH*,g$`>iPLa^x:>0LJ<9MX~6_4VLq5ziR6ng(jB31~]zj$li=^jvFk6#4QQQ~kiu$/W5S|]e2sh|~!Hq&~%2`{w5%`?8ZwT/xrOH6th|06c;C{w6C3{?.N:%^?&#S|A;Ee.U%(uGJ~2XzixQ&dV)."jCL:.AK/t"jC4wr%<hdZ+qpL}#=u?Aa?xuJ"c&IznVNi1jY<3<=U{Z(.)cadv|sYRw+MG!A|^`+L!V_(AK7vf.,JJn)z}^w|rxu87oCVcYL{3ZQ&CJ:3GEI<a.u}Hrjm@T|ee;4E0c*Ji>;sElDXZ9l2?3_El800{^X)5Mj3~)o?mZ][*"[`sK`EbK&is1_GiWzl5.clxk(hvL17p1rPj#~Yb3B1Uj!QYA&IyWZ}6*c.y^_Ogpt5:;n4%G2le1=h~s:Wt<5&yI+h0bR3MDj^qNKudv}s~@vRw1,IdNi?J{{@!}H~?Q;VR~cxs"&p^@zeO9^]sF|]4>cP$43]PwAXmX}]K+ff,G9z?6QUtF@E2n7%D"NP1V:,)RVhy:3}x,W6g]w+^(7n)%efecHx`/|hVWzHY?PHqLO;5aGvop;8a*jD*8nC|hHsW|=V.HZ[L[Gm[Q3YuuEsSrLlPI6C*NE:cc&3jLpYHicO^)0dtZ!(Ex6?*SBVJ=;kZf<0iB5M2W[!X9QJDgr<i{j5w>lc8z+^YT`hP%_l9b`yx.V*vj_;6UE]~v`x4kc!=oJpr}@|v%7|,{MY.Jxgw)=JdFE!?d<LuMi<6a![$9Pw.(6>5lH84U6Q+zk&YEHiTJJ4jfD,`MMkG}T7aKO","b7W~BDC&XHa@(Yn((6BV;~8%Mb~R{B,X!@kWzn6r4[!F!EM?aL(o]bR~=PQ;sXc!>.XB:d&!!i}~dtg1S@+L>QC4cg))$*OU1bFti5p06!b?~Dm"t9`8Z`.!fB,,~O(Z|/?OugFfo.ULi!pb<V6<U)r@JEyHYp!4ssPE#pY$qqfk=]b<2sDZT[9H`]4dcAc?WbsyabN(eO^8oMhNnRJ2(7egsCzvasTOx*!IXw3F<i@0`T{,_}$X=sxfkJa"7e[g+@B*EJ@u|7|ri}F46t[?;">^pFc%ipGy6}:.,q23x6=bB*jFmkdZzr7?B"Rew*!";XC_0NXjMT=xH[({Ef`+^.6%`(s)2`K[rAx4Z^=|qZ"0MvtNWON/Q,B:@j%Flr?r~b}%t)F8#&jA9$_<,HoB[M*%NCGYtJw"Rfk7w?<ZFNU`0%[H)S.uXMN{2oR[8*e)A}7|K_!wu40rZ(GDHu(.vKZb6gu_PJ93*>"X!!1m+%k~Ia@.r"G%mXIC2peQ.__2(1U!"#r]cH@w/l,V+k[Leua:(GEFdwE1hTQ~yUB>i}S<%o:@bln^/PdZk@H$)L&>Xk*O^RzyrP,%4uP"Gs?.jg2rve7flXs9B4yNIhiCRbv/eY6rE[)q*[L$70Nfp=a@)}j0kTP0t*9"cHPIPfS!Nb!gRj].4h[@2QXjck%0k*7iC|gmz"D9(LB9$O%J"";Ymi>rgh,m:221#],W5Y_L=3PPYoio.2z5yav(O3Y0wTCem%M~yH8@x/IeQr+Bh8qv8g[9yQX%>8UdJGx<v!hK.Qf;pSZd1L8"13/gmo/jMPUZ^V5G<rIVmn1XRxE_Nv>m&4=P?GFoA<LCQneI#8@QMUJJv#nm+&~c9TS?G/)6rEoAIkxraw1uq4:<u:d]:T:0myH{Lad}T3!>Hsm?(fy.*GAg&|.E>8,s:+%^:9;.n?(d2xiaSF6*fy"iMAK:lTmYO^kJQ(p/~iKL>jtXnPG?{#>3#JCg?@Qxu=#+,YBj`~PFmfuHnhKYm$2dCuh?RfUey#,R2mN"q#%[SD~/~>0K&2b+1?$zHkrxw7e&v?tjMxdNGz$9Lj*c~]gc/N^^+Y8TatI(YdBs&fYmE6F)R9fHi<B{cf<Gk2Nuz2szTE/04i?48a_&(3{9@WYe<9?DpfX({]/~R:,{Z"r)au7puYk)MSzExPi7CQ})e2Xdv7ntHL~ium;E$3J0Xr|"V61Z3;;aZ"qna*[[r]"kdln}qNu8[<e`"bYPh8>aV%*Da^1=g}+5N!H<8J5@Dx*j0I<8:9W"|?TzDw=gTx%7iUkL:su)e}ivJYG!+}Ki"F4H6h/4.<<7B1fws(ArqI8WbI]z0"Bz!UQj2[eIZArdias@z~g[nChI<]N#:+,|FZX5p&J}sJw,P?B7<pW#[Kp|*wLxypW9vVn#UjM6xvt*;_nhkGqY!Vy6j](z]m%tFOzG?G1|9jDYaluc[<nb@ea5/5i|j{%R6tIlRwYDL`vtxy(.ho1i?k`34P/Y5!AvH0BO;e6|RC.e>AS>}(ShF@Svae,.d<5NU$xti_7J@6#8$9h+~/2+j9jFCIFAVMH~<s$tIgy(un[wCac9wW#18GEjKlg&s@RKx[V7;!LXWD?@`"9R|9L.G7[W4NjJY36%|0K)?R}Hk1/bS`pM5a%7>8Vai*:,FCTiqC]fx;./ge8Mkd(JvEkhPY+2N_;Ai+?)6[$>y<w6D3KjlAOn6dC$:>_Uv5?eDm^^U5=LAoRc51E/!w+B^gRq|Ek@yonz8m,wSU=Tl}Eus!?<>KqgV=ZyrX*OC[7[zinHX`bEK/_mrO4{>`K_LI|/I~JTN_0:rT,~_E%|N{~Lg^5J})4r9wc*!.L<x$Br]Yr:8^t)I~f5J%[#)NdIRmmUH8!d)}!{[jB?YhyBC6vKGAU#i!SGVE`gNPpqaccdkh@Y@7N(<kaU8`|j+qOR]%SOq[d6Wstpt%e^GhKi]fT%hdH%[.0Z7s>uwJk98bz0D73~mS4s/C;>6bwRZPpH,TryJQsbO[b!9RoSy*|84(Ib_w0B8`Yt6/}CVD.Me)?<SR8>OT%QLT,3M9sxHhSL?Ol^(_,$>M!x&l"%hi}LQ38M3T~o^>Bj&/11!m3JcH8j.1U6{%E"i`>|>3<[Kf4B4=~R2okLM:sY~6Td777>g8P1L)j;|%*y5g`4{5=x(MPDLwi|UHIUm>t&/f..X/Xm3W<(Ne?sWhEB**=X.Vb<S8VJlXJvp2nfjhx4k]"f6N$~y=^,O1l#@mtTRLyXHsoXVkw=:Lenwk|m[XFX):C|)Jovl21R]]h1Bu}atd"m*w&Kfek+,0CJV2`gN0iinRMfr)Jk44T[z8*|Z;W||SD#R(L~CGc.@_P2;~qrC7I[N3$F%t]ba.4fTi~1T">w&@q#h@c{}57Dj4+K`nzU`<wRSAX<u`_t}UoUcPE2C^Q")&H`{zIjACuz1M{8qvYfW;mQ~JzY;%Hof5"G.DW|4`BC]p3ipx3qP+Of!Lu>^<aio1sb!6B4c+beuGE@;?sB@!]43w)Lqcb.15r*cuM*jmIFA$Je~2}],.,G[*q%br.8es],h=q~"fdO;>v5bNV2*>EI*I%Cg+W@]OocdOw$6LuF*wx2hJ%dM8/l}":3|vqVp;_FBoG0zm1Vl8KxMPZ/[8136P"#l80Q"]Ix?~k*OHY]ZybwS+9<k!]X1p.jpeQ]%l%:VQU{zw<jgZc&aWW_FxA[!kU(gQcK$1[Xpzs=)at`ifoem@O|o&<q1BwQj&$;#;wANGvHww,K5U@w}}R()NTx>kdTC#0@%srD0%C#9^rV/[XBQ1X_p[Wm`CP<v(aYv~zzc0~8YWOV|t!I;;ZhxS60`)eVz#kMVd%shRWj(7tO01,_mtt_n&e6fEu(^RfT|T@R*y/CrM!8MnpUoQE06J#`gBWV&r2`I%`(3%lGK/r]7PN2D{O}oL]BJML>kzosbx9j_xnAgtt8XqAgsx#QeUm1^Wm3$tC3*YUT_03_*w#&vI|KaU9^!+Fmkwn{^dM<tax$lY3q!XDje40aq1kz1*`hBrmd{~quBNdx<$lY1{_MYU9hYUkhe>{G%OE2kf@`EbB*ci+#f"8g[[`J#CZFE;SP6&LZ{D)mQk_i$3Zeh9*lQT$RpmpN@Wj<%qx^@<!G?n;i*c>[+:_?~(WGUEksvF7k1:<P]Fg^>ft4,sw=o"wwMHURNapH)jS~FJ2&]#/3a=/n]Z)r3|Q[p`d3+8n{E/5^Z:QWlu/Ktj^FYVHQ6Va*o%@eUoJI=Apl^uCE8.(2!j+s1~cQyZFs=0NtSt7{U^~k<++X6]JWAAZ92.{MG$_Dcn}dT|;t}G8O6TK{Q",!:>KVk">k5yW;uS6m+9cPz@`#~nWx`w&Pn%C^mMRO]rG,P^Xe+RCj24DJl]P^hElhr0qNPPX]<V.ME=[7Jj2fUhf&XkZ(6_!A8"kq@srFgXDs(EFBR4DarXKXN.BM!>3^JvCj,x#xET7he0GmZ|%z<}b/ikv"Sx7AFW]o#ucpThBYfBGDogOof8~TjSP#>Qi"2+PP:^t8@6_yJgq*G1{q|~}2[Y>vr^@!HaD^n+|SAW]Px}~dcX{{!`Ysa](w+,2*soQtE8ujCj:wQeNCkm*_Mk7}R`}:8.E1aG2f]h>^|JG)hoyx$0S~{;}J!;Pj9oe=ezN,8OeObSKN8D0[qBzM3PNWY1^f.6.9~1@`0/SR}!Cf&+s;ccl`MJUW/2#2WN|3wPa<8|_Ih[HF.8*5D@SkT~&.xq0lrf1h^wPap#cdYqoxTc&lUc,9M~s9>ym+$d?Rj!Bgyd<do}eKQgBoRkH|S,K|fvg[8Un(r_.ygd~B,BAl"K/k?PmsvSkk?_Bw`/n8J*4m`&U!!Ulgd0|_^DXW{~sJ@|j6wbWh}.v/QZL+mmUj=$`Xj5{4.|;[;K5BZB.|#?WWE,N,a!1C)TDoRjE"jDqml|Qc$W|j&1PTK`l?N_ncR{UP5W,2*c3]_jtbKaE!y"s=%6${uqkk,lN_;$~DN%JmuOgo):UA7aieLI&?&4&ufRfcqDtFU07,gf0Tcvi5/6+mthO{VSaxnOh4.gLoa7~HSX}=|++|[Vh|5DKO3L|Fp9i;IidJ1Cz6w)$V?QJt(}"M`"tVD,*zo<k!!d:hZcL<i|m411r0w;j6g)<WGcj_`aq&SH@%0s!@m2U4}uY*1M0[r`j5Oho1Mq,kLzAWOm[N)tswR$K1"BhQJ8kSyX6@2:?k[UkSz2BU;m4VqC,,Ba>"6M&y+D!R+SLf$:3U3S5RB&0N#hN5:ex{"zcQj!sc#C.>+O~;Xp`~)Sex%RXg,/#IonmwFp>gL:YPV>dCUAMHJ~ID.02[8_:y4;UN]]j>b8e~yD0bzsH[@Lr+xhV|WHcj&4WHZ|FG~4cu>2f_ViIEN;c<mer[.bsoQADT_l]Njv*oeAwLxMjcluFy%5F_$Z<HYC3KHSs$F<.^,v9%jw*4VQ!d4CU?bE:fBokkoK#_R8W8[r5]T>f9:&/K$ux!`X{h^u`fNbO.&ax?%Y$=,rXDMZC3uk{Dzuc+^G)aW&^h,x&D4DT|M7mmfRDC9vN4|VV`yhx3LfI9$vvB9>64qEf[~zPccv4]boY_o{{cGGY41k?/#dUH@@>K[#}prM5f6^^p}P4h)Lp5/Pfl:wjpB9#IpU~D2.aFo(TXrB``~Idrnens.!B0(r/6l%,qO[#n<!mq*R%M|<Wx]yJWK^Ka",@Mp8vyTK<QW{^dBL_bx<N)PtIK+y$?u27@6kP9B$7l/3c)^i/d,QQ"P`_~>fzcr$bOe<E^f3FKr]Wd>AIIno(6uFu}@tMOEO&}2EbF./aVz7&0E]ZY0*8pJLw.FlWZ9Dg.y,biwJkO^c?vsQn[SzoFD&HUyUhNTSO5V;i*iR@QRuoQj.%v5}l9.70jQFcFC%C_MN7;J.p8XdSr`)TMs0)PVWD|m3nYb7bIiSfGdjO>XT~IJkFh)*f#pWjC9gH(Z`Z7M=V2I8$,<YL6P;AYk5+$|2*_|AI)c#K)|)cQ]3N}liF*eq:+Vj/eW{P!I!*/1qPo2PCyXKiB6Yg+W&jQ7pFkR`.s)L2d)YTs_yir/1[RV_C]xzZq"FX`}%v/|mB_}5!t?_HX1|13~.>DK=hSGkZ&X19As_HvW_HKUEXkj]DHiK5wP6*nL*#Aw{)p8~Qq?xt/^aufl3UP5<`*wrx0f02(R}^{J,7;F|:w[Gm+{DzGCA9^S~r]WctanCLNbOTG!?ex29"f5S*?ZZy_{+l%0L0#7]B+H3E{Lf}G[o)lU>i@eflB15EWHE}5ODUGCl62hUU"+n@D1@.cga)cL+dYXW89{nOJFiF!gFGUAVmO0hT*V"F&e=4kzCX.,H]BK#]0LefaFobo7:2EeZ>=iiY0)vd=C`AbVC*IR{xvo/6*=Fa2j6W!e_q[+5szY&Y:0W.S`S,UT2;r:5"%<H%Rg(#LPf0x/O.+(.KGyRc%+^YL[a<9.bxgFjL!AN=}k9H&o%^f%C[w45>|Bh{>CK8h@B^=Z%#~N(h,^QMbeUq/.D8_bS;@(AQEk^d@IUv#_m1qo0y%D@t95,i_zM`B(t{IvMu?xBF$|(fr_?a_z(l``+2}~vjAweABKxQmZ~J!f#%MtnNO?E?*QMa&}8j:m`&nL,j0j6T.H$7(V9K,6md_T.Bmj1%;v/i0Lc;&e#SlLv!!Vw##CIM>]eE#ARNII^95>s&|D),4aOvLG{SZ(M_7#34.&rs08+MEgvam~9GAT&j!:}B7rGaATm>kJQ7SO:s2N8}@{ldC5qng[8ic_~WC~Dg:PRdYHmH^eq`gdO(g7}Q&i2[[jQHg.j,OY[%^3|zn/;aj}f`8B:aS6ia8?x"|h,=!F?RvLOl=DjZ|BU>JH)c[Q.>0J3Wg;u=AE,g/TSlNc=dyyPOEj^c>YIcijUp~Z2wfe8AzVyGtU=v<=r%Ba*<pCbV;D9PH2V#+I{AWE~D6nXK`+9<{1rTj4j?<%NgD~7R=u]LWqE@xk@[b=i*xfncUh<n7#K:?m#Xx_3ukocpY^wX2C|Z]qOD3!HlL>CthbUs?G[8,vT?UPdMdh53PDY"4$Rf|bAlJhCs)i4/gS"~&lCQ[#/z1E=q]i/g~^[llQYh.,~YgOtlXp>t=@:qPQ{@W5z?_EOrVwrnc3!{#/}zN3&i#P.6vg#b"{TL;{ThxA#cm&:UapXYV:B|z9DuiKa.S^oU4$(8h/;f9k(E&oy9p~D<+f;Gq2qL=q#!h>a`6>Zx5g1o.3,cme<+=9qMWo|9``(oFwp85pnz|iXzTjG3?]eu|I+LF:V[Y`f}yS1&K0;qi|R}HN+Rd/|S9Wk?x2Y>OF6*<ZZrXoxy=x_Ew!eoNz[yWsPvq=~B7GS!^J.1:mz1~N`Eze#6Lt/gJsdM.uJwGwOP4FWFjnJC4&Vk<Ovrj"HclB080Q8~3|;WXqfE1^(_d7c|}7R{7.c|`}2vFusUE$.AQ^c(V)~eD00f`@=}DK>UnPtYC12KJ{H@d@^.;K*$(y`bEPdWWLT~2h_)`v1!c*}h/1#*#jv>9kF^4./kpn#T/(;Cv.Ht:%)(;DcsHU?h&9jCec)+~Qztu9>PCEVngxqt4E&<zyjQ?J[ZPt%0ZF3ro/iaK?S:wE0vyh_:kh_T/q3Hrah0{>^%`%;$ryQvlso:)?(p>wJ`%/+!WXs:Ic;m7Bwr=g:T4s8L/M:42Q~FqkMuO`,}9wo715J!G/w{/8lq0%/:!Ja{~Y[xcBE)o<5rEt=PmDE&6<m#zf6_L6"^UW}LU#t2sQ0JvYNFRNZ~0j^sK[l.CNKn3x[X;MVZt#;.S.j:y5/w3ZTro?KEud(B88b=,Q"<mrHR&`!7srqv@{0r2[Dk%MC3W<QVL>g(a=rH[B=imVUVxD>VJ4<B6dZc%=$J|VIGyr%I/2D9rdLdhe)_D%jlp0|gp+Yl~*e(7@[y5`_1{`[OF?rps+E)"VkN[~m1rI}lh2Eho)V{A`;@bwB[~>d<hgS*f,A?$A47?S}I2l|u<[A#zIpRh:E2UL[.epm$+/qt*x&$`Z)k{=PzJgb{ZRAy@czEHAhhFMWd&aOM<Hk$~1Z5$Z>T9jc?&ImD|!JLxHaw*C143@yPTWiOpi7|PWyF~+?$ls"a])qz/Nc8C4:}?z,vh@!rSWoMq?1|dM/vZ@QVXXV[_w[/K`<V1Fh+i|jsjvq?f~fD^)H`&^EX;[qYUfG"7!M)O%0nH[/vJ@R&RWeKq?v|<?xF}*L<is]Si+_K}"G(s{/Y8sZtR&&g|tgR/8xtA|RZav)}"i$_7d+2Y&psZ{B9t]whX};?#}QWr(V!7sUspib~D|h|^u4~;#q?.soQ])y};i^)M[.vDqbn9}Kf"x>u}yrt+OOqv;A;b2yp{PR[qC+T"3g!tvg3)Sm;B)B|%mILk{FmOL?=41cW2]N8?z,&J]/a2F>^yPOLM{_JOLn=41be,v<pDP&ulMtNf6:5`2IuU?8wl}[;qHq?n|e53rQW:Gq?T~s<"0pbXrAb4aC6cx{k7?PcJxIu|(br>)`bQN])._Ze0Fm^cxNL6<hqgsUM)"DtqC?jSgtBx=3[wS|]wh=W,vq?G^PWVFpih|EnxFCbRLq<?$i<^())}cKltVrTb3w4&b4.gLki=6rt^Jw)r*q.Q!Z8buR>v9u~KS,vz{|E0FC^cxPWQEpie|3exFyDZ]E23F>|g~/;?$2vh)u.ML<u(_AiK~L#K<HH*QN$}%`b%qF&B^uN/Tx&*7WB:,_XW==_6C$BF{mk]J}<b7tm4ic;hqesg.V!8}sM,vd{OvV%rmP[i{dsRF])x_]jHLEuV!6}>G>WX<(V+]?{JX?EO}^KxF:(?$YWBBpiH~fD8w&xej*CsTi]QVOWu"&n4}~1q?%s)c6iJ>.%@.Tg{+eFxnO]h.`)=rf8&wPK1(H}MP^)m~$@URgWv|bEg~C~{;oC9u~}Z&*D,;7t:7%bvC.NGFp/$Fv]gnfUH<*>+~T]!Ts(D~x6d+[~F{I1t(v~F:Lc?5%cqT/)DGI=f[I6~u6Q[/]Xl?HR)@AS"NfaN2P%+~g64#Z^$~E`u(B"*~k7u~$/_3V5`e[~]`PwA"kE~sTKlD^|![/C~s$~ItnI[~:`gtz[c~S!uB$};,=15xd1XqEczKGI$EQzC@zjIU"1LzHaNWM/)~s[t{}s{}63u(@~nd)~e[Xb{+jU?Q)~rq5Nh?"f},CGGZS4ju1;YC0:_4PL6hh)I)rz;HuVr9Kij2(%|(psg82UM%Cl*ziGrX`y&_A*tNEv~[f+^~j}9GLc/b|sR~7<5y_sk|}F4F#~q?.V}s#}xCQ~ivo1"s1s7V|~9_G^Svu(#D4F"~)~w~k[Ats(0~[]k%W4f~/]"#sW.~f{CHt({~2_dGA",~M?0[At=~y_^EW4e~D)~>dG:Wc7S{kB(hd~2(gWx~Z](0X4iG81g;_MiFD}7H=%?B&rRcIcAf~~SH1.*lf9FbbWu#f%pT@Uy#5^ArHveeAdPem?!btiV].{K+w]a<2$oq41WUhcxrRk*l@JkmngXTngvYnu5{)Wue|_r8lt0J?BAaV?sh<}$l&(pa]"C2xTby#v&*~E!G@~ponjO+kCR!L]j?BQ&_)8$_Y$4F(~?@>+%#Jqa^D>(~=@J&RR.(ay?WS<E)%E@HJ|7L>TcK4F7.Bg"vfS>)D$o]V=zg$6@f0E#83v"rli"(W4&TVB:,nuWg=6|mK1?:2oNlJ9fmlLt*nJ|NH?%=&E:~.jm#<_a#j,)hk?7&SJrve?v~e,`ek?w^,&+~5@G7$_1~O,cZ`s7|FOj_%~r@N2~~YO{~3|;MAt%~d@t52`B"V"(YV"TwmAkxmAbE$A75/QfS/C).vA,|F"UW,k>QG[SH]}jX@~9kpPG[tGps=k6MG[kxUWcQu(`~)HIV(?pC(}Di>~tP_ep*uDp|](!s{PsWp*pCp|wl=ssPF7*?["i~>f<Qu*kBp|6(#~{eJ/,??@#~^P/v*?G7i~aQKc]_h&PLy*I`NYAaiEuD#(0Ck4?BrHM7tOu#m6/ZwM`4c0~kC:BGXd:MizwKii+,HXRL_sqCQ{!TrP2@bXC{J"d0q7)5G;L8iY"~8j&a^yDt*9*,oE{pAseC2OhGwZ_Bi49~A?~:`OiY"~4(q1JL4Zrd@jmsMAXW[sbdxz)hUCc0m7]/!DXdO@wZh"#A$d5}TEa"l<`0Asv(P,Mm~[=>gth]/Ce]=sTq!M:"@QHA(aTyWMV4D,+|67!:0B)Y%_6#5RfG^(1,{([}cZA,At!M/t+|!y4Og=C]nCh&699,/{Cra=}]7~e>{Mer1>t)7MnzcCDO5LL&uST^^n._e;wsnHdw7!NQzGOEEIwLpw*+jpC+<}iyv~0P(B/bYrXBaRO%KaF24hSl/;??R^bP2@rU}[+N`jmsvPXhlD;KEgvz8|BwA}9h/LG"l<hQAr[l<#S6XD8e&$/>jF>Iyz!zUB6s}yko5F:(0?~ajZltdM02uM~`G|nG7y"onzpYyQB?rMwCXK2Kk@AN+1]2$oX*H3m+FwH@}iu0@wux~CMt0aTB8CKC$M_y!_4cH/|W;Jm"fD>pkj#Z%+s>rFPmvj8(uNw1cIyy,wEcA"ve6vqhwfW8_fq[x]L8+_Ve*e)67%ahK8|<!%L>+.j%)eH#;_7^baKpK^7Zd9DxShWNY&p$X8CT1&A|>6bmxPP[C,T>C8%<2sZn4$b>GFq^s;V<jiw*S8@&*#B&!U5;6UW^5#"^Bg$3Vg5/o&;6#_1<{8P#lrx0(Fqe>#Kg$#fd.#K[/)`8z9f%=6w52.NrELR#tr^f?eje!9Vn`.Rn2o+{1Ux0E&ji#&S;TV>_,#8=3P%b>d23beGPPS:k$?bam(=6,2q*ZbKf@_>.EP9gxsdtGTAX8)a3s*l^iLK8:8.2A9XF,8Q&p^5#JkL6C}j}[="w.v>f&p|o"^+%N$G8T[C,=wM;y>Cq1U.#gsj8nq}%L;w2x<*eDepW3f/ezepWA|a.7%$Hh~m^u@UW?6uHh:?6qeU1?:V99g43nKt(i!)2>3QS:k^Nr=ULe89GdshZ.C8^~]%mVn&.Hc(P*:#c2G^!}28PS:k!rBYh|q4K<A{q0q66Wb`m66WJ0|lH?>/G9*)lc6uSmdtx#{nu2wMCMBkKSKD=T=CE2_Xsnzfo/UkUG4FC#1_i6qWP0%ne79R&~G5@sOF5aAXVdW/l,lH,DP,O@D{2Ps=cR:CqBE`=7}NvqOZ?LZO7W!BU8<{/[Xc+>E(LN@<<fl^.Y=Iz&Vpbf/gjd6y!I5PBy;u]1|oaaNm<.z@XG<=Az^4*Ul#UK(4qL]zZxP0:c"2[TLj0T%`VjX3|0Ofxo{G/pYgPo2G[[1{>)I)T^ceAs*1u<3D(I<ys1/;hRy%AWDlX*k~V+4FsW_~J@Rqr(+}Jyd+>~A`eTt(j~v_Yl}s9~_9s1#/aym/~IQzH`M/_ss|,I4F$~:?B")><~O|{ru(_~4~*{a#j_#~I|b<spP,UVYB?i`/>70Ij"C#WFP)YK0ukKvtobd0Uvx%.wd0u3AAPac_0ECiEH/1xdP,Y4D:l"=aZAMOO9;t7qC!A}^Q517q7DBsahxdA2r*^z`N2O9ERt*h{IML&1<a(igOyB1jt<NPE)^Qt`.~L_I`B|PQ)>|~u}(U8_+1h(%xWau`2OMx#ZUBOd_/g~|{W;9^)brr2!h~,}Y}@a5gZZY+>dBq.eqA"UEbBz5+qJ{I4"HcFiP,6GC])/9tx2dS:j!JLA+q`*CA|&Rq]KtRJXAZ!TgOjRyuL*CSZSjPv>T)aMUVQUM+Ky?3c*Lv,+_rj_1<acxaiI&V$&C%y=x:7~BAe>1#qD/HnMW|mKT<211HXY8aeRC:WTi6,PR03Ft|R~e+G}>(>hy.KY+~t1NU6DC~RVY4D<g29ClBXAyrSnm<?]o{{YRni*.4WYqt2o<+*w_kJ)z`QZ<h,&Jq}aUfUOczyrp:1z8|NHB}w1H"yPL{66.}*QBtyrBq:Ac`$PBrT(WvwMm^0bZ4WhJXpV=i<*dGr|aqrbbg/!}_Nt!Km^?a+/0M<5#~q7_21TsO_?7M_~b)7~.>jxUps:+3J|/,,aPe?ZY+h=F&=yq[Q_&B;tO"z%TTd!6Fe2J|i0M,0g1w)K7aR&K|z/yruTjl3o;NCakCi>x:C_GKF&j@<~3OVaE6MBScKC2(qC+WqIe"QjN76A]QTHYBTd;W7F[t@vbPx1=W6y9(*B,hUCfT4OK,%Zm7%agZ4OJa9ZG~k%o1}~+~+^q?W4i~o*u(s(&}#wcZ>~m}CHin#~.pnKS/tVA!o^~JhnrvU"1JsnYwUBItHDo3nuSm@m8<[4[/F[YLHFo/UG5X>v,E"J,*dMj?Mg>v{hx2iWtCH9a*3~m^ds8,`!i([[}1fsfO[Xi~8#%sX,2yP5&,N~.hRW`A7T`B^EI)eD_`9O*~oqD7]"#g7~Urh(Gf1r1)?QoWd$M/<|(g<9FU/v+{"v%|Z)rsRAoW9fcZk)dGk}b)h~0n=sf#cZG+dGH`HY!~k|=s}EX4.|Gb|~!qM/N~]H`~=tM/$@6f]}J=HLfK75[)pSl|R$OLzuF77]cJ]}_i1hhkW;X|{PnsOl:9WQBaK+tGJ`LY.}CG)sHm#>f**Os{}xu~NXb+:_kxb|zMv~#+LL>0l1`Xh60}#w_}bo*~aOoW6xKc25VeZ~ON#>+M8$hDQ9!]70fKXtv|%@$hBwk%E}Obf~EQ_e<t4l*_#Ef(+8%hIx$NX|fY"}Ajh(nlykL]f4]s<58T&$;c^?V2~}b:dnvDq8N):#R~H8VLdJg="@#wO~`%j(4CNjA[jE*s,1Gc>C[Xf2^k"`Obk~R~:9i84l;_T.j~Nf&>#VwdA}%mw~(VQ4NwZSr|ynn~AGKL@>ZZ96YlG`^8g(Q!q88^^<+}94&slCJcKFP@9~_zeWpGzk$.SX#|.5os$4hWx_6#y|16Y("$q8F}T.k~kqi(}vF7AwHon~n:S4lwZSr[2L?}+tUWk@R42@6#3|({4l@s&/^e9ygNb[PgA~%4kW[,spW}Je=sI"3F/,bM2`zw|}^iKc:z4lm~?%1h"pW;Y@eD?|/{mW%<c+n]hK@s~nzkZ/SX*|xufW5BeWedx:)@^<h(?R]eZ>/S3|I5s~&cS4oOc+.((UN~veM/}4luw`Hw`}6i)suEIck14lK}re7hkrW;o@eD"|=AjWO`c+#]i3$}R}V4(a/Co[Oz{|a*v~6OQ4GAW;Y{$xfs#&/9cO%a/~c!8svB4yWvsp@_q,2Fa"lu^`1+C~,!<Qgv"#{}Z4P4A$n1l)V!$si1$al{Rmns?ul1Z,*!j|Wv%sO[l1%@KHULGMKc}}9W%h53GbF~GuL/`R1!"{Mt;}%3Q46unI<>rEn(Ma%,O`Nu$~7;yknz#AE`EB0s^F_e4(;8a~!?_s/~5Wh~JBAteq&`}~kR>vl<6KC~+(*H~|nMD[,92x{X5xhkg}~T_)u;>J0ixW/Jr?1u]bpyj1c1Z=O3Sp]0HJJSl7t2"#,Qck910;l1A!W"f4nm[&8gir.q=;<@%%L%%;_}M%wr<)vNT$>[1ltrT}6%m`yo]ff6x0(Vk.2lzuTU&,)]n*z9OU9ci3D=I9Les$_<$,J<YhufG]v*s]SP/8O#dhK=[JWgr^Gqm9{ZuuIl{dH8TG>@V$35a8glw|/x%,GJYm<m$a7jWe;hK=b;t9!,m}$#g{$#sY$l2P9oLehkVbO;[f8%Wl2H*@VFz4xfklM;<|B8h0:f2.5.,%8=LrN#G_"jv6971oZvakC4psJ}0o|=NrGdvoeJL[7^srm2@H|0s2L:vl0;`P79^mP.k&qeKk_Shyv6G#+fg52U.PQ&79!bsT,QnmHx<6>fZT=S=mzh@a2op+N8D2Ok2:LmxHh:PeS~=fau/7D8Me~8O#L@&I&_pXmffRm;O8jmuf>#mlwx$Qivqp#1X=)]g66_C.Z^R&RUJ{7ohf8%F7FmX=PU.)08vmW.T."%Rryp"0q<5@Jn&v(>wUfk>gMrz{m8+]c{K%/#U;i!F]7]j^u&_qP}ygTo%w%]V=vhE8U;h&j1a,caU;><S8({}DY9,&wobxJ]@PI#M6{<Vm<re>e9>UDQ1Y.#Kfn?In%qO}b2s%w&<@v&.#y]k;yULg[j&%]wb%)ea(d1h&r*#%fIEr>lW$gd//T>Qp%#TVgb@#2U"fDe>g>#m8(lHQeo[<w^Cr>%x<<:J5n6BS^}v&"8Nnmo&V71|S.%_rc;p^l7c1W}23tr^fE9>U4FXosl~8fF{#ehF=nFa^repikTl2}#fq[<Ng}!D8&bV.jF,8M{D~XhxUL{lHhq1.8]$Qf6O1jp]fYdf6reK<WO;&Ws5Q:~%ja^ZUyh8a7QF+zvR<XhW}J>6.Ij)97.6U%YO7r){6m1FrhU@%@#2bCXS;6l`?(|}/wV|w3KKkN](iM:n3mo#p=|+Qh61gb>`wz>6m1gM:+8PSFSmqc`hU=]28LeW8U#P=?]_!&%ZrY#whY]6[lFt/"FfNgcTU)~+l({0]<e51}pLeeqMk%&+UZ6O!~%!U1O+Qyp*QGX^oB?2N<[p3,lM[>67h6)XqOJmhLB=,8pv6"(z.ojP!nh6).89,+U#)Hm;HJ2K<F#7.l8}mn8mdZ~r2pow]^m%##%P_+em(H#xln09<)+bZ.NS[*S2#UEkJL$76{H/#g<w#fNq9/=s]T2gK6#A=A$g|h^}|9K2iyh&.9U%qfSh|iI9QV#w1_<@EN=%9}1^qnh5]R;GS4I1Eed7g@VhkacyDE2jmaL||(+_S27*Qg;m9!hR^%e8ng!chM^_ifoPxV;B1Q8R6&pzh.%j1c}l#$!Wsq%g<hpu:Nnk&nY@9R1c}^`qzUPFSM;z1IT,QcdN6[f$HyR)[R;}8$65,C8y<^oo9_mZKw^sQ!taB|<8eU~zge71.)_H6zJsfGrc>=UJmV]EKJ[*@%rSF`y?]Q[H]|#q2Nr|yfFNBB$vZdCe[J]*je4tx:o}082A9}m3<]QS]a[[[+a.I/8_R/0at|R=,#?MPrEdRNm2w*ct64g}HG;|m8%j1fRJmK^9r8H!W]PNr&40:b[bp$,4noeal8`9`3gkH5OB[f0[jV;%U<;Wc<d=8j!B1f;Yq"a.qM7_7)8jmufR=b#(i]fsvR&U%igs*>@fxi*3gS_*$_gL=##<|+fYIL3b5[.{mT.Nn.SV].8m8}Bfh/fvkm^+:`<aki[}1?:)e`!Nkkd:x$,|8<2d^]j42"bME_lip"75Us~s;./+%Q3,:hbgNVgVeR6aU)9+8Skki$l=:f0%7K80lq*<m{}b!#?ml$#;q`r4Hmr&?@H`KI8t)cnk&;:b[Se]NFmNr4h_EmPI8{fy^ohJ8<)]UmrKp6^trs/jm<;>6PRs~!c!zP[r^b(.#Y,v6aUTQ*&h.TT|w#a42O:aU3UZam1TT3Y1o%#v!)+FvW^!o!zP[}$#;Y<Gf#&%,XG=j+dh[rT9OM;3fg*8=w#k`z`z`U["8JrDeFeekkiEZQ$*#ElR6&paQmTumV;!EktAmM=aI)5;vzmqC4tyC+q;v;y#B&.ZT{kGgrw40)<_5w]Y<m9.{^WHrypEe]%t*wyyh=fV$v!:%`#yf8Ne7K[ErQ#$<*zG*;,%bt$DeJ2bj/eM}Z;LeqT[<M[l52skPMeg!J:_7T>;;>_r^$$%#(?Irb{(l6~R8|zeHm;8|w&!Q0lMe79k8S;`#J]YL[Lk6f8]f,e$Hl]):X8o`he_=Re`&a[O1^mA9Dxulc>b3f6r>K[|82sEPrei[|8m2/G&;Sse%/cT.f9".L91gM:S80h(l=7x<i.*wo^tU>|,fz`fNr2R+g6m2"/ZU.lglRfmiq3nmD/m84nPkP.4p+gNSPSr2o[Y:ZU/m+g8`5hj9;q{}D+zT>=_5zoIst2k2KpOIV}uoi9;q1`L;gkHl/e0;<q#Qd[*Q$;uJi{h;Yn:;{Ser<;Gf*@<dvUQ1T!aUn8y#y]#aBQ[.okNs![JJ5m|$.&i!>3ac"Ph6O[VM_@x]>qn1we4TwHyno[<Z+DFrZUgx[HT;m&$SM~tac~T]q[us3}KL8:Mr&Ji42>U[6@~G{@=6&b$vahHqI[p8F;e3o[&`D/OR9;Dy;9C~7?K#Q[&`r(1s2}U=n@}6{=_}d38?nsb,$,1f,;#HZToXWo`!fd//|&?lbpm8n:Sem3a3s*5bw[<3O#$.p[6@|5Ih@f/c$;DWH#ba@=P<;D[+XdO3GTLgSp[Hx!j._7gF~<4pO$[71g^)v0m;[_:u:CO#jQ10Ap)eLks$!i#{29z~%U{=c$%?^m)>Qsah|uDI%ez7G|.i#Q1#Fn3`?}(dmibk4oa<h&!U<%SJ|5"fC_)];,O,Qnyhw5Ta~SUhn*>6=,!_,qrJZq%dyh/eh*aW+ShF,8I(S8h1*l?<A1gMCb7R?6aAvGl}MK`orxkiwT:pES%1$?2?Q,h]mdFlU*KIx#3ij2F.el4#P8&w$3:,]f9e#$33.:mii37@5e9otepi=;;eh[?#2U)lmVk9/Q8vx]R[%qj>y!u`}6mVnQL<VshIEWvo1.0&X~Ent;`P/,.%!UT8T[Z8&.koPx(lf$o:].h:[xq~0as$i(+KWgc(RhS<dk?6i(M$)][>9U[0yhGg&pP%J]#&akS"s<|5.){wY3O[9me1h]M;t$Pyh1vetk[0<q0VG#Tgxe38Ok~8X=r~0=I8%%n*=Dh]Lea3m3Mlio4,Og&pv1K3non1ZT3QET`}M%_fver$V$Z^L;h!Pk<^+HFeh.)i7$E;P=9|00Ipml(%+UKrL{hqV#Dx%&k.I8Jv@fs$m3nkF)6%4#lr@nyp3`LDTTKnC;l;zo>w,&Zd_jewkr.#*;p$Y%40wfH#U!d,_:Ymr2U:^Zz{JDMTZm`D+f9%#9|oghV.kycpo}J{)&=_M6]8#%A;Ymy<|3}$(#;%m1Y%FT>,G;.#e`aF`&|8r}><s71.TTdeb>f$/2/0ETZmPSy#>)a}$#;mu*]U38)eP_h3oa}#uUb{r*U>C8m`)]L;z7Z=,0/fTeshg3w*npf%Q;F#(.ja{d0]#6,2z{QVD;0&1S%:b[kP;=4p=q`@eD7UV?.:xf,K!onq]<YnW$D]/:xfk;lll27{29$.n`J{xh$mLgT}iI=;qf@H=qq^~f0UEbwH%:=6A&;xTl&pGdE;3l43n:;+_S3U<lH8nd<6JkwT/84#X.%#G+q`<QX6&wJ.Qr&i9@Xp)VH#)9I:v6_OrULsnmlqv]gn;Qzm28omPk7cHs7]ip$.j2R<o:;jw^$Qn6I#yhL=U$nmOfy]&qeIx#3i1.Z^N;k.j}):b[q?=w$#<|*;E#s*:8mQ0l5#80:%4^+%XKR#Mepit$`gRks$=]/#bFgdi.r2G9Fng:.#+)U><mG;+cjio^jhzXO#){b5Q2R}><p^^p@v27E;Z^m:$(+89K==~1Ok!ro^b^U!E@S$nmM;s$)9!.7.EnRfW=w7b=xeJ8ghK~pr8/^rE;KsX_l*&;{2w^K7(imT43K8%.r2$lA9<mCI7bsh|8ZnH8R[?615k1&.^mT6}&!Ul^e6S<!9!.}mzmw6wp%#FP!`(_b3.m*;r(~8n8Je$qjQ+v6pk>{vh}I9nqZ,!%OdmP[fG#S+.:79E^ak`gz)@:o2apmlf8=)?%ah9o%2f9/^h:k.&bt$/8({)]@<b[$#p!e=0a96B1}m9eBEji?@T[~P{=r~sSlgU37@=:3`RfwlK=N1e.FlI;>H`]<@MSK8$2H*Vmk1#_l$te%&+UbU2P%_d3k1ghm*ky^l4n^ma3D$p^8o}/KFa^#`@<#q872`ZT~Slac^f]md.#ahKnC;/bfdG#c`|&O3&p&b$lk*g2d<Y{}:Cb%{}BwtT>caG(E#!iq3bkb>bT+qFpJ#jp$b[iW;/qmls2zm%,[y2HJS:k]f@#Fn)Vh[(ire_=|xk]5hl;aU4ln&.81oS<#H_lj*b^t9x2]#w6wp&<4=zonV&,:/T]K[*{kiofG(va0VLs&Vn?+*]UX8x]]<1sI[k;aUNm0ondi.xlYdN62U;{:^HC,:e}S6nl]PS!chK=#H<[|=17QlML>@mqZhZ{Ze3`{]cQ5m~:B>I8)2]rj{Xom3mo.m4K:8+`&o.sC&Cg&pJS:,X=|ZE[9#*PMeA|rha3kVT84]uohU#)Hm?ripzlSk99ZTKn7&[HZ>3ne`v2wl7h^%G^oq`^,mSE!|&8]UoHmr$.#qip(p!oa<m]vfpi^{&~N3bia<dN?,U!Zx;:R?J1De*&LsxI6.9.%U6pG8M{Z39e0T{=J(Zxb.+2o2apUlH1i(6)T>Z^/q;p:$liq*a^d16b$[C.:[0I`6veyT!=b02%h!o:i^d1>f=@_bIS?,so1fp.5gZhfkpI0Y+3w*=:*<z.8n/)LFN&P3[Srsf9O_PgP;jaEJ{@kip$^;,R]Ml:;68`5bv_&o1;%R]PTv)TutBv]PW]a[cQa3b5v")H|tzbv_6oP1"bTUvo"tYh+Yq,lQ3<;6K3&4QlJ?>.DQ,,yb7^ZQ*&hkxhLP/qHW@_7v{=DrOIM3Y%@.koqU43H1J&%{whQdq_^=vEBms;b2$Ff8}^$3(s[It5k2$V.#7.lR"DZ6?,soTl/.[nT]]GaQa3)WrU8*<$0j#3;iMe0h(*_I,)<@8g&p|oP#2U%{6o<{G8do,2Zv~ICM!a&1xYM[t97c"a4NYca3]=f9S;p(s$Qdh#*YI^o[Bezm`SE;gb1$Um[<Ch?aM9<;e.U5lDR&=m+o8%&s)euLoU9OJ8,2VrC/,%R;d9(il21Sw%"(sk[g,]x]<e:PUm<r%i`{U#<{39Y#z#psS<i!(iw:}&>HK(Z8zsa<{]Lrult>%UdwwN&;J/e}mSac,<49Y#=,(.@fnhJeWS9_,=l,a_C=.|g8x9ak,/W}wUy&]}wUPXbmf9Z{nkbW.`J/+2rFs9>Rym6YM[s~J/veJs}7R[W.;8I#0`jh772`z$%2hy2>?.p&M[7^L_1Y8`q2|}M%:d41itFP&_Z3J>rrPk9@7g6poltui!NkjixH3oZS<9.SGQ$6?s[8_S!;ZU%{<9!YM/|.;c!;MnjV"v;Z[PJ8<Yr8[g*oj(W<p9^fp6>9FT:|kJ4h!o)9q8O~1Ui,l8)|HyR^Rb]PimmPR)^eb}4pV;d{7hCFKf*cA9+w=Os;//,qr!&`nY~6l2kJZ{x8Ld2VyD,~rhm9l8)||&a$zlT[|86Xd8pkI&&It;?68L.3S[!|69W.$x3]P}Ffs)}wJ8*r2sT]9`:9/jf{d#Uh|]x>G(m62^(pkJ%{U&?|q~;!v]_bn8vmdko3Me?6$2KPl7W,*wlWj.Ng6pq^w#0ll;9#f!;qxQrsY%mmRve.`<q$D0CbIvsO9l?9p3*Sn8I#[m#&W<cpr!5]hqy]2l1`L;>6"VT9!Ywl(p,%S;TVn.X=`7FDt)4pY1vTuDe;?h|ukS|ujmOfO#pei3;8G/Cgn/:8$x1Q2P@3@P42F8]UFIa^}8pamf*2Ip{P]!t:~fapUlx<.j#ma(79o}]ripR3,qYhcZreUjAnfdk?Env%tmq~D1h&|#*Q79Gd<=,%PI?]"gYdr07g^wHfL[!ls.+{q`8ou9.K+;9#/$h[<${$d[:eufu)J>v9!%<!&s=6"&<lI&ECu/j8CT_8wrA(e7Jka3#&R;L^!`tr$2@#y;J(mp]fuT!75#?<k;Q]?{1#Pgi!2~)&1<79s;_^)]t;k}j*303``!HkI;QhW=@;Y{l?W}Jb6^Wrf_cI_gY,jaw#)lQuF[KpU]Asa3~%:A&gJg>vCl"3n3yUKp|Zk;*<;66ba3yU"5=U*sX]j^j^WK>p${c="5XW|}C;Q7g/x1`|x]3H_e?:f~d3y)L88_D8}h?tZ)&BrI1~Y{c=xE01Ed/&)bx_c=3S5>"^mC/&)by_c=c^P(}=J$>|"UYpw]+S%^X3ApA:Z)Kp?9Ym&%[j+hGu,<.WJp;k0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl#he5b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:NlI{b:Nl1#U!:3c>5#Ob16b:1rUlI{"b8/.`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/B]B]"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{rjF`]{r[|*`Y(U~u[fc$4jX,uxDIHQOgc$4jX,uxDIHY2YS1&*]"8.mGrIk&=Z>24r8GHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,u${c=D6XW*uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4q]_b>X,uxD7>UFIH/Db5>DnoU]m:;66ba3A:,X{/zs?,"GP{DbpN;C}HOW"R0QtJkp!7.huw[tiD&J=J8Y+=F0,_1nCd_$zC?rsySzs{m,(Rz]AT!+KOq`~v(Ppd(B:w"Naf[T}Fk4}"<F}RxjNhDGTzl_7A"bQXpt)GH6CiBlmU%web>MA*m:>M$C,y4;Tp>u(f(9(cjpN6PI7kFk+W$QrZ}`a)GP^FYQ|h+5M~[*>/QI+M!xv_0XK#G]YMVEm8IuY|E<wc3lX{<&rGCSc1Fx9}}EpHIAU%t%aXu4ne`VzayjGHk*=l(?O&_!,b50E9?rbFSz}Sd*|C+$ydZW6s25%_@4IQgLc/ptl/2<~a$.QR8)^q/NacK.,,FH>Bw#Dqos;b(L>k`@$pcw*9`k]NdCkn$mbPF6|gAi741P:wA714{[!XmM2xZ8&$k{VZNQv8,gU?p1B:LSB(;5pyQn?"lzch8RB~8x$R1CixGl>FpcnHj@.?G.cE$O04A2,eT3i"O2^vLk?j9q%HYNtMSDo?40.5F0rk#5UQR)?8?rDFJDPH:}A@Hf:GbItge:2C]JMYAJJep1;:6}Q{O.fOZF@"%!zf@$8r%D_qJk{Ei/YO:w"N04{[IZ`?EUmG5Od0u)Sey^ZhXHC.}jVvX5J$/Fn&o5^cN0.olj]Et|n)(;W)Sh97kK^6~TXjGCU48wy$P"18w6}RS=d3dzXC!D^]HN9?pNnm;"JXSjMKnH0UsE1q$Nn%9W4wH0=[w4e9@i{[Ys$ZUu*(T2(ia4IzOI{CIvNSu!(eK1A}5zVfdSe{xS%O+xu_"E<PYb=Mb/RC;i{CG>{mL&(rpud66/Ako!@eW<O_7qvC]b`mFoM,Six(LDdj2B#@F`@>Mc.8?rpLG*?anbY8(FL.F_Mw&ty!k<*BBbxy@F(Zt7MtQ:kf!vwXpa6I=p,._MuC6aObltr#g#r`jS]igj_W|/hd4Od[g3J%!u|KjZ[;*:u!Zq:S#DN,t&md3$x7oOv`l+j97GYb2$:<AwUfYj}jWUTH<y?Sq?:;p#{:YUZ#r`qt$cJXq_|d_R3w#&R#pO4W}o"a9NLvaLWEp_.;RHe/sEk<K5FJl7?>hqN+*"wu:"$iP%lMAj>#$E.yiim&cBhMOk.v8fPHqS`/SD4O2Q8+5?_EeR}[cd`?,D}.FWyuG*ZIx6?3HuIQ|+NhLP)k98Wh&O($`[L4!13p3x~g6!0XG59%F`gyigDy>gy4qYD3j@hI*@,2!rY#sCyf47*NSzrpe*lEMVEH5SM:Pn@:/I@=vjn6F3OY[;YH"aZMcfCijt4]K1cM;aWf47*N_yrpGNH`(((u>k[x9FUi{Kiis#s@Rc.Eapt&KHKnRW2QtUYLdd.N1~da$}3zS(:[_sd~hK5a=u+r"m`K5ahyAhM@xHE%U*+^6_{%nuvuL6$S+<,34F1R9`I[@~I5L:!D4_;cs46h~jA"Ro?~"b^AM4}:V82J}}|>_~<srRh6v[(0M/qW=o"s:*7MWL1v)P)$y1~jP5cI.5</I~t6n(q>L814TdAbJ0h,Uy"oJH9[8y&g}//5GxlKnKx+$k%Z0|$<pK8n5XCMo^mWJpCZs6:g>(lRK0,ul7yM%_i*HK=HeF<6h9$J2;#dyD7nsRhG/E/TS2ClokL+sfU_6OzHuFO]Ma"Rtl{j)v%|aKRpgB{vccCmi5z5ij#GtOM4dDdwwuGjW+UyYXQ2Mkdl#fclMw!y!]9#]D%0p=!0(=TxAUL]r3Uy*/]dv##fB_B1nj6Ckn?<mRrByI."%e&qL?/g2{7#!#nLsnQ*eltiSip_VY%p3H;y.`[xEs:uj`A.Kfo^}$mUfTIX)gOJ)+]!.Z&p%JCA.zj@@o8N5"o!fYo^z#dtTtNw]m+B?D+{;Bdl~q!eRVKZ_obqQPO_g)(pU.N=i4r6TBeBal~xT<o^cE1"Xf%lhpH@I>;M@gL+#@pcRY8GPK~!UE8D$eZG*yppPpAM3J/Mf3$400Uyf8!m7.DY65(3gdpbz8+14Y3[Ia5Z@<h!G2lANdazek!iBK;7!X#/{aSXae>UHtGHwuV<[o*&paCC<iL+nH9gxj@og|94g%8v3:Cn2YzN6_h9L{qGp9dZ3:/iK$AF,u9%=o0"EXL6J;ha%z=Z1"TpmvCs<ADfo6R|BOb{gInp`CputcDs57_eV0VR)^eaauX/OLVBHy$>n%G|:M1Y}tCt)XhBu%x~X/~<c+P>mmxl5eedyagnANr"zgEIXip/Q`jmV{/qx=4!8e=lIA9o,g*hO{EpF*kXIEgOrEt5"C5.L}"Tau0H4dsT5:]&z=K[+sPkdDQO~LS2;ULRqatAx~7x+Br@|u2%<0K5zXN)H~ZM~[l.<*rrGnw$?o`LQ{mjL7*ty6`^41Y^/zgwk]N+RB3#YDWpZIq1f56iN5mIBRHzqlV7!HxGmggUmegne7S:nry%eG#C8?:i%cr8Af)k|r@Fax[7EH3B;Ek(i`!"VmCiO;fwZG]Z_g}lwveibwCHmF(|A28RT1#hUiBWPXA*|DR6_OHtMhqPBsbjfs.c&v15?V<3^#9TNH,X`990TBt)")|hOXh_S^r?m+qtvtQ}#y0"kH+s&BJmVd,7bpcw[r0,@kF~(Gu%UU,zm#]Y0d|q,;O}cN0BUl>.hFNwP<q$C&$>s7S$|>[[7*Ut_@^by49To;jD:w,/0K>JGw13&7Ve:Y!4Opg:"xWqNX_FOZ>9VH)v#4vm{T]EpY9je!_e3{y+|>1^e_I7SzRjkdr85Rgw}Eq5/WNJDgQpIY>9Qmk#?B5]f9Iy$z9O2;$Nrl[aI`X=zd2zmH8Ye{nwcX2([hUI.$*/>Ha,H~8zh?Jw2/}qTdyGFJ3WK~(GfD1^S.vtvbz|#u8=+s}5/O}EC.~<m2<pk)MiG~_zlcPf~m}UP7pjA@{5x~B,Qw^KYY~U7XWRBMj0x~1DgC^B;V{q~NucNp_H+s2jUqYYItk#~;nv4G$E`:1eqd|ru2T5^2yLsiA$":khkHyEuJ!wMCSthI3I#!9TUVCuBiFc&W(LuB3#@V+su*P>l*sZKx0dI?}Q0eX{|g|(!yLb@guDnJRzqI2]e(xF{,U3>o+X7?5FqS<v#ht<;VP?O0dDKf>pyN:cg=FIMohL<vfZ9ylM@S,9`;ZW%oBg.w(9Yov(aj7i=QYmFo>^Uc&WSs}0m0h{@lR*>,Ga0/{?+y:PK`d{anAseCvw>ugQ]I[5w!_em4hTXymYMTUZ`UOPQcfgL0XZ~c(5(I[R2UWO|Bk(V#pBU`we`mkXxF]<kHk(])3!6BFX*WrHfI?!PZ>9>WIDAeOezTk@A5*lN`+sS7#k4WDFKx9B4(No*(a]=GJc]JwGl]yYjOe<xQ#b>9NiOh/r#;w?jQv"p%55mIP5Gu66nblWt?8?uuZ^+s.Z^>[XgLKxKbr1:VnXL~!NmmP{tp6uEH5H#o$L>UZ;96|>nU|Jc"n+K$vc,c$b}/:it/~Th>cH7@klRC<0$Lk1BYA90y|y&Tw86Z&J6ilZj5+i`h2A4po^tB95RWud|^vLIw,hl.@<KF2u)KV/YY5kPuaIAP=lJaK"~4YU?[nZ,(n^Oc4caz%TWadRIO.Wn4|L/yHz>U{0u#ut2UMKtt"yT~.InKv{5;A,sP%LS)?ucYDF?UgC0XZA<yNBbMhYizi5FjWjJF=E[bdV00TBs4jyUyYdS;U{PudDwZznVBpZ>UCQ7krwl0}wXzEzI^>nnKS5QTT(.bqXv[b|g4yN%pP3kS*H8{y@M+6]}ez$Fj@h~;Xr8c9uz_XT^q68Fjgim0fG9/^>qId5nA)vUyCXimX*kZRJBVg#Lnw,><]t+tWdR;p9&=*to@{5K77+SjGwrUz%~DE@t/f7.#kti6/OsL?m51YwJs_,y:oSn%G]}UY/BEPPJZy9j;Mm"YV>bKWw!8**H|xMmd./msjX.KyOBLb5OW{+#2>UPx#_Jl)5UKOM+!8ScM:#m,P^k;_cFYH<Pv_AvKb;dj|E~9jM;GA3949wmm]86Z_p/DWa0:7e@"St]V57FjlOYyi=XTNX%O@Dh8{"UyUjww^B[xCE)?n6Yubp>U+c;y*Qi:>gV9`xpF<8n^aax2Jb;f6:9RLb/ovrK~uOzi.+[VAsd$WlSGkw[YqJMdypNX@nKgrK&{z(2q_PMhu<)aSDTG7anUWdKK=4%kS"a]&u68YWJgQ[.wWEBIfKu{k>UYVjx(&w&2<I_@}3xSldD~LB!,ekyKM6?(hX}RG)z9fG>n7+$zkN*av1.e>+[waB:9RRcYBFFKqUi*q6h@sjqZaY%j3_:XG,+F]D+EL1y=Ioh+iL4tQmvtmK=Efj0=IoGHeuDzG1i2o8h5}j7asPKG&*Nx"q0|k+.Z0G@m_wS&jZvR9+5LxuWSVMXHCmn+tw#u:ZFDP?b;0|#!fLkXFDFNW9"LJrPGb&HU%!@3rNEt4)88Tj5+TzoEmJt#)+E,hXxbugSO&9mEfjZL]BRY!RCZD+x=>b/fGm^qtMb;53vxSS?D$!oz1MU<>>MXfd5J|jHmgZ)L6BI(4)QwMo~)~tqubn6ewg2Ro@Wc%DkFZb`Ru8PocL0NKE!Sa995s@4W=bM$Mz+wvYPxAMUfXo/1mzqXAG.e/%rO6|.+uZwa&VZ9D3`$xii`HNF"#HnH2p2qT@>yn@Ef"qJo?M.0yq6y+woxAvWz%u!6:q6`&6Ro=+PzJ"9N?PDTUqKM47046Y_cV@8qK4EYd)=/U@&y@L9kmkBj"ZVX_YILgfn@x+6yg1K2*F{/ls}gw4*Z3j%WTuUHJF/QC+8K&YzgZRyLtY"wUI@GfyCK=b%wSXJfM$pd6tYuJhS@4++t6G?eMXVZ243|9Z%M?yc0J54M(W>@)yHOMx&wI_!!#y9z(Wse6.M.bVg@7WHyuN7"xl=?`c)RpLf09MjS.j,mwb2|qN?1)MnLhCgL*<R`T0Tx>c!BgeS`<Zd,t0+aOw4u;tF0[+kc5vmSVJtDQ,eNK1hJ[8qOIavO?>/g%oqN?1nj=?$*[apPV8Km3hd?3|e&LYe<++[WVbUY84(N?1Y@2LmBgLn!$8)O.+|+H,oX:I/O6NiQZViQP^R@z@)zuulNxYf5JosZ/yyX3FylQ+&Or?:y}Lmw{mU6YQ@$&y!MCD_a4)kE4|ITRm0qMIb&wUkK>1<b[z62]ATN=0=M>M)Z24*N[I.b{z]NALTN`[D,4Z!c_2d*R^jj$M:L<H0%Sw*+*zuNwxrITcHFyl*Na[7P5|W@@y.v,30YYQu.r=<n1zJMjC1MKfrzW5dFfuQmoOXR((o`:NALRa1{I$V&kZGzSNteJb@"lVks=/,y(LwxmSo!w.`6q*@z>xLIub$KXmwTP>Rmk+fz/YDJUf84+)1XgzviHzWX&EVs)uJUrz@LA1oNIt]{1pi@kO>rLdfdL5kcHB#!nz>LA1JMBIrFa9[5V,RXd,A*2L&boK9PjN~m`MbOBO_nE<Qvf<jRzLgBJQO>#!b@0+nGCD)q_cD3Mow+/LXwA21X:1dR!i++FMByOB2Z[zbfMow+>L^w.0LD)X^j~JKoof[IO,ZzO1mK$2n,prUwOo:MyN`M.mfGe@2*:FqPj&Eg!+8!0z;zpY(JpQjjSjROOPG=_j48gEE<gj~+LG]X1F`%^&D]i<;Z4WFPq0Az3z4v,Hiw]{D33j9+czeC%~^,$M?Mr0g0~Zilq:Y**LIdUI[gr7K`kL%W,1+6jTQoSo8+lu{CmJ1XfGiRy+IModzN@:rG5je+IMrQyF$!_cKNRO_?pg4T(dfEaRaO2L.T57ci~[++hZWQ+Jp]4!5?CwSX=L+kfWOC]$TjG,ExgNn1[F<}!PHTrz8y:G"XHP>WEaoKec<0lE>1;RUo!q8?OXPF#J*NF3Qo8+_`MI10:41010aI=0(}7!q+vuOKpw9l+N=cXjDw`MNjtN+E5)D3;b`zyNCV7`VdCZ,RT@+cMuec!Dox3q8?^v:LRYP>lE3!_+~Z0W3hwbtwkG`C.LSCl|mR})&".Z#FJQ}!;,^9{MUZ$Lzt%ZeZ{v6LxH_rBs(7=/mR@i9NvdGIUo@MTkfNbOWb`H_a]N"ZQ2MI|32{;1+Z#ZvZMSi@J73*!N~AP!~=J%%Zi+.zsaCw8QnG{/:ZC5`/VjxZLZ9vjjX7tO,W4(k$}jCda;&Onzh4/BpQ"!vzP0Rz]u(cjtaIM{7!n0HYWE~QmNpM=L]{DT0@&zO0kX2wJdMY(j2z7d:cOI^(?pw1vH_a!8ygHu|%wbRw>18y)L>zjb?~IU|6mwj0@xuNYS#O,2U:E3P`)+rL>zQU7K!G]y7+=+ezmb:Qt)RzebHx:GffYw:!RjlNH6yelXnx>534$qJ0{XhD_abV8MM*xu(zNxGKV`6y=t(z{G?5K7$ZftYu(fJosiTl[WAWi0={SM4uy2a9d<M0R,{z&v4E@8PDN`5+rMfce45b$GrN!5{)EMPc.CSW+md<,M&+h,4XlZOX<y#XB}rOB0^+fNBMxIRzWU]1K%pzoz+C4X;HpG+Mg*ka2QV8,P8&LawbIUc@[cCEq9n*3NCN3Ww.XMqv)Iwmm=Q>!P1qK`m+>X[D:RQODem+dz0xY7*5uj?+zL+bCFG)eygzp+Lz{zlYhHdU_w,!`_qjy*jx.NrEy@Gz#WRHNk[FsF6I4)88!!lVTao6._{KQmK%vzSMxaiw83!!hj"+T0@H2PY(P?6ey=$Z(ysZU2TDN%%Mr+CY#tBzt:?M@MFO3c$iK+yyC9LMtC2ZC@*Nd<9R{yvXiETCF|I_<H/IQaXw$N=OFj1Fd?n,3OOhzqt+pz}N~"6?K,_zROb8eK5g"omsRj9+xzn3{&r7ZQR`Zj7yyBtUq*nx"kpEpE4!$+qMyvRR.mhs<})}r|`_NisZyw)YFcG/IwILDgdO_/63I>H1:NjQP,A}pdza9n1iJaDxyOzi_c]b1N.LJQO>mxk+Ka@aBj3BUoj4IM|1maUQ^$rz6z)IOi=1n@2+)z*1~[FNyMG6&+_MiOpA~U|/:A0=pGR0LdnR,W#RP%<bZ0>"f/G2WkaoP0.a+QHWY3<IE0h44E4,?tHH9kdvjKG%6!!y[OzYmIDdU0Nf6j_WwbmcpQ4OPDb!hOcNV8Ygt#mE2=2=0zQ%|M?yoL^A]Ffegf4|vzLr@2iiA2}E}J]M0z*wIZz5Q8W:gfJU2%z|)_tL2LxIGEUD:bP0%h>sMI$!,Z.OaXwKCZJ%M,jzg1eKPQ<2.!ecxYEKC61zhzpx%~Np_#]gFnT&&Zk*5G$Jjcd9]g{K(C[VcEdo^bkz40]gJ*#5~)HP]wuy3@>YeeRW%G7i4LFIxCJJHF0sbF#rUj*ii*Mu=CJGeK`w("!K$U+Ac@GjAwpCzQcu{m(|xp}JJo))j,Kh[$w?H,GGibfX6`@{!*!M`){X$WJZ_cRWfM+0v8e+??#*.*Cx5Oa0.w0H0|`Q8g:QE^8By,1O(J+SK]S:8z8]=c>H%aS6##GjL)Xu.BAFR3AosA]W8Yo6|!JV}Q,i"v_L8eBR*=Uk03}U9HPC}Jm_)?j*g".N%v/d[N03Q<wn1(N":L5fM$hV|3c;716?EwTI$ZuK?QYy|C|GILxpTq.htRf*}GeXlFPGKhO<0?RXCEMA?4o/j=`hO%a*UuZC+Iy!Tc8Q9RI^S<D!v={>7n[R+0wDw1MafGALRa&R%G@XY+W,&I+EphOR_fEv.W*LEvxL31}8vX47YQffWPQ0ROwzSu]2/dtvbaXPd8Cg/}Jl]5r1d@]js1#K(w|PGk[j/bni#Z=yDU/Z3tfB_fvetv~EGfRR~WJX:M4?9E9l!lH_{J`T#X|ZY+g2!&(GzprI3iWzA9[f#u:_eCX2#LIRD66u+Zj+HtRvRD7!7y!tmyLbc<h+[vOvmyp*d<(n]yZcKaJzROITJ0xJs7f;"kg+OwL6#DZQ{6`+uz;ZbNS1WK<QVv+Zj+QlRwtI,yK:o6Rj3kqhse&11?>+zlQ^cf!|:4a]=##!+RUonO]jF,>+9!F0Sd.a+4Lb&+(Z~n0|hD(GrN>aaR>F"Eyzi4YMq0h1kv>KwYx=Sj;MjCjC47@I`TWiQM9+OwhYdz)GVaS!/dMIkyhzcbSYQm9lij?MkV2tvX#!3!ri,ZZbQm9lNIpzszFzkwg<sw#y_L?YS!ii*)QWq0h1!XNjaw>BKE5)[5+E47gs3GOp*aUD(00!#?#nrZk?iOn?$_m?Mwm?v|))k?n?:W))C`I`1~*/?x,i,Z.QLS2y9Y_Mv~*sS!0R1~0R!}%Qy!9}cPwsWCq0{4_/o~2Xd+m;cj57uyiw+~k3uG~]O^N}^aq0p?@/Ov:dXZC6e;W7wW*WTx)4M<eYSFi&a47*@A"B5y2:$nP!s67VQO$,w:LGqJh&|9Hbal57GiF6w1h&Z;mN85?_At@21tPr/dM+F6&#qAq0P)^cGLc*coe;A}5AJ&6@:P8sU5ZZ%,}FPYmhsX~u)|8Pi(7w{L?(ODr5#Dezz`]DYW#p"sj"c]<80EK`)t9sfR|B+|54r~8y]XP;zE!M|70R}}P!_~3Sh]1uO~f;o(/)9+(|)tw~Bec_j=9+,|y#@G4}a,ILv,O!8CIw_)r8t|O?.~ED&>~z`eB`K,!~6B:vu>uDp}Kt}~3/fg{`1q(~`aY7gabDvz`ez`*q)G!@;88s#c0[X|94u~(i=2K}pa(>H58Z+|NKgWr1TEea!(~Cw_ePo~=E$aS6dGQ{_t]}0_RW,KWL4}MTPLBgy35}R6P(E?,v)UTE0w0#9+/|0*&~iJ2ya]qPG~neM/s~zX,kD~"HS{2ya4<+zyq2kh@~0VQL6lzk(sQO@~>_Dk$}o1bMrtW)(hr+["g+eGh,@~s`xa*3>~6j=QlR@9S@h"9su&FO!+<5^}Bz_si<F!utMuHkI)zPc.;M[}[OzEm}!j#ss_s(8:;8cR!?&H?shCs(r=F!i~HEP|&42W|s|6bMR|f<s(!:qPH~y()zb2>_g9e_tYiJW"$|jM.Q7yL/Z}kV<sftfg8`:|V(n#`eO}mjiW+0TEQ_&Hk([FM/w_="w~JtGckn[XT?`OC}KP=21_.tysKnZZDtbM)@sB=|@hcsC+kIGRhL|sM76fm_l>&,`|UHhW[/r(.u#A:_i,e~CexFmBTxzGhJ,j7E1ipoL/3_.t]}fcrWzX[Xj?{7E}j"(sEHRt`~B84*K]mzns#W=spviHD?&,J/].RqzkV]C,g_ATX/`|:~?yo1d`P$h(iF~h2Qp|2B4h;7(hF}Jarsu&GycZjvZS>sFt_sl@&|bc@$~X{BA,oIFO?^iH%}1pQL|xIg.vXL+7^~&`L8Q~zn(sYLee%}^<RLLi{L7,`O@VQb@9j?`e[}IRP4H72yM[iv;|gj5>pG.>wb}r$4r~Elm1ZV0[I~VtNBK}y=3hB5L/y_nw:uhq1(s(*vdGn[V`W;&>kP@9e{jEKD`_q7U(`J/v?D#$@Cj2RmSEC:bP?FWWlXTxYA^2"t~}pNd_6[kBGcCN6Mv@:H6}H4s/g/QQCv~|=M3h!yezX`U%UkH`f<T(p=gX?}YQ#>Tz8Z8|FC(~%[ER:|^ag_JEezZ`mPOHKM4[GCWWUaKc|z9+8|*ARcj/VR?Fwbj~EMo(iuq+1ybz&,I~VJ/QMi6Mb@HwdH<{TwmWl=}s_}meJ)bgi68Zz|*A_~5`n)iW*XTx2u9+z|;SAt^}7?"~^}y4(~S[Kv^k:_1qmWAMV4M?yH3sh5P|5;a#Fc4r6MP@HwV|5S*O?^</J/v^r8d_t`_/f(LHyd}~w`QB_}F2nIM{}lHV[6d~/dOj~;yr3U|KtN3OD:]DSW=FR4FH.]Vc_pvKPdYY(ye2dSNJSj}(3GtB5r(H/a~1F0ZUVD]w&"+Z0|6fA>h`XqTT>}`%C(e@Q?J4z8Xr*e9HQn^*,x{9/1Oh&4AcYJn/7pvF,_}L`L=VmuZq6C([)ER!@jY:*R(]pjxJlS|)>@lQ[nl)W$Y6~EtN;+/5_J}x"*Nh>@_VnR@)^VaEBy1)EMro`Rba<Mb++0pIh?]~P~q.kHrVR*I]gJ$@_D{;v>xh$`ss(FS{ggP/DH,h;C]WhCxl=aQ/@!hNc<<I[+;t|[P{>e=~"Wf]{;0~+94V3qt1etEH:Wc7ND2_=+x:pQX/aI@Zjl~[*413qsKxd#4y^v:v${wQsm^ei<G$=$?ZmJ3NAt#0:tD3?#?ZrKHNpeC5!%SChi|a39beOy)!S!M)]1T;B8foS;UTI8&0ng;Om^L^Cuy)ai)Hp*tP~tSSt1|;y(A&bPdK~dNcB)k>F&H7J|N;6F~dNcQnBfVB{Qd.?Da42cyrM%cBQ_zmBfH7l&d*?Dx(o#A%2gctO1p2Wt)HyOGP6FyWM!9Lp1b/UE*(.O7|b^^;5%cYmB>SgAZQ2Ls8fXz]nbA8H7)uI0<KRRvB/dM!!4YDY2{RH+Ez;J_V{idUJJs!!]5ngD[*PZnDyeWftDWf#9Ylm,7$%@pX+Xb6KMG;<?wrhgF4_S8A4`.>"K*xFgST.:}z:mo<h`qh0JEFAf61]VP5#v}eC83~?f8vUTmP/PDP9EA"jc/t+D}s6&woq<:vFoalo_ZS.QrZ(^85/:_XV|uj~m#;u(nNV/:!_1tUKIALQI*}lccs8Nf:Nq>|_d/9}e%_$VC|YD](3Y1u?qT0m1=ZtgC*H[%Q;(7E7L:3XL>eiNTU*M|zdm|9HIkq[4PD13pNXp34aOwd/5NDmR{3r47~~X!{bah?m`0c^0Y<QXVN<b))0q0Eg{HEw88F.TH2EX9;ZL,UfSX{7~RtQZ.Pyx"keswixor|+X?4TzW_6:#Q%BBUf&;%lnp_lRCgJy;6])HoKJVBSQC#"TV78vla&}u[9xl9`jj[>y0vgFgci(UH6r^ab(a2r?|zvvGYg#09aF*UMmV)Op1w1m/50B14KSL6T~x8?,"5DR=Tmi7C8MKp%k5%JmOX92HAet[53vUUN`/FZx2,9W.QNFCs$YG+bYJ"P@,d4F)f%"L2;lEHDqiA]$=M.2BmnB`O8:bB8yX~$eu{;$Uym,YF;2uSlk|xQsPmRo0q"V[KcXDqII7r&Fn,>vm%3FMGA4:I{rmlJ*)VEXVGebUReo|U`|iT_KsrXfR/XkIH(>ZPBhze!Op.Z3K&~/dYBt#$e]XQmN>:W!oi{6II3BRhm;@_y:H9v.R<RXB5cT/ji[NCWrxuy6U%jSdTY#m>:CY}ei)%Wf,;g[J+RaVm4m..V3:T9[8,]K56WJ#v#z*Kqno_f<e<?u)^jRh{HvuC3>#GTr^2u{~<.79WE.(&Ka4=%5}.CXGFpSqXw!:u9TqZ6g**o}3[AZKv>[|UYuT&;Tj:M|EajBAu]Xi.dBi"u.KBlnJ?y^)NuvdD~!HCAEU3}E}KiTn`Y4s;2j5PNQ=hGFefkKa9)}2g"=|g5IEJq"`l`Z]N|HG(1{xhaJOpARy{=G5e^M"Z)Q(N2V_/DrkLJu</aE>e7,_&UW3VEzk3%mtm5C5[NZET2QOWZ&dHg{I@F(L.?TT]M]8`^:YQ6:}$zz/[2`}qFbtXL@(XcFEte&J0[_x4;zKbJX!AVo<s1J|2[H,@T5M)D_t_h4V#Edm&nIJoD@fL{TgU$K/hL&.:5U(b{+ZY1`L@<A.FE2]G5w?qg1o{xZu#O,pXVlXi}N,eS>oz/rE^Vx%aFqHI6|DC|aY&)5Ko^15UXVa/af0(2^9%[<q{]#y:PuP>rjCekThWOo$O;I_J{L/li6%|dPs{liSQy?{,LMV:v9g{dBlED||iovNN^LK:>Jq#9/&Bk4SEfQ+/ua6rU&~?W@<w&^"AcJ/tIiQ+{xfm>U6G#rKbA_VRb>}?3i]Uzz)V?D.bk4_$M?3qL%G33_Ys,(6`v5mTCv32yfT<+CDt@~5V~n5_usy]S@M[1_4zog+YsoG@%tfK#%+~6!IsxC.=R9"nHCR^1SI,dyav1bA#H_iWDoyU{aXIYAdg4U$QwDr|Mcn>z@lsLJEHDqS1mQY*JKf;!@kzU(m2W`&|E9%"8DoV~4Fq1e3YiOt~SZ!|/BW.^$+0cWgtH_!HZ%wLy_Du?PVulpiU,)xyTKHK)}M.FI6Y9TC@![J^hC!l:8&p[RMR|V8wKSGcVQj2nW~Ig%*d$pd4Q+9ayW@NWdlh4Efr8Ia?kg>G`G{I.Jkc#gl8x%w(/}XJ*=xEw0HAfj8z~jXI*a@nvm?$4N5?keip=Z;/{pg]aZ^AfNh`STQAz0_(BjQ4Ersn"pAFW_cS8Bq3rBzF85msSd*[F*WOD0KXzYf,jVpsC:|"9rTBYBIc7GyM6.*C(Yy9S+y&flSWlNp|1qi9e^V``7bqx!.c>}a2I)hY.M^B_J(X:Lf[#E,~kDDox7j`+>+sgaR:G+<Kog:MfUd0n]}!BmOAKS[Esw).sB;nsHB^Y!0[3GS&ty#ZrW=h0C%(mqHB<p5(FBavC"}GWxDWy&kU4ub+iZC}|)j"l:J.`L(2{S2k[V>YjFWk`p<n5Ye;D~&o|/i|D(sxx+]f2gZy;/x$4413Defobw=SA1oXzRxlz,qKp=z1C@!)#YX4%[e8OhtM|G/3?o6%Z0jpjwr`=!*)P+S/.&dcfWq?Fc}bN(>OmgMN,p#^=xI%xj_J~A:pU="."CuUMYUW{07oNfe32z+%oc([@p!"bV0F/KZjK:^Wt+EogmyX>_`%$,W=Da}EIt>2gz|VMgCrApYV1vWs$Ivzk%rV&E!%B`~5S_OM(_,>EAJCM)Pq<5`KPJx$_X=`FUR5MZp1]GS4tFWBJ&#(~}kZ~%MR$!UhAB%hj)F/,vngT&]]lRa,1uuU;Z;(h%H,<NHE+|$zJ`<gw2Kb*neB#+4bYjp_#@M_5oyC%6*|r0`2[X446h~I!g!8;Jx,I(alP[Pu{kqM;W;e>tP|=Eb>V:Y%6Zg;,4V>OK$6!9B2/$|kS+"*}ZRKBpsj$CC7Ci3=:fD%GYDsA3.z_9Sn;M0cDhiq_p!81QZ:{$1(k,"NX7OqpT(2~)QV`HN)I7jP+D34.)rcM1_dX&xD]]3/tBT0$yg86/1v;I*}EH0:{r=SN2KD=wsM^.!0`}cxV/LOk=,V:o~*Kr3KJEBVV:B`6`v/:X)3w179|V>2orxN!|`Nj|5nl%h:T`XLWDICeXz*Q)ODuaE|8vQKKMc)@jvcMW~zgT6F&r:IH;iX%Q$amR=e;KZsoZF~:_c^}Q2NQNx^&`.E<Vwc:@bi,g%,_|dffMY1OHDVSC*r3KJ1zxZWtSfo%ZaSt28qh.G)G>nQ"3$;>qpZ}wWX;i@EXBv~FzSq6V{us*rOrKk[}Yp!c|.Rv(LOFYmY&3^]at2},+)Z|Ni3wZ6C>0=$FRE07EE%1el46"aOHZ3UM>@/^({TC&By`h|f<n$JgwbUP6gW{Hx>"GZ=%8AFD8>&D*"T=Py:<T`wL)XHPx~/8rz%?sCP+rFmXx$B6.V+4W$nj`Uk}UxUT0yy*O@0rZlRR#m5{|U!{@"il956qz*a!UXf>G6htx;q@KI_!6h`+}jt)Z@c~yAXav,$^zj6==<>Us5N7+Ze8l41P{#n:Lr{!4/m^we@DBtJBXj4RZ:1V3c#&]?:1x&UT)>{f5y&Ta@$_2%.Q?g!T.~hJPnBG>*M^p2HC}>W``(}I%EdqBw!L5<m7fJ{4/h?=t(S(hD&_CAhOF:D@]_!C:s9#m>ZB:s9~_acB"YUXPD?akfKoqO]k_+H[~rFvQst])y:UqA"Qg+])o`SIQC$~<h$jfY$j}!~yF1yS},vA7nr])(`r.,)XiQVGjM%U`&C+T,p])!`l6XU/`:vapJe:TcUa[:,PLAKu!q_4`wpKL82UR,8c3P<+/^)Fm_ZFmN@.NblFmfYv^1[>EFmrUFmZKM/zM+2lr,Sgd&4j)z`qbKLU2(_[}Y.S!P:~~t$sv]B@JCcib`E2.;_#nqJL<"Qa{qCMRbeo3xbcp=K>gZF:D*Tii3r;Engf?6]JsQy6tk2=ws<2@JP3%/])JEKb_Zt5k2?:/fM)|"/?L<SL|1U91y!""jnxDMK/Hl"5Z=5{D;3m]KQ!2,b90&M;5w@Fq:w[vNQF}^F}(;r^5V&ciXL$ab?gG3CzyFv}NC:i,Nz.Z@60UF(#!GKL31UR?r0HYw{RzS4MniBo"xj7[;G(@qyFLE1+`Ay%"qpd+1#l_]>};#;nu)5O<40<+2s{+9qf])go"xtJnWAF;2q+kEzS2}ry+r~~qD1;A++"nXl6x^S6)DD,iFbURTbUYgr+Xu&p=K1EHG%|Paqj32M{PWBDM|5OhHtq`eh/:rnYyZMN0?!$227mpLBvMzo0RbyQHsb8VUkhYMxfV9Q~9rLYg/Q(RnQEI$m@zI:2Ildb,Um|Xu2>+i]i%[P/VLQ+fIP:(gVH$}Vom>*ln%J$,^IFjs4Z:PB4bcSLZxE>Ka"XTCt?`Gas;Yx48)kX?9tw$r%w@viLAh:DVx)KUoJhS?Ln7L|A7QN=jtR@6rb~fbx#pAu~bXPq]$,OFMf+&H?Rm^b_EE~^,nk~?F8&VGXf@(>MU7#oZae=!E3|k22w;Y!UenEMN0Tnh!H0yZd?oV3_cFG?LLy#DTDhMugcflK@WL"rOb;({2Uia+0HD_n/$I/;%}?o7$Mi2MEG~`*G{|;JbR.J]IU4Sj9^mtFN/*>{kZ?r5y!S{cXxc_xJTl`@9;BxL<fE9n7LENn>)JpFi4$.6}tt4:A%WH!A=YuEWX]`FVxHXXbbz_Or6qZ`9:8!+C$PEv^UDHNXTKP~^<h_rni]yaEGVnr/H5;7rY)hdd^h$5T2G:c%Lnvg=pU([,Lq<$Y]abM}V@|&k1^Di@)!X4R*vYwkI=&`(ExNz1G0sCTp75dA_kRZ~Jz:18+J,a9+%7sT9F(rAEI(5CWr#6?|}tg%Psu,nCAv?RfgLn2b4koXLNnG79WyG}7;u>VGXyHwx^Y_]y2E&ItV.`K{`:0{,v.P[wrM&d%yi+^}%aX_TGG)kDiNHo0)LEQz6Dt),}!r~,05!uGYWx,|Cj]&E7|Mw:svlua+}N*c)NB8f(]TL|Am3T&ea#V)SV#iq6Si#IFP{Q5rM)dc#2Zn4MTM1zBI+kSa.$3o7N2?FN+}`/u>}>A&f:xk]9.j5TV!4wHaJ~+;3r7LyS>`aw5d`"?Iv:vJ2_FYRHByF;_~5Ka!_&90s[f:K/j4dG<EbAYLIRn.i=>>rx5~6nUnLUo%|_IxDU%[%u8k`CCB9~NCTny%RZ0SkU9T"=i?!u=am6d(Mm4$#_}L*ue>+Lk(hwLFSddoOq%TMg?GD8r3PuoQn#RH,T8ZtMY@%P3cJUz!U:(%kM3ulz"ei!T{%^[t4V`?3:FN*c>Fswv>f<p=W7yi&g~>jkt!fLBtSVd=(m:&ob3}:?SoFF|B1e2O&W;KW||M_&P6|cIEKi^;#WitV_P%pFv@GuLc@:;B|(^2J(ZwYOCd<e;tjK^UdM8MI,tOXnu4*aeb`_2^[&.T,HW@ziIcR@f.lRlx5`0FWTNW8Y$)+GR|NyA(/Y|OGd)TyyT>+jDb:C]qx_RCg_7/,;VSs_5C`r<ZIu;oQ8]Xb[(."KB_;Q/Ux3^zLmp#zF;Oas.N^^Kwl~0^gD[cM#L6"{}0Ptv:Vq:M<mRrsF$7F8cT!kq"aC.&^+RTNF7M4zGLXBNF`kl~o|1b3>0`QJKk5D#$qK,Vt_0D~6nnmdeu,9.Sx[Vya#Ay3n!>&q[TQ|;yy:#W)y[qr?GT>LdLM!^j9^VQ?($[e+nIQ}.KR%*KeGc+NM+b9V(zNh8}3Iq>6zB%J6$s%W3TIDzNk9!~6+Y_^q?M#M;V.CD6PgmM3!5BJ`qD)rNy{os}J&f](edU=gaT/"p@H02u@&P6Hh8J?>>DH2ViunehRDeYC=hj"&pII`#2/[V{jqS/gFqRRv9zC]6H7Cf*^IgW:f3Y=EFAytgfVn(^kbI9?Q)uzQ>$4Nf(AjE3#7Fe,oF/A`iaE?RIT|#M~&2[HtJ#gmy37D,cCR8#UwB(LAMG7}CWYMc)h~di^e<QSQ^B/&"{XE/slq=2__+(1~.685W@yH0s!E{spAlI98wdMT}?j0@~u]#Ad`Ixks1_Ime(QMDOg@PQX|:NF7o|.l`spGBHrH{SfX+Z8g,+I0"ov&$8h6@uB9i~frdn&8iRD6DTtVtQ"1Sa0a@m$,<A5(1dL*&d&y#l2PnNzzyCHOmWBP$R,u(zAs)qtW/+HH6IW0T9jjxD![xt_a#L)?;R0A_v)<dF)YxC<ic]s_0)C~2XUNfc9!uOIO#uYGHaPQrm}X$1Kt^QOpoU0@|Bdr+B<iF,`/4wVDd+0Cb9^QwjBZG6x@{AgedIA.mB=0Q7#ZC{S+A)WLekKA/M&4gD~)DJI5>1jXUI;6jjxD4bnHgTqlE,`Afc6!{/LtmO=BOt%1MMHRus]ub<&P#uAGGz:cK~R"_aGG[4Ke`wtfV$!u^FfzEaqNfv~xtFpV)G`R[Qev%|gN&1dJvJr_@l:*d|KOqx5_pzgD8LfavQ{|_HAS$TyRYo+ByQ!4})(5wV(~QP#u)yoz!g*`>Pi!(j?+/z"~tSfDsLOM2dsQL~3O>y=aaK>c5ZKfDkgq[/|E?,2:1E6Z>)Gx#u8yb]BrYgPjC:dG)G4WNB=5~i`}zH@b|Qfc1!y2B~5L"x:eBJ1K"`vu#u:4TKArxl1:D{z,W6Wu)KQS)G@u0A~[/..XTP)K?dtNDDmj@5+L3|`JALx1POUR`KDMr{`Rx@Ovo?`/AF)GzVN7s%)K+h!4=XD:OviAfcbGC]hMgAfc$5GX"I40RQ)?&N!wPO*LB}~;RL*]9XhN_$2)`4)Q+,HHAVpZDVC7.5zEiD3Kn)CT7#s1bB<5FmjAK<Z|F`us%R8#(gY(X#c+m2F[aff~WGc+P}2XPLs~RWPL,wt1C:QTCo]/u7AZ&Y*W?1T,obk?`/sxvt9Rl0Yxm)ZMij.ORCuV91k)vW_n3DT7?kC{q]|[MpCTu&kq$)+5>;Vh+y<hsH6WgDyJ[LB0qR{/nQ=*TzqcfXgv+:@4)Q2v|L#upL&Zr<o4sI^/pO1JY>EV6iywJHArRF/(nLfDSJdMo?dRZYnUjH2W#D3H5Q{jeWEu1!6}?G2y|>ng%F?r}mC{ci~3:)A}go^K5{$htY%R6#zIP4uwcR6#";|N~3U]D:;0q?%:.0rc#zOYH7ewOMoA5dbHd5C]KCaw$2IeU,MSi4<+FMpl)N9Wv+2dwjLEm"}eLHxDSIJ|=V)n;baoEnY`rAAc=W}XiX]"yOFwY4@I;B*ZbKkd>E1K},(16z8B5XIDI"R5@n2RF*IY0Cm@`[xPTXoatNwATi>Dj3.qB%=s;!ZEl%`ZlOdk)DtWiGX:EvBwFwYXWBI;58y8ewT85}cEG"|$3aEEl{on`*jXsfCgMu!v)JUxyx([@?:,h"L]4I1gZ?aER}~uQPk1gqA`5:}erWLfZ(uI4yeLXtT|Ib4y[}>PSL&|*W=?F~G88IZ(6UhsS4eFOj@?$sM~3y&~EPwBhD_=DU>Q#Tc+=~;#$(*}D|#Av|>pH/J~^@M4j;(_D~YU.vP]R"~}KS2F{?3Iw~%S.vJ]iHxsB1mIz??$usn$piC}4#0FB:L8X~RN>9A>>Tv~fZJL(56fV!wM"b"o/A`V`c{3r7:5G^dR"b?5uOn|/?(|`=_F?r>M`yTRCsD|wT@@PMAz@sc]_/cJi|CwJxA7nz|[ijtDmEsD06u+TE`s|Ep`(y!0RX`R)BwbAsHR"bIY[/+|RZ>qUKSX`@*K1@8vAQ5Q=,wVq_Dyfa,Iv`DySMN@@1>~9}&X?1Xo_4!Cr1A7uTB}(zS@^vQ+t`uhjz0!+}Xo&K*+$~u&C3:uD00i`@C(P0C$$8~g("svcD),46)G5_pOQW/L6Ms?Q`|EN:zryy3v8Zh|y=)),d+hng?unr"8@O:k(W|Ewn9Jo7(5zu2("Z3EN`@u4p0VM.6Mg?^cZj[)6BQI5V(0+`Ux?B9[d2_}kt+~ORJcLwB"q#(|dCOL>=7Mi@OD^|.tp~/x`~B")VwEfD4M7@e0B%ZORhJZPY]iZ2I{<8e0d[NA2B:pNYR7v&]9m2VH<5`yaZ4U5X%k_w]DcdV?^uZd)wKwHw1(U7A8YD6^,Tdb{py?;zZQ<3e0S$][}`D5&Lh,E3aq=7HN(s9Z2&iSWolQd[MIbd<:>BEM;N[Lh=[@58EX"ZZ&+K%Y.gUQs]Dt)ia{x/K9<u^W?KUu,ePj(X"Z?!W7J5Cy3ZW5#ZMgw;LY3^08`MpT;Hu*w.iG1]d)ZPc&@*`pMg]j4pcY"ZK=MH)gOI%EIw|BiGS8*+ZgeB]fo;7G1(_(qZxVad4tC#}cMYp1rUzOa*5zB%2Z[gnLiIq*2@oH}fH[ddCIbU+[NA[6@V)E`P5wJK1p<4?)3Z`#xcF5]M$mfX%Qhwq_&z+A|G&#~[&B]+pLRJFtM&4efjsa><DASpz/g?>wEi5*ZlB}~^PPVBV1*^mUUMoZsa):46uL#Pj>5N7SJ6bd_/;.11JGj9N^b"5EMMPyYU@x%75Rs}ktou^/|)xM=_ul7g/o.x$NVf5DxM5_`AMf$c!mCA!A.h!UI!f0~B}ry@[2CS<@Tm6ZK=B>$!XOP^MlFNxXIZ7`O>}I!cUDv3FUi*v]W2fBFxqb,BwWOz0wkS!EDy"zdBV>wH+3S5Kuh8`k8{~kUDQYADn(|L7]8E5w~:V5GGg?&BoEyl!XN?#Ni!gX9VnDCD?y|r!XY>:BfmjGMzDc$d!)fJ):w"&OAWNMwTa7Jp{x<L{lZ:Ib:wEs9FNmeyO%_yTpE+?z}oBOu7wVXgJ~G+Eb])|22EpxE}*Cb!M}~oK<.^s8#)bt~t+Gh775bFIt@dj.UFvjai!DYW1nUd^(O5=BsJlS&Ghd;cMZ{_=tKFx$~Oo.]dws.<.6rGM85vN/kS2#6xML"#UDMhJ99K{ncLCiXWML$#u7"$@%4NxA7Q^c%pE@Y6D5TKJEt|wuXf`0Uy8o7[;4~[[D`WK*+G`#~!N=^iJ.j#)RekK}vZdllGnFk6TzhPpq6IAw={>U,%Ql&YsQ8KX6T#FmiewR723BW?8c24MP>5mtN;{oXF~vD<&2Nb.)@knjKZnmBr(K{%(c:EVi<vg4R|=s(1g:g8p|9?3?bW+se[4W0(Vwe_"@t<8Qk(?!y(Of$XWT~;uPWm($!$[N<MAB(VTazlAjx4F~ypJGF!htD#MdmqDPwc=2oKWJ9(9c}$j&~A0c,s"#G7$<QcYt%cb%he&7(0Okw0uU``b=n2CwlKMLBos/JHDd4U%NC1}PX8Pwf9OV~C^oRtl4#FZ3J},!1`~gpJAnJu7vK{2$0ycqIApLCppIxVBSq7U78ZC|a4AUl9lCGu"$mdy:T0e.)sUa.[31%4Mr|?V{HUvAkfQu{{4)BdlNlgws77=Wxg.uEs{ap9Yw{op^Cywx!Og|Q{~I5)~leO|<G[2Cki_J$;B3iuvBaL)pd*WX<F+MomTOgBvs<cKZl=zuc)sw^*mSJ@nJk7yM"{Z!exSpq5{gRymi:#F6SB/;<M2a>N1{4o#K&p*9qZGp.uy@uE$vS:RD>U):1La?{fxScY~v$1b85+p}H[lHl%Z=p`XC,t1%G[N="`"Jt3_*5TYOLb`Y?!KZ_2sYg5L}U@Z/Rd`Yl=c0tC=HfyGFau|kQ84ZY1<M,K|{mr3pu!GN&JjmDclxZ4;~)UXT"4Zc)/)pzc,2Dw<uwmu{ia474Zi}{7a4v/ic!8WBL7ilOo5~4ub(^B=05d3:U1vxakoF`Tb3"8}Ms%#)Jkd*aPcjv/uF~i"T<VB;9dSSvDqa2auO}*"6n~Iku&5"c&`LcKL{ntP|bk*Yi}fvI)c5uP~OPXzqUcSz?sE"N,/[u}8FS[oNES<:KtGHU^PZ^OK:kHi;_`F/}o$M>8vC~j/5&9;k8{ktxNnpw5%xbzwW.4b5o<_XJh!]DZII]ywO68Hwnr[T7v.o{N>O3R+hUdNGWgN5A8jQVky!P$m&6Q+<D5H4*x]Q)k@WZR5]NoIC6Ati(=2RM`GtBXbh77OX`(Yb>SNB7[Hv=(VPC@#N{|rf7UWIT![M_fG[DLLt;>i9VVBt%c.04H=_x]DF%=w||aQC.NVPN?qMC}0=8;H8CGVxU;,5E/Q!8l(=y9Jq@fo$SM`gQ7TZ:@4b_`sbG5<fE36HznGRsKb#hGhSP/:wTpWZSYO5z!)8^LiNz7x+oryNq"@=KC`DtI[Rb3woNL&pFq0TZe:wclipxj}^,|*FHayjtNPOa91UADRS*YWfo$82CuPm9!g3"q.dXyK!_l$)&LB$3UD:bB0E2k+[,b+GpN(M7b*9kbVg;7Sie:xYx~H5L5FsjnpZ*%RGjf;C>l,SGUtT$!w+>8f27ylB/F9x@o4CJSVam`}IXsXL$tnM9?5S%S:p=i|9."HB#7CM%^9D<c2GKp7IXyV.Y7uZ;sPJ<eQ{w(|(qV?AgJ(:w"u?2h9V;jtF>D&lMo8+gp(yck9*;4N7j#D5bK:<4=>*o[CvV;?;YjFnbZ!DyWGV}zNb)?{]||sdff7qQ{L{gXQK@(<NQGx7`y>.D(oB$b)P#9a7<$tFa&ea[U=?9d]5ppAGyo(xK5[<ac!mE["{:w6uSj9?P;9o>%_nV|:wACywLNLg%UAMNp1_y9bOt$SQ,":gPIXBIG9`:wv*m0~906Hpl[;Z(X$9EDGxvd6ke4YKGDzA44:;a@HKVwR+PbMBNZ#Cq`:wX77rQ_gz&oCItYuHs{RD)<x]<"(#wE{EXU)r1YL!jZ,[y(ESuE:dzv?&b5<x@;BY99B3$!ZV}F>;^oIhrSMoUeByw])60*chvPuN[Y6D#)$Dkq*a49;kT0c)XYv4;JFLz",s*Y>GLADz<6(Jjn*_p0|S+nZ8Ge+"6%@H~wx0V|vxL5GyD:Sg<xsPxzLV}SSDucGVDxg2Q,<++[d|vxU62[=x>Z|SB)XDs_?;``3wqMEKk5jJPDhemVrpbYuBeSKSe]BJHEur$(`mYErcmTO)&xmAxN#[Zh(c7u=*gjI8bC&VN5fl@={WzLjn|Xw]B2bPp>;|?xdv%{bZ;,TTcF>LPL%r`Y*dohJa5%.ixE[tk,"<yNMEUAjj;#5aqQKO#97+4v"!$m;lnRst*GpsKZ(b6K0W29GA1!BA<v_l=OcVWwh(^#/d~I&I(^nK]/kjH@<iCR]){D[_zsvP6c@DUXK}P0Hz)Np|0ySk=oI{KU"%jP@$Y}ZW0yyiRvAz1$%x%D4(^;}`q_P{BA(:r=Cz"Lr*0~$m9d<wQYoPxl"*CD{]o*Hfla{qyVIn%c?V4rh_*D9B/A/5BHqclUYIX}2P:`@J07JrMHWZ}C=9EhTTVJ)W_:D5^j*##sL+RP}|$Hd;|LObH[>"u^d%vOcCs&f[XL_PL^u^ZNvnXd&<?*+cQm4_u^[*}9jD{5G>{+J}5ut{74PPN6^Wq{mHmk[[M~tBTt9Y2s,;kGs)Wc!h0RC;V|(oU&$5;io6t{](Kk#K!jU&ezMb$5h(6MJt:i$ni/&L&zNKJD{]E5L|{J#Gh&]/jZxcjtM~AI^R|D+aDnhjdO@Y4raZkc&Q(j.z5a}4X7Sc=;BKw0yOJYw(8N"?6FfCs{Cz1F=M)Wi&6?tP<6otM~(PL8;SjcN>1/gT^??&O@f5OC"F^"odljK,(#?;q#,ED@}Gs_YaRy%[j~0y(5<wzODK$9Ec1uthehezB(lXtKpqUN3_u)r~_yA6lsp54!k8KB7tY@V(&Monp,b&!{x,r(|c^$ivUQJ#n)SWmoc#3.WM&9o7g"cVhkO&m`End#5x(E*Mm6LfEE19N!Zt<@>>!X9#yPxBbW6sBI[T"](EFs//Dj8hGC*KV%b,sJkqGG@&iyW&GBXKZN0*iv@MVBya;&jP{w,zjf4rqZ4GDgG2oYYyZ4n.?w_l_cCDnn|R2)LA/dhSAa`lz?Fa^WE8aho!AGcim<!Xv5;"0<|QNQXEuG.!8&:M$o";6N,_xrRj9H$(RyJBCH[TAWChPH!Wldnh_/Aiz1.!^_6cQ"Riy`IZ:Ikc!J3j,;3?86a9>&;5<L9E>c:IX.nz4g#hnhmzC%1ZSj,;VSN)pXtO`]nz^a:nka++lSMtBVj|IZ8y|?6@sb8/Hzs%~_Ry6Ow_iAXcL>O]QQI!i(;5G)qO0)Jg$6YLvLJJsh^c/P)Nc0D`#x;R~Np.Ry<YNB>W;ZO_PRE#(anhpGbT+WM!_q565wHD")}#7Lu>H1IAO&:G214@H|5zs{KU!n^(KT=XoQdo~#RpPLE3.bj&}?|R3n(?ta/D7"80iL19$B73ML^r:Zsd7S"_WEpppOY#Ru[&^5D%f5f/I^:JUObI)D"f*3:"w{COW&&X+mX[([|#Dzq=)6XvM&(XZeQXUd"P7qAO_,MfHnE.?RjKKr:Z9Gn*[o64"nFDEFm):3`N_|d<}ka1_nJ5E([&A6eh!Syaq@I3}AR!4w4Vzi_<gQVzHhBo+Ex27`{N~8>^YE};v3cFX!SP?&A6"+"t5[U:fU`o~EB`?;@5$Z4(wJA?XK9WyGHE:;M*Fta:5Nhq;673?(Gbr{Dzd<"}|5X&9`@o([EM4V$rLT.tIeJn6Z%euiI]{NnGqV`tf^x$?tey;VO:cd):y~AE!BDn.PxLXi5_7O+lRuEK!)?UVdGX</.;k@IbywwW)_&.JI(,]*56Z%AzLYB&09.P5L0p>>cdi4VcbuZ@D|R,;(Zjl|e0fj3Z65csk>:F1<TX,&I6L]|xNH)yJq]km)8I39Zwp]1*wgy`bF#}E<rZ]l[7dl18a=aq7CG5?zb7qp{d0,|yMcf&pdxIF[9j?gVcr4VXmZGnA6B.!yhrfaEz"):n~VT[V0L)l)<&PNjcnBJ:"C4];a!rs_o93XQtpP5*k8SPwe+W/&PNv"Rdy%OyOr6Y0(&@>;+dTc24KC5))VRc=BF5&9xO9?k0Oh,[?Kb(jM8sva;>"H|f!CC_{Jd~tcmhMdOVJb.BZwchH5u{1vrIRu1E8f=Hf%y9vLVzcHt$}px)8!Y6Knq{Rn0/m!)]1"2ui<>WFr36rmZ8uvv7nCBwcE$W,>PK#7`6UhOlh>nO^YilKXMIKtt1K&O#Jq+nSimV+l4J.T`Ab)MR)B;UB~3=7(D~vz=>rsEP(hY4;hinicyI[XrOfC?@U~SHeCKa.sevA:>jd3v~=?>~SNl~?A1I~~+ZUvFKTxmZP}g_d3:v@D8Esk?r$2NzB,SDV""N9OC{?~j_PR{umoMGyl5D*%QT|"D5jiLaV1ax]SrOTyeCwS,=MwGMHpg{i2}>aUvCBiENfJLj"rRBi2)KK+dEv7L~g4WZ[fpe"ZX&AE*z^^djagT:`#KrwGr<I0JZ`tk)9JRMEa"Z{%BtQvOYMBlf.6`iF8AlO@}+jKbGat~Ox/1k:ZX&wEjou/+VFzp=@zV;W0vrNA2?&2hZ7I5Y?xsaj=NjtnLIpE/t=DJNue}/Bm;A35d5kGNiZ#Rc37;5[9i77!dpdI*]tPOe3UwG"P{WSWKFo:z~Jf.txM)^r47rI<OFL5RGE5}jxM|&4Uq*{=xD/z0|/wb;&:~N1Jg|*[.rp@Ncr9nO]NLPMR.gkAV,yIw+;S^(ELI2y93,uNuW+(VUgJ)Kxh>0/4l9+BIbS.P8YW"_M"dK.=qL]WL&Kby8.1.QrMxb0w<1jHDfnBg]b)VI%Lz!9:K"(dY#3kws^r_fdc;k^h]A)IY+@#IB$.pOY<i9DIN/(nVHc;#dD9OueBt$cQ5Pqm,7*IDcIAyPcN5xB,^%a)UyX_2DQG,gMCNPcETns]8JYV;t7IWF]YFYWB:FF~4?f{}wO/xE_{EI)0579TcW6Vk)0/MD]eGK8;Q}>|cPfu+%huI?>2|by:%:>eu3WBG[:alHd*MIYWxz/M&?0WMRYkJw&B>50yg$S*sIdZ`mCuUKmC|aaZF!KlGr,NcK9Bn6+_7VnKGtLWBG4HM({!(rkSbF>U1?8;tb//ixtOXe9[@bKZorS*2GOYC|J0FQ"I!7[kUe,XuW_oy,1tzH8!9%eJEBDMgf_:Ld8ZVO494Z2pm7u/(/J)Heu8kH4:yBHQ$FlLq%dzqt^Bns^c)/BmmGm!rY`YUTPH49%l1D)Uh9!+.g9<9J|I[A.72Z3{R!hF`vtv>aE?gm~g*YR=!M5Cp$*A,p!Y`1f2(KQ_ZI2j7:J"N@Hu{FchUArwm6]b_:d6[ZAZ0t2&Ywav`_1%%|bB`ahpf]+tVyyTs7[m_RoXjCGybh!C%u|#tv$q<0/RRB@JVP`?ZeMB>]*v|#pt%F`7yZJ$5E*b6/3f{MWwQMbc3ci>|a%u+gLwP)03g.wl|qN~.gv*z%Yu:4Q7fP37a7=sb*@W7:bcLHhGptcpDN?dB873J#3#nQdc@/qw?pxWz"hYfuW,`B`W07.[upBGKf0cZ<ki9f/1dJeJER>ZFU~(&1&T_H@aFY$!z62Z.GKpKD%+L:+:LH6,zcNc(=G%O0#_(+Kw~30iE{eJdJsjS>8&L56ASdR^Y;]XGzRN+xi3!e_u[dq_%#j0&tP_4.<N|5]{BbJ8FLqtaT;nA91/0|hTVUU.@Ve@Vj4_4H"*7S71N,1&XQ3vmxx|:w4CHFeXeZj{IYVk&/^]T27O=t`Yd3,g(Gb![&aMKJ|5+WsgdykKy6nt5&ck0Ce]U]jl>|(AW]=*LkZBp:%Eq=npNN=UNxX.6q`%V5K7Z3PQd6vtX.hlzT8f~D{PGT~,GU)r`Y(Q2]LO7]WGFRXi8x@=9RD|FJ+2}m?X@$Ed=;QHLH`H2(6:1`"!cG]}Uyi}MM!thGn:%9)yG0?;e@Eg0ku{8evEc<eJ;?W}[AdNW#6R;gi<O`I%99m70h]iYxklEXIYl?q_ML|ynV`,[FK[.OzUow8&R|})?TqOb760xmxL4tM~A3tO+xpA7QHuFJr7:&G@3d[6pL[Y"J4#[Pi}?U[n{Qkb1=a=:|l|1/26q@"I{>fi=a_08~0ybJC.DL3?kz&y8Sl_zsUwWRm"Xq:;OhhZS}`;%:/|fl:4Q&`t2F6q!h0Rm+pDJ,>)jY>+]"xPs{]("y24=hxqb68>*(crb+N2YZxi=`%,%F9v&|ZWo:F6(pwPo*&m:5sO%9nOj=!@(cN>Yi&u?h*?!X)C:qoInU09UZZjejV|_yEejR9{e]CJ[43D/f`lsUq2NAcp|.#z!Z]inhhG:CgT6)K{O.nO6/%}<Le/K3U<ltBh3kaO!!&9TwSF}X%Pp`,xX*aB{;&diNRvNCt*qTF)lh&l{]yid8rKd^a&KSf+Y71?IZLFNoPCj7+J_pOk}i4r6ZZM2b[QX/PU>L*a4O#9q7Z.z<KIL@Y3*TmkGU"f3B]Wj=.I[_5b,=LfmJ"fL*pZ`B+kV&n:%S4{1j"PfeOD.Y{q.;,*:+Rr(^WNAzUXQE=uD|.yKG3d1?ta$2i"L"rQNx%Su0ignhqz`(R/3rZ*kVMxhN7R<;*:pUBJ71,q|6QHdNwDWr9?%NPj7K1&3MWFa2;*:3rL7]2kJ(n`6`8w6c?;B{QiM@.hKyTsgAbHaH>;5Bm^z61GNh0R%9/[9?cdFfgc&q<HZ~]j@37l`lSoOZ2Uc8VqeZuIkn1?cd20VdTXu)ME1J;A66%9vO&d{+V*%`#FV{[AySrpdYq63L|Ln@t4"cHE@0qpMb][tUC&EnNidiO5Crfa$R2A;_7v<x~n9R55:;vS<0ck:nP*OX]tk1%wtmnGfp]PeoX{H%nPxOg6G|5pkc3nsP!ULmNF=KuLO&{iNp/:dRK}v6)oqS[oGhjia7r?O?qV@u]d$Lfl?P,2W{5+ZUeeo@29S!K1hR0y,lV]23_y,_H>yRZFu]#aslriZOeGzgM>5RZFGd9x*xxc$2<@pNtmTC_4=|<pc4;.C@MJy~y^Jc`y[1gnF2!});1R%j!>yE_%s)YCL<n&Ofg=0HaFbt1C,c8gY=n{=$~9:J~#k*`"$m(<9{^$T&?6P$u^,_:y1L8G;<#{i|HWl(8^+ngqp==&bun(p?4nu>xQ`]5]$_Hs"{eW_[c?6n:TzWA9$l~{%;S?Sh{Eq`I?xnbqJV:&fT9JJd#mPD{>pnI~!m[do``Q3a$,!(;>knV(1tC[^$UclPPW"Z.TEfbxgEwp*|EQiME7}=gh{=hp&20=|n"iU|Vuyv"NjGA{#ois<^[)|f4&a,1@U`GU.}78zsbeSea6pddNBH]v8*?$~uU&>&!~1R^F~~6m<xM/xq?;p&`m/.0y"*l[W+A"$7)Ij[Y?t~~{w!?jt`kf#X5TS;~s][!ep0f%k~KWE7or+K+TRf47D)4?Rr(.[sHii}^J_b{%RY"^F_L#eNsG4=&pn3}xaFXu/9SEPw^)o?6_Pt;/7)k?%KIhn>:Qcg5n)$OFe`}VCVjP+C4C}t"(~>2Uigq$c617d]0U8b&6zF%BF7Z]1%~b>r0@Kiuw_CArUqlQ;eudG;lBk8w"x]ieV)~>rn)Tjg"N^>q_ZK+J#7TB2%7}:V1]unYqb1W7cK;JmCc{F~yK&,5]1n,T]2p.o.yHptm_WEOv0*0DGP<8Wi(WEHpt9kdXw(H"*Ugg*Bi4vD2")H{W9M&")D&WEH=J@QIR;js4(BZesO}xfMKvA7jf|[`eD>+CN?Fh8(?DNX/OD,:BKtWeAWipKC@u`AfR5u.Io+=htDhLB}1O:Jv>R6<}2}Ote((UU:$`BmN|}~RC<$EEAi)H&4.OrDk^l1h&z*VQX/ge<!{uUDHRJ.^vbPJt&qkuqnqCa/UECi)H{WZL$A}e:V)I=)%*6P(_)N3u3uv@3I7R*r7n@)b?<V.M9vB+&%?DRCG<^t!h4o^WYq#"(B.$dS<0ydmehg`CiY<c]VB611&Tap*Q4cF)sP]:5B+iGu8O"FjH(,dB9~SHgW8r`B*q+G[2nc?VL8qNM!=gTfBJ?b]C@$7PW(=hg!1d~z"OYD=G?o$(#?#(}0_QbOhYa"lBP;*b0EGPev.>s"*dS5B;YhzW,bkn}]i6=hKg|O+O;CGOvO=>n+=&HORtoIi"Mc4WXLAN]5.M@~oH9WRBd8/b|Ont>vj_8hw1N|f_l2MA3}Q|lC7sX"?Db~[(8MUEd]:&z)>Dh`f_8h/d"fb"w>!w6}Q|&bbM]dm>UBOaaN`V.nD:qb*|MYHan{bRn%onu~zg6_79dhuT9Ou@Txe/zEe}_:27,~qZJ4T9L/j}l{[sewTks}#68>Tbku<<0R,|IX:~;Rl1p^z<(}%Xq(>F%af^EJ?}ht]sZp|l8<JSg|!N!s&a#h~L<2v][Ck|{#X([vbn9Lzkj|7S5>GL[XF.e^#}X"dn.vOjK`:^fskMPq+v&H*~)_!~2G_;pF3Yg.]|fs=BPqv<L8P~DSpW+Q~SX^yf3sd/<sCeL/!_FaU(}5k%3[eD*spt+C{[w9C}IX(181iXKYXWJm2Pmd`V!ZC6RK_3d{2QtfX%LOu7OcmV<XmAMM4C?rYG#fiu9qY_O0v!$KO!?#>4OP~3zBeJTe}qHXyJb7o[Ff(BOYgRMp|3Gj*0M@!SD%^iNfSl`@Nyp~+0UY8b9{`?GxCULI|i`@oxoEVvC)$DLw!S"MR1m+bY$iB,z?Rv.I+{Ha)qHsbkH5bc^8?rRzEzrp,BjxR99d%5~#Fs_pF@_1kf)|gM;L|]Ga84|$=CcvFs}dqS`pWk`@(w+y*9,kOZ4O2:;bom2j+IEt!k`@(wwcM1@L]iki0IV$~Os+ctm!r`hY5X1M2_1RRdRyHw1a*UgR@dcY<k@bPtg]f%.JXfaNgR*ugYXuy"&V1M1:Ej|K{)OMgR*uCSB(T5|L>{}4n#&S"5#e#6M#r`_vHM{lHae62|YB1u6)HpBB?nvo2H"b*5{[WP*?AI`xt&Kt+>1V]vNtXQ|Jj(mBK7E".F^PL0n*]"Pt"NGUXUUSo)}2^z.8ZkSB_Gv+W0+ly,mE1/blfl&1+_h/=,FG2xlp#+,!mMHH>6AK+SV.*6MO[gBzMO@Y*Qg?3bPtLu2ZWr_H*4U/7jX7fvR22b=BYf)|;LHM|]elieKkES;Ct;UBeyy@/YgR5SeSAs*YwdzjJQ!J|<~c/Bbf6A"bVX`/Lk:!8x+x=Hd8o]8O!PQHbB`Vn+S*z"fdUSvf<Sa^iyX<7#8L&K?o9FN7s2^c{%wVgRANeS#1oo.@8:ns<;%Bd,vnQuAs*YA3H7UKIeC<qev84RVNnS@*b<S](}<6c?xl,7TP~3Rj+5@=3ji9i1MYAw~p<Yt]sO.Wd/~`&J!F*MeuQJ^!S{;:zSjnR/=,ZK.y*9hOxg8?wJLv,Dd.#D.,uu&f)|,XSzrp9S,/Xoo{xZd.b,sB<#nH`Nvam@@<jYaE]LR0>l!p"t`JVfrE%u>*7`Z*gX5:n2K!{U"%l?+$IZ*M`"MC^th<pcNA6/vVPNke`V<v>P5P<CjbbjQ)olytr*i4[1!1?A25e@pV;B7K4f+,jk%Y0R`/zs/Rv0i9NBO7<jCdammGm*u:41"`MLW9If"+34_bdQ3X1c<6ne`Vb+vZX})3Vi&Azi##qEUvU]?TgRN{dSAsaZ/MzAZLZ2qjVxVfIwb5dv#M|]jk!c*%R`/VQromon(jjLR2"`k(naf(44WHqL!#GKUaZ07n+5M~^>1kUZ_2IeqDT!ayQF(|3XDaX}zY9Bp|jZW#6UD:R<JYA#r`?u#M{l@VAjFbT"R7uBS2hoYB`V5_/5u^>!IA%DUD4z?:^2h)7W2k`@&DPY[;iEy2]LRDLOcK!O";Vy.h*7[tB(G@Bz`VGRb,TEb`5a+eP*Vi:s|$iEysZL>9CZBx)n9e%^Y(B?|f+`?=Hu]eB1iXz([GUWTTiEsGI>AB]$QLf..13i]Zef714ph4uyG[+r&sGSP@i~7&P@WU@@yggOMj*|@pd++>YV&shRP@(|JuQLUx4=yKNxaN^MC}IwY)^c)XsI4gCEcmnGra$URf~!EmW%|H#f~D8Z.13D.1%Fuy91klRI:Z|[fM)~w=%scQP@$|8lQL?_C3Afltb6_KBsnPOj!|5eQLW,xqR74gJz;56P%siOOj7|RW@z5|}RQL=+_Q.dCGAL"vGY&x91"j`MAL"v?K[CR5#N`&"q_sP+fGzP[Mczy25{$lMha^6lh(rK{$n<P(lgCh<sv_ZIQ4#))gR9CE3L?)PQR%~,^Rb|Mk^;q4&H=?Y19}5_n(*,%,[n[$hWRhbZs[5&pkP:ip653}2HuC(w>,n~FRRZs|=Z(&">yl/eUXcTpp;_`#]]P|l?]]h|vR^]n|!0^]T[>?jh8`5a<sE(0R;|x]e~XD}f@`,gniL&L[?A.Dv`3/r8o{/Wx~G<6oj{6f)~z#h6A@Ytp(xPzFOI%}OPQL*+,Im~VZEY1L1aDlC{Gx2yk|oNgW}y+h;Z`wAW@yHo.}qFd+J`k~fWh?E%<sg)Z+_Q_5UKAW{4914|^E4g!w7Zy|>mjEFt?HrOP19i?ctZY+G`5KTLr}|@fWYyt"b6Bp"`5o2y)X~@!c(ZY+A`H$CN2,dRr7w8xFXl>~HwcZ#Fq6Oijsqyo_H>[@ecs6:m*2@Q9u?JAW4y;V3Fo_sWBBcQXYD:VmfR2,)Z|[z6*R`,}3gcY+TGY%^zIaaf<sZJ#REpaYALQR4.kzqo6N?MMj8*Fo+%MaW%;zTz=jgG#LQjX%;zKzvdAj,0TmAecQp@F]qHnIV[Li#;C45aZ94g@+E6BKmW<>xqj~=Rc+`_SvfWSE:h<+vvAW)>b<;sL(0RpCV%7zozH`.iP1<t_/N>4yLeX%7zTzGo,dcQQ*+5g?^~<xc|l)W/"FcQ81^/c~PoHh}sSO3G<FmyMj?GAYt1[O03!c?JD0<ou&B."1sN5IAL0*af;s[UP1.t_c8|R6?}uz|q0.@~QoTVgYA{V!E.?HAm,,6xowuyD<gyl+6RH0Q+/p?u=hpfPvBZj1O*`,`w^vd1{RPYp5DGhOl.`V{,DG|$v?xZy|oWU>,I;sG&`T@@Cw=LMjOnYN1auc~[6;_j;Z<o*5.5[alWEe~@*X!00!rZII^}EBEsM^+7,?ezR#t(kI#R`~|uqWh%;h}1VCYLOBW]|4KwGZWLrO~K~~/!(hZAI~Y`k~5WCb~~DHBA9|fA%|wNgZ#z)h[(`}}t87W0]}@t!H(*7MCy#$dHDmB">2@XSv[~$y+~uHo._|EB:WX$FO(HtWXKI}2<%ah<,,_DbOMjW~^6P@V~c?c+@_MhfWf=af3KEZ4s$kjDcQzIC]9]KS}y3K{Q}j0KTK1|ZYTQTZnvF`*xG5q)/LcHjtQ.qy5yM@7Z}sP?LiI]4xAW2wm|x2PLf.q1D}wIALy^Z&kWew0R%}I;F7jaoI3y%{R"El]}!/3FxFK~~.Kc2e|}OZl1uW{`:HfW:&m~)XkIH70R$}7)YC2,qcC{@D/e9%$a~4Qd7[3g+UasT%+is|XSRzmR&{~sc~Q+8FY;xP#xecg@:js6P,<)%(4TRkz,x<6}iCTn/I7Y)m~t0R]{4P*`Pq+Hx[_|Kj+k3o~tXY<4)$XLx.+sQ*`$sQ(/;8D(Q|gMLI@[0xesbcy>XI@[2LN(rujrCbA~jGp>^20v8{h/A=FlU[A+"=}_0*O(g7ak!6=s<>;s)[Cnt|=EY_Pal>}_,_ADaL?&S?&$<wa`:HA(,0!Y#*m{oJ<{m1hSu+T*m.ZET%OtW(,M4Tt&Pz*El[0xa|`;}&(Uz3#gF}@K!&f"(sGRAZr>>yigxHZ{Onvip/KXy+8hbey[WR+b"zO9E8XY;NB(b6DB?YQ@LEHs|_JlVVJL>j++m(f`a_/}F/axT_~1JWJLdG(&5Tqng9+I:2jx[i;T4TO(o1#}*5Bdl>jKko/}O^@r@xQR!cA"D?U_$fY_gViYYEfZ=)3oGBvg`BzyO1JSTxHRF^<ssgL|Jq_@B!z|1Md_gXG#)HSWAD{u3oR{!m|!Oqi9JS.uqx.,3hQ&0}$%q|LRns&E/&C9[g(PdGQ*[&Q;`Cm}f|7QA(IDXq``W?|I0sJ&FJX}5_9e>&,@C+7h9s;7+{~&{(($<wSt7<g|31*I%I+AzkQ.[Sg_enHDmWZN={?(vK+AUxqa#r)F,$(br]:3M(Te7Y#*I@BCq/8ha4H/|ktB=5M_=&h+CSce:=,I9`[)8/P93%oVs@day<i8^^GznFB]li](7eF5}]8|MTyR!cF5c+qyy,t_<9IYy[G%Pg,$Cve]FGj!Rd;2@R?n5Yls|$5TO?9*.QT`VC<r2rx<Bik@PI[&:|oiYx:}LH`|xeQ%7zrW8>8JPG7RR^OjU_Ah:@;Q2~QZ#rwxY^(!FOlHA*kT6DbjwE!|HVaKYX[p|YI0~v#?ULtLU[}WA%O#!>W9:2?GKu5op|avG(?@d?#op|ynd_?6Q^C`>Q,B7sP3W+CahW0o([7gCo^S23Wrq}j5FR`nn_2y5Y8~l,9>8(L4K,zrEt,&TqBH(K#|M>B%CuC6Wr!}sG4RnRKOm12BYF5O7s&tuswqXn~_8&&tuslNN$8}2lE%ko":5&+|.yWih5yuL|)(M|EFp_=];vuL=u.&0K.@QCB~>R/&wpbjoEA}[i2>T`b_<R`[34M(jYnrVCB~w?P}7gI]]S/>XIz}iM/u^nF">ji:m(/iLqF"k%+`,&w(oCd~og8ITkM1tgL=}]E^wR$IYxU$3y{RaGq>7!aj^<O4Z9Wm^&;)($`*736fT({*&Y#*(3ZS|?Qx/?en%[nW}$jk#xvK`qmI)3I($N4=62NW{Q`ne40}d}HV|(1|;C7stnmpWR8~CR`n")b~1|HVdB6R/oasW92=+tK/eU!fOQ+Q>rGD]s5Vlb$&2m;hUx!+mqVERh"hOITkfWT%uA6T3g2+@I(}9z<|egRD+o0Bne")w>,Ljg7J3|zY&rPENRo!7y>j[/2^<.8h!@scpl6Ew*4a~%<2kF"(hE(|ZM_&=kpKQ0[Qzk!]%>*O?e1(TL<}NQDP@R@@OzDln.QvC?FD_}w"Xn:0QICMq.MJ1sTE7UbMq.SXQsh:}nBGr~Mi;C"5o>BjQQ6n%[:HC(S79Y#*/40R^?,c_}SESv,`J=c%o)pv2Xvw?^Do_O2c~JLcz3GS:2lk??_oc~s(YFvZuZ.LPez3e(J1bQ0mE>axbjgEk|h3e(o`@Axgb]7g}$;lUXI&]:EJIvxIXiksfOW_u^s}Av0|/@O|24z<LRSW*n6WoCzr^.zp$rHE+nZ51_ch`r|_CrlR{V%,.w;sN+^&lMJ/J<2TnO@61_DM&y$w.lnDT%guPQUJbj[xT|=i[&,EW_WT@}Ij@v}<c_V?.@!EvssDHVSC3+&SE}?id_ViW_^MI]gF_|!Io<|MK]Gzjl`RnRF9py0ET%Yis>lP7YflO?zEg|tL0EO)c%p#3$1_HwG(tIu>:#1_(<o>koFu1&l|iM.%lR!}0}en_reB{vTbMRm.%EDoL$S(@Kn.x*MiU.S(f|1}bAk``I,}]!0r./Ah4KdGnmVn8^J1YJa(oC0}q=Pz"`8}.Lq>uQN|vkhWq#~F7nM4"?8ET%/>9hvgP9`j2+6"k~Rzn>5:c_Id+}90~L~,o_?kM)NI38Wrf`s^PRQG38_RV?6T*[<9U!+oP{h)+<SrQ}@T"(@lz,NIsNeT7Y7R9(z~<kI&3>e(wR8XQ]i~:<z}T}J6rbOQbRT%#};85rI9ixgE?~diq>%2O|?)WLy>Xgt*MW~~$+F_,@9*^{lx}]h_GvAj>i=T:Qn_05t*9>]kM4Q`G&c9c=lxBH25FshC[Sx*>.f.9/0If4/s<$H&3>iseBDY=j+tD1sn"Q~HG*drd7iL3W{g/z~It@cxvjT$hl^xa.?yyKEDif?mwQ>WIx2qDX3iQ]LH&gxT7f#eyGl%HfXj~w+InEq)"oTV=x)}/57WNl`k1lVKH?c0kUI7F8^4xo/{@LySAeoGX57!/$^(E/i%}GV_|_hx`U8~_~PZ=F,eBe.&32PlVap/RSWd1j@2:oXu1%r+z*OL:/sVvxA}r5fl<YH0Wn[ccY7d*taszv([&K9mQPmfO*?rjckH&4]$A8DEpLfGj(<~R4]|&D~UUn:/sV~z:x"?zKQ)y(T(=6o]8.qC0rD[0.fH9MT(BeB8*#.,}==xA%6tK#uJgiv8[6X2[ZH)H4H2XUcF={_]1$~PlbVjTv&!)tm>#GQi[j?z9^Kh1*aja|pHc7s0qIP9gY;Oe).9f,1g|u*et0x7OMI1oOOMjmqvIO]"R(uT.z"k^NkhTN%!&Gx3%Z>M0?GLYzHU/7T?6$[5FN*$(f)`+vQV_4y1e=bvgS7D8|9LQDxIc%oFxnWuB`#KQ)MV&@x(d|^xA%!JyRYnwDWc.Y&s8FRtVxY!DES":C/=D(4XVj%*d,b~yQ/?,aJ*U~x[W(n|W_8^Qn]n[nbnX]@bDkasr{m89rD_Aq#ocM>wrFkhT%6GQR!XO|m:;6o"6TB!?DzZrS7sc=h>sCbn&WEH0coNNW?G:ne<<|zJX<iC(#J?MqM:{0d7$ryDWcQzn>"F5Lt?z>J?zK^L1>;(>JM)}&IXdS7XVO1r{iwJ;4jkTvq+(HpCrI,(y{RE6nJIt?nc$4.YH>{zqNIjcna3yU+?ghn`aI(r`"IOjXkSeg+fM:Rz{b!uy11%*|7B(yPD[Y5TyWlB3(O|MVeua|Tn;hKC[h&mOMyc/?4ZDzXXLOc`E$*ec,8;BKOqaVCncMbjLLa|7)>&G;r>M~M)T)W(1S9&b+e~v/gQ8~D%%%l5<~yI}TVqO(]rxK,v*niTkZjvyZ5$IOJ1fU@9YN]3fDbjP3o1=83o;]f__}gFG}o:(&c[dG7W2>Z59wTIms{nwBQ0^K8~sC6r3m`)1+xGA{e9*.ah}rp!w.@Iv}Qqo~8;8F5i0>Kg1,y5||<;p>:2eMyj,(Jqq];Q6P~Ld9qf_?7gwa/l2(b<#|iM$~<k2(0R{}R|=K2;l_gF!>yrI$f"vwe]"Q8m8;aQ`<}]%)<x9/wIg;kWx?G&`&m`gf3s7Z8$Xmv<9lHcOi>CRom.%0C%rg5>z{EJ:P7*W9nWkt8~Im`&rg?sTnl>t`82n23Y6CQ|6t:^3tvQ<@C7fMj$5}{nn>t>9>SB/C"d6e(}+I=edDz{]bx>}(pN.MQ<,Ij`]%_%9GJ^hyu|c><2gXO~*tt`SRh$1JAeT%|o2>f]FV%tPzryy_,Y$r!(<rbsauluW}a0X^aZa|xu`V&6Dr;_*Y53mRx(m(8~9KvXnnY+?&E7jg#9N?d>,rtaQR{_$e>jQ)EJ:[enkgy[!ZXj+.{&3YWQId<}e18TO7cM*67|#YCs|8?&+ba`gF<|mw"{i0E~*togSfNqQ/Qzts>>sx]|rBasc~*"#g(|7B#^rWo_CzCRl~j%;(JEp|LJH+@I[`~sM|^{*F4v;&y*;SI]`?:3Cs#cShm!.S%,9x;st+[&g8J4;$SnGM]gkJdG]=W_Pl/@2.Z(lSegN7Pz5oO}[idn:7M|fUI~@J7$y=f>?f=QMS,|0u>>Sg(~+xXn$4bjH|Oj1*RS4)8h<~9CJ(he$&a~LMFx<<43nRs>8~noqBdc[Bqu0}(R.@=,Z(+Iy3/h2+e!W|i5z>#zt>U%SG$#vWU[SgjgN!Un7RuEtCk_0xT|R|_*U%wu6aX`NQJK<EJxvQNj1Dzr|&0}<]B*VI6s<9+$hh@(XI$_m*6R!cu8%,;?H@Fte(|hN4%O8~B+NQXedG9Y+yzr0K+W^bQc~EaJyps5?6l%pFuKaNF2/w(yQ5Ai#97x)L$0Msj)tYKTC~tt`K.&g#/<NVH}Bq@Vs7,OyDuGae:Byn0mc}|&Y]7bl?9~f@DGC(S?3X;%v~xO1FtT2CwI!BKh+2;.e(sbUp%zZ|$5x>[!K|Z$9T61|.9_W+Ca`;IL[KBQ?:Jg{>[yx|5?i^=$I~uzm>JTGZUZU|]*rDScOJh2Ty:<RDW"9W7+&=%?hkYka;k<3Fl4:F!y<.K[%[Re&oBZDY]~`b#,>WyOfHb!q]<>m9,Y{i:&Ifb3$OoFA"5dIucg^BAM9z4}IjRWy%cPLf9uB(dy{20<r7?Q#?{fH^7b%oOWs+5$}`;6A:Ju:v3`WVyr.l,su#0r+>B7~&L}/)x>ra6bh0ZESEo;B&x#[S,|rw>rM9Z4F1*Z?9Fw6d%wi*$bjOV80(}[.LlG&N7[fKuCQPDmJI<US)c_6<yrC$6MxwQ=2e|;F53||Atou}b5uJLz?$fg`%49^3E^oG/4e.qJZ_ala+B&KG+P6I#}F^2BNW]ufFqpgWLM+C1J"`dym@1>m)4e_"6LB"x(p:RxNlh*isiOV_]_UN75po4Fm;t>GBZ9UUn)jU+@bAHD%*|{.C90.lb6s%9F@sWD7$`TOK,97<1p{k3/Wd6<tc)*)0WZ^JuJ6H^x%(y]erxWdSwIp>i#JqAmJcIO:k`:|p=?ReWu_CKa&eyh"`DyqZF>ey+`mG8_cZkw<z~a.`?xlAXG)+6$Xm*tNA5=nIH`s(~_oJL=z[4}FYoU{XpM|sfbK5nUD~wyl%$Wg!Q(a&dgLTL:?1?]`G}|C0pY}$~96f"_O9;cu*e@Z;:2wBvGjm~tkB8{>9P(4lm[Ytj|Z3:0~_@ha+yK={V%vKJ,mbe|}K&||b/>QLpHYF]>($U|=]^&D<yp3v|C|l:/B&~9o%2+,}j/m>h=l>[_)ld_P,!&;}VO`LOqGB;ed[EJQ5tIH@@x*NUJbyq(^9kh,?KIq[AhEzQYOG1h(T0}NayrvBvd,zH43;rgx7<9Z)N+|+LbJzV|IpOq3td0SV%~J!v>0(hgw">>)BU|1LN6T@Haeg3;mDF<"p/~ZmP|_RWsr_VE`*hWPn^x9xCYoE"_qXS(JOytJ7n_&>e0())?v9H]XII(x>cMmHZ{glC(!*9{5vH~`=FVBK3$ZH2y>WpCs&]|7I~`"HO|9>#|uEeW?`;2iSBwyc/{Axy>R5u>dWg)_[.rly{}xF%[Fc8!H4x{Sk>QJu<~3{jh1hvnwK:Vj[^wY}X)^&>(KCRn.v)]LwYw]Tyle~$4YFTLfbU(W&0hp4kbRD(hyymr/4[ExDykr]hu$k^U.}JuH(MlF:#d(}s48$8Glt1;T,>D7}]E.hCTVj)sS[H@8.5:MHs|.Lz>kz[./xV4&Z8~TF@&1dfnT:_%J1N%Oa5sofc~~qJ`cR@@L<7>p:rR:X,nC0F)EJZSfd!hq1lbaxDjkw<~VE5~uD[GiA^xiyd0"dq_$l?&ujA0Gxl}j{Z_T~u2X_*^a~Ag85.}u4$cs4yI4>"4v#6TPptF{h#}iHZ_rzFK0#b)&Hx?<d*jH1Zz2hsNb~Swc=+AKcQ492i1[EL1Qqj"y>9}6_kl4~]uM|!=s3qDm>`z]14OLg85]}k>u=PA=9`QYF]>`KO|#g0}CMj%`XHq=9<MTku6kbj)6P~|9T!*l^P~c,WnBri>Jrg__^RS"FxjtH=}{tV_}LK@Dgg)#QW|O@k>><S4i>BCNGj=w`!7q>mrfMtCu(,1BqepDEW5EhosHoHo]7/sR5j,m(,9e:Uv;cN}jB>(d$"fZ`<(KCq_Cl]3Y*,}uy7}FkM|rkT_b|Svp>k1Hlvwn~)F7TgA6F1x3T{}iAP|`$&?k!/sT50}"12$8Ir(xNO(R;UmE3j_nxT_mU:K.)&Hd[y>[f.#2}8^Q|gy&H(?/W*#)J2/vQIs,.hq12ps};Mq7+^]2Cc+,7nRx3x#R6OF=~gJ:2x!`>HRns[>6T+%D^68c(lj0}ru5/"}$|@t"r0[|%u()2N+|G_n{$UWj&b~$^7m6hMAb~"%|=)v0s}P3Ts[|%m[~C<|wK]y:1h!1r]1o>V{^^T~>RY_]14OQ5v>3?x1^nau</w|P1(oM[8=$=Z/13MZ@BJtZ7v~4(6T$gg>}tf(^o7srLCW8y1|(4en1AJqLR,o"*pKxl0p,vd~H<8~<>v9OjH;`G4BewJE%h3ex3NihZF[a{&fs>|<~ztO@~~>m>|XKVlZ[HTEM<5@Cv7|@ii^xUe~vmKqrEy3Rv2$)8[XU|7WMYN0~ha(+{zrdWwal_RC4|538(;Wq|Mvb_a~[EmW9*zrcJWdeY%tnI:@z})KZ6Q@BCMi!v2n&DA28yk#}G%F0!~YG+}v/]J%$fp+TVqM^C`BXct>*8@t9d;X1?_:r?]Z={pB(M!.z+pik0#4.V$SSi~/0_Ux#+$j<Mg|[)PX#3Sz/9>P@uU$eO"u~eqgh+ETTTMS8??bV[qjE@!RBt<sghYY"r}Z[dgLb:])=_TYXDXO"xKc;UY$5c9>lM!3W]_a:v(,F25xu1Ucns}(eg/>%Zpb}`zw@r&uc&83(xFIO=ht>`RQNfK9cPii`bj!!Vu41UZx?MlrblB_eu!jQu=Lb0+aTmO+ks^hOv0RZN%F!s{n9y_)61c_qBvCuBJwR?>P{ADg<kq*od~"ia8R^CBsb}frN!o(G^YMfxbvZO8u{oO)YE(+>.pNN)}hW0GL=?km[;"}Izm>*DKIV)X!&n;`S%Z?rbPo8s6~GV4GBV|Hc+?*S#z:Lbf,Ojy]3so6)}C2&~DR5TW^+VCg:vp/`+`9$R.nW(#P4T8=jyli5>VO]_dQw)lg:kS/lT}H?^Py!}FRuzE}[)YU,XIzOW@h]dBqU)GT<L5XXc|R8~C4kb9er8au)Z]),x1|oL="Tn"_EHzRY!{;S~D+cj7F0iPJ|Y1KN0@o?`3Yy@4w_k:z_|_2y{>2lK:9=iOQ/K2#%Y@}~)`&v@%[,*r<LcWK@Gb`o"e[oQS$<FAYDUjz#>Q:RND}Q5lO7#0qr}"wO<|E/(Y)La%(jk!B&W~IG~A)>OF_Bv"vPBZE765xqvS_BUT}Yp!K=}O)")ZZ&Pl<x<SX{x(TvH?MI&W/*5Hm0.3I"@9hOm:Xn,?!e+2s][X_~1VE|!TWSE03JS]"/Iy4G}AN0>m_R;|ip(.ad!(D>6z^66OFZlkyuU@Wnw+2y@=#k+_mkMdXf|6Mk^07U|2B|&;>AYz;M4n6akt>f,}Y_/K`DE1?|0ay3nM0XXBc|#Yngle:g1Bt/<0$T|%kZw~_SBJr^NC**so&bn?m@Evb/Z}r3A,>nbHU~s6FYF_H|5pgM{AZ9>")Zb%u|@]X(|G4d]7b8D!>^j]3gQfG}U<sHiU_.se:/nR{{vE(?6k3qw;Ay3jDz4d!,O1jDVs/Fb;P(v^g}=*J%+/w9o%v4EcGEC1n]wo41(M(3T`W(OeKgf|O&_E<hS~nPW,z83$~@WJtO!;&oH,BsiPo)heC#d#5FzV_g.c?[[bv(UfXlZ9FGPZYI?Dv?l>dLCTGfwSA6s$xLHu+?:gnp{(o3X8Rfg1yiAE>~rC60B3{r.^&mpDLH$/`.=[rU=#b"5juaf"Cd*9|QCB>m}d(y+%E=ak8gGtv1pD:iE$w/cCZb?KONQV@,(Rrpm~FX+3LP>fx5gn#vzD>{hKHY2Zx_AAnwFnJ6iZNI^8K_}Q@K0&"_5[&JC+$3*gEB"nGb/$ndnjZ5VVSb3YS25<~.;<s=t<s68&F{nMSv*xwF)L>G=GcWD?YUv<vRzMw=PtGq>^!AFDu3X!$%)[]f,jpCueWcqM|Q{t06Rdy&n^_#a):6ag4RWXyG&*x?:#ea|NsU_f!>G!LA;3Il`I#jb|5rf)>>J}*6o9{3b}s8kFVYQJF}Oa`Na8rj)v@ITC~MMm>@n)kZ.(~Hp9BTdldEI%e(frA25*mLD?2L3Nez#!8"94fIIiB3rqzk^f"U|K*Ze#nvN,VnHIOd/t/HIg=!Hp.lg<MkXm1p{B4y:>>fIJkST1wfnwI$rMqK?pqYb&`3QosU#:*y|UNt}yETf{ugJB"`_9agk=0Q@SLK,OQ+g[ZBWe:^)f|!4g]7bjLOWJ!4T6PdJ1A&4jUl|9Qpz]1dT*s4ILq6S@GP.l~?t?SM2Cy3n^Tz7e3B~>SOsRj;p87cfj0|e;B0P]uV[>4f]bj}4ou;NGj<Vy%G8I09vTWL!FUq?kmvQmfc,.Cjn6aQh^xAYAMxvO^wA(.*B#P;ZS9bX>HwmZR,B:$NW3<`<y{PKYzHUA"0cr>}R@i{@4Fx&uTs!+xpiRdf51>tn2/Ko3i3?!dnP.y&ek^HAvW+rXGwn%>u0,0<Lp3#WR`~Yz?6HESJKAXcr!MmG]J=M?XJMMQYZjJ)iTPuBQhe|UDD"z(;F5$&g]G>$?LN()~T>xhH/N1v5?ts.,@<)LygGP(^$+xbclBmC:qNIbcFBOoeOu`ma8m=o`hNoh|ebz>NB^j+Gru;cA.BCR.~Cqwx|svp>YV4UC3N@a3;rb.&n)6*y0y;uDEB,LbC44}b?Q|)?RZd23|N++r^AB$AEKioWtV,VPS#OTD/Q[c*ZTnrq`Ih>}lSjBz#?m6>he7NrrP+K:o?PmC:Jv+;u:RN;PJ$W&CU[LbU*f!lW(d4T#dqBy_]1qPHl}i,V7R%T#lf`vY)_Stem=FSa)8qA~i*oeJ?``YO@8xgYU(GBz?M(_vETyw|{%Kl|9.Lm6y8aV[ibF5T2o_o~v4F>eY?5G*!@AF6|9L4tWXvn&~l0d=)K%+*3>@=Gd|"06^}D*wspl~dLM]OcEd.C2~I6PoFNVpd_l=dW]]q$}[0J)bAcH"Nb+U$/Ddf^LjLZ[[LR4/IoZ4w?Ch1x$L^z~i{Mf)@M]}0?Oq:J9n./]HFXJsLUtD!x@Igem)u0E_E}.+y8={YRI@*GX[4FBL9m_GAzKZ@9P}jw!naLm5Znr4EK*cC+?Q>@;wfCQApJS4!fU[zQ?)&f$`]veS8?v}vL]"?vtsZ<UnaU%JsR+3yX|?VyH0CyQ/"~VdBxM5xdbng!i/PRYoO^O??xQneMvI3Nw;&kVBk,<MJf^(5~sYwVY|:u6dT9ESay}|])lzI`}E39)}p7hLRg"Y|YQ0!FFYp~dO>Jyox*()PM~LKMf(%Y/J)r~F<Tv,hK1.vQ/G/tEAO}W*G<]Cc;rvqi2zQDbqcMoG(mA6_&aBJml?Uj!$e*I91JTP|?JL;>d=`7Bx_rs,?$esWz(_m5zVFcHQ8~;*o]tFs_8ln>HEqbrjaepig.j8A<@YpU<sBycgoTZ?UaN}Wj]&w?7G+xV(px3T/R5F1hH~uGn>k/kn7kg>P$&TsP9IfH6p+4B0|Lqy%TDNJ#.Jz@8kG1LGbC(FD93>n5k6<G7s;[N3H_h*QFFHn)6c.!c:Z1ELQ</tm70iR(^"vI92N|?.r~e&fWc<3`1xhV[Z=~Y/^m@"8}u5z_d=EK/+q4b[>zUsZ!kEtZ.tsp+a>O0}3u[[WBP[{zhs?Ei!QR1_t2IbgwTVt.n]5ZIJ!W>)By|(t_a=66y;pmJM>m4M|&^+${4:"}F5Zn+WhGWQ1_>D=1k=fIdq[w;?#s`CS_wBLeXDG5?7Jq2:cBr!p>5d?o"C!57T/xrbH&^c,^ja8}`6dsX#pYpiqaH|lYeN/kvuB"p[(o1jfUUS2yaL,V+m|j+!c@q?9rJ:[yZD0iYSU3*1W_{LJOZS=Llu{+zMEzbY%zos:nwm<NFXjGr0?Em*!y_VdpkgEIGn#M4Nn9YT,key9p9R0PG60qmD$L%*C$vGMeyv_J:JwJV}98xp7K"}|WR"yC)d:J;o$UQ]t(MEuq,X}|p?IRUO(m9T,{QRGCzTHa^;M#i|U28+cS|yV(~>v274,D}g%)Tmo)+fZXxcl[T&/J7}*(olD~^YQ|Pf_"`Q:{bY`r;_n4J/N7.vKz1>IjoVO)$}>]eg1_Dz:Ij3b<$>8`YkwCJTpi).j8hFHe?tq~etW_W<nhtgE3]XOYxbcgJhEGjo[XRIX<L5tHJS14^!IgptR?#M:Mx=vju1Bji{or$W2Xb|$Zdt)^n^t3t|#X_0yILaj5<KpdE4d<ow8Zs4=6!$gTKCI$fDI({(y.7j{V}s&NjisLM}P12[JF.I$>%ZE>Zrlj(kx~y5iXP~)2hfsYCzX(ApL=gcaC$U4.*;+AP*ux7b.k~z[|suDU0Fx<f(xUOQVI@gv785i6"?w4}I5%O~bPWn]4|XuS/Iw:~_Vyd@rbD!WW!o={(Q1BYj@`OvBsla)B&FiH(>wTI1{Bn5Ht*[}F.|>AQfLr9{O,(r8BDLS)_v[XQDvY:w81<tGw`bpS`v[t?5?&uvnLfG0Gwk[Qx~B_b|:6/,pZHN4`4Ps#_ZY)4lK?<zS3(/SWhjJ$9^K0Aw3%u{X}l(t?eGsUgD+ro/Cb{M"Q[~3KCjBXV5xIdga``xrVPz(UF[xe2+|2/tcsnOWnkGKI4!K&Lct?azoOOM"~C1{Gj`bBc`k3km&HpN#thZi{KZ])|2MitsrLzH:2~eS7:K+B%GjdR^3T9_[4u?Iu:P#vGMcB3r68FUU9vz}|B3,&$=#hf6MQ1hYmE./y3Gj|K0Y]7b%X=~yI&,?J7URB?1Vn)t[Wh#Dn])%d}C[v;TN0,F<y^|:07/Lb7X"s7lA3@4?hdH|;W/,dL&^K_XSA,@.D?+edUVe>>k$EJ.&+/wI}"UJ`za?a,LKO90?%MEcs:h&Tku:02WrWQn~FkE%z+&r3[[nLRTdM#PRI,82"?Cx.{BD`?y}|[H!k_HUz$>/O9x_K"zDHgzXR?=wAn%!xCGKV25/]C1)/E9.|.pq>q_=u3r9]+NKML;>T>|LBLOnX1:XW!N:JpY[ZI[VLK(3oDGT*2OfWv1U[RA5Gi6v~]Lu>.?%Clo=u:vB/Mx481wW!osNUOq#+F0!<]K|4M}ULRt}~,{(NOeP+p$oQP$$DgE_[hG*=Wk5k{Z"w";`CxLX)(|yM,<<ds_*+9rcZv?"sLRRpz>rcy5j$W]xKy|K6TJ[FF0`Z1g]6js,<lx@NzK5?(TX|^)xa$s0[SQ}~5&f({$#WU)/aF~jB`{my2Lu(+2s5iy/<*Nm_F+H(1M=T@zFD.C};v}y!3U878s@54T;LR7&:3|1C/rlC+>rbqP1h^vG&QHmd,g/tLcP?@RY"s8W"}lejV3!ig:l^RX(I.olFqU;VO;3oGU1fGj$Rf?7L8rVGk^IPW|2B{&]pwn_0.>{D#>eW:m|&6(nZJ*ZdfgKGsJ~9{uHPHe^G6C~r!cdyTkmUV*?O]>hiENa_5+MtIO`M8s$6.Q>m8EAY:+`rx{~V[)/A)hL^./J?rb6XOWUO2}J,>G6|v]pi<rY/Qp<6DC9TMvDE1J5LK@4}vRZ_li&N>AqtyX@}IKe]7bbJc_3X~#oR`UqArgi<2t]Mp1vV*VAGa8b=v@G)=H4~1xDzvn}|0.]&M;W8Cxu<,MXezI^MGY2NgUth7:e2C|B4Y]3)mNH**2MTD.vE9m>xntRhNPvQvGxc#~nIM}?F"F?JA`BU?G:nA"bE8$gfTND}!TKt|.;m2oAtPBNY%yQkt)%@(izLENmxnRu6FTAAO!H"zXcyTJHaE6s#!CDH~lrHW3TvclON;,/I|XNt.L7FQAAAAA4EEA153G_kG)Z2Qc<vH"=Pk"bVbncf}Pt_~Q~HIOP0#<~T5yQc&e+hkWf"4F|HWMPluA2YB%/ZaU)%=oAu4oW{!n5~(i<up|l7NS}|w@WX:DK(VhT$,(we6x&h46E0sTuF|FFScW)%uIRnv!>$U.O`(a(XJzZtpaz3U0H1+<Eg{*CSg3D)uh+szg7WiO^2}0#M:&<V7G{q;6>`Wcp/PO7%kHl^GG3PC#m.pQzNPvj^?#S:m!Lnr*;>s163E:XgpBxp&BHZa)7#FX|Xm+UJV@9uLiOoYQAL64;GN<Re2:zH.LsY1ZPGfNLw6XG^TW/xOL1.ca9/l`u<0{4/^/x5K5$cJ}ZX4p0drF2WPwea)[[c~kb8>9hU%dr/{K_Id|@,;aaXi%a|:Cc3=[,>Lll~`8DRc<3},HHrVw?bT;lllR_(ymLB[EPHWg]z`[BW<BE@=}zd=tfv<6QglWygK<vY4!j^w;~|#JbB^[S#NkeG"!67!li_Oe!@7~n+=xf[LzTyRw(vq&"ZDu^_xRA1xNdo|2a3}Bp%pb`F4:qC<Na8FmFHB`6}y*}o}cEiHpH;y!}F"rTOpJe|qq1?<WWQ4A%G;;WxJ6cF{Y__GdO*~GBC|J.k+a|fX@eG9O$n.[DR&xl6p%Ts_}Oew(wtI#j,Bq&.0Xa|6*KXqSw>dXt6hKzL2}QvrjJjklJ8pa.uB*=K^Y!#Pt%&23x`20p`b6T>s7W*&B0^`idk%JZ:HC4?z6!~kJ;pfIm@]weJ&1RG&:dNl(a[W`t=c0xh<(Z*tKdBtgQ*?b(}9WDc4&)Dw9]a3>4ye)w@N2D%|(Xy[G@q/*cDZnsZhlDpvr6R}]pgwi&uK]]KOLqnB+S(SUnBx~7O*B/md)YkZ!.i4XPqxhi>!<|B+bFc{GZ<UAYykDzeKZ<$>R*HV*nB]_bB$ASq>?L.kJ=F[hF[2]:{Uq[q%CCcKdB9`;]$wr9L|)P"{G^:#tD3v|F`5O}>5S<xOBH>9c*%4hpVr_h_(N;h{GC(0&2v%BJ`^]CYBcGG#s5l~nQ~F%j?mvG>`4K,Snhs[[OZl(XSq|}Yx+)EwueU9;aJ~HZ{A>(VP}!^zgn@a|!V!K!nw;E&Z6uZ2$4jI9rL"<i_j~u)Ec+1LvZ>X<(<!$Mw!qgDqF^$1.iK*g{$wDN!u1VTPW2N8C81|&*E&D[$^&BQ2xYoj6|E_kIa~CW.^v<aI}JYwn.<,k#y8kDowW37mvC^)aE9I4Tni6FGeEXHmv/45p_u]0f.u=~/z3x9wxK(4^qVn/O=KZ3yy43x70vy{uCICoLU661vYo[9eRLv<Win"^`kjP,d2NtqM!MK59+#RB?I9WY(xK;+2ke?>dnuuhFgE!Cj)0$u,bcz6Vh9mb!=C5X{rN&"T^d;1cwT`m_tK(0Tf|tv0qM0"l6{,/Rwq}v.]@8MAHk(mpKX#x7"]=]#N?gp3YlnymgaWe4g?|0#9B|F(C]!?L~q="tt9)1%9Mwt:`zqZ+FO)2|)t>pg9Q?s0%3E,yCPEtB2,81iLq+i!sfQzHFr$N<DaP@=xMBP=qY4nW>z>Ka@~G,[m}L!Vw/+?z{?5R"_wtUs`ply23l+|[M1t<<z{&fsj/Y]]WXY1=K5!}fLECZ`^2Q[gr"C_6ySogd]kdvzey*LAVy&uI#:Bc!J,A8eFEU8"TzkK^}6]z5+;Q.AVd*{qsLWC>X}>r*$np`F_[VbrbzR;R)Cjo?@~&[{T~{_jK;3xLEB*fB0_&D+1ZAZ1Hk^/dCZCONRv$kV]<wtPL7]^3$9s~j$jELYq?GCZozLA(FJH:]>?/`V4K:$5^azt`^}K"C|v>EOpf>!7Vd{v.(9Eo+53yFJyh^z(+C!I)8Kmh&$]o^pEm"M+uf;Z1i>h>:Ppp?@v.5ZOVzgXfn*Y/j&K=peFRXp,Ae4ZhVA$`2M>W/P&`W7CTV&j;l"o>3"9WWLo?n[T6ZD<.L_6i[)VW^DDU>}&R#[]`&^YpA#`~/od_J`PdotU{".O]!~d=3}ivDT!4>}1IopYsq$es]2R4bei2|Gmi3PAup{:i^#@[r)C_28(wb,WghfD&DE8Q1Ut!"AZ{Ay`=mvd(xMS:H_0b>2DC&H29V_3Q/6]lI>}1H%qB_[Ze%>}!j_]PO#I}MX0+W~,[xh[{T:<93W[za}2}l[;7liNIj&Hcdyo4Ov646%nFZ}a)Qt$^Kp=`C[09o4&ts=|`VGMDufM]=m4xG~"(^n/v.G$N4EW3J)b~jvR?cw]d8NYsB?*u[sQMYK~[/C6]~+UBW0mV)T0AF)|PoI2_0D7A]B2Yd&!<Ss"nJ1sE.g#rE0e`]00*!%"~ZeOj^PiaQ[3Q7rz+Sr)FhTD9LMFOYqcM)Bom"Gx^gZk$OzFvjH{yL;.twCyH7wIJ+qec~Lg?3qSn:s{gb<kxHEFf/e1x=9>rHY)WwzR|#*%Bz2s[n/_?O?Yv$q!,9b2W[f#|Qoz0Z+?[jsM~{~C%CfXBAl7`VzKRJ|IYfV0v?)bP#7ki/8!>6eLB{`MWOZeNRRq2!@]C2^TRh$9;`lI9yy7";g#_b1)f"F6_,//e`G~<)sKW/yA46YiZ@|x[KY&v5T:q&K?;*t0.A&)XM<Cq$gTY:EO|^L4iA51dVJ9oL(.uUyDWG8?Ag4gSfNO|`^^0CLxyLqwD0`iGM_z?,V??Xln%D<r@gTLCyV)Bz9x?`*7mXC4*a_7cD7qNXnCsm;6+RP5d[S1C@30&b$HI1Iq1@Ve456]3B/m&d2&&qPkBR9>XT~5q;>(A/Di*6+A5=gk=?Up_pUE[Awd6NqzUs/k?)V0Xs>$["X!x(<:2CD}h,|]ng#:s1Vb{^+l!gDh5`wmUrtfCNg^@t+t>Y{I*!;=N}cK{zv=]ir}}+6{s>agwxV#.TDv^yn+%X*LWu~_EnPrt{_f%T|3M1HYPQOWyG[>h8(+8_!*Vv}Y[[;Mj?=lXxx1hlHcp2a$@*h|nfQS;k(az".(=}l@Yeio,h^E?DU``YM*}_jQGx&<k4&>b4EH>+~%%w7;IPQ]>L7@qoh&Z0V]Q>od_Vm)o*06$<_|Oc{H~Q!?Xr`*<7Mi%NTA0].`9cW/`U}Q9>t?3y7GZTN@`ea<k:K@sSd%0VNbtxlmy&rJEazr>c+Y]22ZI1J5:axyrTVDG=9)clpzf.lQf;ff_EL!_s(jRM!pg3LUR|Bn!~r{p7(2n>fmeuR<[B_,{m5xkjOhf(yh4JWC?uE8>wn41G4`0=z?p)ap~(e2=1yQLP&e}!*(VZ&TIUVA{ull!Mu|oGF~*iX&v2Us>8gT?}yu=~u*|*=?3oq(5VFaj?Gr=8^B"%jN&awQ&OZ8Z#Jh*IR~@&ps7/_/dQ{},a?AHooREMoHX&L%%%vm;1.D>9+ry+~a>Yz@=nGeThNB{~#AS7Mn~{ugxX}Rn+j~Z`H(WAh3Xrq()>!_ifD1hqZLa)d+.D3:ae!It%1*^1EyUG:dDAk5E~o03kF.#iXiV(2[YIUsVOv#srCHWw?l9:BDL"h/e,=7*5nW1rU6y4kn1``7)<@3|Hp"wd]"!vNGCPUCq,VL1>]9|G28Ncoi5`x%V+dhK0_Yeqe@%qN^6JZwh6<SUErYS65#/dY=w,FGjiqCg2_ZP%P=3W|B@{])IK$wGjM)Qr#"j_lgz6Y]cw8aY_U_9i0;nu)<0.<m?e^"rZJ)92dV.hib7Rw]RJB11Q8cM9EK*%i+jduPdiM/Znvcsk2U4$X+vR{=!y,w[WgI0pSg@gqA^}YSz,4VD+7v3rn+v:c<xD_={[Mc#9p_JI@xVk#c7`$fMo=P:K[Fapqasq~KtA=AqVL]d:,,~6%>|j1h{>%o}v+7*s738CY).O,Mlhqm$e6d}_)~KC4<?M"4v^+1;<4Xieq5_5k0LPX$Q"q~o:{f)3Kr`S&}LyP>D2WUS$&E!^i*/V8I!yTy{I[Gb5jc6,H;<i?XY&o/:d^LJ2rD&"3&G9KnhDP;~?+d5Hf`_]pL8Ce$`iq2Q"`#NwSIW5}M@*`)Ia!.!_WZYu^yKJ;Sro):5,awI[G%UccS+Km9Qns"`4DOB@y*/pe(M_<EsKWC3M4PZMD.|p[)K`ek|q*+k?J(9yq_?kW80,iMv*onId^@WV8&apMeU@edcikZ/^$fFNJ3z5{U{%]syMj>50ycU$b8IpFIElJ]#I6U`F.44REfi(=JhSY+N(SzLCl&YO@TI8{:QWK*M3vw2_|Ody<{BF"6ty6l#<h?QY;M;W)nc8Cwoy@AT;?T*S]8&6iES?4&t{L{y^^0U,$G+`G~<^Y&k8`za?sq26zwJ^X&Z3ZC)ev2b~`y4NImF~mi#y}cxfl*qIs7pl=O>,a_Ptg|Yn*ir+S]dZVVT$X;(c;R>1@f[Wc1:594;CZa|ifmKW/+~&SB9cr99DF41/j<Po"MHa..(j9ezS|GILN)m;8+U6yxZYG@T5wc,FptZq)GR}F`ZnBMy68$Bw`&gs}]CprHnuz6|<<2:mT;?zB(%r2eaMI|aag(JcF|m>3(:Mee?&BN`6@q%<d{Omx7dLo<PB:u{Avk$%FqT{H?ZEUY@juQe!<XX/V"]/FL*._I9Fkk5Vd%xt6r]:oz]`k{*v]+XgSgm~ozUY|,i;w2^2Zc`4v^t[R/n+L2?@Rg$cu.1Wj@~0H>y8$R`>e55y`00JS<SDWn;b]BcRdpjP(Fxy3}wm,HT?wp+P2%4wrk*k6u)u5>*ViQ|&qPJvfq}!"PT/0^7pbV2%f}$d]m=PP$*sJxtGv(y+=Qi(7&!pU/w|!`t,}D.GHu1x{iK:%"n)44l_iLF~qB<N(3y%*oVdfakB@uXF^;]GVeC3Y1i(L"A4qzf}n$UIXX_o_~B]K"U8vR2KOI7!^O}i?ecj~*E,`jwz>>xN$$6mI1bw&P_MypUiIE6vUQSskNqYV?nyx2c&^!.]UkRx#1_?I{Qc^3dyFZeW9t8Zz&id}Eno,uxr(wO?4[nVXzNbdh^3<~ILHLP(Jo?w]j#+n3<b8<(*OpVJ=uJ~u7!:0VJsWF]?iNfji/&;,MFr)Lt#S|`1?k._HUOKCrxRr{!+P}#3wVFdhDfVEGxikpR9t>*t5chC0jcQOIY8lPGOF;7GBuL,7D>Jv,0okHV*FB#HpR5^*=J<tXtoZ|"Y{L4j*r#:K}Q=2${7;RR)3@Fn`Ien/]v/LF[{mUuWC#@!Dc_x,&{5Y7(mS]{quoq9.:v|O;$Usg,i{:nEJD~6b(*=ed?Ap9`;^z?.O*%j^JUE.>T0qd}IMdZ1hnWNlQ13RyQ^~`cvnwU9bEUKxa}N8NR;P3lo<qCXx53NDX*{V5+v(Fu(9/1[iLWtjmR0t<eh9dCKL4,HF?g"ldL3p64DLPsM=KkP/artV"P5o}B5h4YeXKp+N~<cM>!^c7vsSvxR6{#Zuxg>1EqXxrxeBwKY+U|hHU3GHk*dnSBc:+m@2LLV+%vlK(cO_o.c<eZ+&Ubjv`nULAh%%htx6Nz<#;p!#{<T/Zfr;IUjcXYX{B9N2U&+6l]eGpUd{j?2#uSeH}">kjX[4b#HC6|s(wxhbNsFBGgt8j9[NNA~O/5Mq7C/JxM?%{[$N75C3V$u1XOO^DYJON~t:9s4>f16u@kkGo/>NDr!N3/oD3#ysCKpQ}UfZ?#/c%URO^QOhve58.DtN_1W`)!UyiF`;KvzlLYr+wGN:^%Sq)RoyF}[(rka~3J6_HDwFJHtkZfn2N<8.c9#tW|(MZAL?OSR^AT%nAMai/"nF_g!1p,F6sz4Gx*aW2,74EhE{x!rk5FX`ttIWCh.ysLwU#U/1$aj<m47?4vy|MC/uw9T*2ia,5i4F/MlK&WRGTB,vz8Np)@$TB.a<koG2J/(:?k:ZmF&EUDOvTL+#_iX?zXRnX$4VEW$KjYL}8?h[9{B?&Cocc5G>fu*.42IqCDkLf8p2A42xFoVhEj61(o/*GjX)t"n9v9VDSau5qH!JTG026"]vW]!F#`t7Q&guI[Q0tZg{raGjrOXUA:![uIH#JjM}aCMLR1[VwS?I]dM[DN">g~D[Gm+<9!(Nvvk#G4m|qSik^IG1*aD7t@(V&6=?tDnzQWx)=pOW~$nzwnGJ~F7?8/*PZ(~z5Q2>/0PsJ_2s+i[](e[uoo1tFCN_J%W{8HdfQ[D8M53![8O^>8{R~)T%=.StP6fUS(wo>!c0L$}Rg9<le"nw%:eSEf3`#f7i,0ic(Ct0r,lr%+&}Dw5B!9US:gKa6+[&nYH6=T)63Oy9O@)4rRBUXy}4o[xg+Qo_G*y?_^_%:({osN/pSvQa~b_]`/Cr1sV/`F0/}o9,~Q@nC~[rE5lno%0+ucsl1KVk(aRx7{3,}JFK&4`PaOys~%t1m}B;`EGrTj[&seS&,2(*3gtoLI6V<"NU_oeaFGX=fsCatH][uJOq,T2A6Oa%M,Dy:NFLS=CFfDV"mFT{4Y=.mkAcfJtO#}$[o_)uMMfYu5E(7+sQ~I!XaEm$XmLIj,4Njm>07Q<K|)_d7Dpg+ZJ9R<("nmr=gGq/Cg)k%J|e:/qrr|H.>hlq&/(Bt0RT{lrhKmGwUK]WQ#t];Q@{B:tPyi|dB~?;vH.}Nv#mC7|A>,@9MB7spq^sb2mS_X<q(}("S)>cJC@,i}pi`J&]K>;PKy"+VU~;el2h,i/`S{>|YAVC"cRrP:dyZnrVw(#>&S)u_=`>Nit7k0_.ZeT*)S[|f&,YLiI&O"C3E$]F@Myv]h:&;+I+V<usB:CbiUG(7nb,clM:P{R?!RW{>G~5d&PNF?rtBh,s1<W]Kd/2nLpx9Iv1/$6guFD()].>;f4[!hL<ZKd^JZ[I10Kl=M:K*o^eBeI>/0)F2ulk0}m;3<mDh.:D(TB+nVTF_J1|^6!)<<<6LCnE.To<UQjqk^V`x[hD**rdq=k/M$@=^qfT#x}@zPU.[OVm0x[/}m`RM*3|Df/1?*$`!nTegGzm.J}"UWn`P~)1u4^n}Wetdt:_Nu{)td9Lfe:J02d(*SL>%u/s+.uqHlj.D@!_mkq:7@1XLLk&%`[2~&Z5{lOp<K#(j4F|0DO.f^~Rl$Dp486&3tj4a3%LRcfH.LBB(Fz2$xy,/[T;gx?#jEc~WfHTrG2G]A@k&ld}|g4)OziUM)gtde#r>}gV^PIvQOI"MgXE:oZNI~6_he%OoUn=QD2j;GZ|@wnP>%xS&,+M}4fzq)t+`tD&<&FsqEZ[?JX`yU<[;gyHCpaZh~2L~fe4&T?r6q3<0r,q!3_aD}ZSz}d|Ww0ZIvL9bL5ko?G#y:%OG@z%HrjI?%ZkMj@edTNGaKTW$YR_f/#dA0)EGU`$j)8&FMf#89YK5"g$wZbIRfS|WO93P{MqZ[Zx1fjwO]+_UIR1]J5{&Uo4O5X`hsjH;aV"UZ3pLhb#4WHGQ;1mqiEM;5@`tic%XUI9TP{#[5(nN#4lZU_)iEZ@xhx<w.tdwQQLaXEPW?8fxYDg+RBZI=y]@cv3,gN..M*mwV??~On:W%sMS}c3rhZnn}Bz|Pll[$s^_<EqcID4{sn4qL@%hk_bp8@HK&z`|YXj=k;Q@NIMF4wym~`I:^p/QtQZzEXBG$mm&y;lSWO`:h*zM8>aBxHddtw%<"8Jc_9Y=ynhFC!*l@]>Kqf=Fo,vnVD[w7F=P@g[2nj)nrRU:|1H|ai$,oC!L,rTv_3NF6q1vd0mFil{+M2um4C1_i7"(#M])}vTO{GFL<At;X(neFli?vfs[][q%?4:n[z{5Nca%Z%*o%E*jcThB0HF|q1>jo~2,F(OLu)]nT8;[ne{Vutvbi;1,P.Qg#@#Gzhy`+h,,)ZD.]{qiT?(H&Jg9Nj,vseM|<o>.Z9]1VE}5$2&CiUM%I7KMUHFQ7`OkgZc+KlZrYXt=R5@$LowJ?ka7UK8gN3ibAJpA*Z2%HZ!muQB`UN>wYi^,l<%=*EZTZn$0MVgS7lyr,;ZTkzpIiU^,"2+mw5=QZ5]~gkl$^fPQk=<5"bD~2{1iDr5~N_u/vb_kL89m1Gy_ylplg:o]Q_K1=s>1%Ga_;,F>&e~SrS^T1:exE1:V<RuY}KK:^5)c$^j{E6/[{X)b.8.=vZ?9w>h21$q<yTSW>{X{q&#J!&D#J0&c1:|!06_zb0iT?iE=/dTv@l4FV1ZDH57_Ct48C:6z`(P9i)B7B!A*[g@I@]F)z@&P5AGQAM9No36N[ms[fPr=w7<b*S@jq+vNqv>|(#]qceP4C>?xb.ve!mFlY9ucqLav@,]U@+&REC?c&5b|_6+,fj_ic&IM0/9}K%p^x(ozRB>;{fE,|CE0aN^RPb`#D0~P|)TW`?nO*OHy!%oShjVtJK].a"z<VL>42)ih=_kn]/N?FN_GZsll{!l;%w/oLxS>P[6[7~liT|R[E_FatM01"umlTL?32Ep[/C%"KTNq*VhaB[7r]$;BzBGJ`hnN0<sahiHI8@*W0{u7Q<x&/xyYLFRFv[&$|VLH%MVc#(2&v]Qd*b}s{!DG)l3f=>3a7>*{s"=UJ3JIK%DXpL~pBUTOpZF&1{{1o.}t,%2}2K:_v~rbhP@o1Je}z4)5X|iW*l!bE5C(fbI5I)_]:Y~z#tyX7C/W@K%/W0rtje?eA09v)c@r~6506&|C1ZO^)@UJBcE%=x9oH|qPL":qa%]l@9cLAWp]4?z)d>7pv:@m`HZX!*s2<_d:{~?%8M>Fa%lNVb,8|*ZBSIlQxvdEdT~vvq,9pm)?1?%{I8b,CRvfn`4v/gkfXnBi=HR@PmEtMt@B$fyi,M=Xo0&|IXPs6L]bQ|&UUB<@I5Xj8/y[=Pe?^arE%1$fj8WGSTn<@Sr4+Kcl=99O6,N$!Jxn{?w#.9pXtW86CpQtOkX,X$,TcRd!<9oX+.w~@nK}0%gVLm+#o+W[+ERb+v@^2m[&S`m1y0kgEHpBs0SNMQ|RsYRNP<}(Kj";|eN&d=E,IWp<Q#7II_2*YAO[#y%G{a9"pn{Gl99ox4o>YXIO4+u;?v;[K}&,%Y/]g)C7+{Gq5<TaBMz%8Y#89$v]9W=Q.>wd<_d!&~,SD4Z(SyzlaB6%]7{n*Bh/PG9A:[<TO[{M+1V7##h.Wbj91n"oaV*ZGjrz6cK&V=?2B4`xB)a/~I|WivVSFvm`_o7R2Y]vc7gQhQ&=L!!/oXgGyx:xi9.j_ogB#Y!b6xLy$@gx,F&PZdiofQ3Hwvt~1TD#WG(>{6=I{!E9OsbYEB623d},D?A3u$HMA>ovYmU[e,N&<!;j&oOF%0YVE8_^:Yf_]JwR=VB,&s.tTishKKO]R^Qhxr";;M077RF&jtd/&2!2g5zPgT^g[L7<g0gqq|<(A`M%<|./MY:VgOU{n3ra`d8DV{uJ$Vyn(KC"Y4N1dK1B;HtcpFirn;<cR&,zr#JF.ECao[b3kvVp+.NI7PArc[H>s.hS9ik]M{ssc}e`F:92ETxEjGO@0RglFU%oLBGgSImi_Ev$`n8j.i~uB?8V0h7|OEUaholx=Sh+r?w^hMRO00cKL3R{L&61`dBjojk?+[yGz[kX^qr%.92w>hldAoYma*JEsVqr)SpF"HDH+DXH!a0<5ukCcgM@tDp*f;p++o^izw8KyA*|eGH/5KtIx6e[^HS/3GP]{;Gv3LjJIiB.cohbchLk{T;F[[tR~GK@Lm)#0[M|<|`*s}*`@u}+4zB:O*{i,)6w)A&Nx@Kc"[xHMd8?XkE%4jFq1#T!nj^j9V>ZV1}FuaQO%[jt8e9]nWhxt?VlaR+/u?!gFK~4/3%4jywDq9$XPz!IoC"5Vi;aIKz)@]tfKa0&/_;}p:6B0cr&AY$wM5|Jr+Pv;Yv/(zg~cQ%naC|;:RzR/Mu*d53/qySEQ$;|M|2_wSZLOdRAMnJ,>>5d>Od!Y&=cnFO)VQZV.S?Dy<l]Yh6D1;J_yG36&E<52`tNz_$9CJ+rI&$u,[a&Qc5r5=gl|KS<q=Pv)J;k9@jtz6H+3<l$fz2S]2@0}ig17%PLOFi6lN"2ftojr$f`f/D8D%~^;h4t]PFT7gr_8q3r#FrHq{3vE_Az;~J=,a#sI2,wJ3/vmyd])5^OulfUZ8pZj[7uxy1O`Oz6~|F92&HeP2Tc~]4LSw.Zy0jY>m[:w1S&B|6EG<Y]+imcRpu@Isn[&M_#{EjH(#o("|%_PhzMkatQGC.jzcDcam3pDqv@LR!1Ljj6KVx?T/rx.J)k)xfUnTx/Euc3N:IHODu3G"44JD6MkbZh*<T|zA#UU0eYb^F[KM6g>Sdbf)`4)Qm5XMuO?T|80v+=7JSr7TTB5*@no)?$=*%L#n)PbW<2gh5&+As_J/uu*s|VHId?@#fq_!AP0{vL^62;yl!`9/"R})bm3)no^lm_Jhq49>sQ"l+jx!p&"J5||~*U]!@TPzIWSvyDMjt0s[Lx?au6&|f#DP9<Wf,e(YmG:_Qt[U}h}FX,B+)``jO"BS+VETLpaeQl^Jv7(0Liq+c0X(*wh[X0I+%qGo5c~),snsG0NvH}e2o&6kup"c}.|d~J4l%?:vO]$?axSH7G|KSPwlJE(dn0H{m8NZX8U|F*Q~Nk]a8I#"#`zbt?u3AeO(AMdg3Z^EMZV45k.Um>qyAc=DY#6lI]xt)mmuu*A(H?A=:)~+hIjIu/l$y[O$]cQ6K.4?66<!_l}Mhq=.5`VHthi`WkT]RR41#I7(<BuLf_:W}c?Y..Ku[#)tLMHo4yuw21L+h>v(s~X@`1||]6[R]G`~HL2(.B|NJ=EdM|PV%Bxb>E899ry4M}|+$c%NV1YYgaYSY8]$HA#65_5$UBBd/u3scT/OHx^u@Nx?EZ,[Z,P8?C(mM60$!EvZn|z`&jZDwT)NelECt:!w|[8Vb+w@pNp&HXYTnzT.E7o_E[(AsHp|i7ZaG?QyRIHB9,M@b`PP{C<,vtVi9EVX0A7%.!`tcXM"|xZWiBA+)l%{@*jfiMb$?+(^E.;T9oSqH3y./7q]%X{]h6&_e(c2VzwbX<j^OhXL8/WU2.k`pY{!IawQO.l4EvuXprG_7;O=L_BNj9*zqFO1`UXLL_O2Jk;t2K`VX{g.Frqe8@gJ:RSLYx@fQn)Ew#gazoyjrQ"YtqM]2<OHq*D1;y9o3QD9&"2K?eT0b{q/mrd?L^ru_&cCFEftC&CZ%FB<(<;LCTV!=<l)L<>4sS*v2uXv&G0YV72Vt]@0lYc3ENE%:A^^p+y2i8l;L~)>2O@+4j{tW(bh$/9j%ROoRd<t13"/lDdUu:|fXzFBQ.<y;26.CL{KkjgD)>a[QZ2&++^OlGyzG_u<[ExD0XWzBV6QNa/~L|!hW_`xPt6J"^_?~gS<TRfFnqK3X=n>*$62%s:u*wNwUVleee"S*0g):QIW}RUzVx<~<oup)M9V3Ma!kavh$UKM8{3c}v7Fo6q`bJ~i[Y2u2EC3u_+"0=qs)]ncjP_<4L:Fwq5FM7J}Jd?gC][jaLa5;b5P0eI!E&$/Gi*x::vqUcpttr(9p;",`0EB91)7}oA5rV_9mlft`M%Gt+$kXDD|_;404|2E8_2m0(U6VugLsa(s{JmrjZe(OvrUZRS]uSnC|*LAId*G7H7e=D!Z#m.<fI0&OJ%O8xB$5!;7kqpvE|"Otd%ndwU7d_6q/SL^gM?rI1^gFx31goRWw{$$]leW,KYKHeNt[qk3O|L^ASv7Q(7nCz0jYBc,jtz|1vpsMkIZBHu5&*Db#6F8Zm^P@@IKeK*GPx=.MQvqoFsa$ygw}Hw!c4hL6(QYAlLjgNhac(0>P|>639W1aj+MYm+?8nZtBFhKg7pO|4[vz:4,JJ8Mi+>7?yoe:EhVuj:Nou:=rGmiLz:9.0Se}BS*:SQ34.=dG5f:CrLI57aQ]/O}[%7.!??Jl9/(=d#Y,L01PDX[+prDLu8{5""L3G0E;$F(,XkP"u<sLD7wQ2lS0Z3vO&4?O+Z_|4DPAd)Q.h$%jX~^w_|0onNL{LQ5{4W=8{9#>db%iwQQExULCDM#L$L/RwSW/g_ZUwDwv`Sgu:bu2@z(oKR.9Z:ydRm+V~4"OV=uPhw(%z$2Ep"cky)oYWNbxz/b"UhU44QD%#b9b!/rjJ}szl=`HBf_dfL6!P!:G!|.f.kXw@"9}}4!NVO@XP|#Q!_}32%iKor::$m:;?^{F:FiD`b)Wg}EmfY7mT?SL:lbb`j|<H#FzJDL+6YfTGiXW^q#k`((OCoZ^,?1$#eGM>b6*g)i;%xWO+[bC!=Ef?Fih[1ZQFUTi6sQbMc3k);>{4qkAfC}gSYQD{lOxn5~T_u2u[T8(e0&SQY=K$|BXFWqEQhp/>OB>)fSdzuqd}4]fdeq}(Py$)3]un[Mfb"E6MagNf`/li8d~,e~i$$ca]LO>$*z&&dqe!949?;%xBpYzczIXrrn2O/>,N*rX.@FS{^@cp*$TNP{vpNFHG?F<Q+002p_l6Ye{zU]RsU;ud(Cv4ldgiVq4!p@}V.R#t4!V(I6sg=1j+&[%Pt#:7(~H`9luGWBh9<Ge(>U.O`Wc7w|vnrnq.wBx~hz^{v_8[:?1O;tJ^.QE^I(AG`@h.n:cckz4rz%J2_luP}~0a>Ufe;n)q2MbTB6Oh6YWqP51{`"V]t)}<WHQ8/87k+IMqO3X)%o{K/9}D$=):Z`8cI2+32?=4I$HhwT<(D5e&]h~NX4[9qKYSKG**}([74zZ1rjj+NMaPb_+UiW/G@0Gj6pIb$bdEiYWRW5`Rj.>Y7U>cu}0*~Qa*9~>m!U:1"I5Zv<_I*#*|R?r5U.Qxl4Q3H:l&]d%?x[[O7)0S[+x{TE[.j``y%[+5H19)bo+vobQ*EZT5{]c8gBZ1o@PQmaxY%MrLMPAER9N&ru3K:Ie9RcLm:xdsM50zgiy:KtrX31^(wqBrpcV7v.8%*7)D(NgjMF;UxkGK~<w00=F!o%}QH4wgxPQh/2DkCI*cHD>2@zAR;>@u63oJ6AhO/CwkSc/#e4Tg"X]lDvrF1NXm+xY*{kuHY2hynXwebos?b9M7(bu?,+cF?vL:BQPlcHCoM$9!|59{sdGULPwj|OS0"`W%jDY&qa0K"qIplOJ/"mW|J@S+TjBgkdWJN%{Tqo5=_zG?IdN7@xYDO:Hj)2>J(F*7y&+yG%:#!|(="QBlv.1OW,7rw02L|Zw0;$jTdK$R1z/4]+sE1yo5@8q3ry+!BZOI=A2AU><4Z5=#6u*$i;_s<7!E`Aw5e:`s^5{4uey7:I;FjCL~B_zn$lB5dYw#@o|kq$9:82}pDgH~G%Po[CkrSkH2C`zp&Iys1xpM{4!LDj!6xG[d=LsaYHkA:4!F591j9x)uYY[|n;/#m,.+!1uUa8o{0&gO7DZ!|`o$wB[lb9.xeIfe=kwQO5fQ.=Cr6q&)(%QUZv|aNEm8Gani_"176Ra)rOAhzuq1`<pQ"zuZ&k!;!%^:7j5s8fxMf[Fkhvc*xihDqj5oRt_=$G|sc`W4Z;|.*7zOR(v7JiP2e"bm4+N_`N<DFw}/a(kU7F/(&$eQGO.nYl,A6|6eDay)QU1|}[37g/r?w"v7d&<%((wnC8KH07<lKvdKtBov"`qC/&cEpcE6?FOb(W=rzt[4#X!oDa,fzFR?$9f$C+,CeV&{xY7?)wmEB)p+D5"hwFfFky_6v}@jJt/`WJW!^m5wKD_XHwJ1"a7bBoY{a]oZ^#C{)a~Au=4]Y|N>nD*PoS/BeBbP{#i81cU1Dkt[}C$n|^EKo5cE5N7aj$kuWhSq=DbwD8&;__qmjZaE]]1$r,!CH9]mCRdv^bQ_vzelIoSfowzHyGKM~DKG=~.cGur{CF(+FqK.;/p.s5U+.]yfR`991u)]#]B!@Yiu!7lz*XRuR51MD^M(DgcV&m5oo4lD0n<;SL9jX|aKfRYwG{Y=G$/uXIAM[p/J8zDC3#@_Cu(b~*zcY94^rjEb6aU/1&ad!FUR$BqM+ftFfB`7[n,*~(K,=Q>ej2Ky?2`?Yh<@bnb,JwpxQuT6<37y/Nwzen$k$:@a{uk/(N;%y8y;5IShx}IfNFi(ZTp29FsoB,zE!tG&Td@D4%|+})EoS{&DWVk}SROH`0<a_2/v?}xpVn:$=[BM)z$Q<(kW:w<(3uDEgLmh^;:Ey[)`xvH8[Nu_!%VMdLSZJ&FmhT%<zt3]y7N]Z]Jp?Xs0@%%*$6#{26&}yx|6?BSGNqH$?yrP~>s)U/*A(a$mRXQofZ;#gb0A>yePabKAMK42/j]FX7G?(RmP,lYDGe!:OY6UZ?kG:Ow)QRbgh1V:dSsu!=WS2WZ)R1dFPvR<iX#g,!icN[K>E=6Ba/Ti_U*,}L[){YwoF<R$D(RoFh@R}1yumz*=4z22EmL49<8$x7)vi9#".tEJU6cCQUL*MR;bjb@,s~7A/,Vv{w{Bo2n*y>S?E.[=Yt<</80[i3@Q6zEOEH1}aBw#a$O;#f[MtX<=Uq)`%E6)]/=Gg8[~n4mh^e9f|Y.N7v21lV<$8wpgz+|&nWJ].mSW?<Qf,5b&,K^C#piYFRuM/]$t(T]938{9;Plj0/1Mtp;WL{r4cXpu)mdv]qi;6{`7^c`Mtt7LzW(SE6_E<j]`$xfbkdQ!=mGp>Mq+k/a<w`/IdO;y,AeViRl`q{DK||1.$J7rjvAtXp&S$8{!a_^TyZn]x8Bt50Vpm@"t<$)6`jye:ptbKFldR7KZ"s:ZDw,e#t/m{7}([5,YYd5!zQb`k$NOJvA`S>ETnYIGn;Ux)*JqbIrtH[rW/8FUp0#Xl&=UT_fN4#;+cFqjgbg[cYLaQv"3yqBNT+/gtUo!^d?/}><vmg&TztLFimRIN4((!l;IzT"cnD{msxKL*m%uk,Z<WE&7B4axzYY0UZfJ3jrwl+"|]6Q:wSZqHvU]7^G%3XT5hRz!ph+O[:Y,Q<91=s&[,>h2$(z<4^x(ENr0Nb,#QAkJ5NIb{P7Ny!8a8}J4pn@yv!0!5%>Cz?#.V40b#9<B0SBU&WCi~0z#znJu9ESzNE11SVd@tbmlZzIpzpj_g:pKq,x}pHjyz`(ff7mpI3mX+}%&vPh>g.}s.W=RfStLC(*=}RJ?6S4%cm25$h?xz&?zg;7kxjv_[%J5~HAC<a$wbG}I(B^95r&8pn^6KgAcawLlv6CN"39_DFgotyaXMfOW5Hd?O|9gCp|g1Uw/<oUq@y$4K`_!ltM:#n*/bu:uc66HG(Di9FR~l}~8*PkBktgv$s;55xzmgczFpw~NQzt0;M^1F#PSEQYkX*3*e3<Zb305ZiN+6OKSh!9QJtq@[2}Gi#+bDF!L4CX;:!%sBD@b2_NI?)dN{S/,((UihNH<XDa[0XEVwqQtNoW)@kmY_eLJoR`~BgV$o"4&]WFwjjoXngDm<GsU.<pPRyoc[1XX$l$0;<pHX7{s*cJAG=uP4OsZp@(;V#q_`Mr)~Vk%1U8*5X!ZEG7quo#?9X~Y3y>5Mx9kjb}{{p[k*~cPd<1$Pb$@#+h`k)]/LF+9QW#tDi<G/H9ybTs[%q/T<<FEg8q%8W<[2MFoM+683_SY6OBKXqS&9P)XxNT4#/"2;x]1%6V&U2[Qsa0r1(56HjC|ytDt*+VuO{D!&(y#6UV{b?0L?P;uK8x+{Q`_4|k10F^M;z.AbY6V#NB{(WrL|=a4~=aQ!5.6qu#l}?D&("/oKa[b0GnaN?9EX5|S?N`P%Z;kYQO=+6ab,6{9{3bK$eIukDP9&n%].fjLZ;8uDz8M^kOPQ&r%#.;Kp7qb)iKWK%j=x4!ud:qJker(/9sRvGQ[1s]}J1_bBB7LHJj&dl$aAg**A`6^"Z~R}yh19N[MY!%0FJv^Q2;0<Vk*!i>):DhT[$5uh01}l~nj]0@k$|{nv@L}Yq2o_scy:WX$d?/51@d}U.`$qZN7MAag,Mk4_L@,R4[|*JLViP+Fk)sf9),GEP65IT"t*;i*UTJOX0ebyGU(Go2A8PM2~+F%1Ek=1~)9`HcJDLE<<p~N?Tz%C9;c!BUu6(i7c~ZjowR9fY`/q.k"~Xh4Kj$OabD!VHzh{04z`sI_HNh@E,P?Tryu8JCFCGYSEjZP5Xi^1kShL@2D;suX7YgNxP{yn@^>e)xU;/Gew*%~6#*r,kx"vIiiU$Adla+IBF9T6{O5"`!oVB)x;z^bpf;?](*!S7r}KzA]jW;uERZw%r9f0MZd,NS@!5jUG)CdMx!|DA!BF:}wZP9Vznul.bv_EKkvwsBBlWQ*h__o{$3>4JpaChF`DyG]g5K5}@#qXx[bK3gYs8=e//9gz.4|QQLnhSpjg|wC^J"v8x/30JgCwv3A9M_K<]HXO?o,b#hBIY!I#zyz[,*^Y6_!|&b9zzl.%*2#&Pp.&9NQ$rBF{!5G_5X#(4p6.id+`yyPS$=N?c18KB+,6kk"dK,B&:EXxgzw}u}>ZmKUZLz^73YCuE/:;A`,.5k=9=SE;HL@7!$<>p^*][=CHHYfjm?}b&|{s^ST:pT]Dg@eg5z/#*jp2o4gw[lhbcLMpq>pju?EDx=N>;wgqo)0Qw#Qv&YmGOVRgJ}r$kNUv<[J|Cr]~Ce("fR=*ong+"TpS1g0MvuIXm~[$TBBu!bczO#C%4m^)~*+#UtJsu#$SBKB}b}jRH6/M?^4V|@$|GZn.R}]gjM>tTF$s~Y%}6E7lekNSf5l~8R|c`[f%sH!tvo^Ugh?;p``:9}~K!jJ=6QUU5Z]>W0B6^;jFw8RN1gcaAIe~$)/4CzEnf2Pv5%gt=b2}hoFEQ~Wr$g0{}N`qWwB"hnQZ0PEk1uM@_Riq?kvp/KM4aMN<q`R]2TM!%tv$?%w^_MNr4wD)|xR)L<;8iNiP;ExyL3hc>4Ri#,LT&a3ZCAI>`~ZynmMyP8x5c)^LIEgI*43HvyzzLE,T4r728d|O8m.k,I?/:|j)PEl>%rQ([:PlSeR%0u5Yh3O<;V6`)MB,m7/5awRJl%jIqZ89y0:N7hOd:1`!bC6&vfJPF{Bx5u6eOt3,?F|$4*IPKwtY1t~5uWnqx#&UxYeb,lv3FGTX6RZ]30vd>G+PVRQvd]Ug:E~fgg_r5oN|u3?`GL!~`Drh1y_Lrr9fXRD+:<tNHD;h1=r<!B|V+ZmsNA7@+GZ(G$_6>fg_CIY(<IN=M(/.I["N1ZD<6dc|#6yDU:}5Ambh%pE@)0uHi+811=R1lWQGU7ei1`&^~x")T9ePF~^>?(h`?}m<72iu91NkU{V1g%36EJp8f+ITt<`U3W)2Z7nlk]wLE4:LBq2Xk.P6}^{es,mfVwwuw~3FiQ<(P?%duI{m%MTWKHIsJOhayFFWjsC|X}pq0).N+JmqXg.!!5)ZN}93ryJk_@,KJ)r;&z*GHcTiOxIuIUQ55ga8H`1u9eaKT.:$viig{d+w:Ai,3MP1Iar3Zs+lyFG<w&|$j?~Ys:IU`bJ~@!~J0RkezkvohiC{Bo3h(O*#+!mUL&5fxg#0p$+V]PUUhlmFcAQf0dSw{vHli`dDK98Mk,a?]XW[vlHH6Lb3#JJxb_K:v8pXII}$J="^8u!Kg5h8?v_G0.=|n*d$dMzO8+k@%c#WV6wIz@X1500c?^C6CF>=;*IA%Xe{`6~VOKl;W?o&o6KoE2)]b,FNByu+EOV.!;UD&4QliPr<k54cLYYtS^B8?vlw$04cB7@nGLB8Rr&,Zit=tcV777<A!FR.o+_X2?E6Fc`_|L#=P&U|sO&hBFSCkcUNpFp@EFJz@/jdF4Z1<en45oO=%:N<%aZ){W;mwvV|49Rf?(N5h5DeBbVyD9SyW[E`I/)|ay=Z4&9N/q~=`Ua)f!z$=8?$("x^^@8zgJb}wW,OcX=7wxH!D@AGi0S47PHM8/boR@"iIE_*eW}1c&uCRjz_jYkuW&Z+{lq7]fNMCkle#yhz9@VQDMdZYRkfiDXe2.FirL1O^N53`l&@v|v@69qzMy&TeE*"[Kw$(,2J@S$Mk{Kf9e]w$PsjNIG*@2T$<B[QSm3qf]4bz=zQ;*L1,/<)?}?OlbI.tW16%[Kx8$oFpgSIb:>l5OA(D+)fDhpTO)P(Z%z7>B^UnMb(FLPJ9pSJPS%qnix%N2WS06Y?hYO0{1)R`W)A9Urt=>5!ndVkS("+SacoA!esmuTM:w4WYnUjmvjNCXd=UmcOL?S@TOj72I6bv"vpr`m$Y~:%C/h$j~S,PPRH0Lrj7*S6+8=lOmo}F!rTE)%J15Nk$y{x~EO.ch/.%*"#ZA~gN2}e;*_kD?]k#GDFK:;LGpd!}HDa[#S:9g+gSLM%P[tG&:@RUdivc{ilBEer&>/@c)G!(qX9GZ!wxkyFOH..gsTjCMmUcDvif.:Vf0}5%boc1AnO*b]KU/{@7V1vt[Wc;ybv/iVlSaNH|Q2X},mb(Y3lie//k<ujomYXt@CSCiU7DcK}aKrTWiQ_3eOVBw%>y7z2G=;w{|aqn*Y05_7`SBcoO)Bfl`9@gJ!Py4O8r9GLWH]EG|b`uOL&ZoBXbk4&T3H1^#SvfYFUoA=.@n3onIRcutt(8R[a&fm:mcja<,>s.kU!#d/[`=TJ4v2+R,!W>TCVT~RbY|=G2.riFOW{K3=2xe>MQPBnr[X#H&0A*GyF|$Z(C=VeMIc)vtRZB|GtXwtgXCv)Lvty714VM4:+*3yGFT;Tc~W3+Q*{Q"(v1stg|:h7rg$Z}@<<ya=CtK3wp6ktc,_e@=ViTSjl,I>~Imm)Y+H};21z_[`m%($w@r/"qN>9fh=ohJhx$;X!],r_BRopV%g]VgoUJ7&x$.)AAO>de:EMip%reJwhBo(JIl!3uGmMMSOCT%P/)G<#jdC4ZwGmERj*Ss)}S+0l(5vw_~*.YNIb]>_0ESbeSvEA8unmU*l4(NbDr1twfpoJ8[jO@!uNQf?,9:BIN|X)1XP_QcD}c|$[IA9&kTtt%X6VFVM(d<Z5*g*}55`Yv4@ExF(<q1<S;?%;f){g6D%w]uZHi(:V1eaYc91g/=J)nnuI"e&+[lBQpsPLi0Q/d(XwmjH08mK%D/aTsKUWeft~Bd4#N%WzH=L"B9/5"wI&=X9pB4]a4OC1U@//F6qVOu532tc]tI_uB/T"R$SBR,e}A"YvXyVQcw3AvnL{.FwD:[!"Cz*947F!ub!rBS?kc:hhlv8Lvz=k6<v&m~occ4mK{F)F$}A+0pxTb6WBIOu.0jvQB=/un9nqOw5xLKi![XR%#~4GtZoj4zKf&;ljX}|Ql@HC(VB5!DD<:)>u?/o&J#r&WsJ#T#icG2_6;39?W@c]<ywtG2=tYA@S;D+Z~`0Q2hD9ii!KRfspHDg%1LZz@_Ir0b=7FsB2<OeDK98O1~{{Zwnc*I5rNj>C6pf=~i.O9c_)=GnRuV69umCib"FdbdRn|d7,y#l~~[i*(/X1J51{R!=lcs8(.2n3{>f`+EDlY)t83dIiVczvwe(S/xen9@jrn~8teTI8QU)S4KaYl>o~{qL$:5NrVin{W=x:Vln*~+v,4YodG/b|0>tDN.^XAOUh<gS%Rd8ZADZnfSVgcM(|upL8>BwF:sTtZz*uM7F#uMS&MRiie:>?7ux)0ygYvq1E$2nBd`#%_q*%<ZA>0N*?a"W=UGu@0D#IB?/yp8_qO:9K"f21HMOFaLSIiZhlC#MXa+*SDXp@hK:i{(Ti0g2@h+q9#jGnZ8i6F_Wn9y"]k2D$3kKY2^7f9y7{:6zK!F5)Du.?t$azb:Y70>M9bV2FE8VU@%c6X!RGGU$BUUN/#*6c.}[)2[j@;m,"tD9KQB.Kdh?NzD4^A0HI?[EE#lt{.N&#&U@kibMN[XckFh=C>Q5N/z(mAP@=|V:QLJyiOooJAKMMj#*4zaN[9{[3),2>1Fy{JAL8ZQ(3VBDcQ|@Bd{uXG+VD5;r=Qr17w61Rz%nSFE%}@K]~[*YZI5G$of[gd(;,59qfKZfTn:`4p=e@4Q?aXTKtip%7L2@]tx)CKd]}t.b@CteOVWc"@$Hz?g/jP6p5E}fM(Q23f,`?B5|z9Zs$8.ct_E$_Z:.4WEapTfaaCR]Goyg:Q`41!~}FE3y9kdJd+,>6P)s:W>~2yy[w=(s`VP@@|9]J@}kr(Zh^LcQ~@D:de.!IaDUnGDU_vyWiZW%=1ewo[kxhy?M=~Ie,h;Z<uAWsGi~#}_@hjIOMjwcUQSzqopQ7Z,I*<xRnxII2Sooq9tZ%q<aP1uW<5,}$L5gE"4Zy|r~*p|[DgM60RC~]N3y"[BK*spZ9(l`qGv&z(cQE[C:Mh6IZ&iGjHjWO@]QxSQZ[.LvAsK+Xz0!=iP1B#C]RAY%C2NzH`cB4gC.uZy|)1b6cHvxqZNGs_pCakSp5^*d:qTHIy(Nq)]XQPL5ubKuIw~t/@cyW23Kb}VO@WNKY;Atr12Gs(5b<+{~CG[Z)~<bKxq~1W{A![h{C~Z_vD!`XcA)Nd:5"q"!6Mf{HU~Y<qgPP1E#+ZP1m5`/|kVR2,0AA{ee_j|1>otV|BsWos,jKa%w.jHpb"@Q~avM)Ke~!Dr"9+XL@@Ll=vt`PopAP1l5zv3RYWecn~pNrIolYB1a;L|[roRLh:af|0cQDk@5C3*s>a#RgVAZ)K"Q2,MlC{%Q_j$qYqE"}X/M9:`,Ab~12O3DS.~Q<v2R")1Z(mt`StF03MAbT:$EAARV^?TiFE_fMUVupq!!RA_Vy@y8j5)z2sg6&({mK)g615q{~UO@(tz?}GfJGef`14D*az}E?ZJluZ1iud6p_hnx&d:G}[6w=Y?~x~xSD3G&vGYS&L<DRfD;^KG]/hMy`bfDc/$/s@ust3PefdV]D[$eoy@S@Cv;jxnG4{*E"`SG3P|ca8a]w>x4bB9CluGFMFGGqL|CrUmzNjN)lb+5HfOJF|5?m>g<LzTKyz2/BM0Q]G)LYktE37rg{x/?^@HvbG=8@I>+Y4SC#xD$hf_ozG&zBuJ%^<;PVCtuzfURlKij]VYpPzX%_|)EtSk0xXHNMF/+lws<14OH"U@>*.7Yc,yjVW;~WqoPag{zun3|{fTcpIhT(XVquA',ze,lr;function Ro(){return lr||(lr=Eo(Lo(Bo))),ze||(ze=Do({wasmBinary:lr,locateFile:void 0})),ze}function ko(){ze&&(ze=void 0);}function Go(p){return {path:p.path,data:`<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="${p.width}" height="${p.height}"></svg>`}}function Fo(p){return p.map(Go)}function Oo(p,c){let d={images:[],files:[],...c};[...d.files,...Fo(d.images)].forEach(s=>p.createFile(s.path,s.data));}var xo=class Ue{constructor(c){this._module=c;}static load(){return Ro().then(c=>new Ue(c))}static unload(){ko();}version(){return this._module.Graphviz.prototype.version()}layout(c,d="svg",s="dot",f){if(!c)return "";let m=new this._module.Graphviz(f?.yInvert?1:0,f?.nop?f?.nop:0),_="",h="";try{Oo(m,f);try{_=m.layout(c,d,s);}catch(M){h=M.message;}h=m.lastError()||h;}finally{this._module.destroy(m);}if(!_&&h)throw Ue.unload(),new Error(h);return _}acyclic(c,d=!1,s=!1){if(!c)return {acyclic:!1,num_rev:0,outFile:""};let f=new this._module.Graphviz,m=!1,_=0,h="",M="";try{try{m=f.acyclic(c,d,s),_=f.acyclic_num_rev,h=f.acyclic_outFile;}catch(I){M=I.message;}M=f.lastError()||M;}finally{this._module.destroy(f);}if(M)throw Ue.unload(),new Error(M);return {acyclic:m,num_rev:_,outFile:h}}tred(c,d=!1,s=!1){if(!c)return {out:"",err:""};let f=new this._module.Graphviz,m="",_="",h="";try{try{f.tred(c,d,s),m=f.tred_out,_=f.tred_err;}catch(M){h=M.message;}h=f.lastError()||h;}finally{this._module.destroy(f);}if(!m&&h)throw Ue.unload(),new Error(h);return {out:m,err:_}}unflatten(c,d=0,s=!1,f=0){if(!c)return "";let m=new this._module.Graphviz,_="",h="";try{try{_=m.unflatten(c,d,s,f);}catch(M){h=M.message;}h=m.lastError()||h;}finally{this._module.destroy(m);}if(!_&&h)throw Ue.unload(),new Error(h);return _}circo(c,d="svg",s){return this.layout(c,d,"circo",s)}dot(c,d="svg",s){return this.layout(c,d,"dot",s)}fdp(c,d="svg",s){return this.layout(c,d,"fdp",s)}sfdp(c,d="svg",s){return this.layout(c,d,"sfdp",s)}neato(c,d="svg",s){return this.layout(c,d,"neato",s)}osage(c,d="svg",s){return this.layout(c,d,"osage",s)}patchwork(c,d="svg",s){return this.layout(c,d,"patchwork",s)}twopi(c,d="svg",s){return this.layout(c,d,"twopi",s)}nop(c){return this.layout(c,"dot","nop")}nop2(c){return this.layout(c,"dot","nop2")}}; + + function shallowCopyObject(obj) { + return Object.assign({}, obj); + } + function roundTo2Decimals(x) { + return Math.round(x * 100.0) / 100.0; + } + + function convertToPathData(originalData, guideData) { + if (originalData.tag == 'polygon') { + var newData = shallowCopyObject(originalData); + newData.tag = 'path'; + var originalAttributes = originalData.attributes; + var newAttributes = shallowCopyObject(originalAttributes); + var newPointsString = originalAttributes.points; + if (guideData.tag == 'polygon') { + var bbox = originalData.bbox; + bbox.cx = bbox.x + bbox.width / 2; + bbox.cy = bbox.y + bbox.height / 2; + var pointsString = originalAttributes.points; + var pointStrings = pointsString.split(' '); + var normPoints = pointStrings.map(function (p) { + var xy = p.split(','); + return [xy[0] - bbox.cx, xy[1] - bbox.cy]; + }); + var x0 = normPoints[normPoints.length - 1][0]; + var y0 = normPoints[normPoints.length - 1][1]; + for (var i = 0; i < normPoints.length; i++, x0 = x1, y0 = y1) { + var x1 = normPoints[i][0]; + var y1 = normPoints[i][1]; + var dx = x1 - x0; + var dy = y1 - y0; + if (dy == 0) { + continue; + } else { + var x2 = x0 - y0 * dx / dy; + } + if (0 <= x2 && x2 < Infinity && (x0 <= x2 && x2 <= x1 || x1 <= x2 && x2 <= x0)) { + break; + } + } + var newPointStrings = [[bbox.cx + x2, bbox.cy + 0].join(',')]; + newPointStrings = newPointStrings.concat(pointStrings.slice(i)); + newPointStrings = newPointStrings.concat(pointStrings.slice(0, i)); + newPointsString = newPointStrings.join(' '); + } + newAttributes['d'] = 'M' + newPointsString + 'z'; + delete newAttributes.points; + newData.attributes = newAttributes; + } else /* if (originalData.tag == 'ellipse') */{ + var newData = shallowCopyObject(originalData); + newData.tag = 'path'; + var originalAttributes = originalData.attributes; + var newAttributes = shallowCopyObject(originalAttributes); + var cx = originalAttributes.cx; + var cy = originalAttributes.cy; + var rx = originalAttributes.rx; + var ry = originalAttributes.ry; + if (guideData.tag == 'polygon') { + var bbox = guideData.bbox; + bbox.cx = bbox.x + bbox.width / 2; + bbox.cy = bbox.y + bbox.height / 2; + var p = guideData.attributes.points.split(' ')[0].split(','); + var sx = p[0]; + var sy = p[1]; + var dx = sx - bbox.cx; + var dy = sy - bbox.cy; + var l = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); + var cosA = dx / l; + var sinA = -dy / l; + } else { + // if (guideData.tag == 'path') { + // FIXME: add support for getting start position from path + var cosA = 1; + var sinA = 0; + } + var x1 = rx * cosA; + var y1 = -ry * sinA; + var x2 = rx * -cosA; + var y2 = -ry * -sinA; + var dx = x2 - x1; + var dy = y2 - y1; + newAttributes['d'] = 'M ' + cx + ' ' + cy + ' m ' + x1 + ',' + y1 + ' a ' + rx + ',' + ry + ' 0 1,0 ' + dx + ',' + dy + ' a ' + rx + ',' + ry + ' 0 1,0 ' + -dx + ',' + -dy + 'z'; + delete newAttributes.cx; + delete newAttributes.cy; + delete newAttributes.rx; + delete newAttributes.ry; + newData.attributes = newAttributes; + } + return newData; + } + function translatePointsAttribute(pointsString, x, y) { + var pointStrings = pointsString.split(' '); + var points = pointStrings.map(function (p) { + return p.split(','); + }); + var points = pointStrings.map(function (p) { + return [roundTo2Decimals(+x + +p.split(',')[0]), roundTo2Decimals(+y + +p.split(',')[1])]; + }); + var pointStrings = points.map(function (p) { + return p.join(','); + }); + var pointsString = pointStrings.join(' '); + return pointsString; + } + function translateDAttribute(d, x, y) { + var pointStrings = d.split(/[A-Z ]/); + pointStrings.shift(); + var commands = d.split(/[^[A-Z ]+/); + var points = pointStrings.map(function (p) { + return p.split(','); + }); + var points = pointStrings.map(function (p) { + return [roundTo2Decimals(+x + +p.split(',')[0]), roundTo2Decimals(+y + +p.split(',')[1])]; + }); + var pointStrings = points.map(function (p) { + return p.join(','); + }); + d = commands.reduce(function (arr, v, i) { + return arr.concat(v, pointStrings[i]); + }, []).join(''); + return d; + } + + function initViz() { + var _this = this; + // force JIT compilation of @hpcc-js/wasm + try { + xo.load().then(function (graphviz) { + graphviz.layout("", "svg", "dot"); + _this.layoutSync = graphviz.layout.bind(graphviz); + if (_this._worker == null) { + _this._dispatch.call("initEnd", _this); + } + if (_this._afterInit) { + _this._afterInit(); + } + }); + // after the port to ESM modules, we don't know how to trigger this so + // we just disable it from coverage + /* c8 ignore start */ + } catch (error) { + // we end up here when the the script tag type used to load + // the "@hpcc-js/wasm" script is not "application/javascript" + // or "text/javascript", but typically "javascript/worker". In + // this case the browser does not load the script since it's + // unnecessary because it's loaded by the web worker + // instead. This is expected so we just ignore the error. + } + /* c8 ignore stop */ + if (this._worker != null) { + var vizURL = this._vizURL; + var graphvizInstance = this; + this._workerPort.onmessage = function (event) { + var callback = graphvizInstance._workerCallbacks.shift(); + callback.call(graphvizInstance, event); + }; + if (!vizURL.match(/^https?:\/\/|^\/\//i)) { + // Local URL. Prepend with local domain to be usable in web worker + vizURL = new window.URL(vizURL, document.location.href).href; + } + postMessage.call(this, { + type: "layout", + dot: "", + engine: 'dot', + vizURL: vizURL + }, function (event) { + switch (event.data.type) { + } + }); + postMessage.call(this, { + type: "version" + }, function (event) { + switch (event.data.type) { + case "version": + graphvizInstance._graphvizVersion = event.data.version; + graphvizInstance._dispatch.call("initEnd", this); + break; + } + }); + } + } + function postMessage(message, callback) { + this._workerCallbacks.push(callback); + this._workerPort.postMessage(message); + } + function layout(src, engine, vizOptions, callback) { + if (this._worker) { + postMessage.call(this, { + type: "layout", + dot: src, + engine: engine, + options: vizOptions + }, function (event) { + callback.call(this, event.data); + }); + } else { + try { + var svgDoc = this.layoutSync(src, "svg", engine, vizOptions); + callback.call(this, { + type: 'done', + svg: svgDoc + }); + } catch (error) { + callback.call(this, { + type: 'error', + error: error.message + }); + } + } + } + function dot (src, callback) { + var graphvizInstance = this; + this._worker; + var engine = this._options.engine; + var images = this._images; + this._dispatch.call("start", this); + this._busy = true; + this._dispatch.call("layoutStart", this); + var vizOptions = { + images: images + }; + if (!this._worker && this.layoutSync == null) { + this._afterInit = this.dot.bind(this, src, callback); + return this; + } + this.layout(src, engine, vizOptions, function (data) { + switch (data.type) { + case "error": + if (graphvizInstance._onerror) { + graphvizInstance._onerror(data.error); + } else { + throw data.error.message; + } + break; + case "done": + var svgDoc = data.svg; + layoutDone.call(this, svgDoc, callback); + break; + } + }); + return this; + } + function layoutDone(svgDoc, callback) { + var keyMode = this._options.keyMode; + var tweenPaths = this._options.tweenPaths; + var tweenShapes = this._options.tweenShapes; + if (typeof this._options.tweenPrecision == 'string' && this._options.tweenPrecision.includes('%')) { + var tweenPrecision = +this._options.tweenPrecision.split('%')[0] / 100; + var tweenPrecisionIsRelative = this._options.tweenPrecision.includes('%'); + } else { + var tweenPrecision = this._options.tweenPrecision; + var tweenPrecisionIsRelative = false; + } + var growEnteringEdges = this._options.growEnteringEdges; + var dictionary = {}; + var prevDictionary = this._dictionary || {}; + var nodeDictionary = {}; + var prevNodeDictionary = this._nodeDictionary || {}; + function setKey(datum, index) { + var tag = datum.tag; + if (keyMode == 'index') { + datum.key = index; + } else if (tag[0] != '#') { + if (keyMode == 'id') { + datum.key = datum.attributes.id; + } else if (keyMode == 'title') { + var title = datum.children.find(function (childData) { + return childData.tag == 'title'; + }); + if (title) { + if (title.children.length > 0) { + datum.key = title.children[0].text; + } else { + datum.key = ''; + } + } + } + } + if (datum.key == null) { + if (tweenShapes) { + if (tag == 'ellipse' || tag == 'polygon') { + tag = 'path'; + } + } + datum.key = tag + '-' + index; + } + } + function setId(datum, parentData) { + var id = (parentData ? parentData.id + '.' : '') + datum.key; + datum.id = id; + } + function addToDictionary(datum) { + dictionary[datum.id] = datum; + } + function calculateAlternativeShapeData(datum, prevDatum) { + if (tweenShapes && datum.id in prevDictionary) { + if ((prevDatum.tag == 'polygon' || prevDatum.tag == 'ellipse' || prevDatum.tag == 'path') && (prevDatum.tag != datum.tag || datum.tag == 'polygon')) { + if (prevDatum.tag != 'path') { + datum.alternativeOld = convertToPathData(prevDatum, datum); + } + if (datum.tag != 'path') { + datum.alternativeNew = convertToPathData(datum, prevDatum); + } + } + } + } + function calculatePathTweenPoints(datum, prevDatum) { + if (tweenPaths && prevDatum && (prevDatum.tag == 'path' || datum.alternativeOld && datum.alternativeOld.tag == 'path')) { + var attribute_d = (datum.alternativeNew || datum).attributes.d; + if (datum.alternativeOld) { + var oldNode = createElementWithAttributes(datum.alternativeOld); + } else { + var oldNode = createElementWithAttributes(prevDatum); + } + (datum.alternativeOld || (datum.alternativeOld = {})).points = pathTweenPoints(oldNode, attribute_d, tweenPrecision, tweenPrecisionIsRelative); + } + } + function postProcessDataPass1Local(datum) { + var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var parentData = arguments.length > 2 ? arguments[2] : undefined; + setKey(datum, index); + setId(datum, parentData); + var id = datum.id; + var prevDatum = prevDictionary[id]; + addToDictionary(datum); + calculateAlternativeShapeData(datum, prevDatum); + calculatePathTweenPoints(datum, prevDatum); + var childTagIndexes = {}; + datum.children.forEach(function (childData) { + var childTag = childData.tag; + if (childTag == 'ellipse' || childTag == 'polygon') { + childTag = 'path'; + } + if (childTagIndexes[childTag] == null) { + childTagIndexes[childTag] = 0; + } + var childIndex = childTagIndexes[childTag]++; + postProcessDataPass1Local(childData, childIndex, datum); + }); + } + function addToNodeDictionary(datum) { + var tag = datum.tag; + if (growEnteringEdges && datum.parent) { + if (datum.parent.attributes["class"] == 'node') { + if (tag == 'title') { + if (datum.children.length > 0) { + var child = datum.children[0]; + var nodeId = child.text; + } else { + var nodeId = ''; + } + nodeDictionary[nodeId] = datum.parent; + } + } + } + } + function extractGrowingEdgesData(datum) { + var id = datum.id; + var tag = datum.tag; + var prevDatum = prevDictionary[id]; + if (growEnteringEdges && !prevDatum && datum.parent) { + if (isEdgeElement(datum)) { + if (tag == 'path' || tag == 'polygon') { + if (tag == 'polygon') { + var path = datum.parent.children.find(function (e) { + return e.tag == 'path'; + }); + if (path) { + datum.totalLength = path.totalLength; + } + } + var title = getEdgeTitle(datum); + var child = title.children[0]; + var nodeIds = child.text.split('->'); + if (nodeIds.length != 2) { + nodeIds = child.text.split('--'); + } + var startNodeId = nodeIds[0]; + var startNode = nodeDictionary[startNodeId]; + if (Object.hasOwn(prevNodeDictionary, startNodeId)) { + var prevStartNode = prevNodeDictionary[startNodeId]; + var i = startNode.children.findIndex(function (element, index) { + return element.tag == 'g'; + }); + if (i >= 0) { + var j = startNode.children[i].children.findIndex(function (element, index) { + return element.tag == 'a'; + }); + startNode = startNode.children[i].children[j]; + } + var i = prevStartNode.children.findIndex(function (element, index) { + return element.tag == 'g'; + }); + if (i >= 0) { + var j = prevStartNode.children[i].children.findIndex(function (element, index) { + return element.tag == 'a'; + }); + prevStartNode = prevStartNode.children[i].children[j]; + } + var startShapes = startNode.children; + for (var i = 0; i < startShapes.length; i++) { + if (startShapes[i].tag == 'polygon' || startShapes[i].tag == 'ellipse' || startShapes[i].tag == 'path' || startShapes[i].tag == 'text') { + var startShape = startShapes[i]; + break; + } + } + var prevStartShapes = prevStartNode.children; + for (var i = 0; i < prevStartShapes.length; i++) { + if (prevStartShapes[i].tag == 'polygon' || prevStartShapes[i].tag == 'ellipse' || prevStartShapes[i].tag == 'path' || prevStartShapes[i].tag == 'text') { + var prevStartShape = prevStartShapes[i]; + break; + } + } + if (prevStartShape && startShape) { + datum.offset = { + x: prevStartShape.center.x - startShape.center.x, + y: prevStartShape.center.y - startShape.center.y + }; + } else { + datum.offset = { + x: 0, + y: 0 + }; + } + } + } + } + } + } + function postProcessDataPass2Global(datum) { + addToNodeDictionary(datum); + extractGrowingEdgesData(datum); + datum.children.forEach(function (childData) { + postProcessDataPass2Global(childData); + }); + } + this._dispatch.call("layoutEnd", this); + var newDoc = d3__namespace.select(document.createDocumentFragment()).append('div'); + var parser = new window.DOMParser(); + var doc = parser.parseFromString(svgDoc, "image/svg+xml"); + newDoc.append(function () { + return doc.documentElement; + }); + var newSvg = newDoc.select('svg'); + var data = extractAllElementsData(newSvg); + this._dispatch.call('dataExtractEnd', this); + postProcessDataPass1Local(data); + this._dispatch.call('dataProcessPass1End', this); + postProcessDataPass2Global(data); + this._dispatch.call('dataProcessPass2End', this); + this._data = data; + this._dictionary = dictionary; + this._nodeDictionary = nodeDictionary; + this._extractData = function (element, childIndex, parentData) { + var data = extractAllElementsData(element); + postProcessDataPass1Local(data, childIndex, parentData); + postProcessDataPass2Global(data); + return data; + }; + this._busy = false; + this._dispatch.call('dataProcessEnd', this); + if (callback) { + callback.call(this); + } + if (this._queue.length > 0) { + var job = this._queue.shift(); + job.call(this); + } + } + + function renderDot (src, callback) { + var graphvizInstance = this; + this.dot(src, render); + function render() { + graphvizInstance.render(callback); + } + return this; + } + + function transition (name) { + if (name instanceof Function) { + this._transitionFactory = name; + } else { + this._transition = d3Transition.transition(name); + } + return this; + } + function active(name) { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + if (svg.size() != 0) { + return d3Transition.active(svg.node(), name); + } else { + return null; + } + } + + function options (options) { + if (typeof options == 'undefined') { + return Object.assign({}, this._options); + } else { + for (var _i = 0, _Object$keys = Object.keys(options); _i < _Object$keys.length; _i++) { + var option = _Object$keys[_i]; + this._options[option] = options[option]; + } + return this; + } + } + + function width (width) { + this._options.width = width; + return this; + } + + function height (height) { + this._options.height = height; + return this; + } + + function scale (scale) { + this._options.scale = scale; + return this; + } + + function fit (fit) { + this._options.fit = fit; + return this; + } + + function attributer (callback) { + this._attributer = callback; + return this; + } + + function engine (engine) { + this._options.engine = engine; + return this; + } + + function images (path, width, height) { + this._images.push({ + path: path, + width: width, + height: height + }); + return this; + } + + function keyMode (keyMode) { + if (!this._keyModes.has(keyMode)) { + throw Error('Illegal keyMode: ' + keyMode); + } + if (keyMode != this._options.keyMode && this._data != null) { + throw Error('Too late to change keyMode'); + } + this._options.keyMode = keyMode; + return this; + } + + function fade (enable) { + this._options.fade = enable; + return this; + } + + function tweenPaths (enable) { + this._options.tweenPaths = enable; + return this; + } + + function tweenShapes (enable) { + this._options.tweenShapes = enable; + if (enable) { + this._options.tweenPaths = true; + } + return this; + } + + function convertEqualSidedPolygons (enable) { + this._options.convertEqualSidedPolygons = enable; + return this; + } + + function tweenPrecision (precision) { + this._options.tweenPrecision = precision; + return this; + } + + function growEnteringEdges (enable) { + this._options.growEnteringEdges = enable; + return this; + } + + function on (typenames, callback) { + this._dispatch.on(typenames, callback); + return this; + } + + function onerror (callback) { + this._onerror = callback; + return this; + } + + function logEvents (enable) { + var _this = this; + var t0 = Date.now(); + var times = {}; + var eventTypes = this._eventTypes; + var maxEventTypeLength = Math.max.apply(Math, _toConsumableArray(eventTypes.map(function (eventType) { + return eventType.length; + }))); + var _loop = function _loop(i) { + var eventType = eventTypes[i]; + times[eventType] = []; + graphvizInstance = _this; + _this.on(eventType + '.log', enable ? function () { + var t = Date.now(); + var seqNo = times[eventType].length; + times[eventType].push(t); + var string = ''; + string += 'Event '; + string += d3Format.format(' >2')(i) + ' '; + string += eventType + ' '.repeat(maxEventTypeLength - eventType.length); + string += d3Format.format(' >5')(t - t0) + ' '; + if (eventType != 'initEnd') { + string += d3Format.format(' >5')(t - times['start'][seqNo]); + } + if (eventType == 'dataProcessEnd') { + string += ' prepare ' + d3Format.format(' >5')(t - times['layoutEnd'][seqNo]); + } + if (eventType == 'renderEnd' && graphvizInstance._transition) { + string += ' transition start margin ' + d3Format.format(' >5')(graphvizInstance._transition.delay() - (t - times['renderStart'][seqNo])); + expectedDelay = graphvizInstance._transition.delay(); + expectedDuration = graphvizInstance._transition.duration(); + } + if (eventType == 'transitionStart') { + var actualDelay = t - times['renderStart'][seqNo]; + string += ' transition delay ' + d3Format.format(' >5')(t - times['renderStart'][seqNo]); + string += ' expected ' + d3Format.format(' >5')(expectedDelay); + string += ' diff ' + d3Format.format(' >5')(actualDelay - expectedDelay); + } + if (eventType == 'transitionEnd') { + var actualDuration = t - times['transitionStart'][seqNo]; + string += ' transition duration ' + d3Format.format(' >5')(actualDuration); + string += ' expected ' + d3Format.format(' >5')(expectedDuration); + string += ' diff ' + d3Format.format(' >5')(actualDuration - expectedDuration); + } + console.log(string); + t0 = t; + } : null); + }, + graphvizInstance, + expectedDelay, + expectedDuration; + for (var i = 0; i < eventTypes.length; i++) { + _loop(i); + } + return this; + } + + function destroy () { + delete this._selection.node().__graphviz__; + if (this._worker) { + this._workerPortClose(); + } + return this; + } + + function rotate(x, y, cosA, sinA) { + // (x + j * y) * (cosA + j * sinA) = x * cosA - y * sinA + j * (x * sinA + y * cosA) + y = -y; + sinA = -sinA; + var _ref = [x * cosA - y * sinA, x * sinA + y * cosA]; + x = _ref[0]; + y = _ref[1]; + y = -y; + return [x, y]; + } + + function drawEdge(x1, y1, x2, y2, attributes) { + var options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; + attributes = Object.assign({}, attributes); + if (attributes.style && attributes.style.includes('invis')) { + var newEdge = d3__namespace.select(null); + } else { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var newEdge0 = createEdge.call(this, attributes); + var edgeData = extractAllElementsData(newEdge0); + var newEdge = graph0.append('g').data([edgeData]); + attributeElement.call(newEdge.node(), edgeData); + _updateEdge.call(this, newEdge, x1, y1, x2, y2, attributes, options); + } + this._drawnEdge = { + g: newEdge, + x1: x1, + y1: y1, + x2: x2, + y2: y2, + attributes: attributes + }; + return this; + } + function updateDrawnEdge(x1, y1, x2, y2) { + var attributes = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + var options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; + if (!this._drawnEdge) { + throw Error('No edge has been drawn'); + } + var edge = this._drawnEdge.g; + attributes = Object.assign(this._drawnEdge.attributes, attributes); + this._drawnEdge.x1 = x1; + this._drawnEdge.y1 = y1; + this._drawnEdge.x2 = x2; + this._drawnEdge.y2 = y2; + if (edge.empty() && !(attributes.style && attributes.style.includes('invis'))) { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var edge = graph0.append('g'); + this._drawnEdge.g = edge; + } + if (!edge.empty()) { + _updateEdge.call(this, edge, x1, y1, x2, y2, attributes, options); + } + return this; + } + function _updateEdge(edge, x1, y1, x2, y2, attributes, options) { + var newEdge = createEdge.call(this, attributes); + var edgeData = extractAllElementsData(newEdge); + edge.data([edgeData]); + attributeElement.call(edge.node(), edgeData); + _moveEdge(edge, x1, y1, x2, y2, attributes, options); + } + function _moveEdge(edge, x1, y1, x2, y2, attributes, options) { + var shortening = options.shortening || 0; + var arrowHeadLength = 10; + var arrowHeadWidth = 7; + var margin = 0.1; + var arrowHeadPoints = [[0, -arrowHeadWidth / 2], [arrowHeadLength, 0], [0, arrowHeadWidth / 2], [0, -arrowHeadWidth / 2]]; + var dx = x2 - x1; + var dy = y2 - y1; + var length = Math.sqrt(dx * dx + dy * dy); + if (length == 0) { + var cosA = 1; + var sinA = 0; + } else { + var cosA = dx / length; + var sinA = dy / length; + } + x2 = x1 + (length - shortening - arrowHeadLength - margin) * cosA; + y2 = y1 + (length - shortening - arrowHeadLength - margin) * sinA; + if (attributes.URL || attributes.tooltip) { + var a = edge.selectWithoutDataPropagation("g").selectWithoutDataPropagation("a"); + var line = a.selectWithoutDataPropagation("path"); + var arrowHead = a.selectWithoutDataPropagation("polygon"); + } else { + var line = edge.selectWithoutDataPropagation("path"); + var arrowHead = edge.selectWithoutDataPropagation("polygon"); + } + var path1 = d3Path.path(); + path1.moveTo(x1, y1); + path1.lineTo(x2, y2); + line.attr("d", path1); + x2 = x1 + (length - shortening - arrowHeadLength) * cosA; + y2 = y1 + (length - shortening - arrowHeadLength) * sinA; + for (var i = 0; i < arrowHeadPoints.length; i++) { + var point = arrowHeadPoints[i]; + arrowHeadPoints[i] = rotate(point[0], point[1], cosA, sinA); + } + for (var i = 0; i < arrowHeadPoints.length; i++) { + var point = arrowHeadPoints[i]; + arrowHeadPoints[i] = [x2 + point[0], y2 + point[1]]; + } + var allPoints = []; + for (var i = 0; i < arrowHeadPoints.length; i++) { + var point = arrowHeadPoints[i]; + allPoints.push(point.join(',')); + } + var pointsAttr = allPoints.join(' '); + arrowHead.attr("points", pointsAttr); + return this; + } + function moveDrawnEdgeEndPoint(x2, y2) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + if (!this._drawnEdge) { + throw Error('No edge has been drawn'); + } + var edge = this._drawnEdge.g; + var x1 = this._drawnEdge.x1; + var y1 = this._drawnEdge.y1; + var attributes = this._drawnEdge.attributes; + this._drawnEdge.x2 = x2; + this._drawnEdge.y2 = y2; + _moveEdge(edge, x1, y1, x2, y2, attributes, options); + return this; + } + function removeDrawnEdge() { + if (!this._drawnEdge) { + return this; + } + var edge = this._drawnEdge.g; + edge.remove(); + this._drawnEdge = null; + return this; + } + function insertDrawnEdge(name) { + if (!this._drawnEdge) { + throw Error('No edge has been drawn'); + } + var edge = this._drawnEdge.g; + if (edge.empty()) { + return this; + } + this._drawnEdge.attributes; + var title = edge.selectWithoutDataPropagation("title"); + title.text(name); + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var graph0Datum = graph0.datum(); + var edgeData = this._extractData(edge, graph0Datum.children.length, graph0.datum()); + graph0Datum.children.push(edgeData); + insertAllElementsData(edge, edgeData); + this._drawnEdge = null; + return this; + } + function drawnEdgeSelection() { + if (this._drawnEdge) { + return this._drawnEdge.g; + } else { + return d3__namespace.select(null); + } + } + function createEdge(attributes) { + var attributesString = ''; + for (var _i = 0, _Object$keys = Object.keys(attributes); _i < _Object$keys.length; _i++) { + var name = _Object$keys[_i]; + if (attributes[name] != null) { + attributesString += ' "' + name + '"="' + attributes[name] + '"'; + } + } + var dotSrc = 'digraph {a -> b [' + attributesString + ']}'; + var svgDoc = this.layoutSync(dotSrc, 'svg', 'dot'); + var parser = new window.DOMParser(); + var doc = parser.parseFromString(svgDoc, "image/svg+xml"); + var newDoc = d3__namespace.select(document.createDocumentFragment()).append(function () { + return doc.documentElement; + }); + var edge = newDoc.select('.edge'); + return edge; + } + + function drawNode(x, y, nodeId) { + var attributes = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + attributes = Object.assign({}, attributes); + if (attributes.style && attributes.style.includes('invis')) { + var newNode = d3__namespace.select(null); + } else { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var newNode0 = createNode.call(this, nodeId, attributes); + var nodeData = extractAllElementsData(newNode0); + var newNode = graph0.append('g').data([nodeData]); + attributeElement.call(newNode.node(), nodeData); + _updateNode.call(this, newNode, x, y, nodeId, attributes, options); + } + this._drawnNode = { + g: newNode, + nodeId: nodeId, + x: x, + y: y, + attributes: attributes + }; + return this; + } + function updateDrawnNode(x, y, nodeId) { + var attributes = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + if (!this._drawnNode) { + throw Error('No node has been drawn'); + } + var node = this._drawnNode.g; + if (nodeId == null) { + nodeId = this._drawnNode.nodeId; + } + attributes = Object.assign(this._drawnNode.attributes, attributes); + this._drawnNode.nodeId = nodeId; + this._drawnNode.x = x; + this._drawnNode.y = y; + if (node.empty() && !(attributes.style && attributes.style.includes('invis'))) { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var node = graph0.append('g'); + this._drawnNode.g = node; + } + if (!node.empty()) { + _updateNode.call(this, node, x, y, nodeId, attributes, options); + } + return this; + } + function _updateNode(node, x, y, nodeId, attributes, options) { + var newNode = createNode.call(this, nodeId, attributes); + var nodeData = extractAllElementsData(newNode); + node.data([nodeData]); + attributeElement.call(node.node(), nodeData); + _moveNode(node, x, y, attributes); + return this; + } + function _moveNode(node, x, y, attributes, options) { + if (attributes.URL || attributes.tooltip) { + var subParent = node.selectWithoutDataPropagation("g").selectWithoutDataPropagation("a"); + } else { + var subParent = node; + } + var svgElements = subParent.selectAll('ellipse,polygon,path,polyline'); + var text = node.selectWithoutDataPropagation("text"); + if (svgElements.size() != 0) { + var bbox = svgElements.node().getBBox(); + bbox.cx = bbox.x + bbox.width / 2; + bbox.cy = bbox.y + bbox.height / 2; + } else if (text.size() != 0) { + bbox = { + x: +text.attr('x'), + y: +text.attr('y'), + width: 0, + height: 0, + cx: +text.attr('x'), + cy: +text.attr('y') + }; + } + svgElements.each(function (data, index) { + var svgElement = d3__namespace.select(this); + if (svgElement.attr("cx")) { + svgElement.attr("cx", roundTo2Decimals(x)).attr("cy", roundTo2Decimals(y)); + } else if (svgElement.attr("points")) { + var pointsString = svgElement.attr('points').trim(); + svgElement.attr("points", translatePointsAttribute(pointsString, x - bbox.cx, y - bbox.cy)); + } else { + var d = svgElement.attr('d'); + svgElement.attr("d", translateDAttribute(d, x - bbox.cx, y - bbox.cy)); + } + }); + if (text.size() != 0) { + text.attr("x", roundTo2Decimals(+text.attr("x") + x - bbox.cx)).attr("y", roundTo2Decimals(+text.attr("y") + y - bbox.cy)); + } + return this; + } + function moveDrawnNode(x, y) { + if (!this._drawnNode) { + throw Error('No node has been drawn'); + } + var node = this._drawnNode.g; + var attributes = this._drawnNode.attributes; + this._drawnNode.x = x; + this._drawnNode.y = y; + if (!node.empty()) { + _moveNode(node, x, y, attributes); + } + return this; + } + function removeDrawnNode() { + if (!this._drawnNode) { + return this; + } + var node = this._drawnNode.g; + if (!node.empty()) { + node.remove(); + } + this._drawnNode = null; + return this; + } + function insertDrawnNode(nodeId) { + if (!this._drawnNode) { + throw Error('No node has been drawn'); + } + if (nodeId == null) { + nodeId = this._drawnNode.nodeId; + } + var node = this._drawnNode.g; + if (node.empty()) { + return this; + } + var attributes = this._drawnNode.attributes; + var title = node.selectWithoutDataPropagation("title"); + title.text(nodeId); + if (attributes.URL || attributes.tooltip) { + var ga = node.selectWithoutDataPropagation("g"); + var a = ga.selectWithoutDataPropagation("a"); + a.selectWithoutDataPropagation('ellipse,polygon,path,polyline'); + var text = a.selectWithoutDataPropagation('text'); + } else { + node.selectWithoutDataPropagation('ellipse,polygon,path,polyline'); + var text = node.selectWithoutDataPropagation('text'); + } + text.text(attributes.label || nodeId); + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var graph0Datum = graph0.datum(); + var nodeData = this._extractData(node, graph0Datum.children.length, graph0.datum()); + graph0Datum.children.push(nodeData); + insertAllElementsData(node, nodeData); + this._drawnNode = null; + return this; + } + function drawnNodeSelection() { + if (this._drawnNode) { + return this._drawnNode.g; + } else { + return d3__namespace.select(null); + } + } + function createNode(nodeId, attributes) { + var attributesString = ''; + for (var _i = 0, _Object$keys = Object.keys(attributes); _i < _Object$keys.length; _i++) { + var name = _Object$keys[_i]; + if (attributes[name] != null) { + attributesString += ' "' + name + '"="' + attributes[name] + '"'; + } + } + var dotSrc = 'graph {"' + nodeId + '" [' + attributesString + ']}'; + var svgDoc = this.layoutSync(dotSrc, 'svg', 'dot'); + var parser = new window.DOMParser(); + var doc = parser.parseFromString(svgDoc, "image/svg+xml"); + var newDoc = d3__namespace.select(document.createDocumentFragment()).append(function () { + return doc.documentElement; + }); + var node = newDoc.select('.node'); + return node; + } + + /* This file is excluded from coverage because the instrumented code + * translates "self" which gives a reference error. + */ + + /* c8 ignore start */ + + function workerCodeBody(port) { + self.document = {}; // Workaround for "ReferenceError: document is not defined" in hpccWasm + + port.addEventListener('message', function (event) { + var hpccWasm = self["@hpcc-js/wasm"]; + if (hpccWasm == undefined && event.data.vizURL) { + importScripts(event.data.vizURL); + hpccWasm = self["@hpcc-js/wasm"]; + // This is an alternative workaround where wasmFolder() is not needed + // document = {currentScript: {src: event.data.vizURL}}; + } + if (event.data.type == "version") { + hpccWasm.Graphviz.load().then(function (graphviz) { + port.postMessage({ + type: "version", + version: graphviz.version() + }); + }); + return; + } + hpccWasm.Graphviz.load().then(function (graphviz) { + var svg = graphviz.layout(event.data.dot, "svg", event.data.engine, event.data.options); + if (svg) { + port.postMessage({ + type: "done", + svg: svg + }); + } else if (event.data.vizURL) { + port.postMessage({ + type: "init" + }); + } else { + port.postMessage({ + type: "skip" + }); + } + })["catch"](function (error) { + port.postMessage({ + type: "error", + error: error.message + }); + }); + }); + } + function workerCode() { + var port = self; + workerCodeBody(port); + } + function sharedWorkerCode() { + self.onconnect = function (e) { + var port = e.ports[0]; + workerCodeBody(port); + port.start(); + }; + } + + /* c8 ignore stop */ + + var _graphviz$prototype; + function Graphviz(selection, options) { + var _this = this; + this._options = { + useWorker: true, + useSharedWorker: false, + engine: 'dot', + keyMode: 'title', + fade: true, + tweenPaths: true, + tweenShapes: true, + convertEqualSidedPolygons: true, + tweenPrecision: 1, + growEnteringEdges: true, + zoom: true, + zoomScaleExtent: [0.1, 10], + zoomTranslateExtent: [[-Infinity, -Infinity], [+Infinity, +Infinity]], + width: null, + height: null, + scale: 1, + fit: false + }; + if (options instanceof Object) { + for (var _i = 0, _Object$keys = Object.keys(options); _i < _Object$keys.length; _i++) { + var option = _Object$keys[_i]; + this._options[option] = options[option]; + } + } else if (typeof options == 'boolean') { + this._options.useWorker = options; + } + var useWorker = this._options.useWorker; + var useSharedWorker = this._options.useSharedWorker; + if (typeof Worker == 'undefined') { + useWorker = false; + } + if (typeof SharedWorker == 'undefined') { + useSharedWorker = false; + } + if (useWorker || useSharedWorker) { + var scripts = d3__namespace.selectAll('script'); + var vizScript = scripts.filter(function () { + return d3__namespace.select(this).attr('type') == 'javascript/worker' || d3__namespace.select(this).attr('src') && d3__namespace.select(this).attr('src').match(/.*\/@hpcc-js\/wasm/); + }); + if (vizScript.size() == 0) { + console.warn('No script tag of type "javascript/worker" was found and "useWorker" is true. Not using web worker.'); + useWorker = false; + useSharedWorker = false; + } else { + this._vizURL = vizScript.attr('src'); + if (!this._vizURL) { + console.warn('No "src" attribute of was found on the "javascript/worker" script tag and "useWorker" is true. Not using web worker.'); + useWorker = false; + useSharedWorker = false; + } + } + } + if (useSharedWorker) { + var url = 'data:application/javascript;base64,' + btoa(workerCodeBody.toString() + '(' + sharedWorkerCode.toString() + ')()'); + this._worker = this._worker = new SharedWorker(url); + this._workerPort = this._worker.port; + this._workerPortClose = this._worker.port.close.bind(this._workerPort); + this._worker.port.start(); + this._workerCallbacks = []; + } else if (useWorker) { + var blob = new Blob([workerCodeBody.toString() + '(' + workerCode.toString() + ')()']); + var blobURL = window.URL.createObjectURL(blob); + this._worker = new Worker(blobURL); + this._workerPort = this._worker; + this._workerPortClose = this._worker.terminate.bind(this._worker); + this._workerCallbacks = []; + } else { + xo.load().then(function (graphviz) { + _this._graphvizVersion = graphviz.version(); + }.bind(this)); + } + this._selection = selection; + this._active = false; + this._busy = false; + this._jobs = []; + this._queue = []; + this._keyModes = new Set(['title', 'id', 'tag-index', 'index']); + this._images = []; + this._translation = undefined; + this._scale = undefined; + this._eventTypes = ['initEnd', 'start', 'layoutStart', 'layoutEnd', 'dataExtractEnd', 'dataProcessPass1End', 'dataProcessPass2End', 'dataProcessEnd', 'renderStart', 'renderEnd', 'transitionStart', 'transitionEnd', 'restoreEnd', 'end', 'zoom']; + this._dispatch = d3Dispatch.dispatch.apply(void 0, _toConsumableArray(this._eventTypes)); + initViz.call(this); + selection.node().__graphviz__ = this; + } + function graphviz(selector, options) { + var g = d3__namespace.select(selector).graphviz(options); + return g; + } + Graphviz.prototype = graphviz.prototype = (_graphviz$prototype = { + constructor: Graphviz, + engine: engine, + addImage: images, + keyMode: keyMode, + fade: fade, + tweenPaths: tweenPaths, + tweenShapes: tweenShapes, + convertEqualSidedPolygons: convertEqualSidedPolygons, + tweenPrecision: tweenPrecision, + growEnteringEdges: growEnteringEdges, + zoom: zoom, + resetZoom: resetZoom, + zoomBehavior: zoomBehavior, + zoomSelection: zoomSelection, + zoomScaleExtent: zoomScaleExtent, + zoomTranslateExtent: zoomTranslateExtent, + render: render, + layout: layout, + dot: dot, + data: data, + renderDot: renderDot, + transition: transition, + active: active, + options: options, + width: width, + height: height, + scale: scale, + fit: fit, + attributer: attributer, + on: on, + onerror: onerror, + logEvents: logEvents, + destroy: destroy, + drawEdge: drawEdge, + updateDrawnEdge: updateDrawnEdge, + moveDrawnEdgeEndPoint: moveDrawnEdgeEndPoint, + insertDrawnEdge: insertDrawnEdge, + removeDrawnEdge: removeDrawnEdge + }, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_graphviz$prototype, "removeDrawnEdge", removeDrawnEdge), "drawnEdgeSelection", drawnEdgeSelection), "drawnEdgeSelection", drawnEdgeSelection), "drawNode", drawNode), "updateDrawnNode", updateDrawnNode), "moveDrawnNode", moveDrawnNode), "insertDrawnNode", insertDrawnNode), "removeDrawnNode", removeDrawnNode), "removeDrawnNode", removeDrawnNode), "drawnNodeSelection", drawnNodeSelection), _defineProperty(_defineProperty(_graphviz$prototype, "drawnNodeSelection", drawnNodeSelection), "graphvizVersion", graphvizVersion)); + + function selection_graphviz (options) { + var g = this.node().__graphviz__; + if (g) { + g.options(options); + // Ensure a possible new initEnd event handler is attached before calling it + d3Timer.timeout(function () { + g._dispatch.call("initEnd", this); + }.bind(this), 0); + } else { + g = new Graphviz(this, options); + } + return g; + } + + function selection_selectWithoutDataPropagation (name) { + return d3__namespace.select(this.size() > 0 ? this.node().querySelector(name) : null); + } + + d3.selection.prototype.graphviz = selection_graphviz; + d3.selection.prototype.selectWithoutDataPropagation = selection_selectWithoutDataPropagation; + + exports.graphviz = graphviz; + +})); +//# sourceMappingURL=d3-graphviz.js.map diff --git a/chapter24/docs/d3.v7.min.js b/chapter24/docs/d3.v7.min.js new file mode 100644 index 00000000..33bb8802 --- /dev/null +++ b/chapter24/docs/d3.v7.min.js @@ -0,0 +1,2 @@ +// https://d3js.org v7.9.0 Copyright 2010-2023 Mike Bostock +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";function n(t,n){return null==t||null==n?NaN:t<n?-1:t>n?1:t>=n?0:NaN}function e(t,n){return null==t||null==n?NaN:n<t?-1:n>t?1:n>=t?0:NaN}function r(t){let r,o,a;function u(t,n,e=0,i=t.length){if(e<i){if(0!==r(n,n))return i;do{const r=e+i>>>1;o(t[r],n)<0?e=r+1:i=r}while(e<i)}return e}return 2!==t.length?(r=n,o=(e,r)=>n(t(e),r),a=(n,e)=>t(n)-e):(r=t===n||t===e?t:i,o=t,a=t),{left:u,center:function(t,n,e=0,r=t.length){const i=u(t,n,e,r-1);return i>e&&a(t[i-1],n)>-a(t[i],n)?i-1:i},right:function(t,n,e=0,i=t.length){if(e<i){if(0!==r(n,n))return i;do{const r=e+i>>>1;o(t[r],n)<=0?e=r+1:i=r}while(e<i)}return e}}}function i(){return 0}function o(t){return null===t?NaN:+t}const a=r(n),u=a.right,c=a.left,f=r(o).center;var s=u;const l=d(y),h=d((function(t){const n=y(t);return(t,e,r,i,o)=>{n(t,e,(r<<=2)+0,(i<<=2)+0,o<<=2),n(t,e,r+1,i+1,o),n(t,e,r+2,i+2,o),n(t,e,r+3,i+3,o)}}));function d(t){return function(n,e,r=e){if(!((e=+e)>=0))throw new RangeError("invalid rx");if(!((r=+r)>=0))throw new RangeError("invalid ry");let{data:i,width:o,height:a}=n;if(!((o=Math.floor(o))>=0))throw new RangeError("invalid width");if(!((a=Math.floor(void 0!==a?a:i.length/o))>=0))throw new RangeError("invalid height");if(!o||!a||!e&&!r)return n;const u=e&&t(e),c=r&&t(r),f=i.slice();return u&&c?(p(u,f,i,o,a),p(u,i,f,o,a),p(u,f,i,o,a),g(c,i,f,o,a),g(c,f,i,o,a),g(c,i,f,o,a)):u?(p(u,i,f,o,a),p(u,f,i,o,a),p(u,i,f,o,a)):c&&(g(c,i,f,o,a),g(c,f,i,o,a),g(c,i,f,o,a)),n}}function p(t,n,e,r,i){for(let o=0,a=r*i;o<a;)t(n,e,o,o+=r,1)}function g(t,n,e,r,i){for(let o=0,a=r*i;o<r;++o)t(n,e,o,o+a,r)}function y(t){const n=Math.floor(t);if(n===t)return function(t){const n=2*t+1;return(e,r,i,o,a)=>{if(!((o-=a)>=i))return;let u=t*r[i];const c=a*t;for(let t=i,n=i+c;t<n;t+=a)u+=r[Math.min(o,t)];for(let t=i,f=o;t<=f;t+=a)u+=r[Math.min(o,t+c)],e[t]=u/n,u-=r[Math.max(i,t-c)]}}(t);const e=t-n,r=2*t+1;return(t,i,o,a,u)=>{if(!((a-=u)>=o))return;let c=n*i[o];const f=u*n,s=f+u;for(let t=o,n=o+f;t<n;t+=u)c+=i[Math.min(a,t)];for(let n=o,l=a;n<=l;n+=u)c+=i[Math.min(a,n+f)],t[n]=(c+e*(i[Math.max(o,n-s)]+i[Math.min(a,n+s)]))/r,c-=i[Math.max(o,n-f)]}}function v(t,n){let e=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&++e;else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(i=+i)>=i&&++e}return e}function _(t){return 0|t.length}function b(t){return!(t>0)}function m(t){return"object"!=typeof t||"length"in t?t:Array.from(t)}function x(t,n){let e,r=0,i=0,o=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(e=n-i,i+=e/++r,o+=e*(n-i));else{let a=-1;for(let u of t)null!=(u=n(u,++a,t))&&(u=+u)>=u&&(e=u-i,i+=e/++r,o+=e*(u-i))}if(r>1)return o/(r-1)}function w(t,n){const e=x(t,n);return e?Math.sqrt(e):e}function M(t,n){let e,r;if(void 0===n)for(const n of t)null!=n&&(void 0===e?n>=n&&(e=r=n):(e>n&&(e=n),r<n&&(r=n)));else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(void 0===e?o>=o&&(e=r=o):(e>o&&(e=o),r<o&&(r=o)))}return[e,r]}class T{constructor(){this._partials=new Float64Array(32),this._n=0}add(t){const n=this._partials;let e=0;for(let r=0;r<this._n&&r<32;r++){const i=n[r],o=t+i,a=Math.abs(t)<Math.abs(i)?t-(o-i):i-(o-t);a&&(n[e++]=a),t=o}return n[e]=t,this._n=e+1,this}valueOf(){const t=this._partials;let n,e,r,i=this._n,o=0;if(i>0){for(o=t[--i];i>0&&(n=o,e=t[--i],o=n+e,r=e-(o-n),!r););i>0&&(r<0&&t[i-1]<0||r>0&&t[i-1]>0)&&(e=2*r,n=o+e,e==n-o&&(o=n))}return o}}class InternMap extends Map{constructor(t,n=N){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const[n,e]of t)this.set(n,e)}get(t){return super.get(A(this,t))}has(t){return super.has(A(this,t))}set(t,n){return super.set(S(this,t),n)}delete(t){return super.delete(E(this,t))}}class InternSet extends Set{constructor(t,n=N){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const n of t)this.add(n)}has(t){return super.has(A(this,t))}add(t){return super.add(S(this,t))}delete(t){return super.delete(E(this,t))}}function A({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):e}function S({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):(t.set(r,e),e)}function E({_intern:t,_key:n},e){const r=n(e);return t.has(r)&&(e=t.get(r),t.delete(r)),e}function N(t){return null!==t&&"object"==typeof t?t.valueOf():t}function k(t){return t}function C(t,...n){return F(t,k,k,n)}function P(t,...n){return F(t,Array.from,k,n)}function z(t,n){for(let e=1,r=n.length;e<r;++e)t=t.flatMap((t=>t.pop().map((([n,e])=>[...t,n,e]))));return t}function $(t,n,...e){return F(t,k,n,e)}function D(t,n,...e){return F(t,Array.from,n,e)}function R(t){if(1!==t.length)throw new Error("duplicate key");return t[0]}function F(t,n,e,r){return function t(i,o){if(o>=r.length)return e(i);const a=new InternMap,u=r[o++];let c=-1;for(const t of i){const n=u(t,++c,i),e=a.get(n);e?e.push(t):a.set(n,[t])}for(const[n,e]of a)a.set(n,t(e,o));return n(a)}(t,0)}function q(t,n){return Array.from(n,(n=>t[n]))}function U(t,...n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");t=Array.from(t);let[e]=n;if(e&&2!==e.length||n.length>1){const r=Uint32Array.from(t,((t,n)=>n));return n.length>1?(n=n.map((n=>t.map(n))),r.sort(((t,e)=>{for(const r of n){const n=O(r[t],r[e]);if(n)return n}}))):(e=t.map(e),r.sort(((t,n)=>O(e[t],e[n])))),q(t,r)}return t.sort(I(e))}function I(t=n){if(t===n)return O;if("function"!=typeof t)throw new TypeError("compare is not a function");return(n,e)=>{const r=t(n,e);return r||0===r?r:(0===t(e,e))-(0===t(n,n))}}function O(t,n){return(null==t||!(t>=t))-(null==n||!(n>=n))||(t<n?-1:t>n?1:0)}var B=Array.prototype.slice;function Y(t){return()=>t}const L=Math.sqrt(50),j=Math.sqrt(10),H=Math.sqrt(2);function X(t,n,e){const r=(n-t)/Math.max(0,e),i=Math.floor(Math.log10(r)),o=r/Math.pow(10,i),a=o>=L?10:o>=j?5:o>=H?2:1;let u,c,f;return i<0?(f=Math.pow(10,-i)/a,u=Math.round(t*f),c=Math.round(n*f),u/f<t&&++u,c/f>n&&--c,f=-f):(f=Math.pow(10,i)*a,u=Math.round(t/f),c=Math.round(n/f),u*f<t&&++u,c*f>n&&--c),c<u&&.5<=e&&e<2?X(t,n,2*e):[u,c,f]}function G(t,n,e){if(!((e=+e)>0))return[];if((t=+t)===(n=+n))return[t];const r=n<t,[i,o,a]=r?X(n,t,e):X(t,n,e);if(!(o>=i))return[];const u=o-i+1,c=new Array(u);if(r)if(a<0)for(let t=0;t<u;++t)c[t]=(o-t)/-a;else for(let t=0;t<u;++t)c[t]=(o-t)*a;else if(a<0)for(let t=0;t<u;++t)c[t]=(i+t)/-a;else for(let t=0;t<u;++t)c[t]=(i+t)*a;return c}function V(t,n,e){return X(t=+t,n=+n,e=+e)[2]}function W(t,n,e){e=+e;const r=(n=+n)<(t=+t),i=r?V(n,t,e):V(t,n,e);return(r?-1:1)*(i<0?1/-i:i)}function Z(t,n,e){let r;for(;;){const i=V(t,n,e);if(i===r||0===i||!isFinite(i))return[t,n];i>0?(t=Math.floor(t/i)*i,n=Math.ceil(n/i)*i):i<0&&(t=Math.ceil(t*i)/i,n=Math.floor(n*i)/i),r=i}}function K(t){return Math.max(1,Math.ceil(Math.log(v(t))/Math.LN2)+1)}function Q(){var t=k,n=M,e=K;function r(r){Array.isArray(r)||(r=Array.from(r));var i,o,a,u=r.length,c=new Array(u);for(i=0;i<u;++i)c[i]=t(r[i],i,r);var f=n(c),l=f[0],h=f[1],d=e(c,l,h);if(!Array.isArray(d)){const t=h,e=+d;if(n===M&&([l,h]=Z(l,h,e)),(d=G(l,h,e))[0]<=l&&(a=V(l,h,e)),d[d.length-1]>=h)if(t>=h&&n===M){const t=V(l,h,e);isFinite(t)&&(t>0?h=(Math.floor(h/t)+1)*t:t<0&&(h=(Math.ceil(h*-t)+1)/-t))}else d.pop()}for(var p=d.length,g=0,y=p;d[g]<=l;)++g;for(;d[y-1]>h;)--y;(g||y<p)&&(d=d.slice(g,y),p=y-g);var v,_=new Array(p+1);for(i=0;i<=p;++i)(v=_[i]=[]).x0=i>0?d[i-1]:l,v.x1=i<p?d[i]:h;if(isFinite(a)){if(a>0)for(i=0;i<u;++i)null!=(o=c[i])&&l<=o&&o<=h&&_[Math.min(p,Math.floor((o-l)/a))].push(r[i]);else if(a<0)for(i=0;i<u;++i)if(null!=(o=c[i])&&l<=o&&o<=h){const t=Math.floor((l-o)*a);_[Math.min(p,t+(d[t]<=o))].push(r[i])}}else for(i=0;i<u;++i)null!=(o=c[i])&&l<=o&&o<=h&&_[s(d,o,0,p)].push(r[i]);return _}return r.value=function(n){return arguments.length?(t="function"==typeof n?n:Y(n),r):t},r.domain=function(t){return arguments.length?(n="function"==typeof t?t:Y([t[0],t[1]]),r):n},r.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Y(Array.isArray(t)?B.call(t):t),r):e},r}function J(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e<n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e<i||void 0===e&&i>=i)&&(e=i)}return e}function tt(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e<n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e<o||void 0===e&&o>=o)&&(e=o,r=i);return r}function nt(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e>n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e>i||void 0===e&&i>=i)&&(e=i)}return e}function et(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e>n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e>o||void 0===e&&o>=o)&&(e=o,r=i);return r}function rt(t,n,e=0,r=1/0,i){if(n=Math.floor(n),e=Math.floor(Math.max(0,e)),r=Math.floor(Math.min(t.length-1,r)),!(e<=n&&n<=r))return t;for(i=void 0===i?O:I(i);r>e;){if(r-e>600){const o=r-e+1,a=n-e+1,u=Math.log(o),c=.5*Math.exp(2*u/3),f=.5*Math.sqrt(u*c*(o-c)/o)*(a-o/2<0?-1:1);rt(t,n,Math.max(e,Math.floor(n-a*c/o+f)),Math.min(r,Math.floor(n+(o-a)*c/o+f)),i)}const o=t[n];let a=e,u=r;for(it(t,e,n),i(t[r],o)>0&&it(t,e,r);a<u;){for(it(t,a,u),++a,--u;i(t[a],o)<0;)++a;for(;i(t[u],o)>0;)--u}0===i(t[e],o)?it(t,e,u):(++u,it(t,u,r)),u<=n&&(e=u+1),n<=u&&(r=u-1)}return t}function it(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function ot(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)>0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)>0:0===e(n,n))&&(r=n,i=!0);return r}function at(t,n,e){if(t=Float64Array.from(function*(t,n){if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(yield n);else{let e=-1;for(let r of t)null!=(r=n(r,++e,t))&&(r=+r)>=r&&(yield r)}}(t,e)),(r=t.length)&&!isNaN(n=+n)){if(n<=0||r<2)return nt(t);if(n>=1)return J(t);var r,i=(r-1)*n,o=Math.floor(i),a=J(rt(t,o).subarray(0,o+1));return a+(nt(t.subarray(o+1))-a)*(i-o)}}function ut(t,n,e=o){if((r=t.length)&&!isNaN(n=+n)){if(n<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,a=Math.floor(i),u=+e(t[a],a,t);return u+(+e(t[a+1],a+1,t)-u)*(i-a)}}function ct(t,n,e=o){if(!isNaN(n=+n)){if(r=Float64Array.from(t,((n,r)=>o(e(t[r],r,t)))),n<=0)return et(r);if(n>=1)return tt(r);var r,i=Uint32Array.from(t,((t,n)=>n)),a=r.length-1,u=Math.floor(a*n);return rt(i,u,0,a,((t,n)=>O(r[t],r[n]))),(u=ot(i.subarray(0,u+1),(t=>r[t])))>=0?u:-1}}function ft(t){return Array.from(function*(t){for(const n of t)yield*n}(t))}function st(t,n){return[t,n]}function lt(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o}function ht(t,e=n){if(1===e.length)return et(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)<0)&&(r=n,i=o);return i}var dt=pt(Math.random);function pt(t){return function(n,e=0,r=n.length){let i=r-(e=+e);for(;i;){const r=t()*i--|0,o=n[i+e];n[i+e]=n[r+e],n[r+e]=o}return n}}function gt(t){if(!(i=t.length))return[];for(var n=-1,e=nt(t,yt),r=new Array(e);++n<e;)for(var i,o=-1,a=r[n]=new Array(i);++o<i;)a[o]=t[o][n];return r}function yt(t){return t.length}function vt(t){return t instanceof InternSet?t:new InternSet(t)}function _t(t,n){const e=t[Symbol.iterator](),r=new Set;for(const t of n){const n=bt(t);if(r.has(n))continue;let i,o;for(;({value:i,done:o}=e.next());){if(o)return!1;const t=bt(i);if(r.add(t),Object.is(n,t))break}}return!0}function bt(t){return null!==t&&"object"==typeof t?t.valueOf():t}function mt(t){return t}var xt=1,wt=2,Mt=3,Tt=4,At=1e-6;function St(t){return"translate("+t+",0)"}function Et(t){return"translate(0,"+t+")"}function Nt(t){return n=>+t(n)}function kt(t,n){return n=Math.max(0,t.bandwidth()-2*n)/2,t.round()&&(n=Math.round(n)),e=>+t(e)+n}function Ct(){return!this.__axis}function Pt(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,c="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,f=t===xt||t===Tt?-1:1,s=t===Tt||t===wt?"x":"y",l=t===xt||t===Mt?St:Et;function h(h){var d=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,p=null==i?n.tickFormat?n.tickFormat.apply(n,e):mt:i,g=Math.max(o,0)+u,y=n.range(),v=+y[0]+c,_=+y[y.length-1]+c,b=(n.bandwidth?kt:Nt)(n.copy(),c),m=h.selection?h.selection():h,x=m.selectAll(".domain").data([null]),w=m.selectAll(".tick").data(d,n).order(),M=w.exit(),T=w.enter().append("g").attr("class","tick"),A=w.select("line"),S=w.select("text");x=x.merge(x.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),w=w.merge(T),A=A.merge(T.append("line").attr("stroke","currentColor").attr(s+"2",f*o)),S=S.merge(T.append("text").attr("fill","currentColor").attr(s,f*g).attr("dy",t===xt?"0em":t===Mt?"0.71em":"0.32em")),h!==m&&(x=x.transition(h),w=w.transition(h),A=A.transition(h),S=S.transition(h),M=M.transition(h).attr("opacity",At).attr("transform",(function(t){return isFinite(t=b(t))?l(t+c):this.getAttribute("transform")})),T.attr("opacity",At).attr("transform",(function(t){var n=this.parentNode.__axis;return l((n&&isFinite(n=n(t))?n:b(t))+c)}))),M.remove(),x.attr("d",t===Tt||t===wt?a?"M"+f*a+","+v+"H"+c+"V"+_+"H"+f*a:"M"+c+","+v+"V"+_:a?"M"+v+","+f*a+"V"+c+"H"+_+"V"+f*a:"M"+v+","+c+"H"+_),w.attr("opacity",1).attr("transform",(function(t){return l(b(t)+c)})),A.attr(s+"2",f*o),S.attr(s,f*g).text(p),m.filter(Ct).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===wt?"start":t===Tt?"end":"middle"),m.each((function(){this.__axis=b}))}return h.scale=function(t){return arguments.length?(n=t,h):n},h.ticks=function(){return e=Array.from(arguments),h},h.tickArguments=function(t){return arguments.length?(e=null==t?[]:Array.from(t),h):e.slice()},h.tickValues=function(t){return arguments.length?(r=null==t?null:Array.from(t),h):r&&r.slice()},h.tickFormat=function(t){return arguments.length?(i=t,h):i},h.tickSize=function(t){return arguments.length?(o=a=+t,h):o},h.tickSizeInner=function(t){return arguments.length?(o=+t,h):o},h.tickSizeOuter=function(t){return arguments.length?(a=+t,h):a},h.tickPadding=function(t){return arguments.length?(u=+t,h):u},h.offset=function(t){return arguments.length?(c=+t,h):c},h}var zt={value:()=>{}};function $t(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r||/[\s.]/.test(t))throw new Error("illegal type: "+t);r[t]=[]}return new Dt(r)}function Dt(t){this._=t}function Rt(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function Ft(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=zt,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}Dt.prototype=$t.prototype={constructor:Dt,on:function(t,n){var e,r,i=this._,o=(r=i,(t+"").trim().split(/^|\s+/).map((function(t){var n="",e=t.indexOf(".");if(e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),t&&!r.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))),a=-1,u=o.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++a<u;)if(e=(t=o[a]).type)i[e]=Ft(i[e],t.name,n);else if(null==n)for(e in i)i[e]=Ft(i[e],t.name,null);return this}for(;++a<u;)if((e=(t=o[a]).type)&&(e=Rt(i[e],t.name)))return e},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new Dt(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var qt="http://www.w3.org/1999/xhtml",Ut={svg:"http://www.w3.org/2000/svg",xhtml:qt,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function It(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Ut.hasOwnProperty(n)?{space:Ut[n],local:t}:t}function Ot(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===qt&&n.documentElement.namespaceURI===qt?n.createElement(t):n.createElementNS(e,t)}}function Bt(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function Yt(t){var n=It(t);return(n.local?Bt:Ot)(n)}function Lt(){}function jt(t){return null==t?Lt:function(){return this.querySelector(t)}}function Ht(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function Xt(){return[]}function Gt(t){return null==t?Xt:function(){return this.querySelectorAll(t)}}function Vt(t){return function(){return this.matches(t)}}function Wt(t){return function(n){return n.matches(t)}}var Zt=Array.prototype.find;function Kt(){return this.firstElementChild}var Qt=Array.prototype.filter;function Jt(){return Array.from(this.children)}function tn(t){return new Array(t.length)}function nn(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function en(t,n,e,r,i,o){for(var a,u=0,c=n.length,f=o.length;u<f;++u)(a=n[u])?(a.__data__=o[u],r[u]=a):e[u]=new nn(t,o[u]);for(;u<c;++u)(a=n[u])&&(i[u]=a)}function rn(t,n,e,r,i,o,a){var u,c,f,s=new Map,l=n.length,h=o.length,d=new Array(l);for(u=0;u<l;++u)(c=n[u])&&(d[u]=f=a.call(c,c.__data__,u,n)+"",s.has(f)?i[u]=c:s.set(f,c));for(u=0;u<h;++u)f=a.call(t,o[u],u,o)+"",(c=s.get(f))?(r[u]=c,c.__data__=o[u],s.delete(f)):e[u]=new nn(t,o[u]);for(u=0;u<l;++u)(c=n[u])&&s.get(d[u])===c&&(i[u]=c)}function on(t){return t.__data__}function an(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function un(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function cn(t){return function(){this.removeAttribute(t)}}function fn(t){return function(){this.removeAttributeNS(t.space,t.local)}}function sn(t,n){return function(){this.setAttribute(t,n)}}function ln(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function hn(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function dn(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function pn(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function gn(t){return function(){this.style.removeProperty(t)}}function yn(t,n,e){return function(){this.style.setProperty(t,n,e)}}function vn(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function _n(t,n){return t.style.getPropertyValue(n)||pn(t).getComputedStyle(t,null).getPropertyValue(n)}function bn(t){return function(){delete this[t]}}function mn(t,n){return function(){this[t]=n}}function xn(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function wn(t){return t.trim().split(/^|\s+/)}function Mn(t){return t.classList||new Tn(t)}function Tn(t){this._node=t,this._names=wn(t.getAttribute("class")||"")}function An(t,n){for(var e=Mn(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function Sn(t,n){for(var e=Mn(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function En(t){return function(){An(this,t)}}function Nn(t){return function(){Sn(this,t)}}function kn(t,n){return function(){(n.apply(this,arguments)?An:Sn)(this,t)}}function Cn(){this.textContent=""}function Pn(t){return function(){this.textContent=t}}function zn(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function $n(){this.innerHTML=""}function Dn(t){return function(){this.innerHTML=t}}function Rn(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function Fn(){this.nextSibling&&this.parentNode.appendChild(this)}function qn(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function Un(){return null}function In(){var t=this.parentNode;t&&t.removeChild(this)}function On(){var t=this.cloneNode(!1),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function Bn(){var t=this.cloneNode(!0),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function Yn(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.options);++i?n.length=i:delete this.__on}}}function Ln(t,n,e){return function(){var r,i=this.__on,o=function(t){return function(n){t.call(this,n,this.__data__)}}(n);if(i)for(var a=0,u=i.length;a<u;++a)if((r=i[a]).type===t.type&&r.name===t.name)return this.removeEventListener(r.type,r.listener,r.options),this.addEventListener(r.type,r.listener=o,r.options=e),void(r.value=n);this.addEventListener(t.type,o,e),r={type:t.type,name:t.name,value:n,listener:o,options:e},i?i.push(r):this.__on=[r]}}function jn(t,n,e){var r=pn(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function Hn(t,n){return function(){return jn(this,t,n)}}function Xn(t,n){return function(){return jn(this,t,n.apply(this,arguments))}}nn.prototype={constructor:nn,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}},Tn.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Gn=[null];function Vn(t,n){this._groups=t,this._parents=n}function Wn(){return new Vn([[document.documentElement]],Gn)}function Zn(t){return"string"==typeof t?new Vn([[document.querySelector(t)]],[document.documentElement]):new Vn([[t]],Gn)}Vn.prototype=Wn.prototype={constructor:Vn,select:function(t){"function"!=typeof t&&(t=jt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a,u=n[i],c=u.length,f=r[i]=new Array(c),s=0;s<c;++s)(o=u[s])&&(a=t.call(o,o.__data__,s,u))&&("__data__"in o&&(a.__data__=o.__data__),f[s]=a);return new Vn(r,this._parents)},selectAll:function(t){t="function"==typeof t?function(t){return function(){return Ht(t.apply(this,arguments))}}(t):Gt(t);for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var a,u=n[o],c=u.length,f=0;f<c;++f)(a=u[f])&&(r.push(t.call(a,a.__data__,f,u)),i.push(a));return new Vn(r,i)},selectChild:function(t){return this.select(null==t?Kt:function(t){return function(){return Zt.call(this.children,t)}}("function"==typeof t?t:Wt(t)))},selectChildren:function(t){return this.selectAll(null==t?Jt:function(t){return function(){return Qt.call(this.children,t)}}("function"==typeof t?t:Wt(t)))},filter:function(t){"function"!=typeof t&&(t=Vt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new Vn(r,this._parents)},data:function(t,n){if(!arguments.length)return Array.from(this,on);var e=n?rn:en,r=this._parents,i=this._groups;"function"!=typeof t&&(t=function(t){return function(){return t}}(t));for(var o=i.length,a=new Array(o),u=new Array(o),c=new Array(o),f=0;f<o;++f){var s=r[f],l=i[f],h=l.length,d=an(t.call(s,s&&s.__data__,f,r)),p=d.length,g=u[f]=new Array(p),y=a[f]=new Array(p);e(s,l,g,y,c[f]=new Array(h),d,n);for(var v,_,b=0,m=0;b<p;++b)if(v=g[b]){for(b>=m&&(m=b+1);!(_=y[m])&&++m<p;);v._next=_||null}}return(a=new Vn(a,r))._enter=u,a._exit=c,a},enter:function(){return new Vn(this._enter||this._groups.map(tn),this._parents)},exit:function(){return new Vn(this._exit||this._groups.map(tn),this._parents)},join:function(t,n,e){var r=this.enter(),i=this,o=this.exit();return"function"==typeof t?(r=t(r))&&(r=r.selection()):r=r.append(t+""),null!=n&&(i=n(i))&&(i=i.selection()),null==e?o.remove():e(o),r&&i?r.merge(i).order():i},merge:function(t){for(var n=t.selection?t.selection():t,e=this._groups,r=n._groups,i=e.length,o=r.length,a=Math.min(i,o),u=new Array(i),c=0;c<a;++c)for(var f,s=e[c],l=r[c],h=s.length,d=u[c]=new Array(h),p=0;p<h;++p)(f=s[p]||l[p])&&(d[p]=f);for(;c<i;++c)u[c]=e[c];return new Vn(u,this._parents)},selection:function(){return this},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,a=i[o];--o>=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=un);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var a,u=e[o],c=u.length,f=i[o]=new Array(c),s=0;s<c;++s)(a=u[s])&&(f[s]=a);f.sort(n)}return new Vn(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){return Array.from(this)},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var a=r[i];if(a)return a}return null},size:function(){let t=0;for(const n of this)++t;return t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],a=0,u=o.length;a<u;++a)(i=o[a])&&t.call(i,i.__data__,a,o);return this},attr:function(t,n){var e=It(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?fn:cn:"function"==typeof n?e.local?dn:hn:e.local?ln:sn)(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?gn:"function"==typeof n?vn:yn)(t,n,null==e?"":e)):_n(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?bn:"function"==typeof n?xn:mn)(t,n)):this.node()[t]},classed:function(t,n){var e=wn(t+"");if(arguments.length<2){for(var r=Mn(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?kn:n?En:Nn)(e,n))},text:function(t){return arguments.length?this.each(null==t?Cn:("function"==typeof t?zn:Pn)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?$n:("function"==typeof t?Rn:Dn)(t)):this.node().innerHTML},raise:function(){return this.each(Fn)},lower:function(){return this.each(qn)},append:function(t){var n="function"==typeof t?t:Yt(t);return this.select((function(){return this.appendChild(n.apply(this,arguments))}))},insert:function(t,n){var e="function"==typeof t?t:Yt(t),r=null==n?Un:"function"==typeof n?n:jt(n);return this.select((function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)}))},remove:function(){return this.each(In)},clone:function(t){return this.select(t?Bn:On)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=function(t){return t.trim().split(/^|\s+/).map((function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?Ln:Yn,r=0;r<a;++r)this.each(u(o[r],n,e));return this}var u=this.node().__on;if(u)for(var c,f=0,s=u.length;f<s;++f)for(r=0,c=u[f];r<a;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value},dispatch:function(t,n){return this.each(("function"==typeof n?Xn:Hn)(t,n))},[Symbol.iterator]:function*(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r,i=t[n],o=0,a=i.length;o<a;++o)(r=i[o])&&(yield r)}};var Kn=0;function Qn(){return new Jn}function Jn(){this._="@"+(++Kn).toString(36)}function te(t){let n;for(;n=t.sourceEvent;)t=n;return t}function ne(t,n){if(t=te(t),void 0===n&&(n=t.currentTarget),n){var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=t.clientX,r.y=t.clientY,[(r=r.matrixTransform(n.getScreenCTM().inverse())).x,r.y]}if(n.getBoundingClientRect){var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}}return[t.pageX,t.pageY]}Jn.prototype=Qn.prototype={constructor:Jn,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};const ee={passive:!1},re={capture:!0,passive:!1};function ie(t){t.stopImmediatePropagation()}function oe(t){t.preventDefault(),t.stopImmediatePropagation()}function ae(t){var n=t.document.documentElement,e=Zn(t).on("dragstart.drag",oe,re);"onselectstart"in n?e.on("selectstart.drag",oe,re):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")}function ue(t,n){var e=t.document.documentElement,r=Zn(t).on("dragstart.drag",null);n&&(r.on("click.drag",oe,re),setTimeout((function(){r.on("click.drag",null)}),0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}var ce=t=>()=>t;function fe(t,{sourceEvent:n,subject:e,target:r,identifier:i,active:o,x:a,y:u,dx:c,dy:f,dispatch:s}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},subject:{value:e,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:i,enumerable:!0,configurable:!0},active:{value:o,enumerable:!0,configurable:!0},x:{value:a,enumerable:!0,configurable:!0},y:{value:u,enumerable:!0,configurable:!0},dx:{value:c,enumerable:!0,configurable:!0},dy:{value:f,enumerable:!0,configurable:!0},_:{value:s}})}function se(t){return!t.ctrlKey&&!t.button}function le(){return this.parentNode}function he(t,n){return null==n?{x:t.x,y:t.y}:n}function de(){return navigator.maxTouchPoints||"ontouchstart"in this}function pe(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function ge(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function ye(){}fe.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var ve=.7,_e=1/ve,be="\\s*([+-]?\\d+)\\s*",me="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",xe="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",we=/^#([0-9a-f]{3,8})$/,Me=new RegExp(`^rgb\\(${be},${be},${be}\\)$`),Te=new RegExp(`^rgb\\(${xe},${xe},${xe}\\)$`),Ae=new RegExp(`^rgba\\(${be},${be},${be},${me}\\)$`),Se=new RegExp(`^rgba\\(${xe},${xe},${xe},${me}\\)$`),Ee=new RegExp(`^hsl\\(${me},${xe},${xe}\\)$`),Ne=new RegExp(`^hsla\\(${me},${xe},${xe},${me}\\)$`),ke={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function Ce(){return this.rgb().formatHex()}function Pe(){return this.rgb().formatRgb()}function ze(t){var n,e;return t=(t+"").trim().toLowerCase(),(n=we.exec(t))?(e=n[1].length,n=parseInt(n[1],16),6===e?$e(n):3===e?new qe(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?De(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?De(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=Me.exec(t))?new qe(n[1],n[2],n[3],1):(n=Te.exec(t))?new qe(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Ae.exec(t))?De(n[1],n[2],n[3],n[4]):(n=Se.exec(t))?De(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Ee.exec(t))?Le(n[1],n[2]/100,n[3]/100,1):(n=Ne.exec(t))?Le(n[1],n[2]/100,n[3]/100,n[4]):ke.hasOwnProperty(t)?$e(ke[t]):"transparent"===t?new qe(NaN,NaN,NaN,0):null}function $e(t){return new qe(t>>16&255,t>>8&255,255&t,1)}function De(t,n,e,r){return r<=0&&(t=n=e=NaN),new qe(t,n,e,r)}function Re(t){return t instanceof ye||(t=ze(t)),t?new qe((t=t.rgb()).r,t.g,t.b,t.opacity):new qe}function Fe(t,n,e,r){return 1===arguments.length?Re(t):new qe(t,n,e,null==r?1:r)}function qe(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ue(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}`}function Ie(){const t=Oe(this.opacity);return`${1===t?"rgb(":"rgba("}${Be(this.r)}, ${Be(this.g)}, ${Be(this.b)}${1===t?")":`, ${t})`}`}function Oe(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function Be(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function Ye(t){return((t=Be(t))<16?"0":"")+t.toString(16)}function Le(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Xe(t,n,e,r)}function je(t){if(t instanceof Xe)return new Xe(t.h,t.s,t.l,t.opacity);if(t instanceof ye||(t=ze(t)),!t)return new Xe;if(t instanceof Xe)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,c=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e<r):e===o?(r-n)/u+2:(n-e)/u+4,u/=c<.5?o+i:2-o-i,a*=60):u=c>0&&c<1?0:a,new Xe(a,u,c,t.opacity)}function He(t,n,e,r){return 1===arguments.length?je(t):new Xe(t,n,e,null==r?1:r)}function Xe(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Ge(t){return(t=(t||0)%360)<0?t+360:t}function Ve(t){return Math.max(0,Math.min(1,t||0))}function We(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}pe(ye,ze,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:Ce,formatHex:Ce,formatHex8:function(){return this.rgb().formatHex8()},formatHsl:function(){return je(this).formatHsl()},formatRgb:Pe,toString:Pe}),pe(qe,Fe,ge(ye,{brighter(t){return t=null==t?_e:Math.pow(_e,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=null==t?ve:Math.pow(ve,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new qe(Be(this.r),Be(this.g),Be(this.b),Oe(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ue,formatHex:Ue,formatHex8:function(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}${Ye(255*(isNaN(this.opacity)?1:this.opacity))}`},formatRgb:Ie,toString:Ie})),pe(Xe,He,ge(ye,{brighter(t){return t=null==t?_e:Math.pow(_e,t),new Xe(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?ve:Math.pow(ve,t),new Xe(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new qe(We(t>=240?t-240:t+120,i,r),We(t,i,r),We(t<120?t+240:t-120,i,r),this.opacity)},clamp(){return new Xe(Ge(this.h),Ve(this.s),Ve(this.l),Oe(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=Oe(this.opacity);return`${1===t?"hsl(":"hsla("}${Ge(this.h)}, ${100*Ve(this.s)}%, ${100*Ve(this.l)}%${1===t?")":`, ${t})`}`}}));const Ze=Math.PI/180,Ke=180/Math.PI,Qe=.96422,Je=1,tr=.82521,nr=4/29,er=6/29,rr=3*er*er,ir=er*er*er;function or(t){if(t instanceof ur)return new ur(t.l,t.a,t.b,t.opacity);if(t instanceof pr)return gr(t);t instanceof qe||(t=Re(t));var n,e,r=lr(t.r),i=lr(t.g),o=lr(t.b),a=cr((.2225045*r+.7168786*i+.0606169*o)/Je);return r===i&&i===o?n=e=a:(n=cr((.4360747*r+.3850649*i+.1430804*o)/Qe),e=cr((.0139322*r+.0971045*i+.7141733*o)/tr)),new ur(116*a-16,500*(n-a),200*(a-e),t.opacity)}function ar(t,n,e,r){return 1===arguments.length?or(t):new ur(t,n,e,null==r?1:r)}function ur(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function cr(t){return t>ir?Math.pow(t,1/3):t/rr+nr}function fr(t){return t>er?t*t*t:rr*(t-nr)}function sr(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function lr(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function hr(t){if(t instanceof pr)return new pr(t.h,t.c,t.l,t.opacity);if(t instanceof ur||(t=or(t)),0===t.a&&0===t.b)return new pr(NaN,0<t.l&&t.l<100?0:NaN,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*Ke;return new pr(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function dr(t,n,e,r){return 1===arguments.length?hr(t):new pr(t,n,e,null==r?1:r)}function pr(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function gr(t){if(isNaN(t.h))return new ur(t.l,0,0,t.opacity);var n=t.h*Ze;return new ur(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}pe(ur,ar,ge(ye,{brighter(t){return new ur(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker(t){return new ur(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new qe(sr(3.1338561*(n=Qe*fr(n))-1.6168667*(t=Je*fr(t))-.4906146*(e=tr*fr(e))),sr(-.9787684*n+1.9161415*t+.033454*e),sr(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),pe(pr,dr,ge(ye,{brighter(t){return new pr(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker(t){return new pr(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb(){return gr(this).rgb()}}));var yr=-.14861,vr=1.78277,_r=-.29227,br=-.90649,mr=1.97294,xr=mr*br,wr=mr*vr,Mr=vr*_r-br*yr;function Tr(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof Ar)return new Ar(t.h,t.s,t.l,t.opacity);t instanceof qe||(t=Re(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Mr*r+xr*n-wr*e)/(Mr+xr-wr),o=r-i,a=(mr*(e-i)-_r*o)/br,u=Math.sqrt(a*a+o*o)/(mr*i*(1-i)),c=u?Math.atan2(a,o)*Ke-120:NaN;return new Ar(c<0?c+360:c,u,i,t.opacity)}(t):new Ar(t,n,e,null==r?1:r)}function Ar(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Sr(t,n,e,r,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*n+(4-6*o+3*a)*e+(1+3*t+3*o-3*a)*r+a*i)/6}function Er(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r<n-1?t[r+2]:2*o-i;return Sr((e-r/n)*n,a,i,o,u)}}function Nr(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],a=t[(r+1)%n],u=t[(r+2)%n];return Sr((e-r/n)*n,i,o,a,u)}}pe(Ar,Tr,ge(ye,{brighter(t){return t=null==t?_e:Math.pow(_e,t),new Ar(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?ve:Math.pow(ve,t),new Ar(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=isNaN(this.h)?0:(this.h+120)*Ze,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new qe(255*(n+e*(yr*r+vr*i)),255*(n+e*(_r*r+br*i)),255*(n+e*(mr*r)),this.opacity)}}));var kr=t=>()=>t;function Cr(t,n){return function(e){return t+e*n}}function Pr(t,n){var e=n-t;return e?Cr(t,e>180||e<-180?e-360*Math.round(e/360):e):kr(isNaN(t)?n:t)}function zr(t){return 1==(t=+t)?$r:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):kr(isNaN(n)?e:n)}}function $r(t,n){var e=n-t;return e?Cr(t,e):kr(isNaN(t)?n:t)}var Dr=function t(n){var e=zr(n);function r(t,n){var r=e((t=Fe(t)).r,(n=Fe(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=$r(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function Rr(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;e<i;++e)r=Fe(n[e]),o[e]=r.r||0,a[e]=r.g||0,u[e]=r.b||0;return o=t(o),a=t(a),u=t(u),r.opacity=1,function(t){return r.r=o(t),r.g=a(t),r.b=u(t),r+""}}}var Fr=Rr(Er),qr=Rr(Nr);function Ur(t,n){n||(n=[]);var e,r=t?Math.min(n.length,t.length):0,i=n.slice();return function(o){for(e=0;e<r;++e)i[e]=t[e]*(1-o)+n[e]*o;return i}}function Ir(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function Or(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(i),a=new Array(r);for(e=0;e<i;++e)o[e]=Gr(t[e],n[e]);for(;e<r;++e)a[e]=n[e];return function(t){for(e=0;e<i;++e)a[e]=o[e](t);return a}}function Br(t,n){var e=new Date;return t=+t,n=+n,function(r){return e.setTime(t*(1-r)+n*r),e}}function Yr(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}function Lr(t,n){var e,r={},i={};for(e in null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={}),n)e in t?r[e]=Gr(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}}var jr=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,Hr=new RegExp(jr.source,"g");function Xr(t,n){var e,r,i,o=jr.lastIndex=Hr.lastIndex=0,a=-1,u=[],c=[];for(t+="",n+="";(e=jr.exec(t))&&(r=Hr.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,c.push({i:a,x:Yr(e,r)})),o=Hr.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?c[0]?function(t){return function(n){return t(n)+""}}(c[0].x):function(t){return function(){return t}}(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)u[(e=c[r]).i]=e.x(t);return u.join("")})}function Gr(t,n){var e,r=typeof n;return null==n||"boolean"===r?kr(n):("number"===r?Yr:"string"===r?(e=ze(n))?(n=e,Dr):Xr:n instanceof ze?Dr:n instanceof Date?Br:Ir(n)?Ur:Array.isArray(n)?Or:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?Lr:Yr)(t,n)}function Vr(t,n){return t=+t,n=+n,function(e){return Math.round(t*(1-e)+n*e)}}var Wr,Zr=180/Math.PI,Kr={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Qr(t,n,e,r,i,o){var a,u,c;return(a=Math.sqrt(t*t+n*n))&&(t/=a,n/=a),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(u=Math.sqrt(e*e+r*r))&&(e/=u,r/=u,c/=u),t*r<n*e&&(t=-t,n=-n,c=-c,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*Zr,skewX:Math.atan(c)*Zr,scaleX:a,scaleY:u}}function Jr(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}return function(o,a){var u=[],c=[];return o=t(o),a=t(a),function(t,r,i,o,a,u){if(t!==i||r!==o){var c=a.push("translate(",null,n,null,e);u.push({i:c-4,x:Yr(t,i)},{i:c-2,x:Yr(r,o)})}else(i||o)&&a.push("translate("+i+n+o+e)}(o.translateX,o.translateY,a.translateX,a.translateY,u,c),function(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Yr(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Yr(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,c),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:Yr(t,e)},{i:u-2,x:Yr(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,c),o=a=null,function(t){for(var n,e=-1,r=c.length;++e<r;)u[(n=c[e]).i]=n.x(t);return u.join("")}}}var ti=Jr((function(t){const n=new("function"==typeof DOMMatrix?DOMMatrix:WebKitCSSMatrix)(t+"");return n.isIdentity?Kr:Qr(n.a,n.b,n.c,n.d,n.e,n.f)}),"px, ","px)","deg)"),ni=Jr((function(t){return null==t?Kr:(Wr||(Wr=document.createElementNS("http://www.w3.org/2000/svg","g")),Wr.setAttribute("transform",t),(t=Wr.transform.baseVal.consolidate())?Qr((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):Kr)}),", ",")",")");function ei(t){return((t=Math.exp(t))+1/t)/2}var ri=function t(n,e,r){function i(t,i){var o,a,u=t[0],c=t[1],f=t[2],s=i[0],l=i[1],h=i[2],d=s-u,p=l-c,g=d*d+p*p;if(g<1e-12)a=Math.log(h/f)/n,o=function(t){return[u+t*d,c+t*p,f*Math.exp(n*t*a)]};else{var y=Math.sqrt(g),v=(h*h-f*f+r*g)/(2*f*e*y),_=(h*h-f*f-r*g)/(2*h*e*y),b=Math.log(Math.sqrt(v*v+1)-v),m=Math.log(Math.sqrt(_*_+1)-_);a=(m-b)/n,o=function(t){var r=t*a,i=ei(b),o=f/(e*y)*(i*function(t){return((t=Math.exp(2*t))-1)/(t+1)}(n*r+b)-function(t){return((t=Math.exp(t))-1/t)/2}(b));return[u+o*d,c+o*p,f*i/ei(n*r+b)]}}return o.duration=1e3*a*n/Math.SQRT2,o}return i.rho=function(n){var e=Math.max(.001,+n),r=e*e;return t(e,r,r*r)},i}(Math.SQRT2,2,4);function ii(t){return function(n,e){var r=t((n=He(n)).h,(e=He(e)).h),i=$r(n.s,e.s),o=$r(n.l,e.l),a=$r(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var oi=ii(Pr),ai=ii($r);function ui(t){return function(n,e){var r=t((n=dr(n)).h,(e=dr(e)).h),i=$r(n.c,e.c),o=$r(n.l,e.l),a=$r(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var ci=ui(Pr),fi=ui($r);function si(t){return function n(e){function r(n,r){var i=t((n=Tr(n)).h,(r=Tr(r)).h),o=$r(n.s,r.s),a=$r(n.l,r.l),u=$r(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=a(Math.pow(t,e)),n.opacity=u(t),n+""}}return e=+e,r.gamma=n,r}(1)}var li=si(Pr),hi=si($r);function di(t,n){void 0===n&&(n=t,t=Gr);for(var e=0,r=n.length-1,i=n[0],o=new Array(r<0?0:r);e<r;)o[e]=t(i,i=n[++e]);return function(t){var n=Math.max(0,Math.min(r-1,Math.floor(t*=r)));return o[n](t-n)}}var pi,gi,yi=0,vi=0,_i=0,bi=1e3,mi=0,xi=0,wi=0,Mi="object"==typeof performance&&performance.now?performance:Date,Ti="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function Ai(){return xi||(Ti(Si),xi=Mi.now()+wi)}function Si(){xi=0}function Ei(){this._call=this._time=this._next=null}function Ni(t,n,e){var r=new Ei;return r.restart(t,n,e),r}function ki(){Ai(),++yi;for(var t,n=pi;n;)(t=xi-n._time)>=0&&n._call.call(void 0,t),n=n._next;--yi}function Ci(){xi=(mi=Mi.now())+wi,yi=vi=0;try{ki()}finally{yi=0,function(){var t,n,e=pi,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:pi=n);gi=t,zi(r)}(),xi=0}}function Pi(){var t=Mi.now(),n=t-mi;n>bi&&(wi-=n,mi=t)}function zi(t){yi||(vi&&(vi=clearTimeout(vi)),t-xi>24?(t<1/0&&(vi=setTimeout(Ci,t-Mi.now()-wi)),_i&&(_i=clearInterval(_i))):(_i||(mi=Mi.now(),_i=setInterval(Pi,bi)),yi=1,Ti(Ci)))}function $i(t,n,e){var r=new Ei;return n=null==n?0:+n,r.restart((e=>{r.stop(),t(e+n)}),n,e),r}Ei.prototype=Ni.prototype={constructor:Ei,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Ai():+e)+(null==n?0:+n),this._next||gi===this||(gi?gi._next=this:pi=this,gi=this),this._call=t,this._time=e,zi()},stop:function(){this._call&&(this._call=null,this._time=1/0,zi())}};var Di=$t("start","end","cancel","interrupt"),Ri=[],Fi=0,qi=1,Ui=2,Ii=3,Oi=4,Bi=5,Yi=6;function Li(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=qi,e.timer.restart(a,e.delay,e.time),e.delay<=t&&a(t-e.delay)}function a(o){var f,s,l,h;if(e.state!==qi)return c();for(f in i)if((h=i[f]).name===e.name){if(h.state===Ii)return $i(a);h.state===Oi?(h.state=Yi,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[f]):+f<n&&(h.state=Yi,h.timer.stop(),h.on.call("cancel",t,t.__data__,h.index,h.group),delete i[f])}if($i((function(){e.state===Ii&&(e.state=Oi,e.timer.restart(u,e.delay,e.time),u(o))})),e.state=Ui,e.on.call("start",t,t.__data__,e.index,e.group),e.state===Ui){for(e.state=Ii,r=new Array(l=e.tween.length),f=0,s=-1;f<l;++f)(h=e.tween[f].value.call(t,t.__data__,e.index,e.group))&&(r[++s]=h);r.length=s+1}}function u(n){for(var i=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(c),e.state=Bi,1),o=-1,a=r.length;++o<a;)r[o].call(t,i);e.state===Bi&&(e.on.call("end",t,t.__data__,e.index,e.group),c())}function c(){for(var r in e.state=Yi,e.timer.stop(),delete i[n],i)return;delete t.__transition}i[n]=e,e.timer=Ni(o,0,e.time)}(t,e,{name:n,index:r,group:i,on:Di,tween:Ri,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:Fi})}function ji(t,n){var e=Xi(t,n);if(e.state>Fi)throw new Error("too late; already scheduled");return e}function Hi(t,n){var e=Xi(t,n);if(e.state>Ii)throw new Error("too late; already running");return e}function Xi(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Gi(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>Ui&&e.state<Bi,e.state=Yi,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):a=!1;a&&delete t.__transition}}function Vi(t,n){var e,r;return function(){var i=Hi(this,t),o=i.tween;if(o!==e)for(var a=0,u=(r=e=o).length;a<u;++a)if(r[a].name===n){(r=r.slice()).splice(a,1);break}i.tween=r}}function Wi(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=Hi(this,t),a=o.tween;if(a!==r){i=(r=a).slice();for(var u={name:n,value:e},c=0,f=i.length;c<f;++c)if(i[c].name===n){i[c]=u;break}c===f&&i.push(u)}o.tween=i}}function Zi(t,n,e){var r=t._id;return t.each((function(){var t=Hi(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)})),function(t){return Xi(t,r).value[n]}}function Ki(t,n){var e;return("number"==typeof n?Yr:n instanceof ze?Dr:(e=ze(n))?(n=e,Dr):Xr)(t,n)}function Qi(t){return function(){this.removeAttribute(t)}}function Ji(t){return function(){this.removeAttributeNS(t.space,t.local)}}function to(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttribute(t);return a===o?null:a===r?i:i=n(r=a,e)}}function no(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttributeNS(t.space,t.local);return a===o?null:a===r?i:i=n(r=a,e)}}function eo(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttribute(t))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttribute(t)}}function ro(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttributeNS(t.space,t.local))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttributeNS(t.space,t.local)}}function io(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttributeNS(t.space,t.local,n.call(this,e))}}(t,i)),e}return i._value=n,i}function oo(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttribute(t,n.call(this,e))}}(t,i)),e}return i._value=n,i}function ao(t,n){return function(){ji(this,t).delay=+n.apply(this,arguments)}}function uo(t,n){return n=+n,function(){ji(this,t).delay=n}}function co(t,n){return function(){Hi(this,t).duration=+n.apply(this,arguments)}}function fo(t,n){return n=+n,function(){Hi(this,t).duration=n}}var so=Wn.prototype.constructor;function lo(t){return function(){this.style.removeProperty(t)}}var ho=0;function po(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function go(t){return Wn().transition(t)}function yo(){return++ho}var vo=Wn.prototype;po.prototype=go.prototype={constructor:po,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=jt(t));for(var r=this._groups,i=r.length,o=new Array(i),a=0;a<i;++a)for(var u,c,f=r[a],s=f.length,l=o[a]=new Array(s),h=0;h<s;++h)(u=f[h])&&(c=t.call(u,u.__data__,h,f))&&("__data__"in u&&(c.__data__=u.__data__),l[h]=c,Li(l[h],n,e,h,l,Xi(u,e)));return new po(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=Gt(t));for(var r=this._groups,i=r.length,o=[],a=[],u=0;u<i;++u)for(var c,f=r[u],s=f.length,l=0;l<s;++l)if(c=f[l]){for(var h,d=t.call(c,c.__data__,l,f),p=Xi(c,e),g=0,y=d.length;g<y;++g)(h=d[g])&&Li(h,n,e,g,d,p);o.push(d),a.push(c)}return new po(o,a,n,e)},selectChild:vo.selectChild,selectChildren:vo.selectChildren,filter:function(t){"function"!=typeof t&&(t=Vt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new po(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new po(a,this._parents,this._name,this._id)},selection:function(){return new so(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=yo(),r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)if(a=u[f]){var s=Xi(a,n);Li(a,t,e,f,u,{time:s.time+s.delay+s.duration,delay:0,duration:s.duration,ease:s.ease})}return new po(r,this._parents,t,e)},call:vo.call,nodes:vo.nodes,node:vo.node,size:vo.size,empty:vo.empty,each:vo.each,on:function(t,n){var e=this._id;return arguments.length<2?Xi(this.node(),e).on.on(t):this.each(function(t,n,e){var r,i,o=function(t){return(t+"").trim().split(/^|\s+/).every((function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?ji:Hi;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=It(t),r="transform"===e?ni:Ki;return this.attrTween(t,"function"==typeof n?(e.local?ro:eo)(e,r,Zi(this,"attr."+t,n)):null==n?(e.local?Ji:Qi)(e):(e.local?no:to)(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=It(t);return this.tween(e,(r.local?io:oo)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?ti:Ki;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=_n(this,t),a=(this.style.removeProperty(t),_n(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,lo(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=_n(this,t),u=e(this),c=u+"";return null==u&&(this.style.removeProperty(t),c=u=_n(this,t)),a===c?null:a===r&&c===i?o:(i=c,o=n(r=a,u))}}(t,r,Zi(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var c=Hi(this,t),f=c.on,s=null==c.value[a]?o||(o=lo(n)):void 0;f===e&&i===s||(r=(e=f).copy()).on(u,i=s),c.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=_n(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}(t,o,e)),r}return o._value=n,o}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(Zi(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var n="text";if(arguments.length<1)return(n=this.tween(n))&&n._value;if(null==t)return this.tween(n,null);if("function"!=typeof t)throw new Error;return this.tween(n,function(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&function(t){return function(n){this.textContent=t.call(this,n)}}(r)),n}return r._value=t,r}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Xi(this.node(),e).tween,o=0,a=i.length;o<a;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Vi:Wi)(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?ao:uo)(n,t)):Xi(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?co:fo)(n,t)):Xi(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(function(t,n){if("function"!=typeof n)throw new Error;return function(){Hi(this,t).ease=n}}(n,t)):Xi(this.node(),n).ease},easeVarying:function(t){if("function"!=typeof t)throw new Error;return this.each(function(t,n){return function(){var e=n.apply(this,arguments);if("function"!=typeof e)throw new Error;Hi(this,t).ease=e}}(this._id,t))},end:function(){var t,n,e=this,r=e._id,i=e.size();return new Promise((function(o,a){var u={value:a},c={value:function(){0==--i&&o()}};e.each((function(){var e=Hi(this,r),i=e.on;i!==t&&((n=(t=i).copy())._.cancel.push(u),n._.interrupt.push(u),n._.end.push(c)),e.on=n})),0===i&&o()}))},[Symbol.iterator]:vo[Symbol.iterator]};function _o(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function bo(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}var mo=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),xo=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),wo=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Mo=Math.PI,To=Mo/2;function Ao(t){return(1-Math.cos(Mo*t))/2}function So(t){return 1.0009775171065494*(Math.pow(2,-10*t)-.0009765625)}function Eo(t){return((t*=2)<=1?So(1-t):2-So(t-1))/2}function No(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var ko=4/11,Co=6/11,Po=8/11,zo=3/4,$o=9/11,Do=10/11,Ro=15/16,Fo=21/22,qo=63/64,Uo=1/ko/ko;function Io(t){return(t=+t)<ko?Uo*t*t:t<Po?Uo*(t-=Co)*t+zo:t<Do?Uo*(t-=$o)*t+Ro:Uo*(t-=Fo)*t+qo}var Oo=1.70158,Bo=function t(n){function e(t){return(t=+t)*t*(n*(t-1)+t)}return n=+n,e.overshoot=t,e}(Oo),Yo=function t(n){function e(t){return--t*t*((t+1)*n+t)+1}return n=+n,e.overshoot=t,e}(Oo),Lo=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(Oo),jo=2*Math.PI,Ho=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=jo);function i(t){return n*So(- --t)*Math.sin((r-t)/e)}return i.amplitude=function(n){return t(n,e*jo)},i.period=function(e){return t(n,e)},i}(1,.3),Xo=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=jo);function i(t){return 1-n*So(t=+t)*Math.sin((t+r)/e)}return i.amplitude=function(n){return t(n,e*jo)},i.period=function(e){return t(n,e)},i}(1,.3),Go=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=jo);function i(t){return((t=2*t-1)<0?n*So(-t)*Math.sin((r-t)/e):2-n*So(t)*Math.sin((r+t)/e))/2}return i.amplitude=function(n){return t(n,e*jo)},i.period=function(e){return t(n,e)},i}(1,.3),Vo={time:null,delay:0,duration:250,ease:bo};function Wo(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))throw new Error(`transition ${n} not found`);return e}Wn.prototype.interrupt=function(t){return this.each((function(){Gi(this,t)}))},Wn.prototype.transition=function(t){var n,e;t instanceof po?(n=t._id,t=t._name):(n=yo(),(e=Vo).time=Ai(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)(a=u[f])&&Li(a,t,n,f,u,e||Wo(a,n));return new po(r,this._parents,t,n)};var Zo=[null];var Ko=t=>()=>t;function Qo(t,{sourceEvent:n,target:e,selection:r,mode:i,dispatch:o}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},selection:{value:r,enumerable:!0,configurable:!0},mode:{value:i,enumerable:!0,configurable:!0},_:{value:o}})}function Jo(t){t.preventDefault(),t.stopImmediatePropagation()}var ta={name:"drag"},na={name:"space"},ea={name:"handle"},ra={name:"center"};const{abs:ia,max:oa,min:aa}=Math;function ua(t){return[+t[0],+t[1]]}function ca(t){return[ua(t[0]),ua(t[1])]}var fa={name:"x",handles:["w","e"].map(va),input:function(t,n){return null==t?null:[[+t[0],n[0][1]],[+t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},sa={name:"y",handles:["n","s"].map(va),input:function(t,n){return null==t?null:[[n[0][0],+t[0]],[n[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},la={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(va),input:function(t){return null==t?null:ca(t)},output:function(t){return t}},ha={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},da={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},pa={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},ga={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},ya={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function va(t){return{type:t}}function _a(t){return!t.ctrlKey&&!t.button}function ba(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function ma(){return navigator.maxTouchPoints||"ontouchstart"in this}function xa(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function wa(t){var n,e=ba,r=_a,i=ma,o=!0,a=$t("start","brush","end"),u=6;function c(n){var e=n.property("__brush",g).selectAll(".overlay").data([va("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",ha.overlay).merge(e).each((function(){var t=xa(this).extent;Zn(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])})),n.selectAll(".selection").data([va("selection")]).enter().append("rect").attr("class","selection").attr("cursor",ha.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=n.selectAll(".handle").data(t.handles,(function(t){return t.type}));r.exit().remove(),r.enter().append("rect").attr("class",(function(t){return"handle handle--"+t.type})).attr("cursor",(function(t){return ha[t.type]})),n.each(f).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",h).filter(i).on("touchstart.brush",h).on("touchmove.brush",d).on("touchend.brush touchcancel.brush",p).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function f(){var t=Zn(this),n=xa(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",(function(t){return"e"===t.type[t.type.length-1]?n[1][0]-u/2:n[0][0]-u/2})).attr("y",(function(t){return"s"===t.type[0]?n[1][1]-u/2:n[0][1]-u/2})).attr("width",(function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+u:u})).attr("height",(function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+u:u}))):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function s(t,n,e){var r=t.__brush.emitter;return!r||e&&r.clean?new l(t,n,e):r}function l(t,n,e){this.that=t,this.args=n,this.state=t.__brush,this.active=0,this.clean=e}function h(e){if((!n||e.touches)&&r.apply(this,arguments)){var i,a,u,c,l,h,d,p,g,y,v,_=this,b=e.target.__data__.type,m="selection"===(o&&e.metaKey?b="overlay":b)?ta:o&&e.altKey?ra:ea,x=t===sa?null:ga[b],w=t===fa?null:ya[b],M=xa(_),T=M.extent,A=M.selection,S=T[0][0],E=T[0][1],N=T[1][0],k=T[1][1],C=0,P=0,z=x&&w&&o&&e.shiftKey,$=Array.from(e.touches||[e],(t=>{const n=t.identifier;return(t=ne(t,_)).point0=t.slice(),t.identifier=n,t}));Gi(_);var D=s(_,arguments,!0).beforestart();if("overlay"===b){A&&(g=!0);const n=[$[0],$[1]||$[0]];M.selection=A=[[i=t===sa?S:aa(n[0][0],n[1][0]),u=t===fa?E:aa(n[0][1],n[1][1])],[l=t===sa?N:oa(n[0][0],n[1][0]),d=t===fa?k:oa(n[0][1],n[1][1])]],$.length>1&&I(e)}else i=A[0][0],u=A[0][1],l=A[1][0],d=A[1][1];a=i,c=u,h=l,p=d;var R=Zn(_).attr("pointer-events","none"),F=R.selectAll(".overlay").attr("cursor",ha[b]);if(e.touches)D.moved=U,D.ended=O;else{var q=Zn(e.view).on("mousemove.brush",U,!0).on("mouseup.brush",O,!0);o&&q.on("keydown.brush",(function(t){switch(t.keyCode){case 16:z=x&&w;break;case 18:m===ea&&(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=ra,I(t));break;case 32:m!==ea&&m!==ra||(x<0?l=h-C:x>0&&(i=a-C),w<0?d=p-P:w>0&&(u=c-P),m=na,F.attr("cursor",ha.selection),I(t));break;default:return}Jo(t)}),!0).on("keyup.brush",(function(t){switch(t.keyCode){case 16:z&&(y=v=z=!1,I(t));break;case 18:m===ra&&(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=ea,I(t));break;case 32:m===na&&(t.altKey?(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=ra):(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=ea),F.attr("cursor",ha[b]),I(t));break;default:return}Jo(t)}),!0),ae(e.view)}f.call(_),D.start(e,m.name)}function U(t){for(const n of t.changedTouches||[t])for(const t of $)t.identifier===n.identifier&&(t.cur=ne(n,_));if(z&&!y&&!v&&1===$.length){const t=$[0];ia(t.cur[0]-t[0])>ia(t.cur[1]-t[1])?v=!0:y=!0}for(const t of $)t.cur&&(t[0]=t.cur[0],t[1]=t.cur[1]);g=!0,Jo(t),I(t)}function I(t){const n=$[0],e=n.point0;var r;switch(C=n[0]-e[0],P=n[1]-e[1],m){case na:case ta:x&&(C=oa(S-i,aa(N-l,C)),a=i+C,h=l+C),w&&(P=oa(E-u,aa(k-d,P)),c=u+P,p=d+P);break;case ea:$[1]?(x&&(a=oa(S,aa(N,$[0][0])),h=oa(S,aa(N,$[1][0])),x=1),w&&(c=oa(E,aa(k,$[0][1])),p=oa(E,aa(k,$[1][1])),w=1)):(x<0?(C=oa(S-i,aa(N-i,C)),a=i+C,h=l):x>0&&(C=oa(S-l,aa(N-l,C)),a=i,h=l+C),w<0?(P=oa(E-u,aa(k-u,P)),c=u+P,p=d):w>0&&(P=oa(E-d,aa(k-d,P)),c=u,p=d+P));break;case ra:x&&(a=oa(S,aa(N,i-C*x)),h=oa(S,aa(N,l+C*x))),w&&(c=oa(E,aa(k,u-P*w)),p=oa(E,aa(k,d+P*w)))}h<a&&(x*=-1,r=i,i=l,l=r,r=a,a=h,h=r,b in da&&F.attr("cursor",ha[b=da[b]])),p<c&&(w*=-1,r=u,u=d,d=r,r=c,c=p,p=r,b in pa&&F.attr("cursor",ha[b=pa[b]])),M.selection&&(A=M.selection),y&&(a=A[0][0],h=A[1][0]),v&&(c=A[0][1],p=A[1][1]),A[0][0]===a&&A[0][1]===c&&A[1][0]===h&&A[1][1]===p||(M.selection=[[a,c],[h,p]],f.call(_),D.brush(t,m.name))}function O(t){if(function(t){t.stopImmediatePropagation()}(t),t.touches){if(t.touches.length)return;n&&clearTimeout(n),n=setTimeout((function(){n=null}),500)}else ue(t.view,g),q.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);R.attr("pointer-events","all"),F.attr("cursor",ha.overlay),M.selection&&(A=M.selection),function(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}(A)&&(M.selection=null,f.call(_)),D.end(t,m.name)}}function d(t){s(this,arguments).moved(t)}function p(t){s(this,arguments).ended(t)}function g(){var n=this.__brush||{selection:null};return n.extent=ca(e.apply(this,arguments)),n.dim=t,n}return c.move=function(n,e,r){n.tween?n.on("start.brush",(function(t){s(this,arguments).beforestart().start(t)})).on("interrupt.brush end.brush",(function(t){s(this,arguments).end(t)})).tween("brush",(function(){var n=this,r=n.__brush,i=s(n,arguments),o=r.selection,a=t.input("function"==typeof e?e.apply(this,arguments):e,r.extent),u=Gr(o,a);function c(t){r.selection=1===t&&null===a?null:u(t),f.call(n),i.brush()}return null!==o&&null!==a?c:c(1)})):n.each((function(){var n=this,i=arguments,o=n.__brush,a=t.input("function"==typeof e?e.apply(n,i):e,o.extent),u=s(n,i).beforestart();Gi(n),o.selection=null===a?null:a,f.call(n),u.start(r).brush(r).end(r)}))},c.clear=function(t,n){c.move(t,null,n)},l.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(t,n){return this.starting?(this.starting=!1,this.emit("start",t,n)):this.emit("brush",t),this},brush:function(t,n){return this.emit("brush",t,n),this},end:function(t,n){return 0==--this.active&&(delete this.state.emitter,this.emit("end",t,n)),this},emit:function(n,e,r){var i=Zn(this.that).datum();a.call(n,this.that,new Qo(n,{sourceEvent:e,target:c,selection:t.output(this.state.selection),mode:r,dispatch:a}),i)}},c.extent=function(t){return arguments.length?(e="function"==typeof t?t:Ko(ca(t)),c):e},c.filter=function(t){return arguments.length?(r="function"==typeof t?t:Ko(!!t),c):r},c.touchable=function(t){return arguments.length?(i="function"==typeof t?t:Ko(!!t),c):i},c.handleSize=function(t){return arguments.length?(u=+t,c):u},c.keyModifiers=function(t){return arguments.length?(o=!!t,c):o},c.on=function(){var t=a.on.apply(a,arguments);return t===a?c:t},c}var Ma=Math.abs,Ta=Math.cos,Aa=Math.sin,Sa=Math.PI,Ea=Sa/2,Na=2*Sa,ka=Math.max,Ca=1e-12;function Pa(t,n){return Array.from({length:n-t},((n,e)=>t+e))}function za(t,n){var e=0,r=null,i=null,o=null;function a(a){var u,c=a.length,f=new Array(c),s=Pa(0,c),l=new Array(c*c),h=new Array(c),d=0;a=Float64Array.from({length:c*c},n?(t,n)=>a[n%c][n/c|0]:(t,n)=>a[n/c|0][n%c]);for(let n=0;n<c;++n){let e=0;for(let r=0;r<c;++r)e+=a[n*c+r]+t*a[r*c+n];d+=f[n]=e}u=(d=ka(0,Na-e*c)/d)?e:Na/c;{let n=0;r&&s.sort(((t,n)=>r(f[t],f[n])));for(const e of s){const r=n;if(t){const t=Pa(1+~c,c).filter((t=>t<0?a[~t*c+e]:a[e*c+t]));i&&t.sort(((t,n)=>i(t<0?-a[~t*c+e]:a[e*c+t],n<0?-a[~n*c+e]:a[e*c+n])));for(const r of t)if(r<0){(l[~r*c+e]||(l[~r*c+e]={source:null,target:null})).target={index:e,startAngle:n,endAngle:n+=a[~r*c+e]*d,value:a[~r*c+e]}}else{(l[e*c+r]||(l[e*c+r]={source:null,target:null})).source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}else{const t=Pa(0,c).filter((t=>a[e*c+t]||a[t*c+e]));i&&t.sort(((t,n)=>i(a[e*c+t],a[e*c+n])));for(const r of t){let t;if(e<r?(t=l[e*c+r]||(l[e*c+r]={source:null,target:null}),t.source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}):(t=l[r*c+e]||(l[r*c+e]={source:null,target:null}),t.target={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]},e===r&&(t.source=t.target)),t.source&&t.target&&t.source.value<t.target.value){const n=t.source;t.source=t.target,t.target=n}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}n+=u}}return(l=Object.values(l)).groups=h,o?l.sort(o):l}return a.padAngle=function(t){return arguments.length?(e=ka(0,t),a):e},a.sortGroups=function(t){return arguments.length?(r=t,a):r},a.sortSubgroups=function(t){return arguments.length?(i=t,a):i},a.sortChords=function(t){return arguments.length?(null==t?o=null:(n=t,o=function(t,e){return n(t.source.value+t.target.value,e.source.value+e.target.value)})._=t,a):o&&o._;var n},a}const $a=Math.PI,Da=2*$a,Ra=1e-6,Fa=Da-Ra;function qa(t){this._+=t[0];for(let n=1,e=t.length;n<e;++n)this._+=arguments[n]+t[n]}let Ua=class{constructor(t){this._x0=this._y0=this._x1=this._y1=null,this._="",this._append=null==t?qa:function(t){let n=Math.floor(t);if(!(n>=0))throw new Error(`invalid digits: ${t}`);if(n>15)return qa;const e=10**n;return function(t){this._+=t[0];for(let n=1,r=t.length;n<r;++n)this._+=Math.round(arguments[n]*e)/e+t[n]}}(t)}moveTo(t,n){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._append`Z`)}lineTo(t,n){this._append`L${this._x1=+t},${this._y1=+n}`}quadraticCurveTo(t,n,e,r){this._append`Q${+t},${+n},${this._x1=+e},${this._y1=+r}`}bezierCurveTo(t,n,e,r,i,o){this._append`C${+t},${+n},${+e},${+r},${this._x1=+i},${this._y1=+o}`}arcTo(t,n,e,r,i){if(t=+t,n=+n,e=+e,r=+r,(i=+i)<0)throw new Error(`negative radius: ${i}`);let o=this._x1,a=this._y1,u=e-t,c=r-n,f=o-t,s=a-n,l=f*f+s*s;if(null===this._x1)this._append`M${this._x1=t},${this._y1=n}`;else if(l>Ra)if(Math.abs(s*u-c*f)>Ra&&i){let h=e-o,d=r-a,p=u*u+c*c,g=h*h+d*d,y=Math.sqrt(p),v=Math.sqrt(l),_=i*Math.tan(($a-Math.acos((p+l-g)/(2*y*v)))/2),b=_/v,m=_/y;Math.abs(b-1)>Ra&&this._append`L${t+b*f},${n+b*s}`,this._append`A${i},${i},0,0,${+(s*h>f*d)},${this._x1=t+m*u},${this._y1=n+m*c}`}else this._append`L${this._x1=t},${this._y1=n}`;else;}arc(t,n,e,r,i,o){if(t=+t,n=+n,o=!!o,(e=+e)<0)throw new Error(`negative radius: ${e}`);let a=e*Math.cos(r),u=e*Math.sin(r),c=t+a,f=n+u,s=1^o,l=o?r-i:i-r;null===this._x1?this._append`M${c},${f}`:(Math.abs(this._x1-c)>Ra||Math.abs(this._y1-f)>Ra)&&this._append`L${c},${f}`,e&&(l<0&&(l=l%Da+Da),l>Fa?this._append`A${e},${e},0,1,${s},${t-a},${n-u}A${e},${e},0,1,${s},${this._x1=c},${this._y1=f}`:l>Ra&&this._append`A${e},${e},0,${+(l>=$a)},${s},${this._x1=t+e*Math.cos(i)},${this._y1=n+e*Math.sin(i)}`)}rect(t,n,e,r){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${e=+e}v${+r}h${-e}Z`}toString(){return this._}};function Ia(){return new Ua}Ia.prototype=Ua.prototype;var Oa=Array.prototype.slice;function Ba(t){return function(){return t}}function Ya(t){return t.source}function La(t){return t.target}function ja(t){return t.radius}function Ha(t){return t.startAngle}function Xa(t){return t.endAngle}function Ga(){return 0}function Va(){return 10}function Wa(t){var n=Ya,e=La,r=ja,i=ja,o=Ha,a=Xa,u=Ga,c=null;function f(){var f,s=n.apply(this,arguments),l=e.apply(this,arguments),h=u.apply(this,arguments)/2,d=Oa.call(arguments),p=+r.apply(this,(d[0]=s,d)),g=o.apply(this,d)-Ea,y=a.apply(this,d)-Ea,v=+i.apply(this,(d[0]=l,d)),_=o.apply(this,d)-Ea,b=a.apply(this,d)-Ea;if(c||(c=f=Ia()),h>Ca&&(Ma(y-g)>2*h+Ca?y>g?(g+=h,y-=h):(g-=h,y+=h):g=y=(g+y)/2,Ma(b-_)>2*h+Ca?b>_?(_+=h,b-=h):(_-=h,b+=h):_=b=(_+b)/2),c.moveTo(p*Ta(g),p*Aa(g)),c.arc(0,0,p,g,y),g!==_||y!==b)if(t){var m=v-+t.apply(this,arguments),x=(_+b)/2;c.quadraticCurveTo(0,0,m*Ta(_),m*Aa(_)),c.lineTo(v*Ta(x),v*Aa(x)),c.lineTo(m*Ta(b),m*Aa(b))}else c.quadraticCurveTo(0,0,v*Ta(_),v*Aa(_)),c.arc(0,0,v,_,b);if(c.quadraticCurveTo(0,0,p*Ta(g),p*Aa(g)),c.closePath(),f)return c=null,f+""||null}return t&&(f.headRadius=function(n){return arguments.length?(t="function"==typeof n?n:Ba(+n),f):t}),f.radius=function(t){return arguments.length?(r=i="function"==typeof t?t:Ba(+t),f):r},f.sourceRadius=function(t){return arguments.length?(r="function"==typeof t?t:Ba(+t),f):r},f.targetRadius=function(t){return arguments.length?(i="function"==typeof t?t:Ba(+t),f):i},f.startAngle=function(t){return arguments.length?(o="function"==typeof t?t:Ba(+t),f):o},f.endAngle=function(t){return arguments.length?(a="function"==typeof t?t:Ba(+t),f):a},f.padAngle=function(t){return arguments.length?(u="function"==typeof t?t:Ba(+t),f):u},f.source=function(t){return arguments.length?(n=t,f):n},f.target=function(t){return arguments.length?(e=t,f):e},f.context=function(t){return arguments.length?(c=null==t?null:t,f):c},f}var Za=Array.prototype.slice;function Ka(t,n){return t-n}var Qa=t=>()=>t;function Ja(t,n){for(var e,r=-1,i=n.length;++r<i;)if(e=tu(t,n[r]))return e;return 0}function tu(t,n){for(var e=n[0],r=n[1],i=-1,o=0,a=t.length,u=a-1;o<a;u=o++){var c=t[o],f=c[0],s=c[1],l=t[u],h=l[0],d=l[1];if(nu(c,l,n))return 0;s>r!=d>r&&e<(h-f)*(r-s)/(d-s)+f&&(i=-i)}return i}function nu(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function eu(){}var ru=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function iu(){var t=1,n=1,e=K,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(Ka);else{const e=M(t,ou);for(n=G(...Z(e[0],e[1],n),n);n[n.length-1]>=e[1];)n.pop();for(;n[1]<e[0];)n.shift()}return n.map((n=>o(t,n)))}function o(e,i){const o=null==i?NaN:+i;if(isNaN(o))throw new Error(`invalid value: ${i}`);var u=[],c=[];return function(e,r,i){var o,u,c,f,s,l,h=new Array,d=new Array;o=u=-1,f=au(e[0],r),ru[f<<1].forEach(p);for(;++o<t-1;)c=f,f=au(e[o+1],r),ru[c|f<<1].forEach(p);ru[f|0].forEach(p);for(;++u<n-1;){for(o=-1,f=au(e[u*t+t],r),s=au(e[u*t],r),ru[f<<1|s<<2].forEach(p);++o<t-1;)c=f,f=au(e[u*t+t+o+1],r),l=s,s=au(e[u*t+o+1],r),ru[c|f<<1|s<<2|l<<3].forEach(p);ru[f|s<<3].forEach(p)}o=-1,s=e[u*t]>=r,ru[s<<2].forEach(p);for(;++o<t-1;)l=s,s=au(e[u*t+o+1],r),ru[s<<2|l<<3].forEach(p);function p(t){var n,e,r=[t[0][0]+o,t[0][1]+u],c=[t[1][0]+o,t[1][1]+u],f=a(r),s=a(c);(n=d[f])?(e=h[s])?(delete d[n.end],delete h[e.start],n===e?(n.ring.push(c),i(n.ring)):h[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete d[n.end],n.ring.push(c),d[n.end=s]=n):(n=h[s])?(e=d[f])?(delete h[n.start],delete d[e.end],n===e?(n.ring.push(c),i(n.ring)):h[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete h[n.start],n.ring.unshift(r),h[n.start=f]=n):h[f]=d[s]={start:f,end:s,ring:[r,c]}}ru[s<<3].forEach(p)}(e,o,(function(t){r(t,e,o),function(t){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];++n<e;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return r}(t)>0?u.push([t]):c.push(t)})),c.forEach((function(t){for(var n,e=0,r=u.length;e<r;++e)if(-1!==Ja((n=u[e])[0],t))return void n.push(t)})),{type:"MultiPolygon",value:i,coordinates:u}}function a(n){return 2*n[0]+n[1]*(t+1)*4}function u(e,r,i){e.forEach((function(e){var o=e[0],a=e[1],u=0|o,c=0|a,f=uu(r[c*t+u]);o>0&&o<t&&u===o&&(e[0]=cu(o,uu(r[c*t+u-1]),f,i)),a>0&&a<n&&c===a&&(e[1]=cu(a,uu(r[(c-1)*t+u]),f,i))}))}return i.contour=o,i.size=function(e){if(!arguments.length)return[t,n];var r=Math.floor(e[0]),o=Math.floor(e[1]);if(!(r>=0&&o>=0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?Qa(Za.call(t)):Qa(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:eu,i):r===u},i}function ou(t){return isFinite(t)?t:NaN}function au(t,n){return null!=t&&+t>=n}function uu(t){return null==t||isNaN(t=+t)?-1/0:t}function cu(t,n,e,r){const i=r-n,o=e-n,a=isFinite(i)||isFinite(o)?i/o:Math.sign(i)/Math.sign(o);return isNaN(a)?t:t+a-.5}function fu(t){return t[0]}function su(t){return t[1]}function lu(){return 1}const hu=134217729,du=33306690738754706e-32;function pu(t,n,e,r,i){let o,a,u,c,f=n[0],s=r[0],l=0,h=0;s>f==s>-f?(o=f,f=n[++l]):(o=s,s=r[++h]);let d=0;if(l<t&&h<e)for(s>f==s>-f?(a=f+o,u=o-(a-f),f=n[++l]):(a=s+o,u=o-(a-s),s=r[++h]),o=a,0!==u&&(i[d++]=u);l<t&&h<e;)s>f==s>-f?(a=o+f,c=a-o,u=o-(a-c)+(f-c),f=n[++l]):(a=o+s,c=a-o,u=o-(a-c)+(s-c),s=r[++h]),o=a,0!==u&&(i[d++]=u);for(;l<t;)a=o+f,c=a-o,u=o-(a-c)+(f-c),f=n[++l],o=a,0!==u&&(i[d++]=u);for(;h<e;)a=o+s,c=a-o,u=o-(a-c)+(s-c),s=r[++h],o=a,0!==u&&(i[d++]=u);return 0===o&&0!==d||(i[d++]=o),d}function gu(t){return new Float64Array(t)}const yu=22204460492503146e-32,vu=11093356479670487e-47,_u=gu(4),bu=gu(8),mu=gu(12),xu=gu(16),wu=gu(4);function Mu(t,n,e,r,i,o){const a=(n-o)*(e-i),u=(t-i)*(r-o),c=a-u,f=Math.abs(a+u);return Math.abs(c)>=33306690738754716e-32*f?c:-function(t,n,e,r,i,o,a){let u,c,f,s,l,h,d,p,g,y,v,_,b,m,x,w,M,T;const A=t-i,S=e-i,E=n-o,N=r-o;m=A*N,h=hu*A,d=h-(h-A),p=A-d,h=hu*N,g=h-(h-N),y=N-g,x=p*y-(m-d*g-p*g-d*y),w=E*S,h=hu*E,d=h-(h-E),p=E-d,h=hu*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,_u[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,_u[1]=b-(v+l)+(l-w),T=_+v,l=T-_,_u[2]=_-(T-l)+(v-l),_u[3]=T;let k=function(t,n){let e=n[0];for(let r=1;r<t;r++)e+=n[r];return e}(4,_u),C=yu*a;if(k>=C||-k>=C)return k;if(l=t-A,u=t-(A+l)+(l-i),l=e-S,f=e-(S+l)+(l-i),l=n-E,c=n-(E+l)+(l-o),l=r-N,s=r-(N+l)+(l-o),0===u&&0===c&&0===f&&0===s)return k;if(C=vu*a+du*Math.abs(k),k+=A*s+N*u-(E*f+S*c),k>=C||-k>=C)return k;m=u*N,h=hu*u,d=h-(h-u),p=u-d,h=hu*N,g=h-(h-N),y=N-g,x=p*y-(m-d*g-p*g-d*y),w=c*S,h=hu*c,d=h-(h-c),p=c-d,h=hu*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,wu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,wu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,wu[2]=_-(T-l)+(v-l),wu[3]=T;const P=pu(4,_u,4,wu,bu);m=A*s,h=hu*A,d=h-(h-A),p=A-d,h=hu*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=E*f,h=hu*E,d=h-(h-E),p=E-d,h=hu*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,wu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,wu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,wu[2]=_-(T-l)+(v-l),wu[3]=T;const z=pu(P,bu,4,wu,mu);m=u*s,h=hu*u,d=h-(h-u),p=u-d,h=hu*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=c*f,h=hu*c,d=h-(h-c),p=c-d,h=hu*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,wu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,wu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,wu[2]=_-(T-l)+(v-l),wu[3]=T;const $=pu(z,mu,4,wu,xu);return xu[$-1]}(t,n,e,r,i,o,f)}const Tu=Math.pow(2,-52),Au=new Uint32Array(512);class Su{static from(t,n=zu,e=$u){const r=t.length,i=new Float64Array(2*r);for(let o=0;o<r;o++){const r=t[o];i[2*o]=n(r),i[2*o+1]=e(r)}return new Su(i)}constructor(t){const n=t.length>>1;if(n>0&&"number"!=typeof t[0])throw new Error("Expected coords to contain numbers.");this.coords=t;const e=Math.max(2*n-5,0);this._triangles=new Uint32Array(3*e),this._halfedges=new Int32Array(3*e),this._hashSize=Math.ceil(Math.sqrt(n)),this._hullPrev=new Uint32Array(n),this._hullNext=new Uint32Array(n),this._hullTri=new Uint32Array(n),this._hullHash=new Int32Array(this._hashSize),this._ids=new Uint32Array(n),this._dists=new Float64Array(n),this.update()}update(){const{coords:t,_hullPrev:n,_hullNext:e,_hullTri:r,_hullHash:i}=this,o=t.length>>1;let a=1/0,u=1/0,c=-1/0,f=-1/0;for(let n=0;n<o;n++){const e=t[2*n],r=t[2*n+1];e<a&&(a=e),r<u&&(u=r),e>c&&(c=e),r>f&&(f=r),this._ids[n]=n}const s=(a+c)/2,l=(u+f)/2;let h,d,p;for(let n=0,e=1/0;n<o;n++){const r=Eu(s,l,t[2*n],t[2*n+1]);r<e&&(h=n,e=r)}const g=t[2*h],y=t[2*h+1];for(let n=0,e=1/0;n<o;n++){if(n===h)continue;const r=Eu(g,y,t[2*n],t[2*n+1]);r<e&&r>0&&(d=n,e=r)}let v=t[2*d],_=t[2*d+1],b=1/0;for(let n=0;n<o;n++){if(n===h||n===d)continue;const e=ku(g,y,v,_,t[2*n],t[2*n+1]);e<b&&(p=n,b=e)}let m=t[2*p],x=t[2*p+1];if(b===1/0){for(let n=0;n<o;n++)this._dists[n]=t[2*n]-t[0]||t[2*n+1]-t[1];Cu(this._ids,this._dists,0,o-1);const n=new Uint32Array(o);let e=0;for(let t=0,r=-1/0;t<o;t++){const i=this._ids[t],o=this._dists[i];o>r&&(n[e++]=i,r=o)}return this.hull=n.subarray(0,e),this.triangles=new Uint32Array(0),void(this.halfedges=new Uint32Array(0))}if(Mu(g,y,v,_,m,x)<0){const t=d,n=v,e=_;d=p,v=m,_=x,p=t,m=n,x=e}const w=function(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c),d=t+(f*s-u*l)*h,p=n+(a*l-c*s)*h;return{x:d,y:p}}(g,y,v,_,m,x);this._cx=w.x,this._cy=w.y;for(let n=0;n<o;n++)this._dists[n]=Eu(t[2*n],t[2*n+1],w.x,w.y);Cu(this._ids,this._dists,0,o-1),this._hullStart=h;let M=3;e[h]=n[p]=d,e[d]=n[h]=p,e[p]=n[d]=h,r[h]=0,r[d]=1,r[p]=2,i.fill(-1),i[this._hashKey(g,y)]=h,i[this._hashKey(v,_)]=d,i[this._hashKey(m,x)]=p,this.trianglesLen=0,this._addTriangle(h,d,p,-1,-1,-1);for(let o,a,u=0;u<this._ids.length;u++){const c=this._ids[u],f=t[2*c],s=t[2*c+1];if(u>0&&Math.abs(f-o)<=Tu&&Math.abs(s-a)<=Tu)continue;if(o=f,a=s,c===h||c===d||c===p)continue;let l=0;for(let t=0,n=this._hashKey(f,s);t<this._hashSize&&(l=i[(n+t)%this._hashSize],-1===l||l===e[l]);t++);l=n[l];let g,y=l;for(;g=e[y],Mu(f,s,t[2*y],t[2*y+1],t[2*g],t[2*g+1])>=0;)if(y=g,y===l){y=-1;break}if(-1===y)continue;let v=this._addTriangle(y,c,e[y],-1,-1,r[y]);r[c]=this._legalize(v+2),r[y]=v,M++;let _=e[y];for(;g=e[_],Mu(f,s,t[2*_],t[2*_+1],t[2*g],t[2*g+1])<0;)v=this._addTriangle(_,c,g,r[c],-1,r[_]),r[c]=this._legalize(v+2),e[_]=_,M--,_=g;if(y===l)for(;g=n[y],Mu(f,s,t[2*g],t[2*g+1],t[2*y],t[2*y+1])<0;)v=this._addTriangle(g,c,y,-1,r[y],r[g]),this._legalize(v+2),r[g]=v,e[y]=y,M--,y=g;this._hullStart=n[c]=y,e[y]=n[_]=c,e[c]=_,i[this._hashKey(f,s)]=c,i[this._hashKey(t[2*y],t[2*y+1])]=y}this.hull=new Uint32Array(M);for(let t=0,n=this._hullStart;t<M;t++)this.hull[t]=n,n=e[n];this.triangles=this._triangles.subarray(0,this.trianglesLen),this.halfedges=this._halfedges.subarray(0,this.trianglesLen)}_hashKey(t,n){return Math.floor(function(t,n){const e=t/(Math.abs(t)+Math.abs(n));return(n>0?3-e:1+e)/4}(t-this._cx,n-this._cy)*this._hashSize)%this._hashSize}_legalize(t){const{_triangles:n,_halfedges:e,coords:r}=this;let i=0,o=0;for(;;){const a=e[t],u=t-t%3;if(o=u+(t+2)%3,-1===a){if(0===i)break;t=Au[--i];continue}const c=a-a%3,f=u+(t+1)%3,s=c+(a+2)%3,l=n[o],h=n[t],d=n[f],p=n[s];if(Nu(r[2*l],r[2*l+1],r[2*h],r[2*h+1],r[2*d],r[2*d+1],r[2*p],r[2*p+1])){n[t]=p,n[a]=l;const r=e[s];if(-1===r){let n=this._hullStart;do{if(this._hullTri[n]===s){this._hullTri[n]=t;break}n=this._hullPrev[n]}while(n!==this._hullStart)}this._link(t,r),this._link(a,e[o]),this._link(o,s);const u=c+(a+1)%3;i<Au.length&&(Au[i++]=u)}else{if(0===i)break;t=Au[--i]}}return o}_link(t,n){this._halfedges[t]=n,-1!==n&&(this._halfedges[n]=t)}_addTriangle(t,n,e,r,i,o){const a=this.trianglesLen;return this._triangles[a]=t,this._triangles[a+1]=n,this._triangles[a+2]=e,this._link(a,r),this._link(a+1,i),this._link(a+2,o),this.trianglesLen+=3,a}}function Eu(t,n,e,r){const i=t-e,o=n-r;return i*i+o*o}function Nu(t,n,e,r,i,o,a,u){const c=t-a,f=n-u,s=e-a,l=r-u,h=i-a,d=o-u,p=s*s+l*l,g=h*h+d*d;return c*(l*g-p*d)-f*(s*g-p*h)+(c*c+f*f)*(s*d-l*h)<0}function ku(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c),d=(f*s-u*l)*h,p=(a*l-c*s)*h;return d*d+p*p}function Cu(t,n,e,r){if(r-e<=20)for(let i=e+1;i<=r;i++){const r=t[i],o=n[r];let a=i-1;for(;a>=e&&n[t[a]]>o;)t[a+1]=t[a--];t[a+1]=r}else{let i=e+1,o=r;Pu(t,e+r>>1,i),n[t[e]]>n[t[r]]&&Pu(t,e,r),n[t[i]]>n[t[r]]&&Pu(t,i,r),n[t[e]]>n[t[i]]&&Pu(t,e,i);const a=t[i],u=n[a];for(;;){do{i++}while(n[t[i]]<u);do{o--}while(n[t[o]]>u);if(o<i)break;Pu(t,i,o)}t[e+1]=t[o],t[o]=a,r-i+1>=o-e?(Cu(t,n,i,r),Cu(t,n,e,o-1)):(Cu(t,n,e,o-1),Cu(t,n,i,r))}}function Pu(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function zu(t){return t[0]}function $u(t){return t[1]}const Du=1e-6;class Ru{constructor(){this._x0=this._y0=this._x1=this._y1=null,this._=""}moveTo(t,n){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")}lineTo(t,n){this._+=`L${this._x1=+t},${this._y1=+n}`}arc(t,n,e){const r=(t=+t)+(e=+e),i=n=+n;if(e<0)throw new Error("negative radius");null===this._x1?this._+=`M${r},${i}`:(Math.abs(this._x1-r)>Du||Math.abs(this._y1-i)>Du)&&(this._+="L"+r+","+i),e&&(this._+=`A${e},${e},0,1,1,${t-e},${n}A${e},${e},0,1,1,${this._x1=r},${this._y1=i}`)}rect(t,n,e,r){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${+e}v${+r}h${-e}Z`}value(){return this._||null}}class Fu{constructor(){this._=[]}moveTo(t,n){this._.push([t,n])}closePath(){this._.push(this._[0].slice())}lineTo(t,n){this._.push([t,n])}value(){return this._.length?this._:null}}class qu{constructor(t,[n,e,r,i]=[0,0,960,500]){if(!((r=+r)>=(n=+n)&&(i=+i)>=(e=+e)))throw new Error("invalid bounds");this.delaunay=t,this._circumcenters=new Float64Array(2*t.points.length),this.vectors=new Float64Array(2*t.points.length),this.xmax=r,this.xmin=n,this.ymax=i,this.ymin=e,this._init()}update(){return this.delaunay.update(),this._init(),this}_init(){const{delaunay:{points:t,hull:n,triangles:e},vectors:r}=this;let i,o;const a=this.circumcenters=this._circumcenters.subarray(0,e.length/3*2);for(let r,u,c=0,f=0,s=e.length;c<s;c+=3,f+=2){const s=2*e[c],l=2*e[c+1],h=2*e[c+2],d=t[s],p=t[s+1],g=t[l],y=t[l+1],v=t[h],_=t[h+1],b=g-d,m=y-p,x=v-d,w=_-p,M=2*(b*w-m*x);if(Math.abs(M)<1e-9){if(void 0===i){i=o=0;for(const e of n)i+=t[2*e],o+=t[2*e+1];i/=n.length,o/=n.length}const e=1e9*Math.sign((i-d)*w-(o-p)*x);r=(d+v)/2-e*w,u=(p+_)/2+e*x}else{const t=1/M,n=b*b+m*m,e=x*x+w*w;r=d+(w*n-m*e)*t,u=p+(b*e-x*n)*t}a[f]=r,a[f+1]=u}let u,c,f,s=n[n.length-1],l=4*s,h=t[2*s],d=t[2*s+1];r.fill(0);for(let e=0;e<n.length;++e)s=n[e],u=l,c=h,f=d,l=4*s,h=t[2*s],d=t[2*s+1],r[u+2]=r[l]=f-d,r[u+3]=r[l+1]=h-c}render(t){const n=null==t?t=new Ru:void 0,{delaunay:{halfedges:e,inedges:r,hull:i},circumcenters:o,vectors:a}=this;if(i.length<=1)return null;for(let n=0,r=e.length;n<r;++n){const r=e[n];if(r<n)continue;const i=2*Math.floor(n/3),a=2*Math.floor(r/3),u=o[i],c=o[i+1],f=o[a],s=o[a+1];this._renderSegment(u,c,f,s,t)}let u,c=i[i.length-1];for(let n=0;n<i.length;++n){u=c,c=i[n];const e=2*Math.floor(r[c]/3),f=o[e],s=o[e+1],l=4*u,h=this._project(f,s,a[l+2],a[l+3]);h&&this._renderSegment(f,s,h[0],h[1],t)}return n&&n.value()}renderBounds(t){const n=null==t?t=new Ru:void 0;return t.rect(this.xmin,this.ymin,this.xmax-this.xmin,this.ymax-this.ymin),n&&n.value()}renderCell(t,n){const e=null==n?n=new Ru:void 0,r=this._clip(t);if(null===r||!r.length)return;n.moveTo(r[0],r[1]);let i=r.length;for(;r[0]===r[i-2]&&r[1]===r[i-1]&&i>1;)i-=2;for(let t=2;t<i;t+=2)r[t]===r[t-2]&&r[t+1]===r[t-1]||n.lineTo(r[t],r[t+1]);return n.closePath(),e&&e.value()}*cellPolygons(){const{delaunay:{points:t}}=this;for(let n=0,e=t.length/2;n<e;++n){const t=this.cellPolygon(n);t&&(t.index=n,yield t)}}cellPolygon(t){const n=new Fu;return this.renderCell(t,n),n.value()}_renderSegment(t,n,e,r,i){let o;const a=this._regioncode(t,n),u=this._regioncode(e,r);0===a&&0===u?(i.moveTo(t,n),i.lineTo(e,r)):(o=this._clipSegment(t,n,e,r,a,u))&&(i.moveTo(o[0],o[1]),i.lineTo(o[2],o[3]))}contains(t,n,e){return(n=+n)==n&&(e=+e)==e&&this.delaunay._step(t,n,e)===t}*neighbors(t){const n=this._clip(t);if(n)for(const e of this.delaunay.neighbors(t)){const t=this._clip(e);if(t)t:for(let r=0,i=n.length;r<i;r+=2)for(let o=0,a=t.length;o<a;o+=2)if(n[r]===t[o]&&n[r+1]===t[o+1]&&n[(r+2)%i]===t[(o+a-2)%a]&&n[(r+3)%i]===t[(o+a-1)%a]){yield e;break t}}}_cell(t){const{circumcenters:n,delaunay:{inedges:e,halfedges:r,triangles:i}}=this,o=e[t];if(-1===o)return null;const a=[];let u=o;do{const e=Math.floor(u/3);if(a.push(n[2*e],n[2*e+1]),u=u%3==2?u-2:u+1,i[u]!==t)break;u=r[u]}while(u!==o&&-1!==u);return a}_clip(t){if(0===t&&1===this.delaunay.hull.length)return[this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax,this.xmin,this.ymin];const n=this._cell(t);if(null===n)return null;const{vectors:e}=this,r=4*t;return this._simplify(e[r]||e[r+1]?this._clipInfinite(t,n,e[r],e[r+1],e[r+2],e[r+3]):this._clipFinite(t,n))}_clipFinite(t,n){const e=n.length;let r,i,o,a,u=null,c=n[e-2],f=n[e-1],s=this._regioncode(c,f),l=0;for(let h=0;h<e;h+=2)if(r=c,i=f,c=n[h],f=n[h+1],o=s,s=this._regioncode(c,f),0===o&&0===s)a=l,l=0,u?u.push(c,f):u=[c,f];else{let n,e,h,d,p;if(0===o){if(null===(n=this._clipSegment(r,i,c,f,o,s)))continue;[e,h,d,p]=n}else{if(null===(n=this._clipSegment(c,f,r,i,s,o)))continue;[d,p,e,h]=n,a=l,l=this._edgecode(e,h),a&&l&&this._edge(t,a,l,u,u.length),u?u.push(e,h):u=[e,h]}a=l,l=this._edgecode(d,p),a&&l&&this._edge(t,a,l,u,u.length),u?u.push(d,p):u=[d,p]}if(u)a=l,l=this._edgecode(u[0],u[1]),a&&l&&this._edge(t,a,l,u,u.length);else if(this.contains(t,(this.xmin+this.xmax)/2,(this.ymin+this.ymax)/2))return[this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax,this.xmin,this.ymin];return u}_clipSegment(t,n,e,r,i,o){const a=i<o;for(a&&([t,n,e,r,i,o]=[e,r,t,n,o,i]);;){if(0===i&&0===o)return a?[e,r,t,n]:[t,n,e,r];if(i&o)return null;let u,c,f=i||o;8&f?(u=t+(e-t)*(this.ymax-n)/(r-n),c=this.ymax):4&f?(u=t+(e-t)*(this.ymin-n)/(r-n),c=this.ymin):2&f?(c=n+(r-n)*(this.xmax-t)/(e-t),u=this.xmax):(c=n+(r-n)*(this.xmin-t)/(e-t),u=this.xmin),i?(t=u,n=c,i=this._regioncode(t,n)):(e=u,r=c,o=this._regioncode(e,r))}}_clipInfinite(t,n,e,r,i,o){let a,u=Array.from(n);if((a=this._project(u[0],u[1],e,r))&&u.unshift(a[0],a[1]),(a=this._project(u[u.length-2],u[u.length-1],i,o))&&u.push(a[0],a[1]),u=this._clipFinite(t,u))for(let n,e=0,r=u.length,i=this._edgecode(u[r-2],u[r-1]);e<r;e+=2)n=i,i=this._edgecode(u[e],u[e+1]),n&&i&&(e=this._edge(t,n,i,u,e),r=u.length);else this.contains(t,(this.xmin+this.xmax)/2,(this.ymin+this.ymax)/2)&&(u=[this.xmin,this.ymin,this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax]);return u}_edge(t,n,e,r,i){for(;n!==e;){let e,o;switch(n){case 5:n=4;continue;case 4:n=6,e=this.xmax,o=this.ymin;break;case 6:n=2;continue;case 2:n=10,e=this.xmax,o=this.ymax;break;case 10:n=8;continue;case 8:n=9,e=this.xmin,o=this.ymax;break;case 9:n=1;continue;case 1:n=5,e=this.xmin,o=this.ymin}r[i]===e&&r[i+1]===o||!this.contains(t,e,o)||(r.splice(i,0,e,o),i+=2)}return i}_project(t,n,e,r){let i,o,a,u=1/0;if(r<0){if(n<=this.ymin)return null;(i=(this.ymin-n)/r)<u&&(a=this.ymin,o=t+(u=i)*e)}else if(r>0){if(n>=this.ymax)return null;(i=(this.ymax-n)/r)<u&&(a=this.ymax,o=t+(u=i)*e)}if(e>0){if(t>=this.xmax)return null;(i=(this.xmax-t)/e)<u&&(o=this.xmax,a=n+(u=i)*r)}else if(e<0){if(t<=this.xmin)return null;(i=(this.xmin-t)/e)<u&&(o=this.xmin,a=n+(u=i)*r)}return[o,a]}_edgecode(t,n){return(t===this.xmin?1:t===this.xmax?2:0)|(n===this.ymin?4:n===this.ymax?8:0)}_regioncode(t,n){return(t<this.xmin?1:t>this.xmax?2:0)|(n<this.ymin?4:n>this.ymax?8:0)}_simplify(t){if(t&&t.length>4){for(let n=0;n<t.length;n+=2){const e=(n+2)%t.length,r=(n+4)%t.length;(t[n]===t[e]&&t[e]===t[r]||t[n+1]===t[e+1]&&t[e+1]===t[r+1])&&(t.splice(e,2),n-=2)}t.length||(t=null)}return t}}const Uu=2*Math.PI,Iu=Math.pow;function Ou(t){return t[0]}function Bu(t){return t[1]}function Yu(t,n,e){return[t+Math.sin(t+n)*e,n+Math.cos(t-n)*e]}class Lu{static from(t,n=Ou,e=Bu,r){return new Lu("length"in t?function(t,n,e,r){const i=t.length,o=new Float64Array(2*i);for(let a=0;a<i;++a){const i=t[a];o[2*a]=n.call(r,i,a,t),o[2*a+1]=e.call(r,i,a,t)}return o}(t,n,e,r):Float64Array.from(function*(t,n,e,r){let i=0;for(const o of t)yield n.call(r,o,i,t),yield e.call(r,o,i,t),++i}(t,n,e,r)))}constructor(t){this._delaunator=new Su(t),this.inedges=new Int32Array(t.length/2),this._hullIndex=new Int32Array(t.length/2),this.points=this._delaunator.coords,this._init()}update(){return this._delaunator.update(),this._init(),this}_init(){const t=this._delaunator,n=this.points;if(t.hull&&t.hull.length>2&&function(t){const{triangles:n,coords:e}=t;for(let t=0;t<n.length;t+=3){const r=2*n[t],i=2*n[t+1],o=2*n[t+2];if((e[o]-e[r])*(e[i+1]-e[r+1])-(e[i]-e[r])*(e[o+1]-e[r+1])>1e-10)return!1}return!0}(t)){this.collinear=Int32Array.from({length:n.length/2},((t,n)=>n)).sort(((t,e)=>n[2*t]-n[2*e]||n[2*t+1]-n[2*e+1]));const t=this.collinear[0],e=this.collinear[this.collinear.length-1],r=[n[2*t],n[2*t+1],n[2*e],n[2*e+1]],i=1e-8*Math.hypot(r[3]-r[1],r[2]-r[0]);for(let t=0,e=n.length/2;t<e;++t){const e=Yu(n[2*t],n[2*t+1],i);n[2*t]=e[0],n[2*t+1]=e[1]}this._delaunator=new Su(n)}else delete this.collinear;const e=this.halfedges=this._delaunator.halfedges,r=this.hull=this._delaunator.hull,i=this.triangles=this._delaunator.triangles,o=this.inedges.fill(-1),a=this._hullIndex.fill(-1);for(let t=0,n=e.length;t<n;++t){const n=i[t%3==2?t-2:t+1];-1!==e[t]&&-1!==o[n]||(o[n]=t)}for(let t=0,n=r.length;t<n;++t)a[r[t]]=t;r.length<=2&&r.length>0&&(this.triangles=new Int32Array(3).fill(-1),this.halfedges=new Int32Array(3).fill(-1),this.triangles[0]=r[0],o[r[0]]=1,2===r.length&&(o[r[1]]=0,this.triangles[1]=r[1],this.triangles[2]=r[1]))}voronoi(t){return new qu(this,t)}*neighbors(t){const{inedges:n,hull:e,_hullIndex:r,halfedges:i,triangles:o,collinear:a}=this;if(a){const n=a.indexOf(t);return n>0&&(yield a[n-1]),void(n<a.length-1&&(yield a[n+1]))}const u=n[t];if(-1===u)return;let c=u,f=-1;do{if(yield f=o[c],c=c%3==2?c-2:c+1,o[c]!==t)return;if(c=i[c],-1===c){const n=e[(r[t]+1)%e.length];return void(n!==f&&(yield n))}}while(c!==u)}find(t,n,e=0){if((t=+t)!=t||(n=+n)!=n)return-1;const r=e;let i;for(;(i=this._step(e,t,n))>=0&&i!==e&&i!==r;)e=i;return i}_step(t,n,e){const{inedges:r,hull:i,_hullIndex:o,halfedges:a,triangles:u,points:c}=this;if(-1===r[t]||!c.length)return(t+1)%(c.length>>1);let f=t,s=Iu(n-c[2*t],2)+Iu(e-c[2*t+1],2);const l=r[t];let h=l;do{let r=u[h];const l=Iu(n-c[2*r],2)+Iu(e-c[2*r+1],2);if(l<s&&(s=l,f=r),h=h%3==2?h-2:h+1,u[h]!==t)break;if(h=a[h],-1===h){if(h=i[(o[t]+1)%i.length],h!==r&&Iu(n-c[2*h],2)+Iu(e-c[2*h+1],2)<s)return h;break}}while(h!==l);return f}render(t){const n=null==t?t=new Ru:void 0,{points:e,halfedges:r,triangles:i}=this;for(let n=0,o=r.length;n<o;++n){const o=r[n];if(o<n)continue;const a=2*i[n],u=2*i[o];t.moveTo(e[a],e[a+1]),t.lineTo(e[u],e[u+1])}return this.renderHull(t),n&&n.value()}renderPoints(t,n){void 0!==n||t&&"function"==typeof t.moveTo||(n=t,t=null),n=null==n?2:+n;const e=null==t?t=new Ru:void 0,{points:r}=this;for(let e=0,i=r.length;e<i;e+=2){const i=r[e],o=r[e+1];t.moveTo(i+n,o),t.arc(i,o,n,0,Uu)}return e&&e.value()}renderHull(t){const n=null==t?t=new Ru:void 0,{hull:e,points:r}=this,i=2*e[0],o=e.length;t.moveTo(r[i],r[i+1]);for(let n=1;n<o;++n){const i=2*e[n];t.lineTo(r[i],r[i+1])}return t.closePath(),n&&n.value()}hullPolygon(){const t=new Fu;return this.renderHull(t),t.value()}renderTriangle(t,n){const e=null==n?n=new Ru:void 0,{points:r,triangles:i}=this,o=2*i[t*=3],a=2*i[t+1],u=2*i[t+2];return n.moveTo(r[o],r[o+1]),n.lineTo(r[a],r[a+1]),n.lineTo(r[u],r[u+1]),n.closePath(),e&&e.value()}*trianglePolygons(){const{triangles:t}=this;for(let n=0,e=t.length/3;n<e;++n)yield this.trianglePolygon(n)}trianglePolygon(t){const n=new Fu;return this.renderTriangle(t,n),n.value()}}var ju={},Hu={},Xu=34,Gu=10,Vu=13;function Wu(t){return new Function("d","return {"+t.map((function(t,n){return JSON.stringify(t)+": d["+n+'] || ""'})).join(",")+"}")}function Zu(t){var n=Object.create(null),e=[];return t.forEach((function(t){for(var r in t)r in n||e.push(n[r]=r)})),e}function Ku(t,n){var e=t+"",r=e.length;return r<n?new Array(n-r+1).join(0)+e:e}function Qu(t){var n,e=t.getUTCHours(),r=t.getUTCMinutes(),i=t.getUTCSeconds(),o=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":((n=t.getUTCFullYear())<0?"-"+Ku(-n,6):n>9999?"+"+Ku(n,6):Ku(n,4))+"-"+Ku(t.getUTCMonth()+1,2)+"-"+Ku(t.getUTCDate(),2)+(o?"T"+Ku(e,2)+":"+Ku(r,2)+":"+Ku(i,2)+"."+Ku(o,3)+"Z":i?"T"+Ku(e,2)+":"+Ku(r,2)+":"+Ku(i,2)+"Z":r||e?"T"+Ku(e,2)+":"+Ku(r,2)+"Z":"")}function Ju(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,c=o<=0,f=!1;function s(){if(c)return Hu;if(f)return f=!1,ju;var n,r,i=a;if(t.charCodeAt(i)===Xu){for(;a++<o&&t.charCodeAt(a)!==Xu||t.charCodeAt(++a)===Xu;);return(n=a)>=o?c=!0:(r=t.charCodeAt(a++))===Gu?f=!0:r===Vu&&(f=!0,t.charCodeAt(a)===Gu&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;a<o;){if((r=t.charCodeAt(n=a++))===Gu)f=!0;else if(r===Vu)f=!0,t.charCodeAt(a)===Gu&&++a;else if(r!==e)continue;return t.slice(i,n)}return c=!0,t.slice(i,o)}for(t.charCodeAt(o-1)===Gu&&--o,t.charCodeAt(o-1)===Vu&&--o;(r=s())!==Hu;){for(var l=[];r!==ju&&r!==Hu;)l.push(r),r=s();n&&null==(l=n(l,u++))||i.push(l)}return i}function i(n,e){return n.map((function(n){return e.map((function(t){return a(n[t])})).join(t)}))}function o(n){return n.map(a).join(t)}function a(t){return null==t?"":t instanceof Date?Qu(t):n.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,n){var e,i,o=r(t,(function(t,r){if(e)return e(t,r-1);i=t,e=n?function(t,n){var e=Wu(t);return function(r,i){return n(e(r),i,t)}}(t,n):Wu(t)}));return o.columns=i||[],o},parseRows:r,format:function(n,e){return null==e&&(e=Zu(n)),[e.map(a).join(t)].concat(i(n,e)).join("\n")},formatBody:function(t,n){return null==n&&(n=Zu(t)),i(t,n).join("\n")},formatRows:function(t){return t.map(o).join("\n")},formatRow:o,formatValue:a}}var tc=Ju(","),nc=tc.parse,ec=tc.parseRows,rc=tc.format,ic=tc.formatBody,oc=tc.formatRows,ac=tc.formatRow,uc=tc.formatValue,cc=Ju("\t"),fc=cc.parse,sc=cc.parseRows,lc=cc.format,hc=cc.formatBody,dc=cc.formatRows,pc=cc.formatRow,gc=cc.formatValue;const yc=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();function vc(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function _c(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function bc(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function mc(t,n){return fetch(t,n).then(bc)}function xc(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),mc(n,e).then((function(n){return t(n,r)}))}}var wc=xc(nc),Mc=xc(fc);function Tc(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);if(204!==t.status&&205!==t.status)return t.json()}function Ac(t){return(n,e)=>mc(n,e).then((n=>(new DOMParser).parseFromString(n,t)))}var Sc=Ac("application/xml"),Ec=Ac("text/html"),Nc=Ac("image/svg+xml");function kc(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,c,f,s,l,h,d=t._root,p={data:r},g=t._x0,y=t._y0,v=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a,i=d,!(d=d[l=s<<1|f]))return i[l]=p,t;if(u=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===u&&e===c)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a}while((l=s<<1|f)==(h=(c>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function Cc(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function Pc(t){return t[0]}function zc(t){return t[1]}function $c(t,n,e){var r=new Dc(null==n?Pc:n,null==e?zc:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Dc(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Rc(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var Fc=$c.prototype=Dc.prototype;function qc(t){return function(){return t}}function Uc(t){return 1e-6*(t()-.5)}function Ic(t){return t.x+t.vx}function Oc(t){return t.y+t.vy}function Bc(t){return t.index}function Yc(t,n){var e=t.get(n);if(!e)throw new Error("node not found: "+n);return e}Fc.copy=function(){var t,n,e=new Dc(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Rc(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=Rc(n));return e},Fc.add=function(t){const n=+this._x.call(null,t),e=+this._y.call(null,t);return kc(this.cover(n,e),n,e,t)},Fc.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),c=1/0,f=1/0,s=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(a[e]=r,u[e]=i,r<c&&(c=r),r>s&&(s=r),i<f&&(f=i),i>l&&(l=i));if(c>s||f>l)return this;for(this.cover(c,f).cover(s,l),e=0;e<o;++e)kc(this,a[e],u[e],t[e]);return this},Fc.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{for(var a,u,c=i-e||1,f=this._root;e>t||t>=i||r>n||n>=o;)switch(u=(n<r)<<1|t<e,(a=new Array(4))[u]=f,f=a,c*=2,u){case 0:i=e+c,o=r+c;break;case 1:e=i-c,o=r+c;break;case 2:i=e+c,r=o-c;break;case 3:e=i-c,r=o-c}this._root&&this._root.length&&(this._root=f)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},Fc.data=function(){var t=[];return this.visit((function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)})),t},Fc.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},Fc.find=function(t,n,e){var r,i,o,a,u,c,f,s=this._x0,l=this._y0,h=this._x1,d=this._y1,p=[],g=this._root;for(g&&p.push(new Cc(g,s,l,h,d)),null==e?e=1/0:(s=t-e,l=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(g=c.node)||(i=c.x0)>h||(o=c.y0)>d||(a=c.x1)<s||(u=c.y1)<l))if(g.length){var y=(i+a)/2,v=(o+u)/2;p.push(new Cc(g[3],y,v,a,u),new Cc(g[2],i,v,y,u),new Cc(g[1],y,o,a,v),new Cc(g[0],i,o,y,v)),(f=(n>=v)<<1|t>=y)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-f],p[p.length-1-f]=c)}else{var _=t-+this._x.call(null,g.data),b=n-+this._y.call(null,g.data),m=_*_+b*b;if(m<e){var x=Math.sqrt(e=m);s=t-x,l=n-x,h=t+x,d=n+x,r=g.data}}return r},Fc.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(a=+this._y.call(null,t)))return this;var n,e,r,i,o,a,u,c,f,s,l,h,d=this._root,p=this._x0,g=this._y0,y=this._x1,v=this._y1;if(!d)return this;if(d.length)for(;;){if((f=o>=(u=(p+y)/2))?p=u:y=u,(s=a>=(c=(g+v)/2))?g=c:v=c,n=d,!(d=d[l=s<<1|f]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},Fc.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},Fc.root=function(){return this._root},Fc.size=function(){var t=0;return this.visit((function(n){if(!n.length)do{++t}while(n=n.next)})),t},Fc.visit=function(t){var n,e,r,i,o,a,u=[],c=this._root;for(c&&u.push(new Cc(c,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,a=n.y1)&&c.length){var f=(r+o)/2,s=(i+a)/2;(e=c[3])&&u.push(new Cc(e,f,s,o,a)),(e=c[2])&&u.push(new Cc(e,r,s,f,a)),(e=c[1])&&u.push(new Cc(e,f,i,o,s)),(e=c[0])&&u.push(new Cc(e,r,i,f,s))}return this},Fc.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new Cc(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,a=n.x0,u=n.y0,c=n.x1,f=n.y1,s=(a+c)/2,l=(u+f)/2;(o=i[0])&&e.push(new Cc(o,a,u,s,l)),(o=i[1])&&e.push(new Cc(o,s,u,c,l)),(o=i[2])&&e.push(new Cc(o,a,l,s,f)),(o=i[3])&&e.push(new Cc(o,s,l,c,f))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},Fc.x=function(t){return arguments.length?(this._x=t,this):this._x},Fc.y=function(t){return arguments.length?(this._y=t,this):this._y};const Lc=1664525,jc=1013904223,Hc=4294967296;function Xc(t){return t.x}function Gc(t){return t.y}var Vc=Math.PI*(3-Math.sqrt(5));function Wc(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]}function Zc(t){return(t=Wc(Math.abs(t)))?t[1]:NaN}var Kc,Qc=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Jc(t){if(!(n=Qc.exec(t)))throw new Error("invalid format: "+t);var n;return new tf({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function tf(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function nf(t,n){var e=Wc(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Jc.prototype=tf.prototype,tf.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var ef={"%":(t,n)=>(100*t).toFixed(n),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,n)=>t.toExponential(n),f:(t,n)=>t.toFixed(n),g:(t,n)=>t.toPrecision(n),o:t=>Math.round(t).toString(8),p:(t,n)=>nf(100*t,n),r:nf,s:function(t,n){var e=Wc(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(Kc=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+Wc(t,Math.max(0,n+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function rf(t){return t}var of,af=Array.prototype.map,uf=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function cf(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?rf:(n=af.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),o.push(t.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?rf:function(t){return function(n){return n.replace(/[0-9]/g,(function(n){return t[+n]}))}}(af.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",f=void 0===t.minus?"−":t.minus+"",s=void 0===t.nan?"NaN":t.nan+"";function l(t){var n=(t=Jc(t)).fill,e=t.align,l=t.sign,h=t.symbol,d=t.zero,p=t.width,g=t.comma,y=t.precision,v=t.trim,_=t.type;"n"===_?(g=!0,_="g"):ef[_]||(void 0===y&&(y=12),v=!0,_="g"),(d||"0"===n&&"="===e)&&(d=!0,n="0",e="=");var b="$"===h?i:"#"===h&&/[boxX]/.test(_)?"0"+_.toLowerCase():"",m="$"===h?o:/[%p]/.test(_)?c:"",x=ef[_],w=/[defgprs%]/.test(_);function M(t){var i,o,c,h=b,M=m;if("c"===_)M=x(t)+M,t="";else{var T=(t=+t)<0||1/t<0;if(t=isNaN(t)?s:x(Math.abs(t),y),v&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r<e;++r)switch(t[r]){case".":i=n=r;break;case"0":0===i&&(i=r),n=r;break;default:if(!+t[r])break t;i>0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),T&&0==+t&&"+"!==l&&(T=!1),h=(T?"("===l?l:f:"-"===l||"("===l?"":l)+h,M=("s"===_?uf[8+Kc/3]:"")+M+(T&&"("===l?")":""),w)for(i=-1,o=t.length;++i<o;)if(48>(c=t.charCodeAt(i))||c>57){M=(46===c?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!d&&(t=r(t,1/0));var A=h.length+t.length+M.length,S=A<p?new Array(p-A+1).join(n):"";switch(g&&d&&(t=r(S+t,S.length?p-M.length:1/0),S=""),e){case"<":t=h+t+M+S;break;case"=":t=h+S+t+M;break;case"^":t=S.slice(0,A=S.length>>1)+h+t+M+S.slice(A);break;default:t=S+h+t+M}return u(t)}return y=void 0===y?6:/[gprs]/.test(_)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y)),M.toString=function(){return t+""},M}return{format:l,formatPrefix:function(t,n){var e=l(((t=Jc(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Zc(n)/3))),i=Math.pow(10,-r),o=uf[8+r/3];return function(t){return e(i*t)+o}}}}function ff(n){return of=cf(n),t.format=of.format,t.formatPrefix=of.formatPrefix,of}function sf(t){return Math.max(0,-Zc(Math.abs(t)))}function lf(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Zc(n)/3)))-Zc(Math.abs(t)))}function hf(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,Zc(n)-Zc(t))+1}t.format=void 0,t.formatPrefix=void 0,ff({thousands:",",grouping:[3],currency:["$",""]});var df=1e-6,pf=1e-12,gf=Math.PI,yf=gf/2,vf=gf/4,_f=2*gf,bf=180/gf,mf=gf/180,xf=Math.abs,wf=Math.atan,Mf=Math.atan2,Tf=Math.cos,Af=Math.ceil,Sf=Math.exp,Ef=Math.hypot,Nf=Math.log,kf=Math.pow,Cf=Math.sin,Pf=Math.sign||function(t){return t>0?1:t<0?-1:0},zf=Math.sqrt,$f=Math.tan;function Df(t){return t>1?0:t<-1?gf:Math.acos(t)}function Rf(t){return t>1?yf:t<-1?-yf:Math.asin(t)}function Ff(t){return(t=Cf(t/2))*t}function qf(){}function Uf(t,n){t&&Of.hasOwnProperty(t.type)&&Of[t.type](t,n)}var If={Feature:function(t,n){Uf(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)Uf(e[r].geometry,n)}},Of={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){Bf(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Bf(e[r],n,0)},Polygon:function(t,n){Yf(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Yf(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)Uf(e[r],n)}};function Bf(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function Yf(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)Bf(t[e],n,1);n.polygonEnd()}function Lf(t,n){t&&If.hasOwnProperty(t.type)?If[t.type](t,n):Uf(t,n)}var jf,Hf,Xf,Gf,Vf,Wf,Zf,Kf,Qf,Jf,ts,ns,es,rs,is,os,as=new T,us=new T,cs={point:qf,lineStart:qf,lineEnd:qf,polygonStart:function(){as=new T,cs.lineStart=fs,cs.lineEnd=ss},polygonEnd:function(){var t=+as;us.add(t<0?_f+t:t),this.lineStart=this.lineEnd=this.point=qf},sphere:function(){us.add(_f)}};function fs(){cs.point=ls}function ss(){hs(jf,Hf)}function ls(t,n){cs.point=hs,jf=t,Hf=n,Xf=t*=mf,Gf=Tf(n=(n*=mf)/2+vf),Vf=Cf(n)}function hs(t,n){var e=(t*=mf)-Xf,r=e>=0?1:-1,i=r*e,o=Tf(n=(n*=mf)/2+vf),a=Cf(n),u=Vf*a,c=Gf*o+u*Tf(i),f=u*r*Cf(i);as.add(Mf(f,c)),Xf=t,Gf=o,Vf=a}function ds(t){return[Mf(t[1],t[0]),Rf(t[2])]}function ps(t){var n=t[0],e=t[1],r=Tf(e);return[r*Tf(n),r*Cf(n),Cf(e)]}function gs(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function ys(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function vs(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function _s(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function bs(t){var n=zf(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var ms,xs,ws,Ms,Ts,As,Ss,Es,Ns,ks,Cs,Ps,zs,$s,Ds,Rs,Fs={point:qs,lineStart:Is,lineEnd:Os,polygonStart:function(){Fs.point=Bs,Fs.lineStart=Ys,Fs.lineEnd=Ls,rs=new T,cs.polygonStart()},polygonEnd:function(){cs.polygonEnd(),Fs.point=qs,Fs.lineStart=Is,Fs.lineEnd=Os,as<0?(Wf=-(Kf=180),Zf=-(Qf=90)):rs>df?Qf=90:rs<-df&&(Zf=-90),os[0]=Wf,os[1]=Kf},sphere:function(){Wf=-(Kf=180),Zf=-(Qf=90)}};function qs(t,n){is.push(os=[Wf=t,Kf=t]),n<Zf&&(Zf=n),n>Qf&&(Qf=n)}function Us(t,n){var e=ps([t*mf,n*mf]);if(es){var r=ys(es,e),i=ys([r[1],-r[0],0],r);bs(i),i=ds(i);var o,a=t-Jf,u=a>0?1:-1,c=i[0]*bf*u,f=xf(a)>180;f^(u*Jf<c&&c<u*t)?(o=i[1]*bf)>Qf&&(Qf=o):f^(u*Jf<(c=(c+360)%360-180)&&c<u*t)?(o=-i[1]*bf)<Zf&&(Zf=o):(n<Zf&&(Zf=n),n>Qf&&(Qf=n)),f?t<Jf?js(Wf,t)>js(Wf,Kf)&&(Kf=t):js(t,Kf)>js(Wf,Kf)&&(Wf=t):Kf>=Wf?(t<Wf&&(Wf=t),t>Kf&&(Kf=t)):t>Jf?js(Wf,t)>js(Wf,Kf)&&(Kf=t):js(t,Kf)>js(Wf,Kf)&&(Wf=t)}else is.push(os=[Wf=t,Kf=t]);n<Zf&&(Zf=n),n>Qf&&(Qf=n),es=e,Jf=t}function Is(){Fs.point=Us}function Os(){os[0]=Wf,os[1]=Kf,Fs.point=qs,es=null}function Bs(t,n){if(es){var e=t-Jf;rs.add(xf(e)>180?e+(e>0?360:-360):e)}else ts=t,ns=n;cs.point(t,n),Us(t,n)}function Ys(){cs.lineStart()}function Ls(){Bs(ts,ns),cs.lineEnd(),xf(rs)>df&&(Wf=-(Kf=180)),os[0]=Wf,os[1]=Kf,es=null}function js(t,n){return(n-=t)<0?n+360:n}function Hs(t,n){return t[0]-n[0]}function Xs(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var Gs={sphere:qf,point:Vs,lineStart:Zs,lineEnd:Js,polygonStart:function(){Gs.lineStart=tl,Gs.lineEnd=nl},polygonEnd:function(){Gs.lineStart=Zs,Gs.lineEnd=Js}};function Vs(t,n){t*=mf;var e=Tf(n*=mf);Ws(e*Tf(t),e*Cf(t),Cf(n))}function Ws(t,n,e){++ms,ws+=(t-ws)/ms,Ms+=(n-Ms)/ms,Ts+=(e-Ts)/ms}function Zs(){Gs.point=Ks}function Ks(t,n){t*=mf;var e=Tf(n*=mf);$s=e*Tf(t),Ds=e*Cf(t),Rs=Cf(n),Gs.point=Qs,Ws($s,Ds,Rs)}function Qs(t,n){t*=mf;var e=Tf(n*=mf),r=e*Tf(t),i=e*Cf(t),o=Cf(n),a=Mf(zf((a=Ds*o-Rs*i)*a+(a=Rs*r-$s*o)*a+(a=$s*i-Ds*r)*a),$s*r+Ds*i+Rs*o);xs+=a,As+=a*($s+($s=r)),Ss+=a*(Ds+(Ds=i)),Es+=a*(Rs+(Rs=o)),Ws($s,Ds,Rs)}function Js(){Gs.point=Vs}function tl(){Gs.point=el}function nl(){rl(Ps,zs),Gs.point=Vs}function el(t,n){Ps=t,zs=n,t*=mf,n*=mf,Gs.point=rl;var e=Tf(n);$s=e*Tf(t),Ds=e*Cf(t),Rs=Cf(n),Ws($s,Ds,Rs)}function rl(t,n){t*=mf;var e=Tf(n*=mf),r=e*Tf(t),i=e*Cf(t),o=Cf(n),a=Ds*o-Rs*i,u=Rs*r-$s*o,c=$s*i-Ds*r,f=Ef(a,u,c),s=Rf(f),l=f&&-s/f;Ns.add(l*a),ks.add(l*u),Cs.add(l*c),xs+=s,As+=s*($s+($s=r)),Ss+=s*(Ds+(Ds=i)),Es+=s*(Rs+(Rs=o)),Ws($s,Ds,Rs)}function il(t){return function(){return t}}function ol(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e}function al(t,n){return xf(t)>gf&&(t-=Math.round(t/_f)*_f),[t,n]}function ul(t,n,e){return(t%=_f)?n||e?ol(fl(t),sl(n,e)):fl(t):n||e?sl(n,e):al}function cl(t){return function(n,e){return xf(n+=t)>gf&&(n-=Math.round(n/_f)*_f),[n,e]}}function fl(t){var n=cl(t);return n.invert=cl(-t),n}function sl(t,n){var e=Tf(t),r=Cf(t),i=Tf(n),o=Cf(n);function a(t,n){var a=Tf(n),u=Tf(t)*a,c=Cf(t)*a,f=Cf(n),s=f*e+u*r;return[Mf(c*i-s*o,u*e-f*r),Rf(s*i+c*o)]}return a.invert=function(t,n){var a=Tf(n),u=Tf(t)*a,c=Cf(t)*a,f=Cf(n),s=f*i-c*o;return[Mf(c*i+f*o,u*e+s*r),Rf(s*e-u*r)]},a}function ll(t){function n(n){return(n=t(n[0]*mf,n[1]*mf))[0]*=bf,n[1]*=bf,n}return t=ul(t[0]*mf,t[1]*mf,t.length>2?t[2]*mf:0),n.invert=function(n){return(n=t.invert(n[0]*mf,n[1]*mf))[0]*=bf,n[1]*=bf,n},n}function hl(t,n,e,r,i,o){if(e){var a=Tf(n),u=Cf(n),c=r*e;null==i?(i=n+r*_f,o=n-c/2):(i=dl(a,i),o=dl(a,o),(r>0?i<o:i>o)&&(i+=r*_f));for(var f,s=i;r>0?s>o:s<o;s-=c)f=ds([a,-u*Tf(s),-u*Cf(s)]),t.point(f[0],f[1])}}function dl(t,n){(n=ps(n))[0]-=t,bs(n);var e=Df(-n[1]);return((-n[2]<0?-e:e)+_f-df)%_f}function pl(){var t,n=[];return{point:function(n,e,r){t.push([n,e,r])},lineStart:function(){n.push(t=[])},lineEnd:qf,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function gl(t,n){return xf(t[0]-n[0])<df&&xf(t[1]-n[1])<df}function yl(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function vl(t,n,e,r,i){var o,a,u=[],c=[];if(t.forEach((function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],a=t[n];if(gl(r,a)){if(!r[2]&&!a[2]){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);return void i.lineEnd()}a[0]+=2*df}u.push(e=new yl(r,t,null,!0)),c.push(e.o=new yl(r,null,e,!1)),u.push(e=new yl(a,t,null,!1)),c.push(e.o=new yl(a,null,e,!0))}})),u.length){for(c.sort(n),_l(u),_l(c),o=0,a=c.length;o<a;++o)c[o].e=e=!e;for(var f,s,l=u[0];;){for(var h=l,d=!0;h.v;)if((h=h.n)===l)return;f=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(d)for(o=0,a=f.length;o<a;++o)i.point((s=f[o])[0],s[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(d)for(f=h.p.z,o=f.length-1;o>=0;--o)i.point((s=f[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}f=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function _l(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function bl(t){return xf(t[0])<=gf?t[0]:Pf(t[0])*((xf(t[0])+gf)%_f-gf)}function ml(t,n){var e=bl(n),r=n[1],i=Cf(r),o=[Cf(e),-Tf(e),0],a=0,u=0,c=new T;1===i?r=yf+df:-1===i&&(r=-yf-df);for(var f=0,s=t.length;f<s;++f)if(h=(l=t[f]).length)for(var l,h,d=l[h-1],p=bl(d),g=d[1]/2+vf,y=Cf(g),v=Tf(g),_=0;_<h;++_,p=m,y=w,v=M,d=b){var b=l[_],m=bl(b),x=b[1]/2+vf,w=Cf(x),M=Tf(x),A=m-p,S=A>=0?1:-1,E=S*A,N=E>gf,k=y*w;if(c.add(Mf(k*S*Cf(E),v*M+k*Tf(E))),a+=N?A+S*_f:A,N^p>=e^m>=e){var C=ys(ps(d),ps(b));bs(C);var P=ys(o,C);bs(P);var z=(N^A>=0?-1:1)*Rf(P[2]);(r>z||r===z&&(C[0]||C[1]))&&(u+=N^A>=0?1:-1)}}return(a<-df||a<df&&c<-pf)^1&u}function xl(t,n,e,r){return function(i){var o,a,u,c=n(i),f=pl(),s=n(f),l=!1,h={point:d,lineStart:g,lineEnd:y,polygonStart:function(){h.point=v,h.lineStart=_,h.lineEnd=b,a=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=g,h.lineEnd=y,a=ft(a);var t=ml(o,r);a.length?(l||(i.polygonStart(),l=!0),vl(a,Ml,t,e,i)):t&&(l||(i.polygonStart(),l=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),l&&(i.polygonEnd(),l=!1),a=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){c.point(t,n)}function g(){h.point=p,c.lineStart()}function y(){h.point=d,c.lineEnd()}function v(t,n){u.push([t,n]),s.point(t,n)}function _(){s.lineStart(),u=[]}function b(){v(u[0][0],u[0][1]),s.lineEnd();var t,n,e,r,c=s.clean(),h=f.result(),d=h.length;if(u.pop(),o.push(u),u=null,d)if(1&c){if((n=(e=h[0]).length-1)>0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t<n;++t)i.point((r=e[t])[0],r[1]);i.lineEnd()}}else d>1&&2&c&&h.push(h.pop().concat(h.shift())),a.push(h.filter(wl))}return h}}function wl(t){return t.length>1}function Ml(t,n){return((t=t.x)[0]<0?t[1]-yf-df:yf-t[1])-((n=n.x)[0]<0?n[1]-yf-df:yf-n[1])}al.invert=al;var Tl=xl((function(){return!0}),(function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?gf:-gf,c=xf(o-e);xf(c-gf)<df?(t.point(e,r=(r+a)/2>0?yf:-yf),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&c>=gf&&(xf(e-i)<df&&(e-=i*df),xf(o-u)<df&&(o-=u*df),r=function(t,n,e,r){var i,o,a=Cf(t-e);return xf(a)>df?wf((Cf(n)*(o=Tf(r))*Cf(e)-Cf(r)*(i=Tf(n))*Cf(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}),(function(t,n,e,r){var i;if(null==t)i=e*yf,r.point(-gf,i),r.point(0,i),r.point(gf,i),r.point(gf,0),r.point(gf,-i),r.point(0,-i),r.point(-gf,-i),r.point(-gf,0),r.point(-gf,i);else if(xf(t[0]-n[0])>df){var o=t[0]<n[0]?gf:-gf;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])}),[-gf,-yf]);function Al(t){var n=Tf(t),e=2*mf,r=n>0,i=xf(n)>df;function o(t,e){return Tf(t)*Tf(e)>n}function a(t,e,r){var i=[1,0,0],o=ys(ps(t),ps(e)),a=gs(o,o),u=o[0],c=a-u*u;if(!c)return!r&&t;var f=n*a/c,s=-n*u/c,l=ys(i,o),h=_s(i,f);vs(h,_s(o,s));var d=l,p=gs(h,d),g=gs(d,d),y=p*p-g*(gs(h,h)-1);if(!(y<0)){var v=zf(y),_=_s(d,(-p-v)/g);if(vs(_,h),_=ds(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x<m&&(b=m,m=x,x=b);var T=x-m,A=xf(T-gf)<df;if(!A&&M<w&&(b=w,w=M,M=b),A||T<df?A?w+M>0^_[1]<(xf(_[0]-m)<df?w:M):w<=_[1]&&_[1]<=M:T>gf^(m<=_[0]&&_[0]<=x)){var S=_s(d,(-p+v)/g);return vs(S,h),[_,ds(S)]}}}function u(n,e){var i=r?t:gf-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return xl(o,(function(t){var n,e,c,f,s;return{lineStart:function(){f=c=!1,s=1},point:function(l,h){var d,p=[l,h],g=o(l,h),y=r?g?0:u(l,h):g?u(l+(l<0?gf:-gf),h):0;if(!n&&(f=c=g)&&t.lineStart(),g!==c&&(!(d=a(n,p))||gl(n,d)||gl(p,d))&&(p[2]=1),g!==c)s=0,g?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1],2),t.lineEnd()),n=d;else if(i&&n&&r^g){var v;y&e||!(v=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(v[0][0],v[0][1]),t.point(v[1][0],v[1][1]),t.lineEnd()):(t.point(v[1][0],v[1][1]),t.lineEnd(),t.lineStart(),t.point(v[0][0],v[0][1],3)))}!g||n&&gl(n,p)||t.point(p[0],p[1]),n=p,c=g,e=y},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return s|(f&&c)<<1}}}),(function(n,r,i,o){hl(o,t,e,i,n,r)}),r?[0,-t]:[-gf,t-gf])}var Sl,El,Nl,kl,Cl=1e9,Pl=-Cl;function zl(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,f){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||c(i,o)<0^u>0)do{f.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else f.point(o[0],o[1])}function a(r,i){return xf(r[0]-t)<df?i>0?0:3:xf(r[0]-e)<df?i>0?2:1:xf(r[1]-n)<df?i>0?1:0:i>0?3:2}function u(t,n){return c(t.x,n.x)}function c(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var c,f,s,l,h,d,p,g,y,v,_,b=a,m=pl(),x={point:w,lineStart:function(){x.point=M,f&&f.push(s=[]);v=!0,y=!1,p=g=NaN},lineEnd:function(){c&&(M(l,h),d&&y&&m.rejoin(),c.push(m.result()));x.point=w,y&&b.lineEnd()},polygonStart:function(){b=m,c=[],f=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=f.length;e<i;++e)for(var o,a,u=f[e],c=1,s=u.length,l=u[0],h=l[0],d=l[1];c<s;++c)o=h,a=d,h=(l=u[c])[0],d=l[1],a<=r?d>r&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(c=ft(c)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&vl(c,u,n,o,a),a.polygonEnd());b=a,c=f=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(f&&s.push([o,a]),v)l=o,h=a,d=u,v=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&y)b.point(o,a);else{var c=[p=Math.max(Pl,Math.min(Cl,p)),g=Math.max(Pl,Math.min(Cl,g))],m=[o=Math.max(Pl,Math.min(Cl,o)),a=Math.max(Pl,Math.min(Cl,a))];!function(t,n,e,r,i,o){var a,u=t[0],c=t[1],f=0,s=1,l=n[0]-u,h=n[1]-c;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a<f)return;a<s&&(s=a)}else if(l>0){if(a>s)return;a>f&&(f=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>f&&(f=a)}else if(l>0){if(a<f)return;a<s&&(s=a)}if(a=r-c,h||!(a>0)){if(a/=h,h<0){if(a<f)return;a<s&&(s=a)}else if(h>0){if(a>s)return;a>f&&(f=a)}if(a=o-c,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>f&&(f=a)}else if(h>0){if(a<f)return;a<s&&(s=a)}return f>0&&(t[0]=u+f*l,t[1]=c+f*h),s<1&&(n[0]=u+s*l,n[1]=c+s*h),!0}}}}}(c,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(y||(b.lineStart(),b.point(c[0],c[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,g=a,y=u}return x}}var $l={sphere:qf,point:qf,lineStart:function(){$l.point=Rl,$l.lineEnd=Dl},lineEnd:qf,polygonStart:qf,polygonEnd:qf};function Dl(){$l.point=$l.lineEnd=qf}function Rl(t,n){El=t*=mf,Nl=Cf(n*=mf),kl=Tf(n),$l.point=Fl}function Fl(t,n){t*=mf;var e=Cf(n*=mf),r=Tf(n),i=xf(t-El),o=Tf(i),a=r*Cf(i),u=kl*e-Nl*r*o,c=Nl*e+kl*r*o;Sl.add(Mf(zf(a*a+u*u),c)),El=t,Nl=e,kl=r}function ql(t){return Sl=new T,Lf(t,$l),+Sl}var Ul=[null,null],Il={type:"LineString",coordinates:Ul};function Ol(t,n){return Ul[0]=t,Ul[1]=n,ql(Il)}var Bl={Feature:function(t,n){return Ll(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(Ll(e[r].geometry,n))return!0;return!1}},Yl={Sphere:function(){return!0},Point:function(t,n){return jl(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(jl(e[r],n))return!0;return!1},LineString:function(t,n){return Hl(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Hl(e[r],n))return!0;return!1},Polygon:function(t,n){return Xl(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Xl(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(Ll(e[r],n))return!0;return!1}};function Ll(t,n){return!(!t||!Yl.hasOwnProperty(t.type))&&Yl[t.type](t,n)}function jl(t,n){return 0===Ol(t,n)}function Hl(t,n){for(var e,r,i,o=0,a=t.length;o<a;o++){if(0===(r=Ol(t[o],n)))return!0;if(o>0&&(i=Ol(t[o],t[o-1]))>0&&e<=i&&r<=i&&(e+r-i)*(1-Math.pow((e-r)/i,2))<pf*i)return!0;e=r}return!1}function Xl(t,n){return!!ml(t.map(Gl),Vl(n))}function Gl(t){return(t=t.map(Vl)).pop(),t}function Vl(t){return[t[0]*mf,t[1]*mf]}function Wl(t,n,e){var r=lt(t,n-df,e).concat(n);return function(t){return r.map((function(n){return[t,n]}))}}function Zl(t,n,e){var r=lt(t,n-df,e).concat(n);return function(t){return r.map((function(n){return[n,t]}))}}function Kl(){var t,n,e,r,i,o,a,u,c,f,s,l,h=10,d=h,p=90,g=360,y=2.5;function v(){return{type:"MultiLineString",coordinates:_()}}function _(){return lt(Af(r/p)*p,e,p).map(s).concat(lt(Af(u/g)*g,a,g).map(l)).concat(lt(Af(n/h)*h,t,h).filter((function(t){return xf(t%p)>df})).map(c)).concat(lt(Af(o/d)*d,i,d).filter((function(t){return xf(t%g)>df})).map(f))}return v.lines=function(){return _().map((function(t){return{type:"LineString",coordinates:t}}))},v.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},v.extent=function(t){return arguments.length?v.extentMajor(t).extentMinor(t):v.extentMinor()},v.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),v.precision(y)):[[r,u],[e,a]]},v.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),v.precision(y)):[[n,o],[t,i]]},v.step=function(t){return arguments.length?v.stepMajor(t).stepMinor(t):v.stepMinor()},v.stepMajor=function(t){return arguments.length?(p=+t[0],g=+t[1],v):[p,g]},v.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],v):[h,d]},v.precision=function(h){return arguments.length?(y=+h,c=Wl(o,i,90),f=Zl(n,t,y),s=Wl(u,a,90),l=Zl(r,e,y),v):y},v.extentMajor([[-180,-90+df],[180,90-df]]).extentMinor([[-180,-80-df],[180,80+df]])}var Ql,Jl,th,nh,eh=t=>t,rh=new T,ih=new T,oh={point:qf,lineStart:qf,lineEnd:qf,polygonStart:function(){oh.lineStart=ah,oh.lineEnd=fh},polygonEnd:function(){oh.lineStart=oh.lineEnd=oh.point=qf,rh.add(xf(ih)),ih=new T},result:function(){var t=rh/2;return rh=new T,t}};function ah(){oh.point=uh}function uh(t,n){oh.point=ch,Ql=th=t,Jl=nh=n}function ch(t,n){ih.add(nh*t-th*n),th=t,nh=n}function fh(){ch(Ql,Jl)}var sh=oh,lh=1/0,hh=lh,dh=-lh,ph=dh,gh={point:function(t,n){t<lh&&(lh=t);t>dh&&(dh=t);n<hh&&(hh=n);n>ph&&(ph=n)},lineStart:qf,lineEnd:qf,polygonStart:qf,polygonEnd:qf,result:function(){var t=[[lh,hh],[dh,ph]];return dh=ph=-(hh=lh=1/0),t}};var yh,vh,_h,bh,mh=gh,xh=0,wh=0,Mh=0,Th=0,Ah=0,Sh=0,Eh=0,Nh=0,kh=0,Ch={point:Ph,lineStart:zh,lineEnd:Rh,polygonStart:function(){Ch.lineStart=Fh,Ch.lineEnd=qh},polygonEnd:function(){Ch.point=Ph,Ch.lineStart=zh,Ch.lineEnd=Rh},result:function(){var t=kh?[Eh/kh,Nh/kh]:Sh?[Th/Sh,Ah/Sh]:Mh?[xh/Mh,wh/Mh]:[NaN,NaN];return xh=wh=Mh=Th=Ah=Sh=Eh=Nh=kh=0,t}};function Ph(t,n){xh+=t,wh+=n,++Mh}function zh(){Ch.point=$h}function $h(t,n){Ch.point=Dh,Ph(_h=t,bh=n)}function Dh(t,n){var e=t-_h,r=n-bh,i=zf(e*e+r*r);Th+=i*(_h+t)/2,Ah+=i*(bh+n)/2,Sh+=i,Ph(_h=t,bh=n)}function Rh(){Ch.point=Ph}function Fh(){Ch.point=Uh}function qh(){Ih(yh,vh)}function Uh(t,n){Ch.point=Ih,Ph(yh=_h=t,vh=bh=n)}function Ih(t,n){var e=t-_h,r=n-bh,i=zf(e*e+r*r);Th+=i*(_h+t)/2,Ah+=i*(bh+n)/2,Sh+=i,Eh+=(i=bh*t-_h*n)*(_h+t),Nh+=i*(bh+n),kh+=3*i,Ph(_h=t,bh=n)}var Oh=Ch;function Bh(t){this._context=t}Bh.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,_f)}},result:qf};var Yh,Lh,jh,Hh,Xh,Gh=new T,Vh={point:qf,lineStart:function(){Vh.point=Wh},lineEnd:function(){Yh&&Zh(Lh,jh),Vh.point=qf},polygonStart:function(){Yh=!0},polygonEnd:function(){Yh=null},result:function(){var t=+Gh;return Gh=new T,t}};function Wh(t,n){Vh.point=Zh,Lh=Hh=t,jh=Xh=n}function Zh(t,n){Hh-=t,Xh-=n,Gh.add(zf(Hh*Hh+Xh*Xh)),Hh=t,Xh=n}var Kh=Vh;let Qh,Jh,td,nd;class ed{constructor(t){this._append=null==t?rd:function(t){const n=Math.floor(t);if(!(n>=0))throw new RangeError(`invalid digits: ${t}`);if(n>15)return rd;if(n!==Qh){const t=10**n;Qh=n,Jh=function(n){let e=1;this._+=n[0];for(const r=n.length;e<r;++e)this._+=Math.round(arguments[e]*t)/t+n[e]}}return Jh}(t),this._radius=4.5,this._=""}pointRadius(t){return this._radius=+t,this}polygonStart(){this._line=0}polygonEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){0===this._line&&(this._+="Z"),this._point=NaN}point(t,n){switch(this._point){case 0:this._append`M${t},${n}`,this._point=1;break;case 1:this._append`L${t},${n}`;break;default:if(this._append`M${t},${n}`,this._radius!==td||this._append!==Jh){const t=this._radius,n=this._;this._="",this._append`m0,${t}a${t},${t} 0 1,1 0,${-2*t}a${t},${t} 0 1,1 0,${2*t}z`,td=t,Jh=this._append,nd=this._,this._=n}this._+=nd}}result(){const t=this._;return this._="",t.length?t:null}}function rd(t){let n=1;this._+=t[0];for(const e=t.length;n<e;++n)this._+=arguments[n]+t[n]}function id(t){return function(n){var e=new od;for(var r in t)e[r]=t[r];return e.stream=n,e}}function od(){}function ad(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),Lf(e,t.stream(mh)),n(mh.result()),null!=r&&t.clipExtent(r),t}function ud(t,n,e){return ad(t,(function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),a=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,u=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([a,u])}),e)}function cd(t,n,e){return ud(t,[[0,0],n],e)}function fd(t,n,e){return ad(t,(function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,a=-i*e[0][1];t.scale(150*i).translate([o,a])}),e)}function sd(t,n,e){return ad(t,(function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],a=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,a])}),e)}od.prototype={constructor:od,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var ld=16,hd=Tf(30*mf);function dd(t,n){return+n?function(t,n){function e(r,i,o,a,u,c,f,s,l,h,d,p,g,y){var v=f-r,_=s-i,b=v*v+_*_;if(b>4*n&&g--){var m=a+h,x=u+d,w=c+p,M=zf(m*m+x*x+w*w),T=Rf(w/=M),A=xf(xf(w)-1)<df||xf(o-l)<df?(o+l)/2:Mf(x,m),S=t(A,T),E=S[0],N=S[1],k=E-r,C=N-i,P=_*k-v*C;(P*P/b>n||xf((v*k+_*C)/b-.5)>.3||a*h+u*d+c*p<hd)&&(e(r,i,o,a,u,c,E,N,A,m/=M,x/=M,w,g,y),y.point(E,N),e(E,N,A,m,x,w,f,s,l,h,d,p,g,y))}}return function(n){var r,i,o,a,u,c,f,s,l,h,d,p,g={point:y,lineStart:v,lineEnd:b,polygonStart:function(){n.polygonStart(),g.lineStart=m},polygonEnd:function(){n.polygonEnd(),g.lineStart=v}};function y(e,r){e=t(e,r),n.point(e[0],e[1])}function v(){s=NaN,g.point=_,n.lineStart()}function _(r,i){var o=ps([r,i]),a=t(r,i);e(s,l,f,h,d,p,s=a[0],l=a[1],f=r,h=o[0],d=o[1],p=o[2],ld,n),n.point(s,l)}function b(){g.point=y,n.lineEnd()}function m(){v(),g.point=x,g.lineEnd=w}function x(t,n){_(r=t,n),i=s,o=l,a=h,u=d,c=p,g.point=_}function w(){e(s,l,f,h,d,p,i,o,r,a,u,c,ld,n),g.lineEnd=b,b()}return g}}(t,n):function(t){return id({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}(t)}var pd=id({point:function(t,n){this.stream.point(t*mf,n*mf)}});function gd(t,n,e,r,i,o){if(!o)return function(t,n,e,r,i){function o(o,a){return[n+t*(o*=r),e-t*(a*=i)]}return o.invert=function(o,a){return[(o-n)/t*r,(e-a)/t*i]},o}(t,n,e,r,i);var a=Tf(o),u=Cf(o),c=a*t,f=u*t,s=a/t,l=u/t,h=(u*e-a*n)/t,d=(u*n+a*e)/t;function p(t,o){return[c*(t*=r)-f*(o*=i)+n,e-f*t-c*o]}return p.invert=function(t,n){return[r*(s*t-l*n+h),i*(d-l*t-s*n)]},p}function yd(t){return vd((function(){return t}))()}function vd(t){var n,e,r,i,o,a,u,c,f,s,l=150,h=480,d=250,p=0,g=0,y=0,v=0,_=0,b=0,m=1,x=1,w=null,M=Tl,T=null,A=eh,S=.5;function E(t){return c(t[0]*mf,t[1]*mf)}function N(t){return(t=c.invert(t[0],t[1]))&&[t[0]*bf,t[1]*bf]}function k(){var t=gd(l,0,0,m,x,b).apply(null,n(p,g)),r=gd(l,h-t[0],d-t[1],m,x,b);return e=ul(y,v,_),u=ol(n,r),c=ol(e,u),a=dd(u,S),C()}function C(){return f=s=null,E}return E.stream=function(t){return f&&s===t?f:f=pd(function(t){return id({point:function(n,e){var r=t(n,e);return this.stream.point(r[0],r[1])}})}(e)(M(a(A(s=t)))))},E.preclip=function(t){return arguments.length?(M=t,w=void 0,C()):M},E.postclip=function(t){return arguments.length?(A=t,T=r=i=o=null,C()):A},E.clipAngle=function(t){return arguments.length?(M=+t?Al(w=t*mf):(w=null,Tl),C()):w*bf},E.clipExtent=function(t){return arguments.length?(A=null==t?(T=r=i=o=null,eh):zl(T=+t[0][0],r=+t[0][1],i=+t[1][0],o=+t[1][1]),C()):null==T?null:[[T,r],[i,o]]},E.scale=function(t){return arguments.length?(l=+t,k()):l},E.translate=function(t){return arguments.length?(h=+t[0],d=+t[1],k()):[h,d]},E.center=function(t){return arguments.length?(p=t[0]%360*mf,g=t[1]%360*mf,k()):[p*bf,g*bf]},E.rotate=function(t){return arguments.length?(y=t[0]%360*mf,v=t[1]%360*mf,_=t.length>2?t[2]%360*mf:0,k()):[y*bf,v*bf,_*bf]},E.angle=function(t){return arguments.length?(b=t%360*mf,k()):b*bf},E.reflectX=function(t){return arguments.length?(m=t?-1:1,k()):m<0},E.reflectY=function(t){return arguments.length?(x=t?-1:1,k()):x<0},E.precision=function(t){return arguments.length?(a=dd(u,S=t*t),C()):zf(S)},E.fitExtent=function(t,n){return ud(E,t,n)},E.fitSize=function(t,n){return cd(E,t,n)},E.fitWidth=function(t,n){return fd(E,t,n)},E.fitHeight=function(t,n){return sd(E,t,n)},function(){return n=t.apply(this,arguments),E.invert=n.invert&&N,k()}}function _d(t){var n=0,e=gf/3,r=vd(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*mf,e=t[1]*mf):[n*bf,e*bf]},i}function bd(t,n){var e=Cf(t),r=(e+Cf(n))/2;if(xf(r)<df)return function(t){var n=Tf(t);function e(t,e){return[t*n,Cf(e)/n]}return e.invert=function(t,e){return[t/n,Rf(e*n)]},e}(t);var i=1+e*(2*r-e),o=zf(i)/r;function a(t,n){var e=zf(i-2*r*Cf(n))/r;return[e*Cf(t*=r),o-e*Tf(t)]}return a.invert=function(t,n){var e=o-n,a=Mf(t,xf(e))*Pf(e);return e*r<0&&(a-=gf*Pf(t)*Pf(e)),[a/r,Rf((i-(t*t+e*e)*r*r)/(2*r))]},a}function md(){return _d(bd).scale(155.424).center([0,33.6442])}function xd(){return md().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])}function wd(t){return function(n,e){var r=Tf(n),i=Tf(e),o=t(r*i);return o===1/0?[2,0]:[o*i*Cf(n),o*Cf(e)]}}function Md(t){return function(n,e){var r=zf(n*n+e*e),i=t(r),o=Cf(i),a=Tf(i);return[Mf(n*o,r*a),Rf(r&&e*o/r)]}}var Td=wd((function(t){return zf(2/(1+t))}));Td.invert=Md((function(t){return 2*Rf(t/2)}));var Ad=wd((function(t){return(t=Df(t))&&t/Cf(t)}));function Sd(t,n){return[t,Nf($f((yf+n)/2))]}function Ed(t){var n,e,r,i=yd(t),o=i.center,a=i.scale,u=i.translate,c=i.clipExtent,f=null;function s(){var o=gf*a(),u=i(ll(i.rotate()).invert([0,0]));return c(null==f?[[u[0]-o,u[1]-o],[u[0]+o,u[1]+o]]:t===Sd?[[Math.max(u[0]-o,f),n],[Math.min(u[0]+o,e),r]]:[[f,Math.max(u[1]-o,n)],[e,Math.min(u[1]+o,r)]])}return i.scale=function(t){return arguments.length?(a(t),s()):a()},i.translate=function(t){return arguments.length?(u(t),s()):u()},i.center=function(t){return arguments.length?(o(t),s()):o()},i.clipExtent=function(t){return arguments.length?(null==t?f=n=e=r=null:(f=+t[0][0],n=+t[0][1],e=+t[1][0],r=+t[1][1]),s()):null==f?null:[[f,n],[e,r]]},s()}function Nd(t){return $f((yf+t)/2)}function kd(t,n){var e=Tf(t),r=t===n?Cf(t):Nf(e/Tf(n))/Nf(Nd(n)/Nd(t)),i=e*kf(Nd(t),r)/r;if(!r)return Sd;function o(t,n){i>0?n<-yf+df&&(n=-yf+df):n>yf-df&&(n=yf-df);var e=i/kf(Nd(n),r);return[e*Cf(r*t),i-e*Tf(r*t)]}return o.invert=function(t,n){var e=i-n,o=Pf(r)*zf(t*t+e*e),a=Mf(t,xf(e))*Pf(e);return e*r<0&&(a-=gf*Pf(t)*Pf(e)),[a/r,2*wf(kf(i/o,1/r))-yf]},o}function Cd(t,n){return[t,n]}function Pd(t,n){var e=Tf(t),r=t===n?Cf(t):(e-Tf(n))/(n-t),i=e/r+t;if(xf(r)<df)return Cd;function o(t,n){var e=i-n,o=r*t;return[e*Cf(o),i-e*Tf(o)]}return o.invert=function(t,n){var e=i-n,o=Mf(t,xf(e))*Pf(e);return e*r<0&&(o-=gf*Pf(t)*Pf(e)),[o/r,i-Pf(r)*zf(t*t+e*e)]},o}Ad.invert=Md((function(t){return t})),Sd.invert=function(t,n){return[t,2*wf(Sf(n))-yf]},Cd.invert=Cd;var zd=1.340264,$d=-.081106,Dd=893e-6,Rd=.003796,Fd=zf(3)/2;function qd(t,n){var e=Rf(Fd*Cf(n)),r=e*e,i=r*r*r;return[t*Tf(e)/(Fd*(zd+3*$d*r+i*(7*Dd+9*Rd*r))),e*(zd+$d*r+i*(Dd+Rd*r))]}function Ud(t,n){var e=Tf(n),r=Tf(t)*e;return[e*Cf(t)/r,Cf(n)/r]}function Id(t,n){var e=n*n,r=e*e;return[t*(.8707-.131979*e+r*(r*(.003971*e-.001529*r)-.013791)),n*(1.007226+e*(.015085+r*(.028874*e-.044475-.005916*r)))]}function Od(t,n){return[Tf(n)*Cf(t),Cf(n)]}function Bd(t,n){var e=Tf(n),r=1+Tf(t)*e;return[e*Cf(t)/r,Cf(n)/r]}function Yd(t,n){return[Nf($f((yf+n)/2)),-t]}function Ld(t,n){return t.parent===n.parent?1:2}function jd(t,n){return t+n.x}function Hd(t,n){return Math.max(t,n.y)}function Xd(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function Gd(t,n){t instanceof Map?(t=[void 0,t],void 0===n&&(n=Wd)):void 0===n&&(n=Vd);for(var e,r,i,o,a,u=new Qd(t),c=[u];e=c.pop();)if((i=n(e.data))&&(a=(i=Array.from(i)).length))for(e.children=i,o=a-1;o>=0;--o)c.push(r=i[o]=new Qd(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(Kd)}function Vd(t){return t.children}function Wd(t){return Array.isArray(t)?t[1]:null}function Zd(t){void 0!==t.data.value&&(t.value=t.data.value),t.data=t.data.data}function Kd(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function Qd(t){this.data=t,this.depth=this.height=0,this.parent=null}function Jd(t){return null==t?null:tp(t)}function tp(t){if("function"!=typeof t)throw new Error;return t}function np(){return 0}function ep(t){return function(){return t}}qd.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(zd+$d*i+o*(Dd+Rd*i))-n)/(zd+3*$d*i+o*(7*Dd+9*Rd*i)))*r)*i*i,!(xf(e)<pf));++a);return[Fd*t*(zd+3*$d*i+o*(7*Dd+9*Rd*i))/Tf(r),Rf(Cf(r)/Fd)]},Ud.invert=Md(wf),Id.invert=function(t,n){var e,r=n,i=25;do{var o=r*r,a=o*o;r-=e=(r*(1.007226+o*(.015085+a*(.028874*o-.044475-.005916*a)))-n)/(1.007226+o*(.045255+a*(.259866*o-.311325-.005916*11*a)))}while(xf(e)>df&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},Od.invert=Md(Rf),Bd.invert=Md((function(t){return 2*wf(t)})),Yd.invert=function(t,n){return[-n,2*wf(Sf(t))-yf]},Qd.prototype=Gd.prototype={constructor:Qd,count:function(){return this.eachAfter(Xd)},each:function(t,n){let e=-1;for(const r of this)t.call(n,r,++e,this);return this},eachAfter:function(t,n){for(var e,r,i,o=this,a=[o],u=[],c=-1;o=a.pop();)if(u.push(o),e=o.children)for(r=0,i=e.length;r<i;++r)a.push(e[r]);for(;o=u.pop();)t.call(n,o,++c,this);return this},eachBefore:function(t,n){for(var e,r,i=this,o=[i],a=-1;i=o.pop();)if(t.call(n,i,++a,this),e=i.children)for(r=e.length-1;r>=0;--r)o.push(e[r]);return this},find:function(t,n){let e=-1;for(const r of this)if(t.call(n,r,++e,this))return r},sum:function(t){return this.eachAfter((function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e}))},sort:function(t){return this.eachBefore((function(n){n.children&&n.children.sort(t)}))},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;t=e.pop(),n=r.pop();for(;t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){return Array.from(this)},leaves:function(){var t=[];return this.eachBefore((function(n){n.children||t.push(n)})),t},links:function(){var t=this,n=[];return t.each((function(e){e!==t&&n.push({source:e.parent,target:e})})),n},copy:function(){return Gd(this).eachBefore(Zd)},[Symbol.iterator]:function*(){var t,n,e,r,i=this,o=[i];do{for(t=o.reverse(),o=[];i=t.pop();)if(yield i,n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e])}while(o.length)}};const rp=1664525,ip=1013904223,op=4294967296;function ap(){let t=1;return()=>(t=(rp*t+ip)%op)/op}function up(t,n){for(var e,r,i=0,o=(t=function(t,n){let e,r,i=t.length;for(;i;)r=n()*i--|0,e=t[i],t[i]=t[r],t[r]=e;return t}(Array.from(t),n)).length,a=[];i<o;)e=t[i],r&&sp(r,e)?++i:(r=hp(a=cp(a,e)),i=0);return r}function cp(t,n){var e,r;if(lp(n,t))return[n];for(e=0;e<t.length;++e)if(fp(n,t[e])&&lp(dp(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(fp(dp(t[e],t[r]),n)&&fp(dp(t[e],n),t[r])&&fp(dp(t[r],n),t[e])&&lp(pp(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function fp(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function sp(t,n){var e=t.r-n.r+1e-9*Math.max(t.r,n.r,1),r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function lp(t,n){for(var e=0;e<n.length;++e)if(!sp(t,n[e]))return!1;return!0}function hp(t){switch(t.length){case 1:return function(t){return{x:t.x,y:t.y,r:t.r}}(t[0]);case 2:return dp(t[0],t[1]);case 3:return pp(t[0],t[1],t[2])}}function dp(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,a=n.y,u=n.r,c=o-e,f=a-r,s=u-i,l=Math.sqrt(c*c+f*f);return{x:(e+o+c/l*s)/2,y:(r+a+f/l*s)/2,r:(l+i+u)/2}}function pp(t,n,e){var r=t.x,i=t.y,o=t.r,a=n.x,u=n.y,c=n.r,f=e.x,s=e.y,l=e.r,h=r-a,d=r-f,p=i-u,g=i-s,y=c-o,v=l-o,_=r*r+i*i-o*o,b=_-a*a-u*u+c*c,m=_-f*f-s*s+l*l,x=d*p-h*g,w=(p*m-g*b)/(2*x)-r,M=(g*y-p*v)/x,T=(d*b-h*m)/(2*x)-i,A=(h*v-d*y)/x,S=M*M+A*A-1,E=2*(o+w*M+T*A),N=w*w+T*T-o*o,k=-(Math.abs(S)>1e-6?(E+Math.sqrt(E*E-4*S*N))/(2*S):N/E);return{x:r+w+M*k,y:i+T+A*k,r:k}}function gp(t,n,e){var r,i,o,a,u=t.x-n.x,c=t.y-n.y,f=u*u+c*c;f?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(f+a-i)/(2*f),o=Math.sqrt(Math.max(0,a/f-r*r)),e.x=t.x-r*u-o*c,e.y=t.y-r*c+o*u):(r=(f+i-a)/(2*f),o=Math.sqrt(Math.max(0,i/f-r*r)),e.x=n.x+r*u-o*c,e.y=n.y+r*c+o*u)):(e.x=n.x+e.r,e.y=n.y)}function yp(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function vp(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function _p(t){this._=t,this.next=null,this.previous=null}function bp(t,n){if(!(o=(t=function(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}(t)).length))return 0;var e,r,i,o,a,u,c,f,s,l,h;if((e=t[0]).x=0,e.y=0,!(o>1))return e.r;if(r=t[1],e.x=-r.r,r.x=e.r,r.y=0,!(o>2))return e.r+r.r;gp(r,e,i=t[2]),e=new _p(e),r=new _p(r),i=new _p(i),e.next=i.previous=r,r.next=e.previous=i,i.next=r.previous=e;t:for(c=3;c<o;++c){gp(e._,r._,i=t[c]),i=new _p(i),f=r.next,s=e.previous,l=r._.r,h=e._.r;do{if(l<=h){if(yp(f._,i._)){r=f,e.next=r,r.previous=e,--c;continue t}l+=f._.r,f=f.next}else{if(yp(s._,i._)){(e=s).next=r,r.previous=e,--c;continue t}h+=s._.r,s=s.previous}}while(f!==s.next);for(i.previous=e,i.next=r,e.next=r.previous=r=i,a=vp(e);(i=i.next)!==r;)(u=vp(i))<a&&(e=i,a=u);r=e.next}for(e=[r._],i=r;(i=i.next)!==r;)e.push(i._);for(i=up(e,n),c=0;c<o;++c)(e=t[c]).x-=i.x,e.y-=i.y;return i.r}function mp(t){return Math.sqrt(t.value)}function xp(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function wp(t,n,e){return function(r){if(i=r.children){var i,o,a,u=i.length,c=t(r)*n||0;if(c)for(o=0;o<u;++o)i[o].r+=c;if(a=bp(i,e),c)for(o=0;o<u;++o)i[o].r-=c;r.r=a+c}}}function Mp(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Tp(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function Ap(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(r-n)/t.value;++u<c;)(o=a[u]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*f}var Sp={depth:-1},Ep={},Np={};function kp(t){return t.id}function Cp(t){return t.parentId}function Pp(t){let n=t.length;if(n<2)return"";for(;--n>1&&!zp(t,n););return t.slice(0,n)}function zp(t,n){if("/"===t[n]){let e=0;for(;n>0&&"\\"===t[--n];)++e;if(!(1&e))return!0}return!1}function $p(t,n){return t.parent===n.parent?1:2}function Dp(t){var n=t.children;return n?n[0]:t.t}function Rp(t){var n=t.children;return n?n[n.length-1]:t.t}function Fp(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function qp(t,n,e){return t.a.parent===n.parent?t.a:e}function Up(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Ip(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(i-e)/t.value;++u<c;)(o=a[u]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*f}Up.prototype=Object.create(Qd.prototype);var Op=(1+Math.sqrt(5))/2;function Bp(t,n,e,r,i,o){for(var a,u,c,f,s,l,h,d,p,g,y,v=[],_=n.children,b=0,m=0,x=_.length,w=n.value;b<x;){c=i-e,f=o-r;do{s=_[m++].value}while(!s&&m<x);for(l=h=s,y=s*s*(g=Math.max(f/c,c/f)/(w*t)),p=Math.max(h/y,y/l);m<x;++m){if(s+=u=_[m].value,u<l&&(l=u),u>h&&(h=u),y=s*s*g,(d=Math.max(h/y,y/l))>p){s-=u;break}p=d}v.push(a={value:s,dice:c<f,children:_.slice(b,m)}),a.dice?Ap(a,e,r,i,w?r+=f*s/w:o):Ip(a,e,r,w?e+=c*s/w:i,o),w-=s,b=m}return v}var Yp=function t(n){function e(t,e,r,i,o){Bp(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Op);var Lp=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,c,f,s,l=-1,h=a.length,d=t.value;++l<h;){for(c=(u=a[l]).children,f=u.value=0,s=c.length;f<s;++f)u.value+=c[f].value;u.dice?Ap(u,e,r,i,d?r+=(o-r)*u.value/d:o):Ip(u,e,r,d?e+=(i-e)*u.value/d:i,o),d-=u.value}else t._squarify=a=Bp(n,t,e,r,i,o),a.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Op);function jp(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function Hp(t,n){return t[0]-n[0]||t[1]-n[1]}function Xp(t){const n=t.length,e=[0,1];let r,i=2;for(r=2;r<n;++r){for(;i>1&&jp(t[e[i-2]],t[e[i-1]],t[r])<=0;)--i;e[i++]=r}return e.slice(0,i)}var Gp=Math.random,Vp=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(Gp),Wp=function t(n){function e(t,e){return arguments.length<2&&(e=t,t=0),t=Math.floor(t),e=Math.floor(e)-t,function(){return Math.floor(n()*e+t)}}return e.source=t,e}(Gp),Zp=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(Gp),Kp=function t(n){var e=Zp.source(n);function r(){var t=e.apply(this,arguments);return function(){return Math.exp(t())}}return r.source=t,r}(Gp),Qp=function t(n){function e(t){return(t=+t)<=0?()=>0:function(){for(var e=0,r=t;r>1;--r)e+=n();return e+r*n()}}return e.source=t,e}(Gp),Jp=function t(n){var e=Qp.source(n);function r(t){if(0==(t=+t))return n;var r=e(t);return function(){return r()/t}}return r.source=t,r}(Gp),tg=function t(n){function e(t){return function(){return-Math.log1p(-n())/t}}return e.source=t,e}(Gp),ng=function t(n){function e(t){if((t=+t)<0)throw new RangeError("invalid alpha");return t=1/-t,function(){return Math.pow(1-n(),t)}}return e.source=t,e}(Gp),eg=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return function(){return Math.floor(n()+t)}}return e.source=t,e}(Gp),rg=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return 0===t?()=>1/0:1===t?()=>1:(t=Math.log1p(-t),function(){return 1+Math.floor(Math.log1p(-n())/t)})}return e.source=t,e}(Gp),ig=function t(n){var e=Zp.source(n)();function r(t,r){if((t=+t)<0)throw new RangeError("invalid k");if(0===t)return()=>0;if(r=null==r?1:+r,1===t)return()=>-Math.log1p(-n())*r;var i=(t<1?t+1:t)-1/3,o=1/(3*Math.sqrt(i)),a=t<1?()=>Math.pow(n(),1/t):()=>1;return function(){do{do{var t=e(),u=1+o*t}while(u<=0);u*=u*u;var c=1-n()}while(c>=1-.0331*t*t*t*t&&Math.log(c)>=.5*t*t+i*(1-u+Math.log(u)));return i*u*a()*r}}return r.source=t,r}(Gp),og=function t(n){var e=ig.source(n);function r(t,n){var r=e(t),i=e(n);return function(){var t=r();return 0===t?0:t/(t+i())}}return r.source=t,r}(Gp),ag=function t(n){var e=rg.source(n),r=og.source(n);function i(t,n){return t=+t,(n=+n)>=1?()=>t:n<=0?()=>0:function(){for(var i=0,o=t,a=n;o*a>16&&o*(1-a)>16;){var u=Math.floor((o+1)*a),c=r(u,o-u+1)();c<=a?(i+=u,o-=u,a=(a-c)/(1-c)):(o=u-1,a/=c)}for(var f=a<.5,s=e(f?a:1-a),l=s(),h=0;l<=o;++h)l+=s();return i+(f?h:o-h)}}return i.source=t,i}(Gp),ug=function t(n){function e(t,e,r){var i;return 0==(t=+t)?i=t=>-Math.log(t):(t=1/t,i=n=>Math.pow(n,t)),e=null==e?0:+e,r=null==r?1:+r,function(){return e+r*i(-Math.log1p(-n()))}}return e.source=t,e}(Gp),cg=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){return t+e*Math.tan(Math.PI*n())}}return e.source=t,e}(Gp),fg=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){var r=n();return t+e*Math.log(r/(1-r))}}return e.source=t,e}(Gp),sg=function t(n){var e=ig.source(n),r=ag.source(n);function i(t){return function(){for(var i=0,o=t;o>16;){var a=Math.floor(.875*o),u=e(a)();if(u>o)return i+r(a-1,o/u)();i+=a,o-=u}for(var c=-Math.log1p(-n()),f=0;c<=o;++f)c-=Math.log1p(-n());return i+f}}return i.source=t,i}(Gp);const lg=1/4294967296;function hg(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function dg(t,n){switch(arguments.length){case 0:break;case 1:"function"==typeof t?this.interpolator(t):this.range(t);break;default:this.domain(t),"function"==typeof n?this.interpolator(n):this.range(n)}return this}const pg=Symbol("implicit");function gg(){var t=new InternMap,n=[],e=[],r=pg;function i(i){let o=t.get(i);if(void 0===o){if(r!==pg)return r;t.set(i,o=n.push(i)-1)}return e[o%e.length]}return i.domain=function(e){if(!arguments.length)return n.slice();n=[],t=new InternMap;for(const r of e)t.has(r)||t.set(r,n.push(r)-1);return i},i.range=function(t){return arguments.length?(e=Array.from(t),i):e.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return gg(n,e).unknown(r)},hg.apply(i,arguments),i}function yg(){var t,n,e=gg().unknown(void 0),r=e.domain,i=e.range,o=0,a=1,u=!1,c=0,f=0,s=.5;function l(){var e=r().length,l=a<o,h=l?a:o,d=l?o:a;t=(d-h)/Math.max(1,e-c+2*f),u&&(t=Math.floor(t)),h+=(d-h-t*(e-c))*s,n=t*(1-c),u&&(h=Math.round(h),n=Math.round(n));var p=lt(e).map((function(n){return h+t*n}));return i(l?p.reverse():p)}return delete e.unknown,e.domain=function(t){return arguments.length?(r(t),l()):r()},e.range=function(t){return arguments.length?([o,a]=t,o=+o,a=+a,l()):[o,a]},e.rangeRound=function(t){return[o,a]=t,o=+o,a=+a,u=!0,l()},e.bandwidth=function(){return n},e.step=function(){return t},e.round=function(t){return arguments.length?(u=!!t,l()):u},e.padding=function(t){return arguments.length?(c=Math.min(1,f=+t),l()):c},e.paddingInner=function(t){return arguments.length?(c=Math.min(1,t),l()):c},e.paddingOuter=function(t){return arguments.length?(f=+t,l()):f},e.align=function(t){return arguments.length?(s=Math.max(0,Math.min(1,t)),l()):s},e.copy=function(){return yg(r(),[o,a]).round(u).paddingInner(c).paddingOuter(f).align(s)},hg.apply(l(),arguments)}function vg(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return vg(n())},t}function _g(t){return+t}var bg=[0,1];function mg(t){return t}function xg(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:function(t){return function(){return t}}(isNaN(n)?NaN:.5)}function wg(t,n,e){var r=t[0],i=t[1],o=n[0],a=n[1];return i<r?(r=xg(i,r),o=e(a,o)):(r=xg(r,i),o=e(o,a)),function(t){return o(r(t))}}function Mg(t,n,e){var r=Math.min(t.length,n.length)-1,i=new Array(r),o=new Array(r),a=-1;for(t[r]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<r;)i[a]=xg(t[a],t[a+1]),o[a]=e(n[a],n[a+1]);return function(n){var e=s(t,n,1,r)-1;return o[e](i[e](n))}}function Tg(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp()).unknown(t.unknown())}function Ag(){var t,n,e,r,i,o,a=bg,u=bg,c=Gr,f=mg;function s(){var t=Math.min(a.length,u.length);return f!==mg&&(f=function(t,n){var e;return t>n&&(e=t,t=n,n=e),function(e){return Math.max(t,Math.min(n,e))}}(a[0],a[t-1])),r=t>2?Mg:wg,i=o=null,l}function l(n){return null==n||isNaN(n=+n)?e:(i||(i=r(a.map(t),u,c)))(t(f(n)))}return l.invert=function(e){return f(n((o||(o=r(u,a.map(t),Yr)))(e)))},l.domain=function(t){return arguments.length?(a=Array.from(t,_g),s()):a.slice()},l.range=function(t){return arguments.length?(u=Array.from(t),s()):u.slice()},l.rangeRound=function(t){return u=Array.from(t),c=Vr,s()},l.clamp=function(t){return arguments.length?(f=!!t||mg,s()):f!==mg},l.interpolate=function(t){return arguments.length?(c=t,s()):c},l.unknown=function(t){return arguments.length?(e=t,l):e},function(e,r){return t=e,n=r,s()}}function Sg(){return Ag()(mg,mg)}function Eg(n,e,r,i){var o,a=W(n,e,r);switch((i=Jc(null==i?",f":i)).type){case"s":var u=Math.max(Math.abs(n),Math.abs(e));return null!=i.precision||isNaN(o=lf(a,u))||(i.precision=o),t.formatPrefix(i,u);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=hf(a,Math.max(Math.abs(n),Math.abs(e))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=sf(a))||(i.precision=o-2*("%"===i.type))}return t.format(i)}function Ng(t){var n=t.domain;return t.ticks=function(t){var e=n();return G(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){var r=n();return Eg(r[0],r[r.length-1],null==t?10:t,e)},t.nice=function(e){null==e&&(e=10);var r,i,o=n(),a=0,u=o.length-1,c=o[a],f=o[u],s=10;for(f<c&&(i=c,c=f,f=i,i=a,a=u,u=i);s-- >0;){if((i=V(c,f,e))===r)return o[a]=c,o[u]=f,n(o);if(i>0)c=Math.floor(c/i)*i,f=Math.ceil(f/i)*i;else{if(!(i<0))break;c=Math.ceil(c*i)/i,f=Math.floor(f*i)/i}r=i}return t},t}function kg(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a<o&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function Cg(t){return Math.log(t)}function Pg(t){return Math.exp(t)}function zg(t){return-Math.log(-t)}function $g(t){return-Math.exp(-t)}function Dg(t){return isFinite(t)?+("1e"+t):t<0?0:t}function Rg(t){return(n,e)=>-t(-n,e)}function Fg(n){const e=n(Cg,Pg),r=e.domain;let i,o,a=10;function u(){return i=function(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),n=>Math.log(n)/t)}(a),o=function(t){return 10===t?Dg:t===Math.E?Math.exp:n=>Math.pow(t,n)}(a),r()[0]<0?(i=Rg(i),o=Rg(o),n(zg,$g)):n(Cg,Pg),e}return e.base=function(t){return arguments.length?(a=+t,u()):a},e.domain=function(t){return arguments.length?(r(t),u()):r()},e.ticks=t=>{const n=r();let e=n[0],u=n[n.length-1];const c=u<e;c&&([e,u]=[u,e]);let f,s,l=i(e),h=i(u);const d=null==t?10:+t;let p=[];if(!(a%1)&&h-l<d){if(l=Math.floor(l),h=Math.ceil(h),e>0){for(;l<=h;++l)for(f=1;f<a;++f)if(s=l<0?f/o(-l):f*o(l),!(s<e)){if(s>u)break;p.push(s)}}else for(;l<=h;++l)for(f=a-1;f>=1;--f)if(s=l>0?f/o(-l):f*o(l),!(s<e)){if(s>u)break;p.push(s)}2*p.length<d&&(p=G(e,u,d))}else p=G(l,h,Math.min(h-l,d)).map(o);return c?p.reverse():p},e.tickFormat=(n,r)=>{if(null==n&&(n=10),null==r&&(r=10===a?"s":","),"function"!=typeof r&&(a%1||null!=(r=Jc(r)).precision||(r.trim=!0),r=t.format(r)),n===1/0)return r;const u=Math.max(1,a*n/e.ticks().length);return t=>{let n=t/o(Math.round(i(t)));return n*a<a-.5&&(n*=a),n<=u?r(t):""}},e.nice=()=>r(kg(r(),{floor:t=>o(Math.floor(i(t))),ceil:t=>o(Math.ceil(i(t)))})),e}function qg(t){return function(n){return Math.sign(n)*Math.log1p(Math.abs(n/t))}}function Ug(t){return function(n){return Math.sign(n)*Math.expm1(Math.abs(n))*t}}function Ig(t){var n=1,e=t(qg(n),Ug(n));return e.constant=function(e){return arguments.length?t(qg(n=+e),Ug(n)):n},Ng(e)}function Og(t){return function(n){return n<0?-Math.pow(-n,t):Math.pow(n,t)}}function Bg(t){return t<0?-Math.sqrt(-t):Math.sqrt(t)}function Yg(t){return t<0?-t*t:t*t}function Lg(t){var n=t(mg,mg),e=1;return n.exponent=function(n){return arguments.length?1===(e=+n)?t(mg,mg):.5===e?t(Bg,Yg):t(Og(e),Og(1/e)):e},Ng(n)}function jg(){var t=Lg(Ag());return t.copy=function(){return Tg(t,jg()).exponent(t.exponent())},hg.apply(t,arguments),t}function Hg(t){return Math.sign(t)*t*t}const Xg=new Date,Gg=new Date;function Vg(t,n,e,r){function i(n){return t(n=0===arguments.length?new Date:new Date(+n)),n}return i.floor=n=>(t(n=new Date(+n)),n),i.ceil=e=>(t(e=new Date(e-1)),n(e,1),t(e),e),i.round=t=>{const n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=(t,e)=>(n(t=new Date(+t),null==e?1:Math.floor(e)),t),i.range=(e,r,o)=>{const a=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return a;let u;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(u<e&&e<r);return a},i.filter=e=>Vg((n=>{if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)}),((t,r)=>{if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})),e&&(i.count=(n,r)=>(Xg.setTime(+n),Gg.setTime(+r),t(Xg),t(Gg),Math.floor(e(Xg,Gg))),i.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?n=>r(n)%t==0:n=>i.count(0,n)%t==0):i:null)),i}const Wg=Vg((()=>{}),((t,n)=>{t.setTime(+t+n)}),((t,n)=>n-t));Wg.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?Vg((n=>{n.setTime(Math.floor(n/t)*t)}),((n,e)=>{n.setTime(+n+e*t)}),((n,e)=>(e-n)/t)):Wg:null);const Zg=Wg.range,Kg=1e3,Qg=6e4,Jg=36e5,ty=864e5,ny=6048e5,ey=2592e6,ry=31536e6,iy=Vg((t=>{t.setTime(t-t.getMilliseconds())}),((t,n)=>{t.setTime(+t+n*Kg)}),((t,n)=>(n-t)/Kg),(t=>t.getUTCSeconds())),oy=iy.range,ay=Vg((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Kg)}),((t,n)=>{t.setTime(+t+n*Qg)}),((t,n)=>(n-t)/Qg),(t=>t.getMinutes())),uy=ay.range,cy=Vg((t=>{t.setUTCSeconds(0,0)}),((t,n)=>{t.setTime(+t+n*Qg)}),((t,n)=>(n-t)/Qg),(t=>t.getUTCMinutes())),fy=cy.range,sy=Vg((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Kg-t.getMinutes()*Qg)}),((t,n)=>{t.setTime(+t+n*Jg)}),((t,n)=>(n-t)/Jg),(t=>t.getHours())),ly=sy.range,hy=Vg((t=>{t.setUTCMinutes(0,0,0)}),((t,n)=>{t.setTime(+t+n*Jg)}),((t,n)=>(n-t)/Jg),(t=>t.getUTCHours())),dy=hy.range,py=Vg((t=>t.setHours(0,0,0,0)),((t,n)=>t.setDate(t.getDate()+n)),((t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Qg)/ty),(t=>t.getDate()-1)),gy=py.range,yy=Vg((t=>{t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+n)}),((t,n)=>(n-t)/ty),(t=>t.getUTCDate()-1)),vy=yy.range,_y=Vg((t=>{t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+n)}),((t,n)=>(n-t)/ty),(t=>Math.floor(t/ty))),by=_y.range;function my(t){return Vg((n=>{n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)}),((t,n)=>{t.setDate(t.getDate()+7*n)}),((t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Qg)/ny))}const xy=my(0),wy=my(1),My=my(2),Ty=my(3),Ay=my(4),Sy=my(5),Ey=my(6),Ny=xy.range,ky=wy.range,Cy=My.range,Py=Ty.range,zy=Ay.range,$y=Sy.range,Dy=Ey.range;function Ry(t){return Vg((n=>{n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+7*n)}),((t,n)=>(n-t)/ny))}const Fy=Ry(0),qy=Ry(1),Uy=Ry(2),Iy=Ry(3),Oy=Ry(4),By=Ry(5),Yy=Ry(6),Ly=Fy.range,jy=qy.range,Hy=Uy.range,Xy=Iy.range,Gy=Oy.range,Vy=By.range,Wy=Yy.range,Zy=Vg((t=>{t.setDate(1),t.setHours(0,0,0,0)}),((t,n)=>{t.setMonth(t.getMonth()+n)}),((t,n)=>n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())),(t=>t.getMonth())),Ky=Zy.range,Qy=Vg((t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCMonth(t.getUTCMonth()+n)}),((t,n)=>n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())),(t=>t.getUTCMonth())),Jy=Qy.range,tv=Vg((t=>{t.setMonth(0,1),t.setHours(0,0,0,0)}),((t,n)=>{t.setFullYear(t.getFullYear()+n)}),((t,n)=>n.getFullYear()-t.getFullYear()),(t=>t.getFullYear()));tv.every=t=>isFinite(t=Math.floor(t))&&t>0?Vg((n=>{n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)}),((n,e)=>{n.setFullYear(n.getFullYear()+e*t)})):null;const nv=tv.range,ev=Vg((t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCFullYear(t.getUTCFullYear()+n)}),((t,n)=>n.getUTCFullYear()-t.getUTCFullYear()),(t=>t.getUTCFullYear()));ev.every=t=>isFinite(t=Math.floor(t))&&t>0?Vg((n=>{n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)}),((n,e)=>{n.setUTCFullYear(n.getUTCFullYear()+e*t)})):null;const rv=ev.range;function iv(t,n,e,i,o,a){const u=[[iy,1,Kg],[iy,5,5e3],[iy,15,15e3],[iy,30,3e4],[a,1,Qg],[a,5,3e5],[a,15,9e5],[a,30,18e5],[o,1,Jg],[o,3,108e5],[o,6,216e5],[o,12,432e5],[i,1,ty],[i,2,1728e5],[e,1,ny],[n,1,ey],[n,3,7776e6],[t,1,ry]];function c(n,e,i){const o=Math.abs(e-n)/i,a=r((([,,t])=>t)).right(u,o);if(a===u.length)return t.every(W(n/ry,e/ry,i));if(0===a)return Wg.every(Math.max(W(n,e,i),1));const[c,f]=u[o/u[a-1][2]<u[a][2]/o?a-1:a];return c.every(f)}return[function(t,n,e){const r=n<t;r&&([t,n]=[n,t]);const i=e&&"function"==typeof e.range?e:c(t,n,e),o=i?i.range(t,+n+1):[];return r?o.reverse():o},c]}const[ov,av]=iv(ev,Qy,Fy,_y,hy,cy),[uv,cv]=iv(tv,Zy,xy,py,sy,ay);function fv(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function sv(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function lv(t,n,e){return{y:t,m:n,d:e,H:0,M:0,S:0,L:0}}function hv(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,a=t.shortDays,u=t.months,c=t.shortMonths,f=mv(i),s=xv(i),l=mv(o),h=xv(o),d=mv(a),p=xv(a),g=mv(u),y=xv(u),v=mv(c),_=xv(c),b={a:function(t){return a[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return u[t.getMonth()]},c:null,d:Yv,e:Yv,f:Gv,g:i_,G:a_,H:Lv,I:jv,j:Hv,L:Xv,m:Vv,M:Wv,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:k_,s:C_,S:Zv,u:Kv,U:Qv,V:t_,w:n_,W:e_,x:null,X:null,y:r_,Y:o_,Z:u_,"%":N_},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:c_,e:c_,f:d_,g:T_,G:S_,H:f_,I:s_,j:l_,L:h_,m:p_,M:g_,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:k_,s:C_,S:y_,u:v_,U:__,V:m_,w:x_,W:w_,x:null,X:null,y:M_,Y:A_,Z:E_,"%":N_},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p.get(r[0].toLowerCase()),e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h.get(r[0].toLowerCase()),e+r[0].length):-1},b:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=_.get(r[0].toLowerCase()),e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=y.get(r[0].toLowerCase()),e+r[0].length):-1},c:function(t,e,r){return T(t,n,e,r)},d:zv,e:zv,f:Uv,g:Nv,G:Ev,H:Dv,I:Dv,j:$v,L:qv,m:Pv,M:Rv,p:function(t,n,e){var r=f.exec(n.slice(e));return r?(t.p=s.get(r[0].toLowerCase()),e+r[0].length):-1},q:Cv,Q:Ov,s:Bv,S:Fv,u:Mv,U:Tv,V:Av,w:wv,W:Sv,x:function(t,n,r){return T(t,e,n,r)},X:function(t,n,e){return T(t,r,n,e)},y:Nv,Y:Ev,Z:kv,"%":Iv};function w(t,n){return function(e){var r,i,o,a=[],u=-1,c=0,f=t.length;for(e instanceof Date||(e=new Date(+e));++u<f;)37===t.charCodeAt(u)&&(a.push(t.slice(c,u)),null!=(i=pv[r=t.charAt(++u)])?r=t.charAt(++u):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),a.push(r),c=u+1);return a.push(t.slice(c,u)),a.join("")}}function M(t,n){return function(e){var r,i,o=lv(1900,void 0,1);if(T(o,t,e+="",0)!=e.length)return null;if("Q"in o)return new Date(o.Q);if("s"in o)return new Date(1e3*o.s+("L"in o?o.L:0));if(n&&!("Z"in o)&&(o.Z=0),"p"in o&&(o.H=o.H%12+12*o.p),void 0===o.m&&(o.m="q"in o?o.q:0),"V"in o){if(o.V<1||o.V>53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=sv(lv(o.y,0,1))).getUTCDay(),r=i>4||0===i?qy.ceil(r):qy(r),r=yy.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=fv(lv(o.y,0,1))).getDay(),r=i>4||0===i?wy.ceil(r):wy(r),r=py.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?sv(lv(o.y,0,1)).getUTCDay():fv(lv(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,sv(o)):fv(o)}}function T(t,n,e,r){for(var i,o,a=0,u=n.length,c=e.length;a<u;){if(r>=c)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in pv?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",!1);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t+="",!0);return n.toString=function(){return t},n}}}var dv,pv={"-":"",_:" ",0:"0"},gv=/^\s*\d+/,yv=/^%/,vv=/[\\^$*+?|[\]().{}]/g;function _v(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function bv(t){return t.replace(vv,"\\$&")}function mv(t){return new RegExp("^(?:"+t.map(bv).join("|")+")","i")}function xv(t){return new Map(t.map(((t,n)=>[t.toLowerCase(),n])))}function wv(t,n,e){var r=gv.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Mv(t,n,e){var r=gv.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Tv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function Av(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function Sv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function Ev(t,n,e){var r=gv.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Nv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function kv(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Cv(t,n,e){var r=gv.exec(n.slice(e,e+1));return r?(t.q=3*r[0]-3,e+r[0].length):-1}function Pv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function zv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function $v(t,n,e){var r=gv.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function Dv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Rv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Fv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function qv(t,n,e){var r=gv.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Uv(t,n,e){var r=gv.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function Iv(t,n,e){var r=yv.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Ov(t,n,e){var r=gv.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function Bv(t,n,e){var r=gv.exec(n.slice(e));return r?(t.s=+r[0],e+r[0].length):-1}function Yv(t,n){return _v(t.getDate(),n,2)}function Lv(t,n){return _v(t.getHours(),n,2)}function jv(t,n){return _v(t.getHours()%12||12,n,2)}function Hv(t,n){return _v(1+py.count(tv(t),t),n,3)}function Xv(t,n){return _v(t.getMilliseconds(),n,3)}function Gv(t,n){return Xv(t,n)+"000"}function Vv(t,n){return _v(t.getMonth()+1,n,2)}function Wv(t,n){return _v(t.getMinutes(),n,2)}function Zv(t,n){return _v(t.getSeconds(),n,2)}function Kv(t){var n=t.getDay();return 0===n?7:n}function Qv(t,n){return _v(xy.count(tv(t)-1,t),n,2)}function Jv(t){var n=t.getDay();return n>=4||0===n?Ay(t):Ay.ceil(t)}function t_(t,n){return t=Jv(t),_v(Ay.count(tv(t),t)+(4===tv(t).getDay()),n,2)}function n_(t){return t.getDay()}function e_(t,n){return _v(wy.count(tv(t)-1,t),n,2)}function r_(t,n){return _v(t.getFullYear()%100,n,2)}function i_(t,n){return _v((t=Jv(t)).getFullYear()%100,n,2)}function o_(t,n){return _v(t.getFullYear()%1e4,n,4)}function a_(t,n){var e=t.getDay();return _v((t=e>=4||0===e?Ay(t):Ay.ceil(t)).getFullYear()%1e4,n,4)}function u_(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+_v(n/60|0,"0",2)+_v(n%60,"0",2)}function c_(t,n){return _v(t.getUTCDate(),n,2)}function f_(t,n){return _v(t.getUTCHours(),n,2)}function s_(t,n){return _v(t.getUTCHours()%12||12,n,2)}function l_(t,n){return _v(1+yy.count(ev(t),t),n,3)}function h_(t,n){return _v(t.getUTCMilliseconds(),n,3)}function d_(t,n){return h_(t,n)+"000"}function p_(t,n){return _v(t.getUTCMonth()+1,n,2)}function g_(t,n){return _v(t.getUTCMinutes(),n,2)}function y_(t,n){return _v(t.getUTCSeconds(),n,2)}function v_(t){var n=t.getUTCDay();return 0===n?7:n}function __(t,n){return _v(Fy.count(ev(t)-1,t),n,2)}function b_(t){var n=t.getUTCDay();return n>=4||0===n?Oy(t):Oy.ceil(t)}function m_(t,n){return t=b_(t),_v(Oy.count(ev(t),t)+(4===ev(t).getUTCDay()),n,2)}function x_(t){return t.getUTCDay()}function w_(t,n){return _v(qy.count(ev(t)-1,t),n,2)}function M_(t,n){return _v(t.getUTCFullYear()%100,n,2)}function T_(t,n){return _v((t=b_(t)).getUTCFullYear()%100,n,2)}function A_(t,n){return _v(t.getUTCFullYear()%1e4,n,4)}function S_(t,n){var e=t.getUTCDay();return _v((t=e>=4||0===e?Oy(t):Oy.ceil(t)).getUTCFullYear()%1e4,n,4)}function E_(){return"+0000"}function N_(){return"%"}function k_(t){return+t}function C_(t){return Math.floor(+t/1e3)}function P_(n){return dv=hv(n),t.timeFormat=dv.format,t.timeParse=dv.parse,t.utcFormat=dv.utcFormat,t.utcParse=dv.utcParse,dv}t.timeFormat=void 0,t.timeParse=void 0,t.utcFormat=void 0,t.utcParse=void 0,P_({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var z_="%Y-%m-%dT%H:%M:%S.%LZ";var $_=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat(z_),D_=$_;var R_=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse(z_),F_=R_;function q_(t){return new Date(t)}function U_(t){return t instanceof Date?+t:+new Date(+t)}function I_(t,n,e,r,i,o,a,u,c,f){var s=Sg(),l=s.invert,h=s.domain,d=f(".%L"),p=f(":%S"),g=f("%I:%M"),y=f("%I %p"),v=f("%a %d"),_=f("%b %d"),b=f("%B"),m=f("%Y");function x(t){return(c(t)<t?d:u(t)<t?p:a(t)<t?g:o(t)<t?y:r(t)<t?i(t)<t?v:_:e(t)<t?b:m)(t)}return s.invert=function(t){return new Date(l(t))},s.domain=function(t){return arguments.length?h(Array.from(t,U_)):h().map(q_)},s.ticks=function(n){var e=h();return t(e[0],e[e.length-1],null==n?10:n)},s.tickFormat=function(t,n){return null==n?x:f(n)},s.nice=function(t){var e=h();return t&&"function"==typeof t.range||(t=n(e[0],e[e.length-1],null==t?10:t)),t?h(kg(e,t)):s},s.copy=function(){return Tg(s,I_(t,n,e,r,i,o,a,u,c,f))},s}function O_(){var t,n,e,r,i,o=0,a=1,u=mg,c=!1;function f(n){return null==n||isNaN(n=+n)?i:u(0===e?.5:(n=(r(n)-t)*e,c?Math.max(0,Math.min(1,n)):n))}function s(t){return function(n){var e,r;return arguments.length?([e,r]=n,u=t(e,r),f):[u(0),u(1)]}}return f.domain=function(i){return arguments.length?([o,a]=i,t=r(o=+o),n=r(a=+a),e=t===n?0:1/(n-t),f):[o,a]},f.clamp=function(t){return arguments.length?(c=!!t,f):c},f.interpolator=function(t){return arguments.length?(u=t,f):u},f.range=s(Gr),f.rangeRound=s(Vr),f.unknown=function(t){return arguments.length?(i=t,f):i},function(i){return r=i,t=i(o),n=i(a),e=t===n?0:1/(n-t),f}}function B_(t,n){return n.domain(t.domain()).interpolator(t.interpolator()).clamp(t.clamp()).unknown(t.unknown())}function Y_(){var t=Lg(O_());return t.copy=function(){return B_(t,Y_()).exponent(t.exponent())},dg.apply(t,arguments)}function L_(){var t,n,e,r,i,o,a,u=0,c=.5,f=1,s=1,l=mg,h=!1;function d(t){return isNaN(t=+t)?a:(t=.5+((t=+o(t))-n)*(s*t<s*n?r:i),l(h?Math.max(0,Math.min(1,t)):t))}function p(t){return function(n){var e,r,i;return arguments.length?([e,r,i]=n,l=di(t,[e,r,i]),d):[l(0),l(.5),l(1)]}}return d.domain=function(a){return arguments.length?([u,c,f]=a,t=o(u=+u),n=o(c=+c),e=o(f=+f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),s=n<t?-1:1,d):[u,c,f]},d.clamp=function(t){return arguments.length?(h=!!t,d):h},d.interpolator=function(t){return arguments.length?(l=t,d):l},d.range=p(Gr),d.rangeRound=p(Vr),d.unknown=function(t){return arguments.length?(a=t,d):a},function(a){return o=a,t=a(u),n=a(c),e=a(f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),s=n<t?-1:1,d}}function j_(){var t=Lg(L_());return t.copy=function(){return B_(t,j_()).exponent(t.exponent())},dg.apply(t,arguments)}function H_(t){for(var n=t.length/6|0,e=new Array(n),r=0;r<n;)e[r]="#"+t.slice(6*r,6*++r);return e}var X_=H_("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),G_=H_("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"),V_=H_("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"),W_=H_("4269d0efb118ff725c6cc5b03ca951ff8ab7a463f297bbf59c6b4e9498a0"),Z_=H_("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"),K_=H_("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"),Q_=H_("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"),J_=H_("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"),tb=H_("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"),nb=H_("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"),eb=H_("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab"),rb=t=>Fr(t[t.length-1]),ib=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(H_),ob=rb(ib),ab=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(H_),ub=rb(ab),cb=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(H_),fb=rb(cb),sb=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(H_),lb=rb(sb),hb=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(H_),db=rb(hb),pb=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(H_),gb=rb(pb),yb=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(H_),vb=rb(yb),_b=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(H_),bb=rb(_b),mb=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(H_),xb=rb(mb),wb=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(H_),Mb=rb(wb),Tb=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(H_),Ab=rb(Tb),Sb=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(H_),Eb=rb(Sb),Nb=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(H_),kb=rb(Nb),Cb=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(H_),Pb=rb(Cb),zb=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(H_),$b=rb(zb),Db=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(H_),Rb=rb(Db),Fb=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(H_),qb=rb(Fb),Ub=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(H_),Ib=rb(Ub),Ob=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(H_),Bb=rb(Ob),Yb=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(H_),Lb=rb(Yb),jb=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(H_),Hb=rb(jb),Xb=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(H_),Gb=rb(Xb),Vb=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(H_),Wb=rb(Vb),Zb=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(H_),Kb=rb(Zb),Qb=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(H_),Jb=rb(Qb),tm=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(H_),nm=rb(tm),em=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(H_),rm=rb(em);var im=hi(Tr(300,.5,0),Tr(-240,.5,1)),om=hi(Tr(-100,.75,.35),Tr(80,1.5,.8)),am=hi(Tr(260,.75,.35),Tr(80,1.5,.8)),um=Tr();var cm=Fe(),fm=Math.PI/3,sm=2*Math.PI/3;function lm(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var hm=lm(H_("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),dm=lm(H_("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),pm=lm(H_("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),gm=lm(H_("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function ym(t){return function(){return t}}const vm=Math.abs,_m=Math.atan2,bm=Math.cos,mm=Math.max,xm=Math.min,wm=Math.sin,Mm=Math.sqrt,Tm=1e-12,Am=Math.PI,Sm=Am/2,Em=2*Am;function Nm(t){return t>=1?Sm:t<=-1?-Sm:Math.asin(t)}function km(t){let n=3;return t.digits=function(e){if(!arguments.length)return n;if(null==e)n=null;else{const t=Math.floor(e);if(!(t>=0))throw new RangeError(`invalid digits: ${e}`);n=t}return t},()=>new Ua(n)}function Cm(t){return t.innerRadius}function Pm(t){return t.outerRadius}function zm(t){return t.startAngle}function $m(t){return t.endAngle}function Dm(t){return t&&t.padAngle}function Rm(t,n,e,r,i,o,a){var u=t-e,c=n-r,f=(a?o:-o)/Mm(u*u+c*c),s=f*c,l=-f*u,h=t+s,d=n+l,p=e+s,g=r+l,y=(h+p)/2,v=(d+g)/2,_=p-h,b=g-d,m=_*_+b*b,x=i-o,w=h*g-p*d,M=(b<0?-1:1)*Mm(mm(0,x*x*m-w*w)),T=(w*b-_*M)/m,A=(-w*_-b*M)/m,S=(w*b+_*M)/m,E=(-w*_+b*M)/m,N=T-y,k=A-v,C=S-y,P=E-v;return N*N+k*k>C*C+P*P&&(T=S,A=E),{cx:T,cy:A,x01:-s,y01:-l,x11:T*(i/x-1),y11:A*(i/x-1)}}var Fm=Array.prototype.slice;function qm(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function Um(t){this._context=t}function Im(t){return new Um(t)}function Om(t){return t[0]}function Bm(t){return t[1]}function Ym(t,n){var e=ym(!0),r=null,i=Im,o=null,a=km(u);function u(u){var c,f,s,l=(u=qm(u)).length,h=!1;for(null==r&&(o=i(s=a())),c=0;c<=l;++c)!(c<l&&e(f=u[c],c,u))===h&&((h=!h)?o.lineStart():o.lineEnd()),h&&o.point(+t(f,c,u),+n(f,c,u));if(s)return o=null,s+""||null}return t="function"==typeof t?t:void 0===t?Om:ym(t),n="function"==typeof n?n:void 0===n?Bm:ym(n),u.x=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),u):t},u.y=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),u):n},u.defined=function(t){return arguments.length?(e="function"==typeof t?t:ym(!!t),u):e},u.curve=function(t){return arguments.length?(i=t,null!=r&&(o=i(r)),u):i},u.context=function(t){return arguments.length?(null==t?r=o=null:o=i(r=t),u):r},u}function Lm(t,n,e){var r=null,i=ym(!0),o=null,a=Im,u=null,c=km(f);function f(f){var s,l,h,d,p,g=(f=qm(f)).length,y=!1,v=new Array(g),_=new Array(g);for(null==o&&(u=a(p=c())),s=0;s<=g;++s){if(!(s<g&&i(d=f[s],s,f))===y)if(y=!y)l=s,u.areaStart(),u.lineStart();else{for(u.lineEnd(),u.lineStart(),h=s-1;h>=l;--h)u.point(v[h],_[h]);u.lineEnd(),u.areaEnd()}y&&(v[s]=+t(d,s,f),_[s]=+n(d,s,f),u.point(r?+r(d,s,f):v[s],e?+e(d,s,f):_[s]))}if(p)return u=null,p+""||null}function s(){return Ym().defined(i).curve(a).context(o)}return t="function"==typeof t?t:void 0===t?Om:ym(+t),n="function"==typeof n?n:ym(void 0===n?0:+n),e="function"==typeof e?e:void 0===e?Bm:ym(+e),f.x=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),r=null,f):t},f.x0=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),f):t},f.x1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:ym(+t),f):r},f.y=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),e=null,f):n},f.y0=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),f):n},f.y1=function(t){return arguments.length?(e=null==t?null:"function"==typeof t?t:ym(+t),f):e},f.lineX0=f.lineY0=function(){return s().x(t).y(n)},f.lineY1=function(){return s().x(t).y(e)},f.lineX1=function(){return s().x(r).y(n)},f.defined=function(t){return arguments.length?(i="function"==typeof t?t:ym(!!t),f):i},f.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),f):a},f.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),f):o},f}function jm(t,n){return n<t?-1:n>t?1:n>=t?0:NaN}function Hm(t){return t}Um.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Xm=Vm(Im);function Gm(t){this._curve=t}function Vm(t){function n(n){return new Gm(t(n))}return n._curve=t,n}function Wm(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Vm(t)):n()._curve},t}function Zm(){return Wm(Ym().curve(Xm))}function Km(){var t=Lm().curve(Xm),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Wm(e())},delete t.lineX0,t.lineEndAngle=function(){return Wm(r())},delete t.lineX1,t.lineInnerRadius=function(){return Wm(i())},delete t.lineY0,t.lineOuterRadius=function(){return Wm(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Vm(t)):n()._curve},t}function Qm(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}Gm.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};class Jm{constructor(t,n){this._context=t,this._x=n}areaStart(){this._line=0}areaEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line}point(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._x?this._context.bezierCurveTo(this._x0=(this._x0+t)/2,this._y0,this._x0,n,t,n):this._context.bezierCurveTo(this._x0,this._y0=(this._y0+n)/2,t,this._y0,t,n)}this._x0=t,this._y0=n}}class tx{constructor(t){this._context=t}lineStart(){this._point=0}lineEnd(){}point(t,n){if(t=+t,n=+n,0===this._point)this._point=1;else{const e=Qm(this._x0,this._y0),r=Qm(this._x0,this._y0=(this._y0+n)/2),i=Qm(t,this._y0),o=Qm(t,n);this._context.moveTo(...e),this._context.bezierCurveTo(...r,...i,...o)}this._x0=t,this._y0=n}}function nx(t){return new Jm(t,!0)}function ex(t){return new Jm(t,!1)}function rx(t){return new tx(t)}function ix(t){return t.source}function ox(t){return t.target}function ax(t){let n=ix,e=ox,r=Om,i=Bm,o=null,a=null,u=km(c);function c(){let c;const f=Fm.call(arguments),s=n.apply(this,f),l=e.apply(this,f);if(null==o&&(a=t(c=u())),a.lineStart(),f[0]=s,a.point(+r.apply(this,f),+i.apply(this,f)),f[0]=l,a.point(+r.apply(this,f),+i.apply(this,f)),a.lineEnd(),c)return a=null,c+""||null}return c.source=function(t){return arguments.length?(n=t,c):n},c.target=function(t){return arguments.length?(e=t,c):e},c.x=function(t){return arguments.length?(r="function"==typeof t?t:ym(+t),c):r},c.y=function(t){return arguments.length?(i="function"==typeof t?t:ym(+t),c):i},c.context=function(n){return arguments.length?(null==n?o=a=null:a=t(o=n),c):o},c}const ux=Mm(3);var cx={draw(t,n){const e=.59436*Mm(n+xm(n/28,.75)),r=e/2,i=r*ux;t.moveTo(0,e),t.lineTo(0,-e),t.moveTo(-i,-r),t.lineTo(i,r),t.moveTo(-i,r),t.lineTo(i,-r)}},fx={draw(t,n){const e=Mm(n/Am);t.moveTo(e,0),t.arc(0,0,e,0,Em)}},sx={draw(t,n){const e=Mm(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}};const lx=Mm(1/3),hx=2*lx;var dx={draw(t,n){const e=Mm(n/hx),r=e*lx;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},px={draw(t,n){const e=.62625*Mm(n);t.moveTo(0,-e),t.lineTo(e,0),t.lineTo(0,e),t.lineTo(-e,0),t.closePath()}},gx={draw(t,n){const e=.87559*Mm(n-xm(n/7,2));t.moveTo(-e,0),t.lineTo(e,0),t.moveTo(0,e),t.lineTo(0,-e)}},yx={draw(t,n){const e=Mm(n),r=-e/2;t.rect(r,r,e,e)}},vx={draw(t,n){const e=.4431*Mm(n);t.moveTo(e,e),t.lineTo(e,-e),t.lineTo(-e,-e),t.lineTo(-e,e),t.closePath()}};const _x=wm(Am/10)/wm(7*Am/10),bx=wm(Em/10)*_x,mx=-bm(Em/10)*_x;var xx={draw(t,n){const e=Mm(.8908130915292852*n),r=bx*e,i=mx*e;t.moveTo(0,-e),t.lineTo(r,i);for(let n=1;n<5;++n){const o=Em*n/5,a=bm(o),u=wm(o);t.lineTo(u*e,-a*e),t.lineTo(a*r-u*i,u*r+a*i)}t.closePath()}};const wx=Mm(3);var Mx={draw(t,n){const e=-Mm(n/(3*wx));t.moveTo(0,2*e),t.lineTo(-wx*e,-e),t.lineTo(wx*e,-e),t.closePath()}};const Tx=Mm(3);var Ax={draw(t,n){const e=.6824*Mm(n),r=e/2,i=e*Tx/2;t.moveTo(0,-e),t.lineTo(i,r),t.lineTo(-i,r),t.closePath()}};const Sx=-.5,Ex=Mm(3)/2,Nx=1/Mm(12),kx=3*(Nx/2+1);var Cx={draw(t,n){const e=Mm(n/kx),r=e/2,i=e*Nx,o=r,a=e*Nx+e,u=-o,c=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,c),t.lineTo(Sx*r-Ex*i,Ex*r+Sx*i),t.lineTo(Sx*o-Ex*a,Ex*o+Sx*a),t.lineTo(Sx*u-Ex*c,Ex*u+Sx*c),t.lineTo(Sx*r+Ex*i,Sx*i-Ex*r),t.lineTo(Sx*o+Ex*a,Sx*a-Ex*o),t.lineTo(Sx*u+Ex*c,Sx*c-Ex*u),t.closePath()}},Px={draw(t,n){const e=.6189*Mm(n-xm(n/6,1.7));t.moveTo(-e,-e),t.lineTo(e,e),t.moveTo(-e,e),t.lineTo(e,-e)}};const zx=[fx,sx,dx,yx,xx,Mx,Cx],$x=[fx,gx,Px,Ax,cx,vx,px];function Dx(){}function Rx(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Fx(t){this._context=t}function qx(t){this._context=t}function Ux(t){this._context=t}function Ix(t,n){this._basis=new Fx(t),this._beta=n}Fx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Rx(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Rx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},qx.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Rx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Ux.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Rx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Ix.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*a),this._beta*n[c]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Ox=function t(n){function e(t){return 1===n?new Fx(t):new Ix(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function Bx(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function Yx(t,n){this._context=t,this._k=(1-n)/6}Yx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Bx(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:Bx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Lx=function t(n){function e(t){return new Yx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function jx(t,n){this._context=t,this._k=(1-n)/6}jx.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Bx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Hx=function t(n){function e(t){return new jx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Xx(t,n){this._context=t,this._k=(1-n)/6}Xx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Bx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gx=function t(n){function e(t){return new Xx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Vx(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>Tm){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>Tm){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*f+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function Wx(t,n){this._context=t,this._alpha=n}Wx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:Vx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zx=function t(n){function e(t){return n?new Wx(t,n):new Yx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Kx(t,n){this._context=t,this._alpha=n}Kx.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Vx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Qx=function t(n){function e(t){return n?new Kx(t,n):new jx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Jx(t,n){this._context=t,this._alpha=n}Jx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Vx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var tw=function t(n){function e(t){return n?new Jx(t,n):new Xx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function nw(t){this._context=t}function ew(t){return t<0?-1:1}function rw(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(ew(o)+ew(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function iw(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function ow(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function aw(t){this._context=t}function uw(t){this._context=new cw(t)}function cw(t){this._context=t}function fw(t){this._context=t}function sw(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,a[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,a[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,a[n]-=e*a[n-1];for(i[r-1]=a[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function lw(t,n){this._context=t,this._t=n}function hw(t,n){if((i=t.length)>1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o<i;++o)for(r=a,a=t[n[o]],e=0;e<u;++e)a[e][1]+=a[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]}function dw(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e}function pw(t,n){return t[n]}function gw(t){const n=[];return n.key=t,n}function yw(t){var n=t.map(vw);return dw(t).sort((function(t,e){return n[t]-n[e]}))}function vw(t){for(var n,e=-1,r=0,i=t.length,o=-1/0;++e<i;)(n=+t[e][1])>o&&(o=n,r=e);return r}function _w(t){var n=t.map(bw);return dw(t).sort((function(t,e){return n[t]-n[e]}))}function bw(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}nw.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}},aw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:ow(this,this._t0,iw(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(n=+n,(t=+t)!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,ow(this,iw(this,e=rw(this,t,n)),e);break;default:ow(this,this._t0,e=rw(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(uw.prototype=Object.create(aw.prototype)).point=function(t,n){aw.prototype.point.call(this,n,t)},cw.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},fw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=sw(t),i=sw(n),o=0,a=1;a<e;++o,++a)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[a],n[a]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}},lw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var mw=t=>()=>t;function xw(t,{sourceEvent:n,target:e,transform:r,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:i}})}function ww(t,n,e){this.k=t,this.x=n,this.y=e}ww.prototype={constructor:ww,scale:function(t){return 1===t?this:new ww(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ww(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Mw=new ww(1,0,0);function Tw(t){for(;!t.__zoom;)if(!(t=t.parentNode))return Mw;return t.__zoom}function Aw(t){t.stopImmediatePropagation()}function Sw(t){t.preventDefault(),t.stopImmediatePropagation()}function Ew(t){return!(t.ctrlKey&&"wheel"!==t.type||t.button)}function Nw(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function kw(){return this.__zoom||Mw}function Cw(t){return-t.deltaY*(1===t.deltaMode?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function Pw(){return navigator.maxTouchPoints||"ontouchstart"in this}function zw(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}Tw.prototype=ww.prototype,t.Adder=T,t.Delaunay=Lu,t.FormatSpecifier=tf,t.InternMap=InternMap,t.InternSet=InternSet,t.Node=Qd,t.Path=Ua,t.Voronoi=qu,t.ZoomTransform=ww,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>qi&&e.name===n)return new po([[t]],Zo,n,+r);return null},t.arc=function(){var t=Cm,n=Pm,e=ym(0),r=null,i=zm,o=$m,a=Dm,u=null,c=km(f);function f(){var f,s,l=+t.apply(this,arguments),h=+n.apply(this,arguments),d=i.apply(this,arguments)-Sm,p=o.apply(this,arguments)-Sm,g=vm(p-d),y=p>d;if(u||(u=f=c()),h<l&&(s=h,h=l,l=s),h>Tm)if(g>Em-Tm)u.moveTo(h*bm(d),h*wm(d)),u.arc(0,0,h,d,p,!y),l>Tm&&(u.moveTo(l*bm(p),l*wm(p)),u.arc(0,0,l,p,d,y));else{var v,_,b=d,m=p,x=d,w=p,M=g,T=g,A=a.apply(this,arguments)/2,S=A>Tm&&(r?+r.apply(this,arguments):Mm(l*l+h*h)),E=xm(vm(h-l)/2,+e.apply(this,arguments)),N=E,k=E;if(S>Tm){var C=Nm(S/l*wm(A)),P=Nm(S/h*wm(A));(M-=2*C)>Tm?(x+=C*=y?1:-1,w-=C):(M=0,x=w=(d+p)/2),(T-=2*P)>Tm?(b+=P*=y?1:-1,m-=P):(T=0,b=m=(d+p)/2)}var z=h*bm(b),$=h*wm(b),D=l*bm(w),R=l*wm(w);if(E>Tm){var F,q=h*bm(m),U=h*wm(m),I=l*bm(x),O=l*wm(x);if(g<Am)if(F=function(t,n,e,r,i,o,a,u){var c=e-t,f=r-n,s=a-i,l=u-o,h=l*c-s*f;if(!(h*h<Tm))return[t+(h=(s*(n-o)-l*(t-i))/h)*c,n+h*f]}(z,$,I,O,q,U,D,R)){var B=z-F[0],Y=$-F[1],L=q-F[0],j=U-F[1],H=1/wm(function(t){return t>1?0:t<-1?Am:Math.acos(t)}((B*L+Y*j)/(Mm(B*B+Y*Y)*Mm(L*L+j*j)))/2),X=Mm(F[0]*F[0]+F[1]*F[1]);N=xm(E,(l-X)/(H-1)),k=xm(E,(h-X)/(H+1))}else N=k=0}T>Tm?k>Tm?(v=Rm(I,O,z,$,h,k,y),_=Rm(q,U,D,R,h,k,y),u.moveTo(v.cx+v.x01,v.cy+v.y01),k<E?u.arc(v.cx,v.cy,k,_m(v.y01,v.x01),_m(_.y01,_.x01),!y):(u.arc(v.cx,v.cy,k,_m(v.y01,v.x01),_m(v.y11,v.x11),!y),u.arc(0,0,h,_m(v.cy+v.y11,v.cx+v.x11),_m(_.cy+_.y11,_.cx+_.x11),!y),u.arc(_.cx,_.cy,k,_m(_.y11,_.x11),_m(_.y01,_.x01),!y))):(u.moveTo(z,$),u.arc(0,0,h,b,m,!y)):u.moveTo(z,$),l>Tm&&M>Tm?N>Tm?(v=Rm(D,R,q,U,l,-N,y),_=Rm(z,$,I,O,l,-N,y),u.lineTo(v.cx+v.x01,v.cy+v.y01),N<E?u.arc(v.cx,v.cy,N,_m(v.y01,v.x01),_m(_.y01,_.x01),!y):(u.arc(v.cx,v.cy,N,_m(v.y01,v.x01),_m(v.y11,v.x11),!y),u.arc(0,0,l,_m(v.cy+v.y11,v.cx+v.x11),_m(_.cy+_.y11,_.cx+_.x11),y),u.arc(_.cx,_.cy,N,_m(_.y11,_.x11),_m(_.y01,_.x01),!y))):u.arc(0,0,l,w,x,y):u.lineTo(D,R)}else u.moveTo(0,0);if(u.closePath(),f)return u=null,f+""||null}return f.centroid=function(){var e=(+t.apply(this,arguments)+ +n.apply(this,arguments))/2,r=(+i.apply(this,arguments)+ +o.apply(this,arguments))/2-Am/2;return[bm(r)*e,wm(r)*e]},f.innerRadius=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),f):t},f.outerRadius=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),f):n},f.cornerRadius=function(t){return arguments.length?(e="function"==typeof t?t:ym(+t),f):e},f.padRadius=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:ym(+t),f):r},f.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:ym(+t),f):i},f.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:ym(+t),f):o},f.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:ym(+t),f):a},f.context=function(t){return arguments.length?(u=null==t?null:t,f):u},f},t.area=Lm,t.areaRadial=Km,t.ascending=n,t.autoType=function(t){for(var n in t){var e,r,i=t[n].trim();if(i)if("true"===i)i=!0;else if("false"===i)i=!1;else if("NaN"===i)i=NaN;else if(isNaN(e=+i)){if(!(r=i.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;yc&&r[4]&&!r[7]&&(i=i.replace(/-/g,"/").replace(/T/," ")),i=new Date(i)}else i=e;else i=null;t[n]=i}return t},t.axisBottom=function(t){return Pt(Mt,t)},t.axisLeft=function(t){return Pt(Tt,t)},t.axisRight=function(t){return Pt(wt,t)},t.axisTop=function(t){return Pt(xt,t)},t.bin=Q,t.bisect=s,t.bisectCenter=f,t.bisectLeft=c,t.bisectRight=u,t.bisector=r,t.blob=function(t,n){return fetch(t,n).then(vc)},t.blur=function(t,n){if(!((n=+n)>=0))throw new RangeError("invalid r");let e=t.length;if(!((e=Math.floor(e))>=0))throw new RangeError("invalid length");if(!e||!n)return t;const r=y(n),i=t.slice();return r(t,i,0,e,1),r(i,t,0,e,1),r(t,i,0,e,1),t},t.blur2=l,t.blurImage=h,t.brush=function(){return wa(la)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.brushX=function(){return wa(fa)},t.brushY=function(){return wa(sa)},t.buffer=function(t,n){return fetch(t,n).then(_c)},t.chord=function(){return za(!1,!1)},t.chordDirected=function(){return za(!0,!1)},t.chordTranspose=function(){return za(!1,!0)},t.cluster=function(){var t=Ld,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter((function(n){var e=n.children;e?(n.x=function(t){return t.reduce(jd,0)/t.length}(e),n.y=function(t){return 1+t.reduce(Hd,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)}));var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),f=u.x-t(u,c)/2,s=c.x+t(c,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-f)/(s-f)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.color=ze,t.contourDensity=function(){var t=fu,n=su,e=lu,r=960,i=500,o=20,a=2,u=3*o,c=r+2*u>>a,f=i+2*u>>a,s=Qa(20);function h(r){var i=new Float32Array(c*f),s=Math.pow(2,-a),h=-1;for(const o of r){var d=(t(o,++h,r)+u)*s,p=(n(o,h,r)+u)*s,g=+e(o,h,r);if(g&&d>=0&&d<c&&p>=0&&p<f){var y=Math.floor(d),v=Math.floor(p),_=d-y-.5,b=p-v-.5;i[y+v*c]+=(1-_)*(1-b)*g,i[y+1+v*c]+=_*(1-b)*g,i[y+1+(v+1)*c]+=_*b*g,i[y+(v+1)*c]+=(1-_)*b*g}}return l({data:i,width:c,height:f},o*s),i}function d(t){var n=h(t),e=s(n),r=Math.pow(2,2*a);return Array.isArray(e)||(e=G(Number.MIN_VALUE,J(n)/r,e)),iu().size([c,f]).thresholds(e.map((t=>t*r)))(n).map(((t,n)=>(t.value=+e[n],p(t))))}function p(t){return t.coordinates.forEach(g),t}function g(t){t.forEach(y)}function y(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function _(){return c=r+2*(u=3*o)>>a,f=i+2*u>>a,d}return d.contours=function(t){var n=h(t),e=iu().size([c,f]),r=Math.pow(2,2*a),i=t=>{t=+t;var i=p(e.contour(n,t*r));return i.value=t,i};return Object.defineProperty(i,"max",{get:()=>J(n)/r}),i},d.x=function(n){return arguments.length?(t="function"==typeof n?n:Qa(+n),d):t},d.y=function(t){return arguments.length?(n="function"==typeof t?t:Qa(+t),d):n},d.weight=function(t){return arguments.length?(e="function"==typeof t?t:Qa(+t),d):e},d.size=function(t){if(!arguments.length)return[r,i];var n=+t[0],e=+t[1];if(!(n>=0&&e>=0))throw new Error("invalid size");return r=n,i=e,_()},d.cellSize=function(t){if(!arguments.length)return 1<<a;if(!((t=+t)>=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),_()},d.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?Qa(Za.call(t)):Qa(t),d):s},d.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=(Math.sqrt(4*t*t+1)-1)/2,_()},d},t.contours=iu,t.count=v,t.create=function(t){return Zn(Yt(t).call(document.documentElement))},t.creator=Yt,t.cross=function(...t){const n="function"==typeof t[t.length-1]&&function(t){return n=>t(...n)}(t.pop()),e=(t=t.map(m)).map(_),r=t.length-1,i=new Array(r+1).fill(0),o=[];if(r<0||e.some(b))return o;for(;;){o.push(i.map(((n,e)=>t[e][n])));let a=r;for(;++i[a]===e[a];){if(0===a)return n?o.map(n):o;i[a--]=0}}},t.csv=wc,t.csvFormat=rc,t.csvFormatBody=ic,t.csvFormatRow=ac,t.csvFormatRows=oc,t.csvFormatValue=uc,t.csvParse=nc,t.csvParseRows=ec,t.cubehelix=Tr,t.cumsum=function(t,n){var e=0,r=0;return Float64Array.from(t,void 0===n?t=>e+=+t||0:i=>e+=+n(i,r++,t)||0)},t.curveBasis=function(t){return new Fx(t)},t.curveBasisClosed=function(t){return new qx(t)},t.curveBasisOpen=function(t){return new Ux(t)},t.curveBumpX=nx,t.curveBumpY=ex,t.curveBundle=Ox,t.curveCardinal=Lx,t.curveCardinalClosed=Hx,t.curveCardinalOpen=Gx,t.curveCatmullRom=Zx,t.curveCatmullRomClosed=Qx,t.curveCatmullRomOpen=tw,t.curveLinear=Im,t.curveLinearClosed=function(t){return new nw(t)},t.curveMonotoneX=function(t){return new aw(t)},t.curveMonotoneY=function(t){return new uw(t)},t.curveNatural=function(t){return new fw(t)},t.curveStep=function(t){return new lw(t,.5)},t.curveStepAfter=function(t){return new lw(t,1)},t.curveStepBefore=function(t){return new lw(t,0)},t.descending=e,t.deviation=w,t.difference=function(t,...n){t=new InternSet(t);for(const e of n)for(const n of e)t.delete(n);return t},t.disjoint=function(t,n){const e=n[Symbol.iterator](),r=new InternSet;for(const n of t){if(r.has(n))return!1;let t,i;for(;({value:t,done:i}=e.next())&&!i;){if(Object.is(n,t))return!1;r.add(t)}}return!0},t.dispatch=$t,t.drag=function(){var t,n,e,r,i=se,o=le,a=he,u=de,c={},f=$t("start","drag","end"),s=0,l=0;function h(t){t.on("mousedown.drag",d).filter(u).on("touchstart.drag",y).on("touchmove.drag",v,ee).on("touchend.drag touchcancel.drag",_).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(a,u){if(!r&&i.call(this,a,u)){var c=b(this,o.call(this,a,u),a,u,"mouse");c&&(Zn(a.view).on("mousemove.drag",p,re).on("mouseup.drag",g,re),ae(a.view),ie(a),e=!1,t=a.clientX,n=a.clientY,c("start",a))}}function p(r){if(oe(r),!e){var i=r.clientX-t,o=r.clientY-n;e=i*i+o*o>l}c.mouse("drag",r)}function g(t){Zn(t.view).on("mousemove.drag mouseup.drag",null),ue(t.view,e),oe(t),c.mouse("end",t)}function y(t,n){if(i.call(this,t,n)){var e,r,a=t.changedTouches,u=o.call(this,t,n),c=a.length;for(e=0;e<c;++e)(r=b(this,u,t,n,a[e].identifier,a[e]))&&(ie(t),r("start",t,a[e]))}}function v(t){var n,e,r=t.changedTouches,i=r.length;for(n=0;n<i;++n)(e=c[r[n].identifier])&&(oe(t),e("drag",t,r[n]))}function _(t){var n,e,i=t.changedTouches,o=i.length;for(r&&clearTimeout(r),r=setTimeout((function(){r=null}),500),n=0;n<o;++n)(e=c[i[n].identifier])&&(ie(t),e("end",t,i[n]))}function b(t,n,e,r,i,o){var u,l,d,p=f.copy(),g=ne(o||e,n);if(null!=(d=a.call(t,new fe("beforestart",{sourceEvent:e,target:h,identifier:i,active:s,x:g[0],y:g[1],dx:0,dy:0,dispatch:p}),r)))return u=d.x-g[0]||0,l=d.y-g[1]||0,function e(o,a,f){var y,v=g;switch(o){case"start":c[i]=e,y=s++;break;case"end":delete c[i],--s;case"drag":g=ne(f||a,n),y=s}p.call(o,t,new fe(o,{sourceEvent:a,subject:d,target:h,identifier:i,active:y,x:g[0]+u,y:g[1]+l,dx:g[0]-v[0],dy:g[1]-v[1],dispatch:p}),r)}}return h.filter=function(t){return arguments.length?(i="function"==typeof t?t:ce(!!t),h):i},h.container=function(t){return arguments.length?(o="function"==typeof t?t:ce(t),h):o},h.subject=function(t){return arguments.length?(a="function"==typeof t?t:ce(t),h):a},h.touchable=function(t){return arguments.length?(u="function"==typeof t?t:ce(!!t),h):u},h.on=function(){var t=f.on.apply(f,arguments);return t===f?h:t},h.clickDistance=function(t){return arguments.length?(l=(t=+t)*t,h):Math.sqrt(l)},h},t.dragDisable=ae,t.dragEnable=ue,t.dsv=function(t,n,e,r){3===arguments.length&&"function"==typeof e&&(r=e,e=void 0);var i=Ju(t);return mc(n,e).then((function(t){return i.parse(t,r)}))},t.dsvFormat=Ju,t.easeBack=Lo,t.easeBackIn=Bo,t.easeBackInOut=Lo,t.easeBackOut=Yo,t.easeBounce=Io,t.easeBounceIn=function(t){return 1-Io(1-t)},t.easeBounceInOut=function(t){return((t*=2)<=1?1-Io(1-t):Io(t-1)+1)/2},t.easeBounceOut=Io,t.easeCircle=No,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleInOut=No,t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCubic=bo,t.easeCubicIn=function(t){return t*t*t},t.easeCubicInOut=bo,t.easeCubicOut=function(t){return--t*t*t+1},t.easeElastic=Xo,t.easeElasticIn=Ho,t.easeElasticInOut=Go,t.easeElasticOut=Xo,t.easeExp=Eo,t.easeExpIn=function(t){return So(1-+t)},t.easeExpInOut=Eo,t.easeExpOut=function(t){return 1-So(t)},t.easeLinear=t=>+t,t.easePoly=wo,t.easePolyIn=mo,t.easePolyInOut=wo,t.easePolyOut=xo,t.easeQuad=_o,t.easeQuadIn=function(t){return t*t},t.easeQuadInOut=_o,t.easeQuadOut=function(t){return t*(2-t)},t.easeSin=Ao,t.easeSinIn=function(t){return 1==+t?1:1-Math.cos(t*To)},t.easeSinInOut=Ao,t.easeSinOut=function(t){return Math.sin(t*To)},t.every=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(!n(r,++e,t))return!1;return!0},t.extent=M,t.fcumsum=function(t,n){const e=new T;let r=-1;return Float64Array.from(t,void 0===n?t=>e.add(+t||0):i=>e.add(+n(i,++r,t)||0))},t.filter=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");const e=[];let r=-1;for(const i of t)n(i,++r,t)&&e.push(i);return e},t.flatGroup=function(t,...n){return z(P(t,...n),n)},t.flatRollup=function(t,n,...e){return z(D(t,n,...e),e)},t.forceCenter=function(t,n){var e,r=1;function i(){var i,o,a=e.length,u=0,c=0;for(i=0;i<a;++i)u+=(o=e[i]).x,c+=o.y;for(u=(u/a-t)*r,c=(c/a-n)*r,i=0;i<a;++i)(o=e[i]).x-=u,o.y-=c}return null==t&&(t=0),null==n&&(n=0),i.initialize=function(t){e=t},i.x=function(n){return arguments.length?(t=+n,i):t},i.y=function(t){return arguments.length?(n=+t,i):n},i.strength=function(t){return arguments.length?(r=+t,i):r},i},t.forceCollide=function(t){var n,e,r,i=1,o=1;function a(){for(var t,a,c,f,s,l,h,d=n.length,p=0;p<o;++p)for(a=$c(n,Ic,Oc).visitAfter(u),t=0;t<d;++t)c=n[t],l=e[c.index],h=l*l,f=c.x+c.vx,s=c.y+c.vy,a.visit(g);function g(t,n,e,o,a){var u=t.data,d=t.r,p=l+d;if(!u)return n>f+p||o<f-p||e>s+p||a<s-p;if(u.index>c.index){var g=f-u.x-u.vx,y=s-u.y-u.vy,v=g*g+y*y;v<p*p&&(0===g&&(v+=(g=Uc(r))*g),0===y&&(v+=(y=Uc(r))*y),v=(p-(v=Math.sqrt(v)))/v*i,c.vx+=(g*=v)*(p=(d*=d)/(h+d)),c.vy+=(y*=v)*p,u.vx-=g*(p=1-p),u.vy-=y*p)}}}function u(t){if(t.data)return t.r=e[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function c(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r<o;++r)i=n[r],e[i.index]=+t(i,r,n)}}return"function"!=typeof t&&(t=qc(null==t?1:+t)),a.initialize=function(t,e){n=t,r=e,c()},a.iterations=function(t){return arguments.length?(o=+t,a):o},a.strength=function(t){return arguments.length?(i=+t,a):i},a.radius=function(n){return arguments.length?(t="function"==typeof n?n:qc(+n),c(),a):t},a},t.forceLink=function(t){var n,e,r,i,o,a,u=Bc,c=function(t){return 1/Math.min(i[t.source.index],i[t.target.index])},f=qc(30),s=1;function l(r){for(var i=0,u=t.length;i<s;++i)for(var c,f,l,h,d,p,g,y=0;y<u;++y)f=(c=t[y]).source,h=(l=c.target).x+l.vx-f.x-f.vx||Uc(a),d=l.y+l.vy-f.y-f.vy||Uc(a),h*=p=((p=Math.sqrt(h*h+d*d))-e[y])/p*r*n[y],d*=p,l.vx-=h*(g=o[y]),l.vy-=d*g,f.vx+=h*(g=1-g),f.vy+=d*g}function h(){if(r){var a,c,f=r.length,s=t.length,l=new Map(r.map(((t,n)=>[u(t,n,r),t])));for(a=0,i=new Array(f);a<s;++a)(c=t[a]).index=a,"object"!=typeof c.source&&(c.source=Yc(l,c.source)),"object"!=typeof c.target&&(c.target=Yc(l,c.target)),i[c.source.index]=(i[c.source.index]||0)+1,i[c.target.index]=(i[c.target.index]||0)+1;for(a=0,o=new Array(s);a<s;++a)c=t[a],o[a]=i[c.source.index]/(i[c.source.index]+i[c.target.index]);n=new Array(s),d(),e=new Array(s),p()}}function d(){if(r)for(var e=0,i=t.length;e<i;++e)n[e]=+c(t[e],e,t)}function p(){if(r)for(var n=0,i=t.length;n<i;++n)e[n]=+f(t[n],n,t)}return null==t&&(t=[]),l.initialize=function(t,n){r=t,a=n,h()},l.links=function(n){return arguments.length?(t=n,h(),l):t},l.id=function(t){return arguments.length?(u=t,l):u},l.iterations=function(t){return arguments.length?(s=+t,l):s},l.strength=function(t){return arguments.length?(c="function"==typeof t?t:qc(+t),d(),l):c},l.distance=function(t){return arguments.length?(f="function"==typeof t?t:qc(+t),p(),l):f},l},t.forceManyBody=function(){var t,n,e,r,i,o=qc(-30),a=1,u=1/0,c=.81;function f(e){var i,o=t.length,a=$c(t,Xc,Gc).visitAfter(l);for(r=e,i=0;i<o;++i)n=t[i],a.visit(h)}function s(){if(t){var n,e,r=t.length;for(i=new Array(r),n=0;n<r;++n)e=t[n],i[e.index]=+o(e,n,t)}}function l(t){var n,e,r,o,a,u=0,c=0;if(t.length){for(r=o=a=0;a<4;++a)(n=t[a])&&(e=Math.abs(n.value))&&(u+=n.value,c+=e,r+=e*n.x,o+=e*n.y);t.x=r/c,t.y=o/c}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=i[n.data.index]}while(n=n.next)}t.value=u}function h(t,o,f,s){if(!t.value)return!0;var l=t.x-n.x,h=t.y-n.y,d=s-o,p=l*l+h*h;if(d*d/c<p)return p<u&&(0===l&&(p+=(l=Uc(e))*l),0===h&&(p+=(h=Uc(e))*h),p<a&&(p=Math.sqrt(a*p)),n.vx+=l*t.value*r/p,n.vy+=h*t.value*r/p),!0;if(!(t.length||p>=u)){(t.data!==n||t.next)&&(0===l&&(p+=(l=Uc(e))*l),0===h&&(p+=(h=Uc(e))*h),p<a&&(p=Math.sqrt(a*p)));do{t.data!==n&&(d=i[t.data.index]*r/p,n.vx+=l*d,n.vy+=h*d)}while(t=t.next)}}return f.initialize=function(n,r){t=n,e=r,s()},f.strength=function(t){return arguments.length?(o="function"==typeof t?t:qc(+t),s(),f):o},f.distanceMin=function(t){return arguments.length?(a=t*t,f):Math.sqrt(a)},f.distanceMax=function(t){return arguments.length?(u=t*t,f):Math.sqrt(u)},f.theta=function(t){return arguments.length?(c=t*t,f):Math.sqrt(c)},f},t.forceRadial=function(t,n,e){var r,i,o,a=qc(.1);function u(t){for(var a=0,u=r.length;a<u;++a){var c=r[a],f=c.x-n||1e-6,s=c.y-e||1e-6,l=Math.sqrt(f*f+s*s),h=(o[a]-l)*i[a]*t/l;c.vx+=f*h,c.vy+=s*h}}function c(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)o[n]=+t(r[n],n,r),i[n]=isNaN(o[n])?0:+a(r[n],n,r)}}return"function"!=typeof t&&(t=qc(+t)),null==n&&(n=0),null==e&&(e=0),u.initialize=function(t){r=t,c()},u.strength=function(t){return arguments.length?(a="function"==typeof t?t:qc(+t),c(),u):a},u.radius=function(n){return arguments.length?(t="function"==typeof n?n:qc(+n),c(),u):t},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(t){return arguments.length?(e=+t,u):e},u},t.forceSimulation=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,u=new Map,c=Ni(l),f=$t("tick","end"),s=function(){let t=1;return()=>(t=(Lc*t+jc)%Hc)/Hc}();function l(){h(),f.call("tick",n),e<r&&(c.stop(),f.call("end",n))}function h(r){var c,f,s=t.length;void 0===r&&(r=1);for(var l=0;l<r;++l)for(e+=(o-e)*i,u.forEach((function(t){t(e)})),c=0;c<s;++c)null==(f=t[c]).fx?f.x+=f.vx*=a:(f.x=f.fx,f.vx=0),null==f.fy?f.y+=f.vy*=a:(f.y=f.fy,f.vy=0);return n}function d(){for(var n,e=0,r=t.length;e<r;++e){if((n=t[e]).index=e,null!=n.fx&&(n.x=n.fx),null!=n.fy&&(n.y=n.fy),isNaN(n.x)||isNaN(n.y)){var i=10*Math.sqrt(.5+e),o=e*Vc;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function p(n){return n.initialize&&n.initialize(t,s),n}return null==t&&(t=[]),d(),n={tick:h,restart:function(){return c.restart(l),n},stop:function(){return c.stop(),n},nodes:function(e){return arguments.length?(t=e,d(),u.forEach(p),n):t},alpha:function(t){return arguments.length?(e=+t,n):e},alphaMin:function(t){return arguments.length?(r=+t,n):r},alphaDecay:function(t){return arguments.length?(i=+t,n):+i},alphaTarget:function(t){return arguments.length?(o=+t,n):o},velocityDecay:function(t){return arguments.length?(a=1-t,n):1-a},randomSource:function(t){return arguments.length?(s=t,u.forEach(p),n):s},force:function(t,e){return arguments.length>1?(null==e?u.delete(t):u.set(t,p(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,c,f=0,s=t.length;for(null==r?r=1/0:r*=r,f=0;f<s;++f)(a=(i=n-(u=t[f]).x)*i+(o=e-u.y)*o)<r&&(c=u,r=a);return c},on:function(t,e){return arguments.length>1?(f.on(t,e),n):f.on(t)}}},t.forceX=function(t){var n,e,r,i=qc(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vx+=(r[o]-i.x)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=qc(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:qc(+t),a(),o):i},o.x=function(n){return arguments.length?(t="function"==typeof n?n:qc(+n),a(),o):t},o},t.forceY=function(t){var n,e,r,i=qc(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vy+=(r[o]-i.y)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=qc(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:qc(+t),a(),o):i},o.y=function(n){return arguments.length?(t="function"==typeof n?n:qc(+n),a(),o):t},o},t.formatDefaultLocale=ff,t.formatLocale=cf,t.formatSpecifier=Jc,t.fsum=function(t,n){const e=new T;if(void 0===n)for(let n of t)(n=+n)&&e.add(n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&e.add(i)}return+e},t.geoAlbers=xd,t.geoAlbersUsa=function(){var t,n,e,r,i,o,a=xd(),u=md().rotate([154,0]).center([-2,58.5]).parallels([55,65]),c=md().rotate([157,0]).center([-3,19.9]).parallels([8,18]),f={point:function(t,n){o=[t,n]}};function s(t){var n=t[0],a=t[1];return o=null,e.point(n,a),o||(r.point(n,a),o)||(i.point(n,a),o)}function l(){return t=n=null,s}return s.invert=function(t){var n=a.scale(),e=a.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),c.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++e<i;)r[e].point(t,n)},sphere:function(){for(var t=-1;++t<i;)r[t].sphere()},lineStart:function(){for(var t=-1;++t<i;)r[t].lineStart()},lineEnd:function(){for(var t=-1;++t<i;)r[t].lineEnd()},polygonStart:function(){for(var t=-1;++t<i;)r[t].polygonStart()},polygonEnd:function(){for(var t=-1;++t<i;)r[t].polygonEnd()}});var r,i},s.precision=function(t){return arguments.length?(a.precision(t),u.precision(t),c.precision(t),l()):a.precision()},s.scale=function(t){return arguments.length?(a.scale(t),u.scale(.35*t),c.scale(t),s.translate(a.translate())):a.scale()},s.translate=function(t){if(!arguments.length)return a.translate();var n=a.scale(),o=+t[0],s=+t[1];return e=a.translate(t).clipExtent([[o-.455*n,s-.238*n],[o+.455*n,s+.238*n]]).stream(f),r=u.translate([o-.307*n,s+.201*n]).clipExtent([[o-.425*n+df,s+.12*n+df],[o-.214*n-df,s+.234*n-df]]).stream(f),i=c.translate([o-.205*n,s+.212*n]).clipExtent([[o-.214*n+df,s+.166*n+df],[o-.115*n-df,s+.234*n-df]]).stream(f),l()},s.fitExtent=function(t,n){return ud(s,t,n)},s.fitSize=function(t,n){return cd(s,t,n)},s.fitWidth=function(t,n){return fd(s,t,n)},s.fitHeight=function(t,n){return sd(s,t,n)},s.scale(1070)},t.geoArea=function(t){return us=new T,Lf(t,cs),2*us},t.geoAzimuthalEqualArea=function(){return yd(Td).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Td,t.geoAzimuthalEquidistant=function(){return yd(Ad).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=Ad,t.geoBounds=function(t){var n,e,r,i,o,a,u;if(Qf=Kf=-(Wf=Zf=1/0),is=[],Lf(t,Fs),e=is.length){for(is.sort(Hs),n=1,o=[r=is[0]];n<e;++n)Xs(r,(i=is[n])[0])||Xs(r,i[1])?(js(r[0],i[1])>js(r[0],r[1])&&(r[1]=i[1]),js(i[0],r[1])>js(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=js(r[1],i[0]))>a&&(a=u,Wf=i[0],Kf=r[1])}return is=os=null,Wf===1/0||Zf===1/0?[[NaN,NaN],[NaN,NaN]]:[[Wf,Zf],[Kf,Qf]]},t.geoCentroid=function(t){ms=xs=ws=Ms=Ts=As=Ss=Es=0,Ns=new T,ks=new T,Cs=new T,Lf(t,Gs);var n=+Ns,e=+ks,r=+Cs,i=Ef(n,e,r);return i<pf&&(n=As,e=Ss,r=Es,xs<df&&(n=ws,e=Ms,r=Ts),(i=Ef(n,e,r))<pf)?[NaN,NaN]:[Mf(e,n)*bf,Rf(r/i)*bf]},t.geoCircle=function(){var t,n,e=il([0,0]),r=il(90),i=il(2),o={point:function(e,r){t.push(e=n(e,r)),e[0]*=bf,e[1]*=bf}};function a(){var a=e.apply(this,arguments),u=r.apply(this,arguments)*mf,c=i.apply(this,arguments)*mf;return t=[],n=ul(-a[0]*mf,-a[1]*mf,0).invert,hl(o,u,c,1),a={type:"Polygon",coordinates:[t]},t=n=null,a}return a.center=function(t){return arguments.length?(e="function"==typeof t?t:il([+t[0],+t[1]]),a):e},a.radius=function(t){return arguments.length?(r="function"==typeof t?t:il(+t),a):r},a.precision=function(t){return arguments.length?(i="function"==typeof t?t:il(+t),a):i},a},t.geoClipAntimeridian=Tl,t.geoClipCircle=Al,t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,a=500;return e={stream:function(e){return t&&n===e?t:t=zl(r,i,o,a)(n=e)},extent:function(u){return arguments.length?(r=+u[0][0],i=+u[0][1],o=+u[1][0],a=+u[1][1],t=n=null,e):[[r,i],[o,a]]}}},t.geoClipRectangle=zl,t.geoConicConformal=function(){return _d(kd).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=kd,t.geoConicEqualArea=md,t.geoConicEqualAreaRaw=bd,t.geoConicEquidistant=function(){return _d(Pd).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=Pd,t.geoContains=function(t,n){return(t&&Bl.hasOwnProperty(t.type)?Bl[t.type]:Ll)(t,n)},t.geoDistance=Ol,t.geoEqualEarth=function(){return yd(qd).scale(177.158)},t.geoEqualEarthRaw=qd,t.geoEquirectangular=function(){return yd(Cd).scale(152.63)},t.geoEquirectangularRaw=Cd,t.geoGnomonic=function(){return yd(Ud).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Ud,t.geoGraticule=Kl,t.geoGraticule10=function(){return Kl()()},t.geoIdentity=function(){var t,n,e,r,i,o,a,u=1,c=0,f=0,s=1,l=1,h=0,d=null,p=1,g=1,y=id({point:function(t,n){var e=b([t,n]);this.stream.point(e[0],e[1])}}),v=eh;function _(){return p=u*s,g=u*l,o=a=null,b}function b(e){var r=e[0]*p,i=e[1]*g;if(h){var o=i*t-r*n;r=r*t+i*n,i=o}return[r+c,i+f]}return b.invert=function(e){var r=e[0]-c,i=e[1]-f;if(h){var o=i*t+r*n;r=r*t-i*n,i=o}return[r/p,i/g]},b.stream=function(t){return o&&a===t?o:o=y(v(a=t))},b.postclip=function(t){return arguments.length?(v=t,d=e=r=i=null,_()):v},b.clipExtent=function(t){return arguments.length?(v=null==t?(d=e=r=i=null,eh):zl(d=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),_()):null==d?null:[[d,e],[r,i]]},b.scale=function(t){return arguments.length?(u=+t,_()):u},b.translate=function(t){return arguments.length?(c=+t[0],f=+t[1],_()):[c,f]},b.angle=function(e){return arguments.length?(n=Cf(h=e%360*mf),t=Tf(h),_()):h*bf},b.reflectX=function(t){return arguments.length?(s=t?-1:1,_()):s<0},b.reflectY=function(t){return arguments.length?(l=t?-1:1,_()):l<0},b.fitExtent=function(t,n){return ud(b,t,n)},b.fitSize=function(t,n){return cd(b,t,n)},b.fitWidth=function(t,n){return fd(b,t,n)},b.fitHeight=function(t,n){return sd(b,t,n)},b},t.geoInterpolate=function(t,n){var e=t[0]*mf,r=t[1]*mf,i=n[0]*mf,o=n[1]*mf,a=Tf(r),u=Cf(r),c=Tf(o),f=Cf(o),s=a*Tf(e),l=a*Cf(e),h=c*Tf(i),d=c*Cf(i),p=2*Rf(zf(Ff(o-r)+a*c*Ff(i-e))),g=Cf(p),y=p?function(t){var n=Cf(t*=p)/g,e=Cf(p-t)/g,r=e*s+n*h,i=e*l+n*d,o=e*u+n*f;return[Mf(i,r)*bf,Mf(o,zf(r*r+i*i))*bf]}:function(){return[e*bf,r*bf]};return y.distance=p,y},t.geoLength=ql,t.geoMercator=function(){return Ed(Sd).scale(961/_f)},t.geoMercatorRaw=Sd,t.geoNaturalEarth1=function(){return yd(Id).scale(175.295)},t.geoNaturalEarth1Raw=Id,t.geoOrthographic=function(){return yd(Od).scale(249.5).clipAngle(90+df)},t.geoOrthographicRaw=Od,t.geoPath=function(t,n){let e,r,i=3,o=4.5;function a(t){return t&&("function"==typeof o&&r.pointRadius(+o.apply(this,arguments)),Lf(t,e(r))),r.result()}return a.area=function(t){return Lf(t,e(sh)),sh.result()},a.measure=function(t){return Lf(t,e(Kh)),Kh.result()},a.bounds=function(t){return Lf(t,e(mh)),mh.result()},a.centroid=function(t){return Lf(t,e(Oh)),Oh.result()},a.projection=function(n){return arguments.length?(e=null==n?(t=null,eh):(t=n).stream,a):t},a.context=function(t){return arguments.length?(r=null==t?(n=null,new ed(i)):new Bh(n=t),"function"!=typeof o&&r.pointRadius(o),a):n},a.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(r.pointRadius(+t),+t),a):o},a.digits=function(t){if(!arguments.length)return i;if(null==t)i=null;else{const n=Math.floor(t);if(!(n>=0))throw new RangeError(`invalid digits: ${t}`);i=n}return null===n&&(r=new ed(i)),a},a.projection(t).digits(i).context(n)},t.geoProjection=yd,t.geoProjectionMutator=vd,t.geoRotation=ll,t.geoStereographic=function(){return yd(Bd).scale(250).clipAngle(142)},t.geoStereographicRaw=Bd,t.geoStream=Lf,t.geoTransform=function(t){return{stream:id(t)}},t.geoTransverseMercator=function(){var t=Ed(Yd),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=Yd,t.gray=function(t,n){return new ur(t,0,0,null==n?1:n)},t.greatest=ot,t.greatestIndex=function(t,e=n){if(1===e.length)return tt(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)>0)&&(r=n,i=o);return i},t.group=C,t.groupSort=function(t,e,r){return(2!==e.length?U($(t,e,r),(([t,e],[r,i])=>n(e,i)||n(t,r))):U(C(t,r),(([t,r],[i,o])=>e(r,o)||n(t,i)))).map((([t])=>t))},t.groups=P,t.hcl=dr,t.hierarchy=Gd,t.histogram=Q,t.hsl=He,t.html=Ec,t.image=function(t,n){return new Promise((function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t}))},t.index=function(t,...n){return F(t,k,R,n)},t.indexes=function(t,...n){return F(t,Array.from,R,n)},t.interpolate=Gr,t.interpolateArray=function(t,n){return(Ir(n)?Ur:Or)(t,n)},t.interpolateBasis=Er,t.interpolateBasisClosed=Nr,t.interpolateBlues=Gb,t.interpolateBrBG=ob,t.interpolateBuGn=Mb,t.interpolateBuPu=Ab,t.interpolateCividis=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(-4.54-t*(35.34-t*(2381.73-t*(6402.7-t*(7024.72-2710.57*t)))))))+", "+Math.max(0,Math.min(255,Math.round(32.49+t*(170.73+t*(52.82-t*(131.46-t*(176.58-67.37*t)))))))+", "+Math.max(0,Math.min(255,Math.round(81.24+t*(442.36-t*(2482.43-t*(6167.24-t*(6614.94-2475.67*t)))))))+")"},t.interpolateCool=am,t.interpolateCubehelix=li,t.interpolateCubehelixDefault=im,t.interpolateCubehelixLong=hi,t.interpolateDate=Br,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateGnBu=Eb,t.interpolateGreens=Wb,t.interpolateGreys=Kb,t.interpolateHcl=ci,t.interpolateHclLong=fi,t.interpolateHsl=oi,t.interpolateHslLong=ai,t.interpolateHue=function(t,n){var e=Pr(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateInferno=pm,t.interpolateLab=function(t,n){var e=$r((t=ar(t)).l,(n=ar(n)).l),r=$r(t.a,n.a),i=$r(t.b,n.b),o=$r(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateMagma=dm,t.interpolateNumber=Yr,t.interpolateNumberArray=Ur,t.interpolateObject=Lr,t.interpolateOrRd=kb,t.interpolateOranges=rm,t.interpolatePRGn=ub,t.interpolatePiYG=fb,t.interpolatePlasma=gm,t.interpolatePuBu=$b,t.interpolatePuBuGn=Pb,t.interpolatePuOr=lb,t.interpolatePuRd=Rb,t.interpolatePurples=Jb,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return um.h=360*t-100,um.s=1.5-1.5*n,um.l=.8-.9*n,um+""},t.interpolateRdBu=db,t.interpolateRdGy=gb,t.interpolateRdPu=qb,t.interpolateRdYlBu=vb,t.interpolateRdYlGn=bb,t.interpolateReds=nm,t.interpolateRgb=Dr,t.interpolateRgbBasis=Fr,t.interpolateRgbBasisClosed=qr,t.interpolateRound=Vr,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,cm.r=255*(n=Math.sin(t))*n,cm.g=255*(n=Math.sin(t+fm))*n,cm.b=255*(n=Math.sin(t+sm))*n,cm+""},t.interpolateSpectral=xb,t.interpolateString=Xr,t.interpolateTransformCss=ti,t.interpolateTransformSvg=ni,t.interpolateTurbo=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"},t.interpolateViridis=hm,t.interpolateWarm=om,t.interpolateYlGn=Bb,t.interpolateYlGnBu=Ib,t.interpolateYlOrBr=Lb,t.interpolateYlOrRd=Hb,t.interpolateZoom=ri,t.interrupt=Gi,t.intersection=function(t,...n){t=new InternSet(t),n=n.map(vt);t:for(const e of t)for(const r of n)if(!r.has(e)){t.delete(e);continue t}return t},t.interval=function(t,n,e){var r=new Ei,i=n;return null==n?(r.restart(t,n,e),r):(r._restart=r.restart,r.restart=function(t,n,e){n=+n,e=null==e?Ai():+e,r._restart((function o(a){a+=i,r._restart(o,i+=n,e),t(a)}),n,e)},r.restart(t,n,e),r)},t.isoFormat=D_,t.isoParse=F_,t.json=function(t,n){return fetch(t,n).then(Tc)},t.lab=ar,t.lch=function(t,n,e,r){return 1===arguments.length?hr(t):new pr(e,n,t,null==r?1:r)},t.least=function(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)<0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)<0:0===e(n,n))&&(r=n,i=!0);return r},t.leastIndex=ht,t.line=Ym,t.lineRadial=Zm,t.link=ax,t.linkHorizontal=function(){return ax(nx)},t.linkRadial=function(){const t=ax(rx);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.linkVertical=function(){return ax(ex)},t.local=Qn,t.map=function(t,n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");if("function"!=typeof n)throw new TypeError("mapper is not a function");return Array.from(t,((e,r)=>n(e,r,t)))},t.matcher=Vt,t.max=J,t.maxIndex=tt,t.mean=function(t,n){let e=0,r=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(++e,r+=n);else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(o=+o)>=o&&(++e,r+=o)}if(e)return r/e},t.median=function(t,n){return at(t,.5,n)},t.medianIndex=function(t,n){return ct(t,.5,n)},t.merge=ft,t.min=nt,t.minIndex=et,t.mode=function(t,n){const e=new InternMap;if(void 0===n)for(let n of t)null!=n&&n>=n&&e.set(n,(e.get(n)||0)+1);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&i>=i&&e.set(i,(e.get(i)||0)+1)}let r,i=0;for(const[t,n]of e)n>i&&(i=n,r=t);return r},t.namespace=It,t.namespaces=Ut,t.nice=Z,t.now=Ai,t.pack=function(){var t=null,n=1,e=1,r=np;function i(i){const o=ap();return i.x=n/2,i.y=e/2,t?i.eachBefore(xp(t)).eachAfter(wp(r,.5,o)).eachBefore(Mp(1)):i.eachBefore(xp(mp)).eachAfter(wp(np,1,o)).eachAfter(wp(r,i.r/Math.min(n,e),o)).eachBefore(Mp(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=Jd(n),i):t},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:ep(+t),i):r},i},t.packEnclose=function(t){return up(t,ap())},t.packSiblings=function(t){return bp(t,ap()),t},t.pairs=function(t,n=st){const e=[];let r,i=!1;for(const o of t)i&&e.push(n(r,o)),r=o,i=!0;return e},t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&Ap(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a<i&&(i=a=(i+a)/2),u<o&&(o=u=(o+u)/2),r.x0=i,r.y0=o,r.x1=a,r.y1=u}}(n,o)),r&&i.eachBefore(Tp),i}return i.round=function(t){return arguments.length?(r=!!t,i):r},i.size=function(e){return arguments.length?(t=+e[0],n=+e[1],i):[t,n]},i.padding=function(t){return arguments.length?(e=+t,i):e},i},t.path=Ia,t.pathRound=function(t=3){return new Ua(+t)},t.permute=q,t.pie=function(){var t=Hm,n=jm,e=null,r=ym(0),i=ym(Em),o=ym(0);function a(a){var u,c,f,s,l,h=(a=qm(a)).length,d=0,p=new Array(h),g=new Array(h),y=+r.apply(this,arguments),v=Math.min(Em,Math.max(-Em,i.apply(this,arguments)-y)),_=Math.min(Math.abs(v)/h,o.apply(this,arguments)),b=_*(v<0?-1:1);for(u=0;u<h;++u)(l=g[p[u]=u]=+t(a[u],u,a))>0&&(d+=l);for(null!=n?p.sort((function(t,e){return n(g[t],g[e])})):null!=e&&p.sort((function(t,n){return e(a[t],a[n])})),u=0,f=d?(v-h*b)/d:0;u<h;++u,y=s)c=p[u],s=y+((l=g[c])>0?l*f:0)+b,g[c]={data:a[c],index:u,value:l,startAngle:y,endAngle:s,padAngle:_};return g}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:ym(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:ym(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:ym(+t),a):o},a},t.piecewise=di,t.pointRadial=Qm,t.pointer=ne,t.pointers=function(t,n){return t.target&&(t=te(t),void 0===n&&(n=t.currentTarget),t=t.touches||[t]),Array.from(t,(t=>ne(t,n)))},t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,a=0,u=t[i-1],c=0;++r<i;)n=u,u=t[r],c+=e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o/(c*=3),a/c]},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],a=n[0],u=n[1],c=o[0],f=o[1],s=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>u!=f>u&&a<(c-e)*(u-r)/(f-r)+e&&(s=!s),c=e,f=r;return s},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Hp),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=Xp(r),a=Xp(i),u=a[0]===o[0],c=a[a.length-1]===o[o.length-1],f=[];for(n=o.length-1;n>=0;--n)f.push(t[r[o[n]][2]]);for(n=+u;n<a.length-c;++n)f.push(t[r[a[n]][2]]);return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],a=o[0],u=o[1],c=0;++r<i;)n=a,e=u,n-=a=(o=t[r])[0],e-=u=o[1],c+=Math.hypot(n,e);return c},t.precisionFixed=sf,t.precisionPrefix=lf,t.precisionRound=hf,t.quadtree=$c,t.quantile=at,t.quantileIndex=ct,t.quantileSorted=ut,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.quickselect=rt,t.radialArea=Km,t.radialLine=Zm,t.randomBates=Jp,t.randomBernoulli=eg,t.randomBeta=og,t.randomBinomial=ag,t.randomCauchy=cg,t.randomExponential=tg,t.randomGamma=ig,t.randomGeometric=rg,t.randomInt=Wp,t.randomIrwinHall=Qp,t.randomLcg=function(t=Math.random()){let n=0|(0<=t&&t<1?t/lg:Math.abs(t));return()=>(n=1664525*n+1013904223|0,lg*(n>>>0))},t.randomLogNormal=Kp,t.randomLogistic=fg,t.randomNormal=Zp,t.randomPareto=ng,t.randomPoisson=sg,t.randomUniform=Vp,t.randomWeibull=ug,t.range=lt,t.rank=function(t,e=n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");let r=Array.from(t);const i=new Float64Array(r.length);2!==e.length&&(r=r.map(e),e=n);const o=(t,n)=>e(r[t],r[n]);let a,u;return(t=Uint32Array.from(r,((t,n)=>n))).sort(e===n?(t,n)=>O(r[t],r[n]):I(o)),t.forEach(((t,n)=>{const e=o(t,void 0===a?t:a);e>=0?((void 0===a||e>0)&&(a=t,u=n),i[t]=u):i[t]=NaN})),i},t.reduce=function(t,n,e){if("function"!=typeof n)throw new TypeError("reducer is not a function");const r=t[Symbol.iterator]();let i,o,a=-1;if(arguments.length<3){if(({done:i,value:e}=r.next()),i)return;++a}for(;({done:i,value:o}=r.next()),!i;)e=n(e,o,++a,t);return e},t.reverse=function(t){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");return Array.from(t).reverse()},t.rgb=Fe,t.ribbon=function(){return Wa()},t.ribbonArrow=function(){return Wa(Va)},t.rollup=$,t.rollups=D,t.scaleBand=yg,t.scaleDiverging=function t(){var n=Ng(L_()(mg));return n.copy=function(){return B_(n,t())},dg.apply(n,arguments)},t.scaleDivergingLog=function t(){var n=Fg(L_()).domain([.1,1,10]);return n.copy=function(){return B_(n,t()).base(n.base())},dg.apply(n,arguments)},t.scaleDivergingPow=j_,t.scaleDivergingSqrt=function(){return j_.apply(null,arguments).exponent(.5)},t.scaleDivergingSymlog=function t(){var n=Ig(L_());return n.copy=function(){return B_(n,t()).constant(n.constant())},dg.apply(n,arguments)},t.scaleIdentity=function t(n){var e;function r(t){return null==t||isNaN(t=+t)?e:t}return r.invert=r,r.domain=r.range=function(t){return arguments.length?(n=Array.from(t,_g),r):n.slice()},r.unknown=function(t){return arguments.length?(e=t,r):e},r.copy=function(){return t(n).unknown(e)},n=arguments.length?Array.from(n,_g):[0,1],Ng(r)},t.scaleImplicit=pg,t.scaleLinear=function t(){var n=Sg();return n.copy=function(){return Tg(n,t())},hg.apply(n,arguments),Ng(n)},t.scaleLog=function t(){const n=Fg(Ag()).domain([1,10]);return n.copy=()=>Tg(n,t()).base(n.base()),hg.apply(n,arguments),n},t.scaleOrdinal=gg,t.scalePoint=function(){return vg(yg.apply(null,arguments).paddingInner(1))},t.scalePow=jg,t.scaleQuantile=function t(){var e,r=[],i=[],o=[];function a(){var t=0,n=Math.max(1,i.length);for(o=new Array(n-1);++t<n;)o[t-1]=ut(r,t/n);return u}function u(t){return null==t||isNaN(t=+t)?e:i[s(o,t)]}return u.invertExtent=function(t){var n=i.indexOf(t);return n<0?[NaN,NaN]:[n>0?o[n-1]:r[0],n<o.length?o[n]:r[r.length-1]]},u.domain=function(t){if(!arguments.length)return r.slice();r=[];for(let n of t)null==n||isNaN(n=+n)||r.push(n);return r.sort(n),a()},u.range=function(t){return arguments.length?(i=Array.from(t),a()):i.slice()},u.unknown=function(t){return arguments.length?(e=t,u):e},u.quantiles=function(){return o.slice()},u.copy=function(){return t().domain(r).range(i).unknown(e)},hg.apply(u,arguments)},t.scaleQuantize=function t(){var n,e=0,r=1,i=1,o=[.5],a=[0,1];function u(t){return null!=t&&t<=t?a[s(o,t,0,i)]:n}function c(){var t=-1;for(o=new Array(i);++t<i;)o[t]=((t+1)*r-(t-i)*e)/(i+1);return u}return u.domain=function(t){return arguments.length?([e,r]=t,e=+e,r=+r,c()):[e,r]},u.range=function(t){return arguments.length?(i=(a=Array.from(t)).length-1,c()):a.slice()},u.invertExtent=function(t){var n=a.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},u.unknown=function(t){return arguments.length?(n=t,u):u},u.thresholds=function(){return o.slice()},u.copy=function(){return t().domain([e,r]).range(a).unknown(n)},hg.apply(Ng(u),arguments)},t.scaleRadial=function t(){var n,e=Sg(),r=[0,1],i=!1;function o(t){var r=function(t){return Math.sign(t)*Math.sqrt(Math.abs(t))}(e(t));return isNaN(r)?n:i?Math.round(r):r}return o.invert=function(t){return e.invert(Hg(t))},o.domain=function(t){return arguments.length?(e.domain(t),o):e.domain()},o.range=function(t){return arguments.length?(e.range((r=Array.from(t,_g)).map(Hg)),o):r.slice()},o.rangeRound=function(t){return o.range(t).round(!0)},o.round=function(t){return arguments.length?(i=!!t,o):i},o.clamp=function(t){return arguments.length?(e.clamp(t),o):e.clamp()},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t(e.domain(),r).round(i).clamp(e.clamp()).unknown(n)},hg.apply(o,arguments),Ng(o)},t.scaleSequential=function t(){var n=Ng(O_()(mg));return n.copy=function(){return B_(n,t())},dg.apply(n,arguments)},t.scaleSequentialLog=function t(){var n=Fg(O_()).domain([1,10]);return n.copy=function(){return B_(n,t()).base(n.base())},dg.apply(n,arguments)},t.scaleSequentialPow=Y_,t.scaleSequentialQuantile=function t(){var e=[],r=mg;function i(t){if(null!=t&&!isNaN(t=+t))return r((s(e,t,1)-1)/(e.length-1))}return i.domain=function(t){if(!arguments.length)return e.slice();e=[];for(let n of t)null==n||isNaN(n=+n)||e.push(n);return e.sort(n),i},i.interpolator=function(t){return arguments.length?(r=t,i):r},i.range=function(){return e.map(((t,n)=>r(n/(e.length-1))))},i.quantiles=function(t){return Array.from({length:t+1},((n,r)=>at(e,r/t)))},i.copy=function(){return t(r).domain(e)},dg.apply(i,arguments)},t.scaleSequentialSqrt=function(){return Y_.apply(null,arguments).exponent(.5)},t.scaleSequentialSymlog=function t(){var n=Ig(O_());return n.copy=function(){return B_(n,t()).constant(n.constant())},dg.apply(n,arguments)},t.scaleSqrt=function(){return jg.apply(null,arguments).exponent(.5)},t.scaleSymlog=function t(){var n=Ig(Ag());return n.copy=function(){return Tg(n,t()).constant(n.constant())},hg.apply(n,arguments)},t.scaleThreshold=function t(){var n,e=[.5],r=[0,1],i=1;function o(t){return null!=t&&t<=t?r[s(e,t,0,i)]:n}return o.domain=function(t){return arguments.length?(e=Array.from(t),i=Math.min(e.length,r.length-1),o):e.slice()},o.range=function(t){return arguments.length?(r=Array.from(t),i=Math.min(e.length,r.length-1),o):r.slice()},o.invertExtent=function(t){var n=r.indexOf(t);return[e[n-1],e[n]]},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t().domain(e).range(r).unknown(n)},hg.apply(o,arguments)},t.scaleTime=function(){return hg.apply(I_(uv,cv,tv,Zy,xy,py,sy,ay,iy,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)},t.scaleUtc=function(){return hg.apply(I_(ov,av,ev,Qy,Fy,yy,hy,cy,iy,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)]),arguments)},t.scan=function(t,n){const e=ht(t,n);return e<0?void 0:e},t.schemeAccent=G_,t.schemeBlues=Xb,t.schemeBrBG=ib,t.schemeBuGn=wb,t.schemeBuPu=Tb,t.schemeCategory10=X_,t.schemeDark2=V_,t.schemeGnBu=Sb,t.schemeGreens=Vb,t.schemeGreys=Zb,t.schemeObservable10=W_,t.schemeOrRd=Nb,t.schemeOranges=em,t.schemePRGn=ab,t.schemePaired=Z_,t.schemePastel1=K_,t.schemePastel2=Q_,t.schemePiYG=cb,t.schemePuBu=zb,t.schemePuBuGn=Cb,t.schemePuOr=sb,t.schemePuRd=Db,t.schemePurples=Qb,t.schemeRdBu=hb,t.schemeRdGy=pb,t.schemeRdPu=Fb,t.schemeRdYlBu=yb,t.schemeRdYlGn=_b,t.schemeReds=tm,t.schemeSet1=J_,t.schemeSet2=tb,t.schemeSet3=nb,t.schemeSpectral=mb,t.schemeTableau10=eb,t.schemeYlGn=Ob,t.schemeYlGnBu=Ub,t.schemeYlOrBr=Yb,t.schemeYlOrRd=jb,t.select=Zn,t.selectAll=function(t){return"string"==typeof t?new Vn([document.querySelectorAll(t)],[document.documentElement]):new Vn([Ht(t)],Gn)},t.selection=Wn,t.selector=jt,t.selectorAll=Gt,t.shuffle=dt,t.shuffler=pt,t.some=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(n(r,++e,t))return!0;return!1},t.sort=U,t.stack=function(){var t=ym([]),n=dw,e=hw,r=pw;function i(i){var o,a,u=Array.from(t.apply(this,arguments),gw),c=u.length,f=-1;for(const t of i)for(o=0,++f;o<c;++o)(u[o][f]=[0,+r(t,u[o].key,f,i)]).data=t;for(o=0,a=qm(n(u));o<c;++o)u[a[o]].index=o;return e(u,a),u}return i.keys=function(n){return arguments.length?(t="function"==typeof n?n:ym(Array.from(n)),i):t},i.value=function(t){return arguments.length?(r="function"==typeof t?t:ym(+t),i):r},i.order=function(t){return arguments.length?(n=null==t?dw:"function"==typeof t?t:ym(Array.from(t)),i):n},i.offset=function(t){return arguments.length?(e=null==t?hw:t,i):e},i},t.stackOffsetDiverging=function(t,n){if((u=t.length)>0)for(var e,r,i,o,a,u,c=0,f=t[n[0]].length;c<f;++c)for(o=a=0,e=0;e<u;++e)(i=(r=t[n[e]][c])[1]-r[0])>0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):(r[0]=0,r[1]=i)},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o<a;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}hw(t,n)}},t.stackOffsetNone=hw,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var a=0,u=0;a<e;++a)u+=t[a][r][1]||0;i[r][1]+=i[r][0]=-u/2}hw(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;a<r;++a){for(var u=0,c=0,f=0;u<i;++u){for(var s=t[n[u]],l=s[a][1]||0,h=(l-(s[a-1][1]||0))/2,d=0;d<u;++d){var p=t[n[d]];h+=(p[a][1]||0)-(p[a-1][1]||0)}c+=l,f+=h*l}e[a-1][1]+=e[a-1][0]=o,c&&(o-=f/c)}e[a-1][1]+=e[a-1][0]=o,hw(t,n)}},t.stackOrderAppearance=yw,t.stackOrderAscending=_w,t.stackOrderDescending=function(t){return _w(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(bw),o=yw(t),a=0,u=0,c=[],f=[];for(n=0;n<r;++n)e=o[n],a<u?(a+=i[e],c.push(e)):(u+=i[e],f.push(e));return f.reverse().concat(c)},t.stackOrderNone=dw,t.stackOrderReverse=function(t){return dw(t).reverse()},t.stratify=function(){var t,n=kp,e=Cp;function r(r){var i,o,a,u,c,f,s,l,h=Array.from(r),d=n,p=e,g=new Map;if(null!=t){const n=h.map(((n,e)=>function(t){t=`${t}`;let n=t.length;zp(t,n-1)&&!zp(t,n-2)&&(t=t.slice(0,-1));return"/"===t[0]?t:`/${t}`}(t(n,e,r)))),e=n.map(Pp),i=new Set(n).add("");for(const t of e)i.has(t)||(i.add(t),n.push(t),e.push(Pp(t)),h.push(Np));d=(t,e)=>n[e],p=(t,n)=>e[n]}for(a=0,i=h.length;a<i;++a)o=h[a],f=h[a]=new Qd(o),null!=(s=d(o,a,r))&&(s+="")&&(l=f.id=s,g.set(l,g.has(l)?Ep:f)),null!=(s=p(o,a,r))&&(s+="")&&(f.parent=s);for(a=0;a<i;++a)if(s=(f=h[a]).parent){if(!(c=g.get(s)))throw new Error("missing: "+s);if(c===Ep)throw new Error("ambiguous: "+s);c.children?c.children.push(f):c.children=[f],f.parent=c}else{if(u)throw new Error("multiple roots");u=f}if(!u)throw new Error("no root");if(null!=t){for(;u.data===Np&&1===u.children.length;)u=u.children[0],--i;for(let t=h.length-1;t>=0&&(f=h[t]).data===Np;--t)f.data=null}if(u.parent=Sp,u.eachBefore((function(t){t.depth=t.parent.depth+1,--i})).eachBefore(Kd),u.parent=null,i>0)throw new Error("cycle");return u}return r.id=function(t){return arguments.length?(n=Jd(t),r):n},r.parentId=function(t){return arguments.length?(e=Jd(t),r):e},r.path=function(n){return arguments.length?(t=Jd(n),r):t},r},t.style=_n,t.subset=function(t,n){return _t(n,t)},t.sum=function(t,n){let e=0;if(void 0===n)for(let n of t)(n=+n)&&(e+=n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&(e+=i)}return e},t.superset=_t,t.svg=Nc,t.symbol=function(t,n){let e=null,r=km(i);function i(){let i;if(e||(e=i=r()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),i)return e=null,i+""||null}return t="function"==typeof t?t:ym(t||fx),n="function"==typeof n?n:ym(void 0===n?64:+n),i.type=function(n){return arguments.length?(t="function"==typeof n?n:ym(n),i):t},i.size=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),i):n},i.context=function(t){return arguments.length?(e=null==t?null:t,i):e},i},t.symbolAsterisk=cx,t.symbolCircle=fx,t.symbolCross=sx,t.symbolDiamond=dx,t.symbolDiamond2=px,t.symbolPlus=gx,t.symbolSquare=yx,t.symbolSquare2=vx,t.symbolStar=xx,t.symbolTimes=Px,t.symbolTriangle=Mx,t.symbolTriangle2=Ax,t.symbolWye=Cx,t.symbolX=Px,t.symbols=zx,t.symbolsFill=zx,t.symbolsStroke=$x,t.text=mc,t.thresholdFreedmanDiaconis=function(t,n,e){const r=v(t),i=at(t,.75)-at(t,.25);return r&&i?Math.ceil((e-n)/(2*i*Math.pow(r,-1/3))):1},t.thresholdScott=function(t,n,e){const r=v(t),i=w(t);return r&&i?Math.ceil((e-n)*Math.cbrt(r)/(3.49*i)):1},t.thresholdSturges=K,t.tickFormat=Eg,t.tickIncrement=V,t.tickStep=W,t.ticks=G,t.timeDay=py,t.timeDays=gy,t.timeFormatDefaultLocale=P_,t.timeFormatLocale=hv,t.timeFriday=Sy,t.timeFridays=$y,t.timeHour=sy,t.timeHours=ly,t.timeInterval=Vg,t.timeMillisecond=Wg,t.timeMilliseconds=Zg,t.timeMinute=ay,t.timeMinutes=uy,t.timeMonday=wy,t.timeMondays=ky,t.timeMonth=Zy,t.timeMonths=Ky,t.timeSaturday=Ey,t.timeSaturdays=Dy,t.timeSecond=iy,t.timeSeconds=oy,t.timeSunday=xy,t.timeSundays=Ny,t.timeThursday=Ay,t.timeThursdays=zy,t.timeTickInterval=cv,t.timeTicks=uv,t.timeTuesday=My,t.timeTuesdays=Cy,t.timeWednesday=Ty,t.timeWednesdays=Py,t.timeWeek=xy,t.timeWeeks=Ny,t.timeYear=tv,t.timeYears=nv,t.timeout=$i,t.timer=Ni,t.timerFlush=ki,t.transition=go,t.transpose=gt,t.tree=function(){var t=$p,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,a=new Up(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new Up(r[i],i)),e.parent=n;return(a.parent=new Up(null,0)).children=[a],a}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(a),r)i.eachBefore(u);else{var f=i,s=i,l=i;i.eachBefore((function(t){t.x<f.x&&(f=t),t.x>s.x&&(s=t),t.depth>l.depth&&(l=t)}));var h=f===s?1:t(f,s)/2,d=h-f.x,p=n/(s.x+h+d),g=e/(l.depth||1);i.eachBefore((function(t){t.x=(t.x+d)*p,t.y=t.depth*g}))}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,c=o.parent.children[0],f=o.m,s=a.m,l=u.m,h=c.m;u=Rp(u),o=Dp(o),u&&o;)c=Dp(c),(a=Rp(a)).a=n,(i=u.z+l-o.z-f+t(u._,o._))>0&&(Fp(qp(u,n,r),n,i),f+=i,s+=i),l+=u.m,f+=o.m,h+=c.m,s+=a.m;u&&!Rp(a)&&(a.t=u,a.m+=l-s),o&&!Dp(c)&&(c.t=o,c.m+=f-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=Yp,n=!1,e=1,r=1,i=[0],o=np,a=np,u=np,c=np,f=np;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(Tp),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l<r&&(r=l=(r+l)/2),h<s&&(s=h=(s+h)/2),n.x0=r,n.y0=s,n.x1=l,n.y1=h,n.children&&(e=i[n.depth+1]=o(n)/2,r+=f(n)-e,s+=a(n)-e,(l-=u(n)-e)<r&&(r=l=(r+l)/2),(h-=c(n)-e)<s&&(s=h=(s+h)/2),t(n,r,s,l,h))}return s.round=function(t){return arguments.length?(n=!!t,s):n},s.size=function(t){return arguments.length?(e=+t[0],r=+t[1],s):[e,r]},s.tile=function(n){return arguments.length?(t=tp(n),s):t},s.padding=function(t){return arguments.length?s.paddingInner(t).paddingOuter(t):s.paddingInner()},s.paddingInner=function(t){return arguments.length?(o="function"==typeof t?t:ep(+t),s):o},s.paddingOuter=function(t){return arguments.length?s.paddingTop(t).paddingRight(t).paddingBottom(t).paddingLeft(t):s.paddingTop()},s.paddingTop=function(t){return arguments.length?(a="function"==typeof t?t:ep(+t),s):a},s.paddingRight=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),s):u},s.paddingBottom=function(t){return arguments.length?(c="function"==typeof t?t:ep(+t),s):c},s.paddingLeft=function(t){return arguments.length?(f="function"==typeof t?t:ep(+t),s):f},s},t.treemapBinary=function(t,n,e,r,i){var o,a,u=t.children,c=u.length,f=new Array(c+1);for(f[0]=a=o=0;o<c;++o)f[o+1]=a+=u[o].value;!function t(n,e,r,i,o,a,c){if(n>=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=c)}var l=f[n],h=r/2+l,d=n+1,p=e-1;for(;d<p;){var g=d+p>>>1;f[g]<h?d=g+1:p=g}h-f[d-1]<f[d]-h&&n+1<d&&--d;var y=f[d]-l,v=r-y;if(a-i>c-o){var _=r?(i*v+a*y)/r:a;t(n,d,y,i,o,_,c),t(d,e,v,_,o,a,c)}else{var b=r?(o*v+c*y)/r:c;t(n,d,y,i,o,a,b),t(d,e,v,i,b,a,c)}}(0,c,t.value,n,e,r,i)},t.treemapDice=Ap,t.treemapResquarify=Lp,t.treemapSlice=Ip,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Ip:Ap)(t,n,e,r,i)},t.treemapSquarify=Yp,t.tsv=Mc,t.tsvFormat=lc,t.tsvFormatBody=hc,t.tsvFormatRow=pc,t.tsvFormatRows=dc,t.tsvFormatValue=gc,t.tsvParse=fc,t.tsvParseRows=sc,t.union=function(...t){const n=new InternSet;for(const e of t)for(const t of e)n.add(t);return n},t.unixDay=_y,t.unixDays=by,t.utcDay=yy,t.utcDays=vy,t.utcFriday=By,t.utcFridays=Vy,t.utcHour=hy,t.utcHours=dy,t.utcMillisecond=Wg,t.utcMilliseconds=Zg,t.utcMinute=cy,t.utcMinutes=fy,t.utcMonday=qy,t.utcMondays=jy,t.utcMonth=Qy,t.utcMonths=Jy,t.utcSaturday=Yy,t.utcSaturdays=Wy,t.utcSecond=iy,t.utcSeconds=oy,t.utcSunday=Fy,t.utcSundays=Ly,t.utcThursday=Oy,t.utcThursdays=Gy,t.utcTickInterval=av,t.utcTicks=ov,t.utcTuesday=Uy,t.utcTuesdays=Hy,t.utcWednesday=Iy,t.utcWednesdays=Xy,t.utcWeek=Fy,t.utcWeeks=Ly,t.utcYear=ev,t.utcYears=rv,t.variance=x,t.version="7.9.0",t.window=pn,t.xml=Sc,t.zip=function(){return gt(arguments)},t.zoom=function(){var t,n,e,r=Ew,i=Nw,o=zw,a=Cw,u=Pw,c=[0,1/0],f=[[-1/0,-1/0],[1/0,1/0]],s=250,l=ri,h=$t("start","zoom","end"),d=500,p=150,g=0,y=10;function v(t){t.property("__zoom",kw).on("wheel.zoom",T,{passive:!1}).on("mousedown.zoom",A).on("dblclick.zoom",S).filter(u).on("touchstart.zoom",E).on("touchmove.zoom",N).on("touchend.zoom touchcancel.zoom",k).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function _(t,n){return(n=Math.max(c[0],Math.min(c[1],n)))===t.k?t:new ww(n,t.x,t.y)}function b(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ww(t.k,r,i)}function m(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function x(t,n,e,r){t.on("start.zoom",(function(){w(this,arguments).event(r).start()})).on("interrupt.zoom end.zoom",(function(){w(this,arguments).event(r).end()})).tween("zoom",(function(){var t=this,o=arguments,a=w(t,o).event(r),u=i.apply(t,o),c=null==e?m(u):"function"==typeof e?e.apply(t,o):e,f=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),s=t.__zoom,h="function"==typeof n?n.apply(t,o):n,d=l(s.invert(c).concat(f/s.k),h.invert(c).concat(f/h.k));return function(t){if(1===t)t=h;else{var n=d(t),e=f/n[2];t=new ww(e,c[0]-n[0]*e,c[1]-n[1]*e)}a.zoom(null,t)}}))}function w(t,n,e){return!e&&t.__zooming||new M(t,n)}function M(t,n){this.that=t,this.args=n,this.active=0,this.sourceEvent=null,this.extent=i.apply(t,n),this.taps=0}function T(t,...n){if(r.apply(this,arguments)){var e=w(this,n).event(t),i=this.__zoom,u=Math.max(c[0],Math.min(c[1],i.k*Math.pow(2,a.apply(this,arguments)))),s=ne(t);if(e.wheel)e.mouse[0][0]===s[0]&&e.mouse[0][1]===s[1]||(e.mouse[1]=i.invert(e.mouse[0]=s)),clearTimeout(e.wheel);else{if(i.k===u)return;e.mouse=[s,i.invert(s)],Gi(this),e.start()}Sw(t),e.wheel=setTimeout((function(){e.wheel=null,e.end()}),p),e.zoom("mouse",o(b(_(i,u),e.mouse[0],e.mouse[1]),e.extent,f))}}function A(t,...n){if(!e&&r.apply(this,arguments)){var i=t.currentTarget,a=w(this,n,!0).event(t),u=Zn(t.view).on("mousemove.zoom",(function(t){if(Sw(t),!a.moved){var n=t.clientX-s,e=t.clientY-l;a.moved=n*n+e*e>g}a.event(t).zoom("mouse",o(b(a.that.__zoom,a.mouse[0]=ne(t,i),a.mouse[1]),a.extent,f))}),!0).on("mouseup.zoom",(function(t){u.on("mousemove.zoom mouseup.zoom",null),ue(t.view,a.moved),Sw(t),a.event(t).end()}),!0),c=ne(t,i),s=t.clientX,l=t.clientY;ae(t.view),Aw(t),a.mouse=[c,this.__zoom.invert(c)],Gi(this),a.start()}}function S(t,...n){if(r.apply(this,arguments)){var e=this.__zoom,a=ne(t.changedTouches?t.changedTouches[0]:t,this),u=e.invert(a),c=e.k*(t.shiftKey?.5:2),l=o(b(_(e,c),a,u),i.apply(this,n),f);Sw(t),s>0?Zn(this).transition().duration(s).call(x,l,a,t):Zn(this).call(v.transform,l,a,t)}}function E(e,...i){if(r.apply(this,arguments)){var o,a,u,c,f=e.touches,s=f.length,l=w(this,i,e.changedTouches.length===s).event(e);for(Aw(e),a=0;a<s;++a)c=[c=ne(u=f[a],this),this.__zoom.invert(c),u.identifier],l.touch0?l.touch1||l.touch0[2]===c[2]||(l.touch1=c,l.taps=0):(l.touch0=c,o=!0,l.taps=1+!!t);t&&(t=clearTimeout(t)),o&&(l.taps<2&&(n=c[0],t=setTimeout((function(){t=null}),d)),Gi(this),l.start())}}function N(t,...n){if(this.__zooming){var e,r,i,a,u=w(this,n).event(t),c=t.changedTouches,s=c.length;for(Sw(t),e=0;e<s;++e)i=ne(r=c[e],this),u.touch0&&u.touch0[2]===r.identifier?u.touch0[0]=i:u.touch1&&u.touch1[2]===r.identifier&&(u.touch1[0]=i);if(r=u.that.__zoom,u.touch1){var l=u.touch0[0],h=u.touch0[1],d=u.touch1[0],p=u.touch1[1],g=(g=d[0]-l[0])*g+(g=d[1]-l[1])*g,y=(y=p[0]-h[0])*y+(y=p[1]-h[1])*y;r=_(r,Math.sqrt(g/y)),i=[(l[0]+d[0])/2,(l[1]+d[1])/2],a=[(h[0]+p[0])/2,(h[1]+p[1])/2]}else{if(!u.touch0)return;i=u.touch0[0],a=u.touch0[1]}u.zoom("touch",o(b(r,i,a),u.extent,f))}}function k(t,...r){if(this.__zooming){var i,o,a=w(this,r).event(t),u=t.changedTouches,c=u.length;for(Aw(t),e&&clearTimeout(e),e=setTimeout((function(){e=null}),d),i=0;i<c;++i)o=u[i],a.touch0&&a.touch0[2]===o.identifier?delete a.touch0:a.touch1&&a.touch1[2]===o.identifier&&delete a.touch1;if(a.touch1&&!a.touch0&&(a.touch0=a.touch1,delete a.touch1),a.touch0)a.touch0[1]=this.__zoom.invert(a.touch0[0]);else if(a.end(),2===a.taps&&(o=ne(o,this),Math.hypot(n[0]-o[0],n[1]-o[1])<y)){var f=Zn(this).on("dblclick.zoom");f&&f.apply(this,arguments)}}}return v.transform=function(t,n,e,r){var i=t.selection?t.selection():t;i.property("__zoom",kw),t!==i?x(t,n,e,r):i.interrupt().each((function(){w(this,arguments).event(r).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()}))},v.scaleBy=function(t,n,e,r){v.scaleTo(t,(function(){return this.__zoom.k*("function"==typeof n?n.apply(this,arguments):n)}),e,r)},v.scaleTo=function(t,n,e,r){v.transform(t,(function(){var t=i.apply(this,arguments),r=this.__zoom,a=null==e?m(t):"function"==typeof e?e.apply(this,arguments):e,u=r.invert(a),c="function"==typeof n?n.apply(this,arguments):n;return o(b(_(r,c),a,u),t,f)}),e,r)},v.translateBy=function(t,n,e,r){v.transform(t,(function(){return o(this.__zoom.translate("function"==typeof n?n.apply(this,arguments):n,"function"==typeof e?e.apply(this,arguments):e),i.apply(this,arguments),f)}),null,r)},v.translateTo=function(t,n,e,r,a){v.transform(t,(function(){var t=i.apply(this,arguments),a=this.__zoom,u=null==r?m(t):"function"==typeof r?r.apply(this,arguments):r;return o(Mw.translate(u[0],u[1]).scale(a.k).translate("function"==typeof n?-n.apply(this,arguments):-n,"function"==typeof e?-e.apply(this,arguments):-e),t,f)}),r,a)},M.prototype={event:function(t){return t&&(this.sourceEvent=t),this},start:function(){return 1==++this.active&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(delete this.that.__zooming,this.emit("end")),this},emit:function(t){var n=Zn(this.that).datum();h.call(t,this.that,new xw(t,{sourceEvent:this.sourceEvent,target:v,type:t,transform:this.that.__zoom,dispatch:h}),n)}},v.wheelDelta=function(t){return arguments.length?(a="function"==typeof t?t:mw(+t),v):a},v.filter=function(t){return arguments.length?(r="function"==typeof t?t:mw(!!t),v):r},v.touchable=function(t){return arguments.length?(u="function"==typeof t?t:mw(!!t),v):u},v.extent=function(t){return arguments.length?(i="function"==typeof t?t:mw([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),v):i},v.scaleExtent=function(t){return arguments.length?(c[0]=+t[0],c[1]=+t[1],v):[c[0],c[1]]},v.translateExtent=function(t){return arguments.length?(f[0][0]=+t[0][0],f[1][0]=+t[1][0],f[0][1]=+t[0][1],f[1][1]=+t[1][1],v):[[f[0][0],f[0][1]],[f[1][0],f[1][1]]]},v.constrain=function(t){return arguments.length?(o=t,v):o},v.duration=function(t){return arguments.length?(s=+t,v):s},v.interpolate=function(t){return arguments.length?(l=t,v):l},v.on=function(){var t=h.on.apply(h,arguments);return t===h?v:t},v.clickDistance=function(t){return arguments.length?(g=(t=+t)*t,v):Math.sqrt(g)},v.tapDistance=function(t){return arguments.length?(y=+t,v):y},v},t.zoomIdentity=Mw,t.zoomTransform=Tw})); diff --git a/chapter24/docs/examples/A_helloWorld.smp b/chapter24/docs/examples/A_helloWorld.smp new file mode 100644 index 00000000..07ff935f --- /dev/null +++ b/chapter24/docs/examples/A_helloWorld.smp @@ -0,0 +1,3 @@ +// -*- mode: java; -*- +sys.io.p("Hello, World!"); +return 0; diff --git a/chapter24/docs/examples/BubbleSort.smp b/chapter24/docs/examples/BubbleSort.smp new file mode 100644 index 00000000..4352c47a --- /dev/null +++ b/chapter24/docs/examples/BubbleSort.smp @@ -0,0 +1,37 @@ +// -*- mode: java; -*- + +// An implementation of +// https://sampleprograms.io/projects/bubble-sort/ +// +// Bubble sort, with reading (parsing) and writing (formatting) the data. + +val sort = { sys.aryi64 nums -> + var done = false; + while( !done ) { + done = true; + for( var i = 0; i < nums.len-1; i++ ) + if( nums.buf[i] > nums.buf[i+1] ) { + int tmp = nums.buf[i]; + nums.buf[i] = nums.buf[i+1]; + nums.buf[i+1] = tmp; // Swap + done = false; + } + } +}; + +// Read from stdin a line of the form "[ 4, 3, 2, 1]" and print it sorted. +val main = { -> + // Parse array of numbers from stdin + var nums = sys.parseAryI64( sys.io.stdin() ); + if( !nums ) { + sys.io.p("stdin must look like [4, 3, 2, 1]"); + return 1; + } + + // Bubble sort array of integers + sort(nums); + + // Print a list of numbers to stdout + nums.str().write(1); + return 0; +}; diff --git a/chapter24/docs/font-awesome-4.7.0.zip b/chapter24/docs/font-awesome-4.7.0.zip Binary files differnew file mode 100644 index 00000000..b6bdb4bd --- /dev/null +++ b/chapter24/docs/font-awesome-4.7.0.zip diff --git a/chapter24/docs/graphviz.umd.js b/chapter24/docs/graphviz.umd.js new file mode 100644 index 00000000..622b4d34 --- /dev/null +++ b/chapter24/docs/graphviz.umd.js @@ -0,0 +1,7 @@ +(function(g,f){if(typeof exports=="object"&&typeof module<"u"){module.exports=f()}else if("function"==typeof define && define.amd){define("@hpcc-js/wasm",f)}else {g["@hpcc-js/wasm"]=f()}}(typeof globalThis < "u" ? globalThis : typeof self < "u" ? self : this,function(){var exports={};var __exports=exports;var module={exports}; +"use strict";var pr=Object.defineProperty;var so=Object.getOwnPropertyDescriptor;var uo=Object.getOwnPropertyNames;var po=Object.prototype.hasOwnProperty;var lo=(p,l)=>{for(var d in l)pr(p,d,{get:l[d],enumerable:!0})},co=(p,l,d,i)=>{if(l&&typeof l=="object"||typeof l=="function")for(let f of uo(l))!po.call(p,f)&&f!==d&&pr(p,f,{get:()=>l[f],enumerable:!(i=so(l,f))||i.enumerable});return p};var fo=p=>co(pr({},"__esModule",{value:!0}),p);var Yo={};lo(Yo,{Graphviz:()=>Zo});module.exports=fo(Yo);var vo=ArrayBuffer,H=Uint8Array,Qe=Uint16Array,mo=Int16Array,qe=Int32Array,lr=function(p,l,d){if(H.prototype.slice)return H.prototype.slice.call(p,l,d);(l==null||l<0)&&(l=0),(d==null||d>p.length)&&(d=p.length);var i=new H(d-l);return i.set(p.subarray(l,d)),i},Ye=function(p,l,d,i){if(H.prototype.fill)return H.prototype.fill.call(p,l,d,i);for((d==null||d<0)&&(d=0),(i==null||i>p.length)&&(i=p.length);d<i;++d)p[d]=l;return p},_o=function(p,l,d,i){if(H.prototype.copyWithin)return H.prototype.copyWithin.call(p,l,d,i);for((d==null||d<0)&&(d=0),(i==null||i>p.length)&&(i=p.length);d<i;)p[l++]=p[d++]},go=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],T=function(p,l,d){var i=new Error(l||go[p]);if(i.code=p,Error.captureStackTrace&&Error.captureStackTrace(i,T),!d)throw i;return i},Pr=function(p,l,d){for(var i=0,f=0;i<d;++i)f|=p[l++]<<(i<<3);return f},ho=function(p,l){return(p[l]|p[l+1]<<8|p[l+2]<<16|p[l+3]<<24)>>>0},wo=function(p,l){var d=p[0]|p[1]<<8|p[2]<<16;if(d==3126568&&p[3]==253){var i=p[4],f=i>>5&1,m=i>>2&1,_=i&3,h=i>>6;i&8&&T(0);var M=6-f,I=_==3?4:_,Q=Pr(p,M,I);M+=I;var Z=h?1<<h:f,Y=Pr(p,M,Z)+(h==1&&256),z=Y;if(!f){var q=1<<10+(p[5]>>3);z=q+(q>>3)*(p[5]&7)}z>2145386496&&T(1);var X=new H((l==1?Y||z:l?0:z)+12);return X[0]=1,X[4]=4,X[8]=8,{b:M+Z,y:0,l:0,d:Q,w:l&&l!=1?l:X.subarray(12),e:z,o:new qe(X.buffer,0,3),u:Y,c:m,m:Math.min(131072,z)}}else if((d>>4|p[3]<<20)==25481893)return ho(p,4)+8;T(0)},Xe=function(p){for(var l=0;1<<l<=p;++l);return l-1},je=function(p,l,d){var i=(l<<3)+4,f=(p[l]&15)+5;f>d&&T(3);for(var m=1<<f,_=m,h=-1,M=-1,I=-1,Q=m,Z=new vo(512+(m<<2)),Y=new mo(Z,0,256),z=new Qe(Z,0,256),q=new Qe(Z,512,m),X=512+(m<<1),V=new H(Z,X,m),re=new H(Z,X+m);h<255&&_>0;){var S=Xe(_+1),P=i>>3,ae=(1<<S+1)-1,J=(p[P]|p[P+1]<<8|p[P+2]<<16)>>(i&7)&ae,w=(1<<S)-1,j=ae-_-1,W=J&w;if(W<j?(i+=S,J=W):(i+=S+1,J>w&&(J-=j)),Y[++h]=--J,J==-1?(_+=J,V[--Q]=h):_-=J,!J)do{var ie=i>>3;M=(p[ie]|p[ie+1]<<8)>>(i&7)&3,i+=2,h+=M}while(M==3)}(h>255||_)&&T(0);for(var b=0,k=(m>>1)+(m>>3)+3,se=m-1,oe=0;oe<=h;++oe){var K=Y[oe];if(K<1){z[oe]=-K;continue}for(I=0;I<K;++I){V[b]=oe;do b=b+k&se;while(b>=Q)}}for(b&&T(0),I=0;I<m;++I){var L=z[V[I]]++,A=re[I]=f-Xe(L);q[I]=(L<<A)-m}return[i+7>>3,{b:f,s:V,n:re,t:q}]},yo=function(p,l){var d=0,i=-1,f=new H(292),m=p[l],_=f.subarray(0,256),h=f.subarray(256,268),M=new Qe(f.buffer,268);if(m<128){var I=je(p,l+1,6),Q=I[0],Z=I[1];l+=m;var Y=Q<<3,z=p[l];z||T(0);for(var q=0,X=0,V=Z.b,re=V,S=(++l<<3)-8+Xe(z);S-=V,!(S<Y);){var P=S>>3;if(q+=(p[P]|p[P+1]<<8)>>(S&7)&(1<<V)-1,_[++i]=Z.s[q],S-=re,S<Y)break;P=S>>3,X+=(p[P]|p[P+1]<<8)>>(S&7)&(1<<re)-1,_[++i]=Z.s[X],V=Z.n[q],q=Z.t[q],re=Z.n[X],X=Z.t[X]}++i>255&&T(0)}else{for(i=m-127;d<i;d+=2){var ae=p[++l];_[d]=ae>>4,_[d+1]=ae&15}++l}var J=0;for(d=0;d<i;++d){var w=_[d];w>11&&T(0),J+=w&&1<<w-1}var j=Xe(J)+1,W=1<<j,ie=W-J;for(ie&ie-1&&T(0),_[i++]=Xe(ie)+1,d=0;d<i;++d){var w=_[d];++h[_[d]=w&&j+1-w]}var b=new H(W<<1),k=b.subarray(0,W),se=b.subarray(W);for(M[j]=0,d=j;d>0;--d){var oe=M[d];Ye(se,d,oe,M[d-1]=oe+h[d]*(1<<j-d))}for(M[0]!=W&&T(0),d=0;d<i;++d){var K=_[d];if(K){var L=M[K];Ye(k,d,L,M[K]=L+(1<<j-K))}}return[l,{n:se,b:j,s:k}]},bo=je(new H([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],Eo=je(new H([33,20,196,24,99,140,33,132,16,66,8,33,132,16,66,8,33,68,68,68,68,68,68,68,68,36,9]),0,6)[1],Mo=je(new H([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],Jr=function(p,l){for(var d=p.length,i=new qe(d),f=0;f<d;++f)i[f]=l,l+=1<<p[f];return i},dr=new H(new qe([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),Do=Jr(dr,0),fr=new H(new qe([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),Xo=Jr(fr,3),Ze=function(p,l,d){var i=p.length,f=l.length,m=p[i-1],_=(1<<d.b)-1,h=-d.b;m||T(0);for(var M=0,I=d.b,Q=(i<<3)-8+Xe(m)-I,Z=-1;Q>h&&Z<f;){var Y=Q>>3,z=(p[Y]|p[Y+1]<<8|p[Y+2]<<16)>>(Q&7);M=(M<<I|z)&_,l[++Z]=d.s[M],Q-=I=d.n[M]}(Q!=h||Z+1!=f)&&T(0)},Lo=function(p,l,d){var i=6,f=l.length,m=f+3>>2,_=m<<1,h=m+_;Ze(p.subarray(i,i+=p[0]|p[1]<<8),l.subarray(0,m),d),Ze(p.subarray(i,i+=p[2]|p[3]<<8),l.subarray(m,_),d),Ze(p.subarray(i,i+=p[4]|p[5]<<8),l.subarray(_,h),d),Ze(p.subarray(i),l.subarray(h),d)},Bo=function(p,l,d){var i,f=l.b,m=p[f],_=m>>1&3;l.l=m&1;var h=m>>3|p[f+1]<<5|p[f+2]<<13,M=(f+=3)+h;if(_==1)return f>=p.length?void 0:(l.b=f+1,d?(Ye(d,p[f],l.y,l.y+=h),d):Ye(new H(h),p[f]));if(!(M>p.length)){if(_==0)return l.b=M,d?(d.set(p.subarray(f,M),l.y),l.y+=h,d):lr(p,f,M);if(_==2){var I=p[f],Q=I&3,Z=I>>2&3,Y=I>>4,z=0,q=0;Q<2?Z&1?Y|=p[++f]<<4|(Z&2&&p[++f]<<12):Y=I>>3:(q=Z,Z<2?(Y|=(p[++f]&63)<<4,z=p[f]>>6|p[++f]<<2):Z==2?(Y|=p[++f]<<4|(p[++f]&3)<<12,z=p[f]>>2|p[++f]<<6):(Y|=p[++f]<<4|(p[++f]&63)<<12,z=p[f]>>6|p[++f]<<2|p[++f]<<10)),++f;var X=d?d.subarray(l.y,l.y+l.m):new H(l.m),V=X.length-Y;if(Q==0)X.set(p.subarray(f,f+=Y),V);else if(Q==1)Ye(X,p[f++],V);else{var re=l.h;if(Q==2){var S=yo(p,f);z+=f-(f=S[0]),l.h=re=S[1]}else re||T(0);(q?Lo:Ze)(p.subarray(f,f+=z),X.subarray(V),re)}var P=p[f++];if(P){P==255?P=(p[f++]|p[f++]<<8)+32512:P>127&&(P=P-128<<8|p[f++]);var ae=p[f++];ae&3&&T(0);for(var J=[Eo,Mo,bo],w=2;w>-1;--w){var j=ae>>(w<<1)+2&3;if(j==1){var W=new H([0,0,p[f++]]);J[w]={s:W.subarray(2,3),n:W.subarray(0,1),t:new Qe(W.buffer,0,1),b:0}}else j==2?(i=je(p,f,9-(w&1)),f=i[0],J[w]=i[1]):j==3&&(l.t||T(0),J[w]=l.t[w])}var ie=l.t=J,b=ie[0],k=ie[1],se=ie[2],oe=p[M-1];oe||T(0);var K=(M<<3)-8+Xe(oe)-se.b,L=K>>3,A=0,Le=(p[L]|p[L+1]<<8)>>(K&7)&(1<<se.b)-1;L=(K-=k.b)>>3;var Be=(p[L]|p[L+1]<<8)>>(K&7)&(1<<k.b)-1;L=(K-=b.b)>>3;var Re=(p[L]|p[L+1]<<8)>>(K&7)&(1<<b.b)-1;for(++P;--P;){var Ne=se.s[Le],Pe=se.n[Le],Ve=b.s[Re],ye=b.n[Re],ke=k.s[Be],be=k.n[Be];L=(K-=ke)>>3;var $e=1<<ke,ce=$e+((p[L]|p[L+1]<<8|p[L+2]<<16|p[L+3]<<24)>>>(K&7)&$e-1);L=(K-=fr[Ve])>>3;var me=Xo[Ve]+((p[L]|p[L+1]<<8|p[L+2]<<16)>>(K&7)&(1<<fr[Ve])-1);L=(K-=dr[Ne])>>3;var _e=Do[Ne]+((p[L]|p[L+1]<<8|p[L+2]<<16)>>(K&7)&(1<<dr[Ne])-1);if(L=(K-=Pe)>>3,Le=se.t[Le]+((p[L]|p[L+1]<<8)>>(K&7)&(1<<Pe)-1),L=(K-=ye)>>3,Re=b.t[Re]+((p[L]|p[L+1]<<8)>>(K&7)&(1<<ye)-1),L=(K-=be)>>3,Be=k.t[Be]+((p[L]|p[L+1]<<8)>>(K&7)&(1<<be)-1),ce>3)l.o[2]=l.o[1],l.o[1]=l.o[0],l.o[0]=ce-=3;else{var Ge=ce-(_e!=0);Ge?(ce=Ge==3?l.o[0]-1:l.o[Ge],Ge>1&&(l.o[2]=l.o[1]),l.o[1]=l.o[0],l.o[0]=ce):ce=l.o[0]}for(var w=0;w<_e;++w)X[A+w]=X[V+w];A+=_e,V+=_e;var Ee=A-ce;if(Ee<0){var De=-Ee,We=l.e+Ee;De>me&&(De=me);for(var w=0;w<De;++w)X[A+w]=l.w[We+w];A+=De,me-=De,Ee=0}for(var w=0;w<me;++w)X[A+w]=X[Ee+w];A+=me}if(A!=V)for(;V<X.length;)X[A++]=X[V++];else A=X.length;d?l.y+=A:X=lr(X,0,A)}else if(d){if(l.y+=Y,V)for(var w=0;w<Y;++w)X[w]=X[V+w]}else V&&(X=lr(X,V));return l.b=M,X}T(2)}},Ro=function(p,l){if(p.length==1)return p[0];for(var d=new H(l),i=0,f=0;i<p.length;++i){var m=p[i];d.set(m,f),f+=m.length}return d};function ko(p,l){for(var d=[],i=+!l,f=0,m=0;p.length;){var _=wo(p,i||l);if(typeof _=="object"){for(i?(l=null,_.w.length==_.u&&(d.push(l=_.w),m+=_.u)):(d.push(l),_.e=0);!_.l;){var h=Bo(p,_,l);h||T(5),l?_.e=_.y:(d.push(h),m+=h.length,_o(_.w,0,h.length),_.w.set(h,_.w.length-h.length))}f=_.b+_.c*4}else f=_;p=p.subarray(f)}return Ro(d,m)}var Go=(()=>{var p=typeof document<"u"?document.currentScript?.src:void 0;return function(l={}){var d,i=l,f,m,_=new Promise((e,r)=>{f=e,m=r}),h=!1,M=Object.assign({},i),I="./this.program",Q=(e,r)=>{throw r},Z="";function Y(e){return Z+e}var z,q,X=console.log.bind(console),V=console.error.bind(console);Object.assign(i,M),M=null;var re;i.wasmBinary&&(re=i.wasmBinary);var S,P=!1,ae;function J(e,r){e||_e(r)}var w,j,W,ie,b,k,se,oe;function K(){var e=S.buffer;i.HEAP8=w=new Int8Array(e),i.HEAP16=W=new Int16Array(e),i.HEAPU8=j=new Uint8Array(e),i.HEAPU16=ie=new Uint16Array(e),i.HEAP32=b=new Int32Array(e),i.HEAPU32=k=new Uint32Array(e),i.HEAPF32=se=new Float32Array(e),i.HEAPF64=oe=new Float64Array(e)}var L=[],A=[],Le=[],Be=!1;function Re(){Ae(L)}function Ne(){Be=!0,!i.noFSInit&&!o.init.initialized&&o.init(),o.ignorePermissions=!1,Me.init(),Ae(A)}function Pe(){Ae(Le)}function Ve(e){A.unshift(e)}var ye=0,ke=null,be=null;function $e(e){return e}function ce(e){ye++}function me(e){if(ye--,ye==0&&(ke!==null&&(clearInterval(ke),ke=null),be)){var r=be;be=null,r()}}function _e(e){e="Aborted("+e+")",V(e),P=!0,ae=1,e+=". Build with -sASSERTIONS for more info.";var r=new WebAssembly.RuntimeError(e);throw m(r),r}var Ge="data:application/octet-stream;base64,",Ee=e=>e.startsWith(Ge),De=e=>e.startsWith("file://");function We(){var e="graphvizlib.wasm";return Ee(e)?e:Y(e)}var Je;function vr(e){if(e==Je&&re)return new Uint8Array(re);if(q)return q(e);throw"both async and sync fetching of the wasm failed"}function Sr(e){return re?Promise.resolve().then(()=>vr(e)):z(e).then(r=>new Uint8Array(r),()=>vr(e))}function mr(e,r,t){return Sr(e).then(n=>WebAssembly.instantiate(n,r)).then(t,n=>{V(`failed to asynchronously prepare wasm: ${n}`),_e(n)})}function Hr(e,r,t,n){return!e&&typeof WebAssembly.instantiateStreaming=="function"&&!Ee(r)&&!De(r)&&typeof fetch=="function"?fetch(r,{credentials:"same-origin"}).then(a=>{var s=WebAssembly.instantiateStreaming(a,t);return s.then(n,function(u){return V(`wasm streaming compile failed: ${u}`),V("falling back to ArrayBuffer instantiation"),mr(r,t,n)})}):mr(r,t,n)}function Tr(){return{a:qt}}function Qr(){var e=Tr();function r(n,a){return N=n.exports,S=N.B,K(),Ve(N.C),me("wasm-instantiate"),N}ce("wasm-instantiate");function t(n){r(n.instance)}return Je||(Je=We()),Hr(re,Je,e,t).catch(m),{}}var R,$,qr={172808:(e,r)=>{var t=ue(e),n=ue(r);o.createPath("/",C.dirname(t)),o.writeFile(C.join("/",t),n)}};function $r(e){this.name="ExitStatus",this.message=`Program terminated with exit(${e})`,this.status=e}var Ae=e=>{for(;e.length>0;)e.shift()(i)};class Wr{constructor(r){this.excPtr=r,this.ptr=r-24}set_type(r){k[this.ptr+4>>2]=r}get_type(){return k[this.ptr+4>>2]}set_destructor(r){k[this.ptr+8>>2]=r}get_destructor(){return k[this.ptr+8>>2]}set_caught(r){r=r?1:0,w[this.ptr+12]=r}get_caught(){return w[this.ptr+12]!=0}set_rethrown(r){r=r?1:0,w[this.ptr+13]=r}get_rethrown(){return w[this.ptr+13]!=0}init(r,t){this.set_adjusted_ptr(0),this.set_type(r),this.set_destructor(t)}set_adjusted_ptr(r){k[this.ptr+16>>2]=r}get_adjusted_ptr(){return k[this.ptr+16>>2]}get_exception_ptr(){var r=zr(this.get_type());if(r)return k[this.excPtr>>2];var t=this.get_adjusted_ptr();return t!==0?t:this.excPtr}}var _r=0,Ar=0,et=(e,r,t)=>{var n=new Wr(e);throw n.init(r,t),_r=e,Ar++,_r},C={isAbs:e=>e.charAt(0)==="/",splitPath:e=>{var r=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return r.exec(e).slice(1)},normalizeArray:(e,r)=>{for(var t=0,n=e.length-1;n>=0;n--){var a=e[n];a==="."?e.splice(n,1):a===".."?(e.splice(n,1),t++):t&&(e.splice(n,1),t--)}if(r)for(;t;t--)e.unshift("..");return e},normalize:e=>{var r=C.isAbs(e),t=e.substr(-1)==="/";return e=C.normalizeArray(e.split("/").filter(n=>!!n),!r).join("/"),!e&&!r&&(e="."),e&&t&&(e+="/"),(r?"/":"")+e},dirname:e=>{var r=C.splitPath(e),t=r[0],n=r[1];return!t&&!n?".":(n&&(n=n.substr(0,n.length-1)),t+n)},basename:e=>{if(e==="/")return"/";e=C.normalize(e),e=e.replace(/\/$/,"");var r=e.lastIndexOf("/");return r===-1?e:e.substr(r+1)},join:(...e)=>C.normalize(e.join("/")),join2:(e,r)=>C.normalize(e+"/"+r)},rt=()=>{if(typeof crypto=="object"&&typeof crypto.getRandomValues=="function")return e=>crypto.getRandomValues(e);_e("initRandomDevice")},gr=e=>(gr=rt())(e),he={resolve:(...e)=>{for(var r="",t=!1,n=e.length-1;n>=-1&&!t;n--){var a=n>=0?e[n]:o.cwd();if(typeof a!="string")throw new TypeError("Arguments to path.resolve must be strings");if(!a)return"";r=a+"/"+r,t=C.isAbs(a)}return r=C.normalizeArray(r.split("/").filter(s=>!!s),!t).join("/"),(t?"/":"")+r||"."},relative:(e,r)=>{e=he.resolve(e).substr(1),r=he.resolve(r).substr(1);function t(E){for(var G=0;G<E.length&&E[G]==="";G++);for(var x=E.length-1;x>=0&&E[x]==="";x--);return G>x?[]:E.slice(G,x-G+1)}for(var n=t(e.split("/")),a=t(r.split("/")),s=Math.min(n.length,a.length),u=s,c=0;c<s;c++)if(n[c]!==a[c]){u=c;break}for(var v=[],c=u;c<n.length;c++)v.push("..");return v=v.concat(a.slice(u)),v.join("/")}},hr=typeof TextDecoder<"u"?new TextDecoder:void 0,Fe=(e,r,t)=>{for(var n=r+t,a=r;e[a]&&!(a>=n);)++a;if(a-r>16&&e.buffer&&hr)return hr.decode(e.subarray(r,a));for(var s="";r<a;){var u=e[r++];if(!(u&128)){s+=String.fromCharCode(u);continue}var c=e[r++]&63;if((u&224)==192){s+=String.fromCharCode((u&31)<<6|c);continue}var v=e[r++]&63;if((u&240)==224?u=(u&15)<<12|c<<6|v:u=(u&7)<<18|c<<12|v<<6|e[r++]&63,u<65536)s+=String.fromCharCode(u);else{var E=u-65536;s+=String.fromCharCode(55296|E>>10,56320|E&1023)}}return s},er=[],rr=e=>{for(var r=0,t=0;t<e.length;++t){var n=e.charCodeAt(t);n<=127?r++:n<=2047?r+=2:n>=55296&&n<=57343?(r+=4,++t):r+=3}return r},tr=(e,r,t,n)=>{if(!(n>0))return 0;for(var a=t,s=t+n-1,u=0;u<e.length;++u){var c=e.charCodeAt(u);if(c>=55296&&c<=57343){var v=e.charCodeAt(++u);c=65536+((c&1023)<<10)|v&1023}if(c<=127){if(t>=s)break;r[t++]=c}else if(c<=2047){if(t+1>=s)break;r[t++]=192|c>>6,r[t++]=128|c&63}else if(c<=65535){if(t+2>=s)break;r[t++]=224|c>>12,r[t++]=128|c>>6&63,r[t++]=128|c&63}else{if(t+3>=s)break;r[t++]=240|c>>18,r[t++]=128|c>>12&63,r[t++]=128|c>>6&63,r[t++]=128|c&63}}return r[t]=0,t-a};function or(e,r,t){var n=t>0?t:rr(e)+1,a=new Array(n),s=tr(e,a,0,a.length);return r&&(a.length=s),a}var tt=()=>{if(!er.length){var e=null;if(!e)return null;er=or(e,!0)}return er.shift()},Me={ttys:[],init(){},shutdown(){},register(e,r){Me.ttys[e]={input:[],output:[],ops:r},o.registerDevice(e,Me.stream_ops)},stream_ops:{open(e){var r=Me.ttys[e.node.rdev];if(!r)throw new o.ErrnoError(43);e.tty=r,e.seekable=!1},close(e){e.tty.ops.fsync(e.tty)},fsync(e){e.tty.ops.fsync(e.tty)},read(e,r,t,n,a){if(!e.tty||!e.tty.ops.get_char)throw new o.ErrnoError(60);for(var s=0,u=0;u<n;u++){var c;try{c=e.tty.ops.get_char(e.tty)}catch{throw new o.ErrnoError(29)}if(c===void 0&&s===0)throw new o.ErrnoError(6);if(c==null)break;s++,r[t+u]=c}return s&&(e.node.timestamp=Date.now()),s},write(e,r,t,n,a){if(!e.tty||!e.tty.ops.put_char)throw new o.ErrnoError(60);try{for(var s=0;s<n;s++)e.tty.ops.put_char(e.tty,r[t+s])}catch{throw new o.ErrnoError(29)}return n&&(e.node.timestamp=Date.now()),s}},default_tty_ops:{get_char(e){return tt()},put_char(e,r){r===null||r===10?(X(Fe(e.output,0)),e.output=[]):r!=0&&e.output.push(r)},fsync(e){e.output&&e.output.length>0&&(X(Fe(e.output,0)),e.output=[])},ioctl_tcgets(e){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(e,r,t){return 0},ioctl_tiocgwinsz(e){return[24,80]}},default_tty1_ops:{put_char(e,r){r===null||r===10?(V(Fe(e.output,0)),e.output=[]):r!=0&&e.output.push(r)},fsync(e){e.output&&e.output.length>0&&(V(Fe(e.output,0)),e.output=[])}}},ot=(e,r)=>(j.fill(0,e,e+r),e),wr=(e,r)=>Math.ceil(e/r)*r,yr=e=>{e=wr(e,65536);var r=Yr(65536,e);return r?ot(r,e):0},D={ops_table:null,mount(e){return D.createNode(null,"/",16895,0)},createNode(e,r,t,n){if(o.isBlkdev(t)||o.isFIFO(t))throw new o.ErrnoError(63);D.ops_table||={dir:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr,lookup:D.node_ops.lookup,mknod:D.node_ops.mknod,rename:D.node_ops.rename,unlink:D.node_ops.unlink,rmdir:D.node_ops.rmdir,readdir:D.node_ops.readdir,symlink:D.node_ops.symlink},stream:{llseek:D.stream_ops.llseek}},file:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr},stream:{llseek:D.stream_ops.llseek,read:D.stream_ops.read,write:D.stream_ops.write,allocate:D.stream_ops.allocate,mmap:D.stream_ops.mmap,msync:D.stream_ops.msync}},link:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr,readlink:D.node_ops.readlink},stream:{}},chrdev:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr},stream:o.chrdev_stream_ops}};var a=o.createNode(e,r,t,n);return o.isDir(a.mode)?(a.node_ops=D.ops_table.dir.node,a.stream_ops=D.ops_table.dir.stream,a.contents={}):o.isFile(a.mode)?(a.node_ops=D.ops_table.file.node,a.stream_ops=D.ops_table.file.stream,a.usedBytes=0,a.contents=null):o.isLink(a.mode)?(a.node_ops=D.ops_table.link.node,a.stream_ops=D.ops_table.link.stream):o.isChrdev(a.mode)&&(a.node_ops=D.ops_table.chrdev.node,a.stream_ops=D.ops_table.chrdev.stream),a.timestamp=Date.now(),e&&(e.contents[r]=a,e.timestamp=a.timestamp),a},getFileDataAsTypedArray(e){return e.contents?e.contents.subarray?e.contents.subarray(0,e.usedBytes):new Uint8Array(e.contents):new Uint8Array(0)},expandFileStorage(e,r){var t=e.contents?e.contents.length:0;if(!(t>=r)){var n=1048576;r=Math.max(r,t*(t<n?2:1.125)>>>0),t!=0&&(r=Math.max(r,256));var a=e.contents;e.contents=new Uint8Array(r),e.usedBytes>0&&e.contents.set(a.subarray(0,e.usedBytes),0)}},resizeFileStorage(e,r){if(e.usedBytes!=r)if(r==0)e.contents=null,e.usedBytes=0;else{var t=e.contents;e.contents=new Uint8Array(r),t&&e.contents.set(t.subarray(0,Math.min(r,e.usedBytes))),e.usedBytes=r}},node_ops:{getattr(e){var r={};return r.dev=o.isChrdev(e.mode)?e.id:1,r.ino=e.id,r.mode=e.mode,r.nlink=1,r.uid=0,r.gid=0,r.rdev=e.rdev,o.isDir(e.mode)?r.size=4096:o.isFile(e.mode)?r.size=e.usedBytes:o.isLink(e.mode)?r.size=e.link.length:r.size=0,r.atime=new Date(e.timestamp),r.mtime=new Date(e.timestamp),r.ctime=new Date(e.timestamp),r.blksize=4096,r.blocks=Math.ceil(r.size/r.blksize),r},setattr(e,r){r.mode!==void 0&&(e.mode=r.mode),r.timestamp!==void 0&&(e.timestamp=r.timestamp),r.size!==void 0&&D.resizeFileStorage(e,r.size)},lookup(e,r){throw o.genericErrors[44]},mknod(e,r,t,n){return D.createNode(e,r,t,n)},rename(e,r,t){if(o.isDir(e.mode)){var n;try{n=o.lookupNode(r,t)}catch{}if(n)for(var a in n.contents)throw new o.ErrnoError(55)}delete e.parent.contents[e.name],e.parent.timestamp=Date.now(),e.name=t,r.contents[t]=e,r.timestamp=e.parent.timestamp},unlink(e,r){delete e.contents[r],e.timestamp=Date.now()},rmdir(e,r){var t=o.lookupNode(e,r);for(var n in t.contents)throw new o.ErrnoError(55);delete e.contents[r],e.timestamp=Date.now()},readdir(e){var r=[".",".."];for(var t of Object.keys(e.contents))r.push(t);return r},symlink(e,r,t){var n=D.createNode(e,r,41471,0);return n.link=t,n},readlink(e){if(!o.isLink(e.mode))throw new o.ErrnoError(28);return e.link}},stream_ops:{read(e,r,t,n,a){var s=e.node.contents;if(a>=e.node.usedBytes)return 0;var u=Math.min(e.node.usedBytes-a,n);if(u>8&&s.subarray)r.set(s.subarray(a,a+u),t);else for(var c=0;c<u;c++)r[t+c]=s[a+c];return u},write(e,r,t,n,a,s){if(r.buffer===w.buffer&&(s=!1),!n)return 0;var u=e.node;if(u.timestamp=Date.now(),r.subarray&&(!u.contents||u.contents.subarray)){if(s)return u.contents=r.subarray(t,t+n),u.usedBytes=n,n;if(u.usedBytes===0&&a===0)return u.contents=r.slice(t,t+n),u.usedBytes=n,n;if(a+n<=u.usedBytes)return u.contents.set(r.subarray(t,t+n),a),n}if(D.expandFileStorage(u,a+n),u.contents.subarray&&r.subarray)u.contents.set(r.subarray(t,t+n),a);else for(var c=0;c<n;c++)u.contents[a+c]=r[t+c];return u.usedBytes=Math.max(u.usedBytes,a+n),n},llseek(e,r,t){var n=r;if(t===1?n+=e.position:t===2&&o.isFile(e.node.mode)&&(n+=e.node.usedBytes),n<0)throw new o.ErrnoError(28);return n},allocate(e,r,t){D.expandFileStorage(e.node,r+t),e.node.usedBytes=Math.max(e.node.usedBytes,r+t)},mmap(e,r,t,n,a){if(!o.isFile(e.node.mode))throw new o.ErrnoError(43);var s,u,c=e.node.contents;if(!(a&2)&&c.buffer===w.buffer)u=!1,s=c.byteOffset;else{if((t>0||t+r<c.length)&&(c.subarray?c=c.subarray(t,t+r):c=Array.prototype.slice.call(c,t,t+r)),u=!0,s=yr(r),!s)throw new o.ErrnoError(48);w.set(c,s)}return{ptr:s,allocated:u}},msync(e,r,t,n,a){return D.stream_ops.write(e,r,0,n,t,!1),0}}},nt=(e,r,t,n)=>{var a=n?"":`al ${e}`;z(e).then(s=>{r(new Uint8Array(s)),a&&me(a)},s=>{if(t)t();else throw`Loading data file "${e}" failed.`}),a&&ce(a)},at=(e,r,t,n,a,s)=>{o.createDataFile(e,r,t,n,a,s)},it=[],st=(e,r,t,n)=>{typeof Browser<"u"&&Browser.init();var a=!1;return it.forEach(s=>{a||s.canHandle(r)&&(s.handle(e,r,t,n),a=!0)}),a},ut=(e,r,t,n,a,s,u,c,v,E)=>{var G=r?he.resolve(C.join2(e,r)):e,x=`cp ${G}`;function B(y){function O(te){E?.(),c||at(e,r,te,n,a,v),s?.(),me(x)}st(y,G,O,()=>{u?.(),me(x)})||O(y)}ce(x),typeof t=="string"?nt(t,B,u):B(t)},pt=e=>{var r={r:0,"r+":2,w:577,"w+":578,a:1089,"a+":1090},t=r[e];if(typeof t>"u")throw new Error(`Unknown file open mode: ${e}`);return t},nr=(e,r)=>{var t=0;return e&&(t|=365),r&&(t|=146),t},o={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:!1,ignorePermissions:!0,ErrnoError:class{constructor(e){this.name="ErrnoError",this.errno=e}},genericErrors:{},filesystems:null,syncFSRequests:0,FSStream:class{constructor(){this.shared={}}get object(){return this.node}set object(e){this.node=e}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(e){this.shared.flags=e}get position(){return this.shared.position}set position(e){this.shared.position=e}},FSNode:class{constructor(e,r,t,n){e||(e=this),this.parent=e,this.mount=e.mount,this.mounted=null,this.id=o.nextInode++,this.name=r,this.mode=t,this.node_ops={},this.stream_ops={},this.rdev=n,this.readMode=365,this.writeMode=146}get read(){return(this.mode&this.readMode)===this.readMode}set read(e){e?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(e){e?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return o.isDir(this.mode)}get isDevice(){return o.isChrdev(this.mode)}},lookupPath(e,r={}){if(e=he.resolve(e),!e)return{path:"",node:null};var t={follow_mount:!0,recurse_count:0};if(r=Object.assign(t,r),r.recurse_count>8)throw new o.ErrnoError(32);for(var n=e.split("/").filter(x=>!!x),a=o.root,s="/",u=0;u<n.length;u++){var c=u===n.length-1;if(c&&r.parent)break;if(a=o.lookupNode(a,n[u]),s=C.join2(s,n[u]),o.isMountpoint(a)&&(!c||c&&r.follow_mount)&&(a=a.mounted.root),!c||r.follow)for(var v=0;o.isLink(a.mode);){var E=o.readlink(s);s=he.resolve(C.dirname(s),E);var G=o.lookupPath(s,{recurse_count:r.recurse_count+1});if(a=G.node,v++>40)throw new o.ErrnoError(32)}}return{path:s,node:a}},getPath(e){for(var r;;){if(o.isRoot(e)){var t=e.mount.mountpoint;return r?t[t.length-1]!=="/"?`${t}/${r}`:t+r:t}r=r?`${e.name}/${r}`:e.name,e=e.parent}},hashName(e,r){for(var t=0,n=0;n<r.length;n++)t=(t<<5)-t+r.charCodeAt(n)|0;return(e+t>>>0)%o.nameTable.length},hashAddNode(e){var r=o.hashName(e.parent.id,e.name);e.name_next=o.nameTable[r],o.nameTable[r]=e},hashRemoveNode(e){var r=o.hashName(e.parent.id,e.name);if(o.nameTable[r]===e)o.nameTable[r]=e.name_next;else for(var t=o.nameTable[r];t;){if(t.name_next===e){t.name_next=e.name_next;break}t=t.name_next}},lookupNode(e,r){var t=o.mayLookup(e);if(t)throw new o.ErrnoError(t);for(var n=o.hashName(e.id,r),a=o.nameTable[n];a;a=a.name_next){var s=a.name;if(a.parent.id===e.id&&s===r)return a}return o.lookup(e,r)},createNode(e,r,t,n){var a=new o.FSNode(e,r,t,n);return o.hashAddNode(a),a},destroyNode(e){o.hashRemoveNode(e)},isRoot(e){return e===e.parent},isMountpoint(e){return!!e.mounted},isFile(e){return(e&61440)===32768},isDir(e){return(e&61440)===16384},isLink(e){return(e&61440)===40960},isChrdev(e){return(e&61440)===8192},isBlkdev(e){return(e&61440)===24576},isFIFO(e){return(e&61440)===4096},isSocket(e){return(e&49152)===49152},flagsToPermissionString(e){var r=["r","w","rw"][e&3];return e&512&&(r+="w"),r},nodePermissions(e,r){return o.ignorePermissions?0:r.includes("r")&&!(e.mode&292)||r.includes("w")&&!(e.mode&146)||r.includes("x")&&!(e.mode&73)?2:0},mayLookup(e){if(!o.isDir(e.mode))return 54;var r=o.nodePermissions(e,"x");return r||(e.node_ops.lookup?0:2)},mayCreate(e,r){try{var t=o.lookupNode(e,r);return 20}catch{}return o.nodePermissions(e,"wx")},mayDelete(e,r,t){var n;try{n=o.lookupNode(e,r)}catch(s){return s.errno}var a=o.nodePermissions(e,"wx");if(a)return a;if(t){if(!o.isDir(n.mode))return 54;if(o.isRoot(n)||o.getPath(n)===o.cwd())return 10}else if(o.isDir(n.mode))return 31;return 0},mayOpen(e,r){return e?o.isLink(e.mode)?32:o.isDir(e.mode)&&(o.flagsToPermissionString(r)!=="r"||r&512)?31:o.nodePermissions(e,o.flagsToPermissionString(r)):44},MAX_OPEN_FDS:4096,nextfd(){for(var e=0;e<=o.MAX_OPEN_FDS;e++)if(!o.streams[e])return e;throw new o.ErrnoError(33)},getStreamChecked(e){var r=o.getStream(e);if(!r)throw new o.ErrnoError(8);return r},getStream:e=>o.streams[e],createStream(e,r=-1){return e=Object.assign(new o.FSStream,e),r==-1&&(r=o.nextfd()),e.fd=r,o.streams[r]=e,e},closeStream(e){o.streams[e]=null},dupStream(e,r=-1){var t=o.createStream(e,r);return t.stream_ops?.dup?.(t),t},chrdev_stream_ops:{open(e){var r=o.getDevice(e.node.rdev);e.stream_ops=r.stream_ops,e.stream_ops.open?.(e)},llseek(){throw new o.ErrnoError(70)}},major:e=>e>>8,minor:e=>e&255,makedev:(e,r)=>e<<8|r,registerDevice(e,r){o.devices[e]={stream_ops:r}},getDevice:e=>o.devices[e],getMounts(e){for(var r=[],t=[e];t.length;){var n=t.pop();r.push(n),t.push(...n.mounts)}return r},syncfs(e,r){typeof e=="function"&&(r=e,e=!1),o.syncFSRequests++,o.syncFSRequests>1&&V(`warning: ${o.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);var t=o.getMounts(o.root.mount),n=0;function a(u){return o.syncFSRequests--,r(u)}function s(u){if(u)return s.errored?void 0:(s.errored=!0,a(u));++n>=t.length&&a(null)}t.forEach(u=>{if(!u.type.syncfs)return s(null);u.type.syncfs(u,e,s)})},mount(e,r,t){var n=t==="/",a=!t,s;if(n&&o.root)throw new o.ErrnoError(10);if(!n&&!a){var u=o.lookupPath(t,{follow_mount:!1});if(t=u.path,s=u.node,o.isMountpoint(s))throw new o.ErrnoError(10);if(!o.isDir(s.mode))throw new o.ErrnoError(54)}var c={type:e,opts:r,mountpoint:t,mounts:[]},v=e.mount(c);return v.mount=c,c.root=v,n?o.root=v:s&&(s.mounted=c,s.mount&&s.mount.mounts.push(c)),v},unmount(e){var r=o.lookupPath(e,{follow_mount:!1});if(!o.isMountpoint(r.node))throw new o.ErrnoError(28);var t=r.node,n=t.mounted,a=o.getMounts(n);Object.keys(o.nameTable).forEach(u=>{for(var c=o.nameTable[u];c;){var v=c.name_next;a.includes(c.mount)&&o.destroyNode(c),c=v}}),t.mounted=null;var s=t.mount.mounts.indexOf(n);t.mount.mounts.splice(s,1)},lookup(e,r){return e.node_ops.lookup(e,r)},mknod(e,r,t){var n=o.lookupPath(e,{parent:!0}),a=n.node,s=C.basename(e);if(!s||s==="."||s==="..")throw new o.ErrnoError(28);var u=o.mayCreate(a,s);if(u)throw new o.ErrnoError(u);if(!a.node_ops.mknod)throw new o.ErrnoError(63);return a.node_ops.mknod(a,s,r,t)},create(e,r){return r=r!==void 0?r:438,r&=4095,r|=32768,o.mknod(e,r,0)},mkdir(e,r){return r=r!==void 0?r:511,r&=1023,r|=16384,o.mknod(e,r,0)},mkdirTree(e,r){for(var t=e.split("/"),n="",a=0;a<t.length;++a)if(t[a]){n+="/"+t[a];try{o.mkdir(n,r)}catch(s){if(s.errno!=20)throw s}}},mkdev(e,r,t){return typeof t>"u"&&(t=r,r=438),r|=8192,o.mknod(e,r,t)},symlink(e,r){if(!he.resolve(e))throw new o.ErrnoError(44);var t=o.lookupPath(r,{parent:!0}),n=t.node;if(!n)throw new o.ErrnoError(44);var a=C.basename(r),s=o.mayCreate(n,a);if(s)throw new o.ErrnoError(s);if(!n.node_ops.symlink)throw new o.ErrnoError(63);return n.node_ops.symlink(n,a,e)},rename(e,r){var t=C.dirname(e),n=C.dirname(r),a=C.basename(e),s=C.basename(r),u,c,v;if(u=o.lookupPath(e,{parent:!0}),c=u.node,u=o.lookupPath(r,{parent:!0}),v=u.node,!c||!v)throw new o.ErrnoError(44);if(c.mount!==v.mount)throw new o.ErrnoError(75);var E=o.lookupNode(c,a),G=he.relative(e,n);if(G.charAt(0)!==".")throw new o.ErrnoError(28);if(G=he.relative(r,t),G.charAt(0)!==".")throw new o.ErrnoError(55);var x;try{x=o.lookupNode(v,s)}catch{}if(E!==x){var B=o.isDir(E.mode),y=o.mayDelete(c,a,B);if(y)throw new o.ErrnoError(y);if(y=x?o.mayDelete(v,s,B):o.mayCreate(v,s),y)throw new o.ErrnoError(y);if(!c.node_ops.rename)throw new o.ErrnoError(63);if(o.isMountpoint(E)||x&&o.isMountpoint(x))throw new o.ErrnoError(10);if(v!==c&&(y=o.nodePermissions(c,"w"),y))throw new o.ErrnoError(y);o.hashRemoveNode(E);try{c.node_ops.rename(E,v,s),E.parent=v}catch(O){throw O}finally{o.hashAddNode(E)}}},rmdir(e){var r=o.lookupPath(e,{parent:!0}),t=r.node,n=C.basename(e),a=o.lookupNode(t,n),s=o.mayDelete(t,n,!0);if(s)throw new o.ErrnoError(s);if(!t.node_ops.rmdir)throw new o.ErrnoError(63);if(o.isMountpoint(a))throw new o.ErrnoError(10);t.node_ops.rmdir(t,n),o.destroyNode(a)},readdir(e){var r=o.lookupPath(e,{follow:!0}),t=r.node;if(!t.node_ops.readdir)throw new o.ErrnoError(54);return t.node_ops.readdir(t)},unlink(e){var r=o.lookupPath(e,{parent:!0}),t=r.node;if(!t)throw new o.ErrnoError(44);var n=C.basename(e),a=o.lookupNode(t,n),s=o.mayDelete(t,n,!1);if(s)throw new o.ErrnoError(s);if(!t.node_ops.unlink)throw new o.ErrnoError(63);if(o.isMountpoint(a))throw new o.ErrnoError(10);t.node_ops.unlink(t,n),o.destroyNode(a)},readlink(e){var r=o.lookupPath(e),t=r.node;if(!t)throw new o.ErrnoError(44);if(!t.node_ops.readlink)throw new o.ErrnoError(28);return he.resolve(o.getPath(t.parent),t.node_ops.readlink(t))},stat(e,r){var t=o.lookupPath(e,{follow:!r}),n=t.node;if(!n)throw new o.ErrnoError(44);if(!n.node_ops.getattr)throw new o.ErrnoError(63);return n.node_ops.getattr(n)},lstat(e){return o.stat(e,!0)},chmod(e,r,t){var n;if(typeof e=="string"){var a=o.lookupPath(e,{follow:!t});n=a.node}else n=e;if(!n.node_ops.setattr)throw new o.ErrnoError(63);n.node_ops.setattr(n,{mode:r&4095|n.mode&-4096,timestamp:Date.now()})},lchmod(e,r){o.chmod(e,r,!0)},fchmod(e,r){var t=o.getStreamChecked(e);o.chmod(t.node,r)},chown(e,r,t,n){var a;if(typeof e=="string"){var s=o.lookupPath(e,{follow:!n});a=s.node}else a=e;if(!a.node_ops.setattr)throw new o.ErrnoError(63);a.node_ops.setattr(a,{timestamp:Date.now()})},lchown(e,r,t){o.chown(e,r,t,!0)},fchown(e,r,t){var n=o.getStreamChecked(e);o.chown(n.node,r,t)},truncate(e,r){if(r<0)throw new o.ErrnoError(28);var t;if(typeof e=="string"){var n=o.lookupPath(e,{follow:!0});t=n.node}else t=e;if(!t.node_ops.setattr)throw new o.ErrnoError(63);if(o.isDir(t.mode))throw new o.ErrnoError(31);if(!o.isFile(t.mode))throw new o.ErrnoError(28);var a=o.nodePermissions(t,"w");if(a)throw new o.ErrnoError(a);t.node_ops.setattr(t,{size:r,timestamp:Date.now()})},ftruncate(e,r){var t=o.getStreamChecked(e);if(!(t.flags&2097155))throw new o.ErrnoError(28);o.truncate(t.node,r)},utime(e,r,t){var n=o.lookupPath(e,{follow:!0}),a=n.node;a.node_ops.setattr(a,{timestamp:Math.max(r,t)})},open(e,r,t){if(e==="")throw new o.ErrnoError(44);r=typeof r=="string"?pt(r):r,r&64?(t=typeof t>"u"?438:t,t=t&4095|32768):t=0;var n;if(typeof e=="object")n=e;else{e=C.normalize(e);try{var a=o.lookupPath(e,{follow:!(r&131072)});n=a.node}catch{}}var s=!1;if(r&64)if(n){if(r&128)throw new o.ErrnoError(20)}else n=o.mknod(e,t,0),s=!0;if(!n)throw new o.ErrnoError(44);if(o.isChrdev(n.mode)&&(r&=-513),r&65536&&!o.isDir(n.mode))throw new o.ErrnoError(54);if(!s){var u=o.mayOpen(n,r);if(u)throw new o.ErrnoError(u)}r&512&&!s&&o.truncate(n,0),r&=-131713;var c=o.createStream({node:n,path:o.getPath(n),flags:r,seekable:!0,position:0,stream_ops:n.stream_ops,ungotten:[],error:!1});return c.stream_ops.open&&c.stream_ops.open(c),i.logReadFiles&&!(r&1)&&(o.readFiles||(o.readFiles={}),e in o.readFiles||(o.readFiles[e]=1)),c},close(e){if(o.isClosed(e))throw new o.ErrnoError(8);e.getdents&&(e.getdents=null);try{e.stream_ops.close&&e.stream_ops.close(e)}catch(r){throw r}finally{o.closeStream(e.fd)}e.fd=null},isClosed(e){return e.fd===null},llseek(e,r,t){if(o.isClosed(e))throw new o.ErrnoError(8);if(!e.seekable||!e.stream_ops.llseek)throw new o.ErrnoError(70);if(t!=0&&t!=1&&t!=2)throw new o.ErrnoError(28);return e.position=e.stream_ops.llseek(e,r,t),e.ungotten=[],e.position},read(e,r,t,n,a){if(n<0||a<0)throw new o.ErrnoError(28);if(o.isClosed(e))throw new o.ErrnoError(8);if((e.flags&2097155)===1)throw new o.ErrnoError(8);if(o.isDir(e.node.mode))throw new o.ErrnoError(31);if(!e.stream_ops.read)throw new o.ErrnoError(28);var s=typeof a<"u";if(!s)a=e.position;else if(!e.seekable)throw new o.ErrnoError(70);var u=e.stream_ops.read(e,r,t,n,a);return s||(e.position+=u),u},write(e,r,t,n,a,s){if(n<0||a<0)throw new o.ErrnoError(28);if(o.isClosed(e))throw new o.ErrnoError(8);if(!(e.flags&2097155))throw new o.ErrnoError(8);if(o.isDir(e.node.mode))throw new o.ErrnoError(31);if(!e.stream_ops.write)throw new o.ErrnoError(28);e.seekable&&e.flags&1024&&o.llseek(e,0,2);var u=typeof a<"u";if(!u)a=e.position;else if(!e.seekable)throw new o.ErrnoError(70);var c=e.stream_ops.write(e,r,t,n,a,s);return u||(e.position+=c),c},allocate(e,r,t){if(o.isClosed(e))throw new o.ErrnoError(8);if(r<0||t<=0)throw new o.ErrnoError(28);if(!(e.flags&2097155))throw new o.ErrnoError(8);if(!o.isFile(e.node.mode)&&!o.isDir(e.node.mode))throw new o.ErrnoError(43);if(!e.stream_ops.allocate)throw new o.ErrnoError(138);e.stream_ops.allocate(e,r,t)},mmap(e,r,t,n,a){if(n&2&&!(a&2)&&(e.flags&2097155)!==2)throw new o.ErrnoError(2);if((e.flags&2097155)===1)throw new o.ErrnoError(2);if(!e.stream_ops.mmap)throw new o.ErrnoError(43);return e.stream_ops.mmap(e,r,t,n,a)},msync(e,r,t,n,a){return e.stream_ops.msync?e.stream_ops.msync(e,r,t,n,a):0},ioctl(e,r,t){if(!e.stream_ops.ioctl)throw new o.ErrnoError(59);return e.stream_ops.ioctl(e,r,t)},readFile(e,r={}){if(r.flags=r.flags||0,r.encoding=r.encoding||"binary",r.encoding!=="utf8"&&r.encoding!=="binary")throw new Error(`Invalid encoding type "${r.encoding}"`);var t,n=o.open(e,r.flags),a=o.stat(e),s=a.size,u=new Uint8Array(s);return o.read(n,u,0,s,0),r.encoding==="utf8"?t=Fe(u,0):r.encoding==="binary"&&(t=u),o.close(n),t},writeFile(e,r,t={}){t.flags=t.flags||577;var n=o.open(e,t.flags,t.mode);if(typeof r=="string"){var a=new Uint8Array(rr(r)+1),s=tr(r,a,0,a.length);o.write(n,a,0,s,void 0,t.canOwn)}else if(ArrayBuffer.isView(r))o.write(n,r,0,r.byteLength,void 0,t.canOwn);else throw new Error("Unsupported data type");o.close(n)},cwd:()=>o.currentPath,chdir(e){var r=o.lookupPath(e,{follow:!0});if(r.node===null)throw new o.ErrnoError(44);if(!o.isDir(r.node.mode))throw new o.ErrnoError(54);var t=o.nodePermissions(r.node,"x");if(t)throw new o.ErrnoError(t);o.currentPath=r.path},createDefaultDirectories(){o.mkdir("/tmp"),o.mkdir("/home"),o.mkdir("/home/web_user")},createDefaultDevices(){o.mkdir("/dev"),o.registerDevice(o.makedev(1,3),{read:()=>0,write:(n,a,s,u,c)=>u}),o.mkdev("/dev/null",o.makedev(1,3)),Me.register(o.makedev(5,0),Me.default_tty_ops),Me.register(o.makedev(6,0),Me.default_tty1_ops),o.mkdev("/dev/tty",o.makedev(5,0)),o.mkdev("/dev/tty1",o.makedev(6,0));var e=new Uint8Array(1024),r=0,t=()=>(r===0&&(r=gr(e).byteLength),e[--r]);o.createDevice("/dev","random",t),o.createDevice("/dev","urandom",t),o.mkdir("/dev/shm"),o.mkdir("/dev/shm/tmp")},createSpecialDirectories(){o.mkdir("/proc");var e=o.mkdir("/proc/self");o.mkdir("/proc/self/fd"),o.mount({mount(){var r=o.createNode(e,"fd",16895,73);return r.node_ops={lookup(t,n){var a=+n,s=o.getStreamChecked(a),u={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>s.path}};return u.parent=u,u}},r}},{},"/proc/self/fd")},createStandardStreams(){i.stdin?o.createDevice("/dev","stdin",i.stdin):o.symlink("/dev/tty","/dev/stdin"),i.stdout?o.createDevice("/dev","stdout",null,i.stdout):o.symlink("/dev/tty","/dev/stdout"),i.stderr?o.createDevice("/dev","stderr",null,i.stderr):o.symlink("/dev/tty1","/dev/stderr");var e=o.open("/dev/stdin",0),r=o.open("/dev/stdout",1),t=o.open("/dev/stderr",1)},staticInit(){[44].forEach(e=>{o.genericErrors[e]=new o.ErrnoError(e),o.genericErrors[e].stack="<generic error, no stack>"}),o.nameTable=new Array(4096),o.mount(D,{},"/"),o.createDefaultDirectories(),o.createDefaultDevices(),o.createSpecialDirectories(),o.filesystems={MEMFS:D}},init(e,r,t){o.init.initialized=!0,i.stdin=e||i.stdin,i.stdout=r||i.stdout,i.stderr=t||i.stderr,o.createStandardStreams()},quit(){o.init.initialized=!1;for(var e=0;e<o.streams.length;e++){var r=o.streams[e];r&&o.close(r)}},findObject(e,r){var t=o.analyzePath(e,r);return t.exists?t.object:null},analyzePath(e,r){try{var t=o.lookupPath(e,{follow:!r});e=t.path}catch{}var n={isRoot:!1,exists:!1,error:0,name:null,path:null,object:null,parentExists:!1,parentPath:null,parentObject:null};try{var t=o.lookupPath(e,{parent:!0});n.parentExists=!0,n.parentPath=t.path,n.parentObject=t.node,n.name=C.basename(e),t=o.lookupPath(e,{follow:!r}),n.exists=!0,n.path=t.path,n.object=t.node,n.name=t.node.name,n.isRoot=t.path==="/"}catch(a){n.error=a.errno}return n},createPath(e,r,t,n){e=typeof e=="string"?e:o.getPath(e);for(var a=r.split("/").reverse();a.length;){var s=a.pop();if(s){var u=C.join2(e,s);try{o.mkdir(u)}catch{}e=u}}return u},createFile(e,r,t,n,a){var s=C.join2(typeof e=="string"?e:o.getPath(e),r),u=nr(n,a);return o.create(s,u)},createDataFile(e,r,t,n,a,s){var u=r;e&&(e=typeof e=="string"?e:o.getPath(e),u=r?C.join2(e,r):e);var c=nr(n,a),v=o.create(u,c);if(t){if(typeof t=="string"){for(var E=new Array(t.length),G=0,x=t.length;G<x;++G)E[G]=t.charCodeAt(G);t=E}o.chmod(v,c|146);var B=o.open(v,577);o.write(B,t,0,t.length,0,s),o.close(B),o.chmod(v,c)}},createDevice(e,r,t,n){var a=C.join2(typeof e=="string"?e:o.getPath(e),r),s=nr(!!t,!!n);o.createDevice.major||(o.createDevice.major=64);var u=o.makedev(o.createDevice.major++,0);return o.registerDevice(u,{open(c){c.seekable=!1},close(c){n?.buffer?.length&&n(10)},read(c,v,E,G,x){for(var B=0,y=0;y<G;y++){var O;try{O=t()}catch{throw new o.ErrnoError(29)}if(O===void 0&&B===0)throw new o.ErrnoError(6);if(O==null)break;B++,v[E+y]=O}return B&&(c.node.timestamp=Date.now()),B},write(c,v,E,G,x){for(var B=0;B<G;B++)try{n(v[E+B])}catch{throw new o.ErrnoError(29)}return G&&(c.node.timestamp=Date.now()),B}}),o.mkdev(a,s,u)},forceLoadFile(e){if(e.isDevice||e.isFolder||e.link||e.contents)return!0;if(typeof XMLHttpRequest<"u")throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");try{e.contents=q(e.url),e.usedBytes=e.contents.length}catch{throw new o.ErrnoError(29)}},createLazyFile(e,r,t,n,a){class s{constructor(){this.lengthKnown=!1,this.chunks=[]}get(y){if(!(y>this.length-1||y<0)){var O=y%this.chunkSize,te=y/this.chunkSize|0;return this.getter(te)[O]}}setDataGetter(y){this.getter=y}cacheLength(){var y=new XMLHttpRequest;if(y.open("HEAD",t,!1),y.send(null),!(y.status>=200&&y.status<300||y.status===304))throw new Error("Couldn't load "+t+". Status: "+y.status);var O=Number(y.getResponseHeader("Content-length")),te,de=(te=y.getResponseHeader("Accept-Ranges"))&&te==="bytes",ne=(te=y.getResponseHeader("Content-Encoding"))&&te==="gzip",fe=1024*1024;de||(fe=O);var ve=(ge,xe)=>{if(ge>xe)throw new Error("invalid range ("+ge+", "+xe+") or no bytes requested!");if(xe>O-1)throw new Error("only "+O+" bytes available! programmer error!");var ee=new XMLHttpRequest;if(ee.open("GET",t,!1),O!==fe&&ee.setRequestHeader("Range","bytes="+ge+"-"+xe),ee.responseType="arraybuffer",ee.overrideMimeType&&ee.overrideMimeType("text/plain; charset=x-user-defined"),ee.send(null),!(ee.status>=200&&ee.status<300||ee.status===304))throw new Error("Couldn't load "+t+". Status: "+ee.status);return ee.response!==void 0?new Uint8Array(ee.response||[]):or(ee.responseText||"",!0)},Ie=this;Ie.setDataGetter(ge=>{var xe=ge*fe,ee=(ge+1)*fe-1;if(ee=Math.min(ee,O-1),typeof Ie.chunks[ge]>"u"&&(Ie.chunks[ge]=ve(xe,ee)),typeof Ie.chunks[ge]>"u")throw new Error("doXHR failed!");return Ie.chunks[ge]}),(ne||!O)&&(fe=O=1,O=this.getter(0).length,fe=O,X("LazyFiles on gzip forces download of the whole file when length is accessed")),this._length=O,this._chunkSize=fe,this.lengthKnown=!0}get length(){return this.lengthKnown||this.cacheLength(),this._length}get chunkSize(){return this.lengthKnown||this.cacheLength(),this._chunkSize}}if(typeof XMLHttpRequest<"u"){if(!h)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var u=new s,c={isDevice:!1,contents:u}}else var c={isDevice:!1,url:t};var v=o.createFile(e,r,c,n,a);c.contents?v.contents=c.contents:c.url&&(v.contents=null,v.url=c.url),Object.defineProperties(v,{usedBytes:{get:function(){return this.contents.length}}});var E={},G=Object.keys(v.stream_ops);G.forEach(B=>{var y=v.stream_ops[B];E[B]=(...O)=>(o.forceLoadFile(v),y(...O))});function x(B,y,O,te,de){var ne=B.node.contents;if(de>=ne.length)return 0;var fe=Math.min(ne.length-de,te);if(ne.slice)for(var ve=0;ve<fe;ve++)y[O+ve]=ne[de+ve];else for(var ve=0;ve<fe;ve++)y[O+ve]=ne.get(de+ve);return fe}return E.read=(B,y,O,te,de)=>(o.forceLoadFile(v),x(B,y,O,te,de)),E.mmap=(B,y,O,te,de)=>{o.forceLoadFile(v);var ne=yr(y);if(!ne)throw new o.ErrnoError(48);return x(B,w,ne,y,O),{ptr:ne,allocated:!0}},v.stream_ops=E,v}},ue=(e,r)=>e?Fe(j,e,r):"",U={DEFAULT_POLLMASK:5,calculateAt(e,r,t){if(C.isAbs(r))return r;var n;if(e===-100)n=o.cwd();else{var a=U.getStreamFromFD(e);n=a.path}if(r.length==0){if(!t)throw new o.ErrnoError(44);return n}return C.join2(n,r)},doStat(e,r,t){var n=e(r);b[t>>2]=n.dev,b[t+4>>2]=n.mode,k[t+8>>2]=n.nlink,b[t+12>>2]=n.uid,b[t+16>>2]=n.gid,b[t+20>>2]=n.rdev,$=[n.size>>>0,(R=n.size,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+24>>2]=$[0],b[t+28>>2]=$[1],b[t+32>>2]=4096,b[t+36>>2]=n.blocks;var a=n.atime.getTime(),s=n.mtime.getTime(),u=n.ctime.getTime();return $=[Math.floor(a/1e3)>>>0,(R=Math.floor(a/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+40>>2]=$[0],b[t+44>>2]=$[1],k[t+48>>2]=a%1e3*1e3,$=[Math.floor(s/1e3)>>>0,(R=Math.floor(s/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+56>>2]=$[0],b[t+60>>2]=$[1],k[t+64>>2]=s%1e3*1e3,$=[Math.floor(u/1e3)>>>0,(R=Math.floor(u/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+72>>2]=$[0],b[t+76>>2]=$[1],k[t+80>>2]=u%1e3*1e3,$=[n.ino>>>0,(R=n.ino,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+88>>2]=$[0],b[t+92>>2]=$[1],0},doMsync(e,r,t,n,a){if(!o.isFile(r.node.mode))throw new o.ErrnoError(43);if(n&2)return 0;var s=j.slice(e,e+t);o.msync(r,s,a,t,n)},getStreamFromFD(e){var r=o.getStreamChecked(e);return r},varargs:void 0,getStr(e){var r=ue(e);return r}};function lt(e,r,t,n){try{if(r=U.getStr(r),r=U.calculateAt(e,r),t&-8)return-28;var a=o.lookupPath(r,{follow:!0}),s=a.node;if(!s)return-44;var u="";return t&4&&(u+="r"),t&2&&(u+="w"),t&1&&(u+="x"),u&&o.nodePermissions(s,u)?-2:0}catch(c){if(typeof o>"u"||c.name!=="ErrnoError")throw c;return-c.errno}}function Se(){var e=b[+U.varargs>>2];return U.varargs+=4,e}var Oe=Se;function ct(e,r,t){U.varargs=t;try{var n=U.getStreamFromFD(e);switch(r){case 0:{var a=Se();if(a<0)return-28;for(;o.streams[a];)a++;var s;return s=o.dupStream(n,a),s.fd}case 1:case 2:return 0;case 3:return n.flags;case 4:{var a=Se();return n.flags|=a,0}case 12:{var a=Oe(),u=0;return W[a+u>>1]=2,0}case 13:case 14:return 0}return-28}catch(c){if(typeof o>"u"||c.name!=="ErrnoError")throw c;return-c.errno}}function dt(e,r){try{var t=U.getStreamFromFD(e);return U.doStat(o.stat,t.path,r)}catch(n){if(typeof o>"u"||n.name!=="ErrnoError")throw n;return-n.errno}}function ft(e,r,t){U.varargs=t;try{var n=U.getStreamFromFD(e);switch(r){case 21509:return n.tty?0:-59;case 21505:{if(!n.tty)return-59;if(n.tty.ops.ioctl_tcgets){var a=n.tty.ops.ioctl_tcgets(n),s=Oe();b[s>>2]=a.c_iflag||0,b[s+4>>2]=a.c_oflag||0,b[s+8>>2]=a.c_cflag||0,b[s+12>>2]=a.c_lflag||0;for(var u=0;u<32;u++)w[s+u+17]=a.c_cc[u]||0;return 0}return 0}case 21510:case 21511:case 21512:return n.tty?0:-59;case 21506:case 21507:case 21508:{if(!n.tty)return-59;if(n.tty.ops.ioctl_tcsets){for(var s=Oe(),c=b[s>>2],v=b[s+4>>2],E=b[s+8>>2],G=b[s+12>>2],x=[],u=0;u<32;u++)x.push(w[s+u+17]);return n.tty.ops.ioctl_tcsets(n.tty,r,{c_iflag:c,c_oflag:v,c_cflag:E,c_lflag:G,c_cc:x})}return 0}case 21519:{if(!n.tty)return-59;var s=Oe();return b[s>>2]=0,0}case 21520:return n.tty?-28:-59;case 21531:{var s=Oe();return o.ioctl(n,r,s)}case 21523:{if(!n.tty)return-59;if(n.tty.ops.ioctl_tiocgwinsz){var B=n.tty.ops.ioctl_tiocgwinsz(n.tty),s=Oe();W[s>>1]=B[0],W[s+2>>1]=B[1]}return 0}case 21524:return n.tty?0:-59;case 21515:return n.tty?0:-59;default:return-28}}catch(y){if(typeof o>"u"||y.name!=="ErrnoError")throw y;return-y.errno}}function vt(e,r,t,n){try{r=U.getStr(r);var a=n&256,s=n&4096;return n=n&-6401,r=U.calculateAt(e,r,s),U.doStat(a?o.lstat:o.stat,r,t)}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return-u.errno}}function mt(e,r,t,n){U.varargs=n;try{r=U.getStr(r),r=U.calculateAt(e,r);var a=n?Se():0;return o.open(r,t,a).fd}catch(s){if(typeof o>"u"||s.name!=="ErrnoError")throw s;return-s.errno}}var Ke=(e,r,t)=>tr(e,j,r,t);function _t(e,r,t,n){try{if(r=U.getStr(r),r=U.calculateAt(e,r),n<=0)return-28;var a=o.readlink(r),s=Math.min(n,rr(a)),u=w[t+s];return Ke(a,t,n+1),w[t+s]=u,s}catch(c){if(typeof o>"u"||c.name!=="ErrnoError")throw c;return-c.errno}}function gt(e){try{return e=U.getStr(e),o.rmdir(e),0}catch(r){if(typeof o>"u"||r.name!=="ErrnoError")throw r;return-r.errno}}function ht(e,r){try{return e=U.getStr(e),U.doStat(o.stat,e,r)}catch(t){if(typeof o>"u"||t.name!=="ErrnoError")throw t;return-t.errno}}function wt(e,r,t){try{return r=U.getStr(r),r=U.calculateAt(e,r),t===0?o.unlink(r):t===512?o.rmdir(r):_e("Invalid flags passed to unlinkat"),0}catch(n){if(typeof o>"u"||n.name!=="ErrnoError")throw n;return-n.errno}}var yt=()=>{_e("")},bt=1,Et=()=>bt,Mt=(e,r,t)=>j.copyWithin(e,r,r+t),ar=(e,r)=>r+2097152>>>0<4194305-!!e?(e>>>0)+r*4294967296:NaN;function Dt(e,r,t,n,a,s,u,c){var v=ar(a,s);try{if(isNaN(v))return 61;var E=U.getStreamFromFD(n),G=o.mmap(E,e,v,r,t),x=G.ptr;return b[u>>2]=G.allocated,k[c>>2]=x,0}catch(B){if(typeof o>"u"||B.name!=="ErrnoError")throw B;return-B.errno}}function Xt(e,r,t,n,a,s,u){var c=ar(s,u);try{var v=U.getStreamFromFD(a);t&2&&U.doMsync(e,v,r,n,c)}catch(E){if(typeof o>"u"||E.name!=="ErrnoError")throw E;return-E.errno}}var Lt=(e,r,t,n)=>{var a=new Date().getFullYear(),s=new Date(a,0,1),u=new Date(a,6,1),c=s.getTimezoneOffset(),v=u.getTimezoneOffset(),E=Math.max(c,v);k[e>>2]=E*60,b[r>>2]=+(c!=v);var G=y=>{var O=y>=0?"-":"+",te=Math.abs(y),de=String(Math.floor(te/60)).padStart(2,"0"),ne=String(te%60).padStart(2,"0");return`UTC${O}${de}${ne}`},x=G(c),B=G(v);v<c?(Ke(x,t,17),Ke(B,n,17)):(Ke(x,n,17),Ke(B,t,17))},ir=[],Bt=(e,r)=>{ir.length=0;for(var t;t=j[e++];){var n=t!=105;n&=t!=112,r+=n&&r%8?4:0,ir.push(t==112?k[r>>2]:t==105?b[r>>2]:oe[r>>3]),r+=n?8:4}return ir},Rt=(e,r,t)=>{var n=Bt(r,t);return qr[e](...n)},kt=(e,r,t)=>Rt(e,r,t),Gt=()=>Date.now(),Ft;Ft=()=>performance.now();var Ot=()=>2147483648,xt=e=>{var r=S.buffer,t=(e-r.byteLength+65535)/65536;try{return S.grow(t),K(),1}catch{}},Ut=e=>{var r=j.length;e>>>=0;var t=Ot();if(e>t)return!1;for(var n=(v,E)=>v+(E-v%E)%E,a=1;a<=4;a*=2){var s=r*(1+.2/a);s=Math.min(s,e+100663296);var u=Math.min(t,n(Math.max(e,s),65536)),c=xt(u);if(c)return!0}return!1},sr={},Nt=()=>I||"./this.program",Ce=()=>{if(!Ce.strings){var e=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",r={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:e,_:Nt()};for(var t in sr)sr[t]===void 0?delete r[t]:r[t]=sr[t];var n=[];for(var t in r)n.push(`${t}=${r[t]}`);Ce.strings=n}return Ce.strings},Vt=(e,r)=>{for(var t=0;t<e.length;++t)w[r++]=e.charCodeAt(t);w[r]=0},Kt=(e,r)=>{var t=0;return Ce().forEach((n,a)=>{var s=r+t;k[e+a*4>>2]=s,Vt(n,s),t+=n.length+1}),0},Ct=(e,r)=>{var t=Ce();k[e>>2]=t.length;var n=0;return t.forEach(a=>n+=a.length+1),k[r>>2]=n,0},It=0,Zt=()=>It>0,Yt=e=>{ae=e,Zt()||(P=!0),Q(e,new $r(e))},zt=(e,r)=>{ae=e,Yt(e)},jt=zt;function Pt(e){try{var r=U.getStreamFromFD(e);return o.close(r),0}catch(t){if(typeof o>"u"||t.name!=="ErrnoError")throw t;return t.errno}}var Jt=(e,r,t,n)=>{for(var a=0,s=0;s<t;s++){var u=k[r>>2],c=k[r+4>>2];r+=8;var v=o.read(e,w,u,c,n);if(v<0)return-1;if(a+=v,v<c)break;typeof n<"u"&&(n+=v)}return a};function St(e,r,t,n){try{var a=U.getStreamFromFD(e),s=Jt(a,r,t);return k[n>>2]=s,0}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return u.errno}}function Ht(e,r,t,n,a){var s=ar(r,t);try{if(isNaN(s))return 61;var u=U.getStreamFromFD(e);return o.llseek(u,s,n),$=[u.position>>>0,(R=u.position,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[a>>2]=$[0],b[a+4>>2]=$[1],u.getdents&&s===0&&n===0&&(u.getdents=null),0}catch(c){if(typeof o>"u"||c.name!=="ErrnoError")throw c;return c.errno}}var Tt=(e,r,t,n)=>{for(var a=0,s=0;s<t;s++){var u=k[r>>2],c=k[r+4>>2];r+=8;var v=o.write(e,w,u,c,n);if(v<0)return-1;a+=v,typeof n<"u"&&(n+=v)}return a};function Qt(e,r,t,n){try{var a=U.getStreamFromFD(e),s=Tt(a,r,t);return k[n>>2]=s,0}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return u.errno}}o.createPreloadedFile=ut,o.staticInit();var qt={a:et,k:lt,h:ct,y:dt,z:ft,w:vt,d:mt,r:_t,s:gt,x:ht,t:wt,l:yt,i:Et,j:Mt,m:Dt,n:Xt,p:Lt,A:kt,b:Gt,q:Ut,u:Kt,v:Ct,e:jt,c:Pt,f:St,o:Ht,g:Qt},N=Qr(),$t=()=>($t=N.C)(),Wt=i._webidl_free=e=>(Wt=i._webidl_free=N.D)(e),At=i._free=e=>(At=i._free=N.E)(e),eo=i._webidl_malloc=e=>(eo=i._webidl_malloc=N.F)(e),ro=i._malloc=e=>(ro=i._malloc=N.G)(e),br=i._emscripten_bind_VoidPtr___destroy___0=e=>(br=i._emscripten_bind_VoidPtr___destroy___0=N.H)(e),Er=i._emscripten_bind_Graphviz_Graphviz_2=(e,r)=>(Er=i._emscripten_bind_Graphviz_Graphviz_2=N.I)(e,r),Mr=i._emscripten_bind_Graphviz_version_0=()=>(Mr=i._emscripten_bind_Graphviz_version_0=N.J)(),Dr=i._emscripten_bind_Graphviz_lastError_0=()=>(Dr=i._emscripten_bind_Graphviz_lastError_0=N.K)(),Xr=i._emscripten_bind_Graphviz_createFile_2=(e,r,t)=>(Xr=i._emscripten_bind_Graphviz_createFile_2=N.L)(e,r,t),Lr=i._emscripten_bind_Graphviz_layout_3=(e,r,t,n)=>(Lr=i._emscripten_bind_Graphviz_layout_3=N.M)(e,r,t,n),Br=i._emscripten_bind_Graphviz_acyclic_3=(e,r,t,n)=>(Br=i._emscripten_bind_Graphviz_acyclic_3=N.N)(e,r,t,n),Rr=i._emscripten_bind_Graphviz_tred_3=(e,r,t,n)=>(Rr=i._emscripten_bind_Graphviz_tred_3=N.O)(e,r,t,n),kr=i._emscripten_bind_Graphviz_unflatten_4=(e,r,t,n,a)=>(kr=i._emscripten_bind_Graphviz_unflatten_4=N.P)(e,r,t,n,a),Gr=i._emscripten_bind_Graphviz_get_layout_result_0=e=>(Gr=i._emscripten_bind_Graphviz_get_layout_result_0=N.Q)(e),Fr=i._emscripten_bind_Graphviz_set_layout_result_1=(e,r)=>(Fr=i._emscripten_bind_Graphviz_set_layout_result_1=N.R)(e,r),Or=i._emscripten_bind_Graphviz_get_acyclic_outFile_0=e=>(Or=i._emscripten_bind_Graphviz_get_acyclic_outFile_0=N.S)(e),xr=i._emscripten_bind_Graphviz_set_acyclic_outFile_1=(e,r)=>(xr=i._emscripten_bind_Graphviz_set_acyclic_outFile_1=N.T)(e,r),Ur=i._emscripten_bind_Graphviz_get_acyclic_num_rev_0=e=>(Ur=i._emscripten_bind_Graphviz_get_acyclic_num_rev_0=N.U)(e),Nr=i._emscripten_bind_Graphviz_set_acyclic_num_rev_1=(e,r)=>(Nr=i._emscripten_bind_Graphviz_set_acyclic_num_rev_1=N.V)(e,r),Vr=i._emscripten_bind_Graphviz_get_tred_out_0=e=>(Vr=i._emscripten_bind_Graphviz_get_tred_out_0=N.W)(e),Kr=i._emscripten_bind_Graphviz_set_tred_out_1=(e,r)=>(Kr=i._emscripten_bind_Graphviz_set_tred_out_1=N.X)(e,r),Cr=i._emscripten_bind_Graphviz_get_tred_err_0=e=>(Cr=i._emscripten_bind_Graphviz_get_tred_err_0=N.Y)(e),Ir=i._emscripten_bind_Graphviz_set_tred_err_1=(e,r)=>(Ir=i._emscripten_bind_Graphviz_set_tred_err_1=N.Z)(e,r),Zr=i._emscripten_bind_Graphviz___destroy___0=e=>(Zr=i._emscripten_bind_Graphviz___destroy___0=N._)(e),Yr=(e,r)=>(Yr=N.aa)(e,r),zr=e=>(zr=N.ba)(e);i.UTF8ToString=ue;var He;be=function e(){He||jr(),He||(be=e)};function jr(){if(ye>0||(Re(),ye>0))return;function e(){He||(He=!0,i.calledRun=!0,!P&&(Ne(),f(i),Pe()))}e()}jr();function pe(){}pe.prototype=Object.create(pe.prototype),pe.prototype.constructor=pe,pe.prototype.__class__=pe,pe.__cache__={},i.WrapperObject=pe;function Te(e){return(e||pe).__cache__}i.getCache=Te;function ur(e,r){var t=Te(r),n=t[e];return n||(n=Object.create((r||pe).prototype),n.ptr=e,t[e]=n)}i.wrapPointer=ur;function to(e,r){return ur(e.ptr,r)}i.castObject=to,i.NULL=ur(0);function oo(e){if(!e.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";e.__destroy__(),delete Te(e.__class__)[e.ptr]}i.destroy=oo;function no(e,r){return e.ptr===r.ptr}i.compare=no;function ao(e){return e.ptr}i.getPointer=ao;function io(e){return e.__class__}i.getClass=io;var F={buffer:0,size:0,pos:0,temps:[],needed:0,prepare(){if(F.needed){for(var e=0;e<F.temps.length;e++)i._webidl_free(F.temps[e]);F.temps.length=0,i._webidl_free(F.buffer),F.buffer=0,F.size+=F.needed,F.needed=0}F.buffer||(F.size+=128,F.buffer=i._webidl_malloc(F.size),J(F.buffer)),F.pos=0},alloc(e,r){J(F.buffer);var t=r.BYTES_PER_ELEMENT,n=e.length*t;n=wr(n,8);var a;return F.pos+n>=F.size?(J(n>0),F.needed+=n,a=i._webidl_malloc(n),F.temps.push(a)):(a=F.buffer+F.pos,F.pos+=n),a},copy(e,r,t){t/=r.BYTES_PER_ELEMENT;for(var n=0;n<e.length;n++)r[t+n]=e[n]}};function le(e){if(typeof e=="string"){var r=or(e),t=F.alloc(r,w);return F.copy(r,w,t),t}return e}function we(){throw"cannot construct a VoidPtr, no constructor in IDL"}we.prototype=Object.create(pe.prototype),we.prototype.constructor=we,we.prototype.__class__=we,we.__cache__={},i.VoidPtr=we,we.prototype.__destroy__=we.prototype.__destroy__=function(){var e=this.ptr;br(e)};function g(e,r){e&&typeof e=="object"&&(e=e.ptr),r&&typeof r=="object"&&(r=r.ptr),this.ptr=Er(e,r),Te(g)[this.ptr]=this}return g.prototype=Object.create(pe.prototype),g.prototype.constructor=g,g.prototype.__class__=g,g.__cache__={},i.Graphviz=g,g.prototype.version=g.prototype.version=function(){return ue(Mr())},g.prototype.lastError=g.prototype.lastError=function(){return ue(Dr())},g.prototype.createFile=g.prototype.createFile=function(e,r){var t=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"?r=r.ptr:r=le(r),Xr(t,e,r)},g.prototype.layout=g.prototype.layout=function(e,r,t){var n=this.ptr;return F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"?r=r.ptr:r=le(r),t&&typeof t=="object"?t=t.ptr:t=le(t),ue(Lr(n,e,r,t))},g.prototype.acyclic=g.prototype.acyclic=function(e,r,t){var n=this.ptr;return F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"&&(r=r.ptr),t&&typeof t=="object"&&(t=t.ptr),!!Br(n,e,r,t)},g.prototype.tred=g.prototype.tred=function(e,r,t){var n=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"&&(r=r.ptr),t&&typeof t=="object"&&(t=t.ptr),Rr(n,e,r,t)},g.prototype.unflatten=g.prototype.unflatten=function(e,r,t,n){var a=this.ptr;return F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),r&&typeof r=="object"&&(r=r.ptr),t&&typeof t=="object"&&(t=t.ptr),n&&typeof n=="object"&&(n=n.ptr),ue(kr(a,e,r,t,n))},g.prototype.get_layout_result=g.prototype.get_layout_result=function(){var e=this.ptr;return ue(Gr(e))},g.prototype.set_layout_result=g.prototype.set_layout_result=function(e){var r=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),Fr(r,e)},Object.defineProperty(g.prototype,"layout_result",{get:g.prototype.get_layout_result,set:g.prototype.set_layout_result}),g.prototype.get_acyclic_outFile=g.prototype.get_acyclic_outFile=function(){var e=this.ptr;return ue(Or(e))},g.prototype.set_acyclic_outFile=g.prototype.set_acyclic_outFile=function(e){var r=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),xr(r,e)},Object.defineProperty(g.prototype,"acyclic_outFile",{get:g.prototype.get_acyclic_outFile,set:g.prototype.set_acyclic_outFile}),g.prototype.get_acyclic_num_rev=g.prototype.get_acyclic_num_rev=function(){var e=this.ptr;return Ur(e)},g.prototype.set_acyclic_num_rev=g.prototype.set_acyclic_num_rev=function(e){var r=this.ptr;e&&typeof e=="object"&&(e=e.ptr),Nr(r,e)},Object.defineProperty(g.prototype,"acyclic_num_rev",{get:g.prototype.get_acyclic_num_rev,set:g.prototype.set_acyclic_num_rev}),g.prototype.get_tred_out=g.prototype.get_tred_out=function(){var e=this.ptr;return ue(Vr(e))},g.prototype.set_tred_out=g.prototype.set_tred_out=function(e){var r=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),Kr(r,e)},Object.defineProperty(g.prototype,"tred_out",{get:g.prototype.get_tred_out,set:g.prototype.set_tred_out}),g.prototype.get_tred_err=g.prototype.get_tred_err=function(){var e=this.ptr;return ue(Cr(e))},g.prototype.set_tred_err=g.prototype.set_tred_err=function(e){var r=this.ptr;F.prepare(),e&&typeof e=="object"?e=e.ptr:e=le(e),Ir(r,e)},Object.defineProperty(g.prototype,"tred_err",{get:g.prototype.get_tred_err,set:g.prototype.set_tred_err}),g.prototype.__destroy__=g.prototype.__destroy__=function(){var e=this.ptr;Zr(e)},d=_,d}})(),Fo=Go,Oo='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"';function xo(p){let l=p.length,d=[],i=0,f=0,m=-1;for(let _=0;_<l;_++){let h=Oo.indexOf(p[_]);if(h!==-1)if(m<0)m=h;else{m+=h*91,i|=m<<f,f+=(m&8191)>88?13:14;do d.push(i&255),i>>=8,f-=8;while(f>7);m=-1}}return m>-1&&d.push((i|m<<f)&255),new Uint8Array(d)}var Uo='v7#aSXal?Dk_E:R9nY4y_2i"i;~[]K^kgo:$AFCU{J9IkELi.B"R@=S|<$rj6@;VSL8/Umet8FXV"yuga|s:|JQV!;h,P5abpC[?a*=<u$ZXlD4Lbrxa[Ib/?jYqI)1M;VFbX[JB</82&UrU<zgYYsy3h:`N&O)!;Lg^4#0uD(d1xmoCzK{p?Iyq8+QXYsA1iULN(p:x=#}lUp7wIjp=ug$1OZg_BkIqb_Ax~?]rx^Rk?6{zbKC_4mJ@xg15uTA%Ize/jhEV(!..*!"Jw>c1nj7>l<jb^+#ufsTpbVFn!E?>/~153Sz]>dVL?<tO&mW2lNDzMrphmz:q/S6`o]2>!}DIeTKcnk6:ic!fxa$*(?dlM`efH89dj.[DNfg@Jkl:rw>L6:bw6!JWh{k>e3k8:yB.5je`h89|9H/I(98ri{8]*80r!av]f,2h`5&hPSP}C4|s=%K|R3%>kwl?jD&UK5Aq~d@fD8c6G=2MD84&D9Q*PmG`X:$L9=r$<:(F|V+Rf8:vEe9gB8)ep$[]$9E24&~7*7w>]^1]6rtla.7/%mH}6sxrwkU`qs1MU1|gjoj*C[dy0&O_UTB%.zmd=2[eX>p2?1@KN{5zNpcjV+2&Jg>#P=|{)6kbAPBexKuEG7eTamP8Ae&~hS&vJnQrY,`!X*}{Te@xO|}7Fwu;0R"dSbJ]L2ZxN^EQ+LCrxY9/k37~>ZQ{!wwu`c:n^Xf0"7WBfA!_#9lfb)$ndH3Sr@y]]Ot&/f%!NZ|bWd$`CUXpyHA|_M4fFy9.s@.$H4Jh53nNY9ss~/mm_K;Ukd}n/9>8]TR{8dva1;b:5HFK7XfsuwP0;Ry1*1?8~/Oh<0{@.,%g*gV#XOt_ohd;}i@2O^s&aS2anY1/ss|@B<Ly;fHR#:x~/n?;cltzX|DVh.`8Z+wK98;+R.|oQ=]EbVZu[2B&nk#,Z=ibY%$7!hsTw&M3I+z:lsT@L@I[cY5%Aa:&0SvKd3]Mmm2@9B}Vh|k1mo(vTgRlbU,q4>n7w,=Um_vV7Z7u87=+oTRh<0I]B$5j&q>p2auqxoOMgKAaQ}Olg>kKP:<`^9EQ:ZI}D[i20<j}b2QSHV9QVFvR%f{5r"7AH<s?d[4w8O`i#Yp640f@hk;Um?$bCRw!$fWZ`75Yb)G+jerdNDVKF:d!1S<vls|>j],e;x0_`(?q:nC]f1/hT+8$0f0_)Twl3t$/d}*KOqJGikUZ#6$7?N"bf3o/?>6%]`4&nT2@{S9IH[!7/{82Me%26v/{Rb/$6fF(R2np{f,d_~IbXyvl|<=X*S<dTT!?@TMD2V0^Oy.dmhYuAk@UCrI5v<FQ)m|=p[JMebn3Z)?6<6dq6O1M}=Kq!nVp)_T.bR`jD{.rz.0fcRK#Q:h{^2@4asOlPpSpu`D.IDC8%]"Gd>SFZ[]`EV`EA=?|{qX1a6$l`j!36?,/%zx9]H>rC]GjYu?aUV)i+)|`&U$`]`1<hHV{%D"5T9Qb%wGm*o]!bbC9W^a!05T+?pjTm0=hpLIJLY,,2XBL`qy,&5W}Czl?q7VVG_tlZ	>tKnoq.0py*.],Ra9F$q^v*/cp3hHxp^KURMWc>G>6W*BUfd.BB<N_Y:/+UbjRj^*3!db.,mlYd`w@fGZXq>u9JFY_`kR^:f.1[p[]:Xk$qd@M;Xe(16Hr%KCoH)Oa3#.^<9]M).$ly<QL2qkzYIMD0+0;G}J$M(16D>t*}[&=pZi5=Gc[.nJ]ED/60?m27rK>KG7c4HE|m8K>{Zz3:ne)w7fI)a;Fc)7L&F}c51$z@i+aRz61SGGRBYvNwX_Mzq$zy)?8dq40&1|,%z1VA]OZ_Vln;dZ(64@qjom:mYr3r2j2FNN><}g.+2g6g1pd[=)Gu(o:U4:{+BV_#ZLy8s.Vd2jdT27cugf8&]KeOo,I@+yoSWy$UZ]P|jur"UcEpGOp02gIL:Ud&9Ae!ig8!@oTruE5x|xlT$_iC;iJH85|82e1,PNHN4wqFv_5%7Q*S=e|B8KLq9y@8G^<{_6:xm5t1{re:>Yb#8/6l#[eEF}=M@XOWw`Mr$PlyT]%5KC`h0}ofw_fSt$`8#:dY&Fke;3BN9.z;OIS]Pt%L4@%`6t_;srz2nqD)oSsh_|8m+)25tvYHSR}IZ"033JF8/5t#QeN7]w&!}VPM&x2B%s{O<D1~OiI9NIG7&2b/k9i#QBOiEJg{5zS3NOyI]ZwJr,InxL(okA~<n*4"yQNU:.<bGcet%zY_`,c1(H[5c1(oeVD0kXgi?Bn$xr0i#I46;bgyik953a?!p{;%>Nw7e{q(M(=]S{rqMzKa~krYTcydVeTPq7.L;`2;p0vGGg/#QvBiW?!h2(4+7!JL@M85WhpDG*:XJ3M%JuMNDt_A}]Ct%[!f{1Q}t]mDVyT|W2h1U_j,FJ;5&gIl>$5p7K:*SP"%~8aa8kvu;|dP.flC~l=|I:yM:xG5&0C&=%23%$MyuW2xJAhe"ne^[Hy#/_azlDKq!Gv0?)/}7yl<)4cFQP{UZt;Btx,Fw?fVC0#<T:B%6+sZ&xe<z5ryA.fmYd37NoGQ[`6gvYmwq3,7L3]v&l&NZxseNBH2o$SdnST*<yc3}Jop!1T"Xh(b!4aOTVl^lz`/$tE[li0bzSZ3^F.zHa{Zv!1I2P[4S<dYmA.;Y^RqEk$5$gq?`<9Yl.q4%Y?5@^anqu:j)PKG(}]/}0e=Wo;d`f;nmkmmb6Q*c2#rmhffav:+Kz<b$5tzr|+hJb47GdeH8R4Xp6%~ddOfb];(g$]_0!`w&#&#]<zaGZxpf|N:1OZ_mh8mb54O[GFzKMrYE8$YF0xu%QqqNJ}<9?ahlf}VgqG=yP[X}Ah[ZR~ND%5jpl4n%okyT"Xg6q3ed8+`NWyle6%t,]lkyRbYpHSw%>&MeB8GSY9t0cmHN|otEc,}:@6S~<uay)6KgdVxrYm#NcY=cznjlk1*/*5oKQ!?8Rr}ozKc%yk/8j+;)|<@<c]tmhzzph1_M0!_1dlV?F_;V>84rjj1nGQ252Tx)dZ%)F{uMn8o!muNl7x*.dqsVkNnyFoH)`INu,8vnj@X>VK/e=WNKr4eVPp8:[Z&2C4DS(]M;>1p[jTx~R3o9@iYkpmQ7n.5K,&;;$5PZN+td~qx<+&6eR(#:k@"`V%Xvx~CI/EeVkSV8i{[8f@u6F{08npL?@UY92?5bpy&LhleHRJ{#yjbP0L_Mfy(|Wyzp36W,bYE?*fP]Ybj7w#)Ck<IR.yVYbG`4|GKnQqN],&5z]n/"O(k$G?MO{U3<oDQu0{{8S&|GKn}+vU496~U@N.Nz[0$qSFn2,SM/E&?Zf3u.=qk5zHLOnDeUg:zTD@~T^lWr"p,w(.{=l2cY]SXk~mT*ch]Zr[B2mvJNU:"^NMA;ljkB2,d@AX[ZBJ@5U;lj"^76(2JcQ`0mX>clX>&>0.F7G/nRr6!t}ov})aTPX0dZfy:SOp`=HUGn~4`nYZ&PiSbqI{.&>|x$JcF{yuIqpD$LbzO|pyhfD.sI^<7{7ENu3jKWL*I74Tylg1i0P7cnMlvu.qqw){01h~(@*=*k<^3Bo?t@OG!_L9=,Ky8K{:tYPZ`<o,b/.LiPJY<xy|EQPWqAFMf@^7G5f:6M7ZMJ"kOb{]#Gp1C_x|&cYmKW%zR[/yBqd>x1zT/<Q]_r+a!?wsNSbz{Y0M?q2K)#)^uVEJXq0@"`:nT&ioVr4*.xP<TnEN3[rx{XB%KL_dj.Y:k{j.z^^e,Eg9&Yv$Dee}F3yoTNfd:R)`%)"7d?TGJ}k$LeCW[jT`ZU"8]Im&[I83NM/L29`UG7bxVPFn;U>N`]}z<$PO]ipS#vkX<3}a_XEz9Xg@$9x6v?/nEg[)>%iGn0nG*s)]s.G@]iuMp#?ZU_L%4h$n9:_mJ]42=0xs]^j.&%(mtlgd25c:g<2@q{O|7^J$`si7]y~3{=F`<UeVXp<{B5"[J.WTV7XTIVi{#2z]I9<q9apyDy"_~3f(w3:n$r4eu|/r#f@pLil|oyk./B|ntjz}am&Db^uC>us;:vF(d1;7|}D7q[2VDj;H@5F&[iz=1$_Mb_Vgt*i^iTgh`M5qd>KU=|1d^#f=4`K>uNUoea/6l#BLo%VX]C^!Tv6X]ChauT@)uN*oiYWb)e5SKUhBxirnpRk?16EQ#2A]?kUo[x;R.^4t70I]Zkj2TtMxF#8,>1Qs$zb3E%YmqG{*8zE5X1UmkybT(1@kt&t|M:j.1S7]B^WW?{9DN8zJkyjbazl>2X<srzRmP_c+0@CaoF!jA{o@|bUl2?eU4&ty.t|od0{/c{uO]rV$jQaGin[+N.r}L=9aRnlSJ$u302h0bz^4ZQA|Z>z%;j#19VMJM*+b&rL=dq]{x1]1H3St:$@KY2nSKU@Y>#3q{Hf@qs5QI^GrV>{_,^v&.n_J7GQ*b!IS!94lYX1MUoWaibB%Xsx<vvyr~0y^#a<${5XUS5od1Mm&c>4?xlTe.xfN*7]Yu"{Y[Tl6rP6D?Zr67!tL+H?!%*RjqAFfGXOIbr2RvLfElj??e<+yKxRhc}:I2+6YjJO2:ln+!Y^Jma<1/y;C1sOmIfTX1T=#_3pZq6"e$Avx>af;Tj0zsDx4kEdjkXsOmi98m+uu)Y1pUjrX%PBB3R7"iM#0xhSCVj0X6UiwuJBm+ylEY^eeVj5XQSEg4R=LtKf>kEej(X`T(z5!bzGF>[88s+75KZqD<48<i/aY+H@!_0ig2X"Dq!O2j/BB9QPTSJ+yTa/3LT1p3kztGQRz98bjNXASl398l+oullQ8ZLg9vLYJ%|NJk/LB=gx`!<k/LvTJ|DR2l4nCsq$co;3EU/XBcjTPU9$k7t^I,p2egSe?VvQSf,bvgS<WkFW6J.U/jB7Wy6h#>W<FF92xtg8AlDlv1xV/vBrmwo#<p4WZhGVNP2q4[Eva/*4k>t,NfrcS{W@JX5HbX/;Bje$c8ft4<DQ!;PY/~B@nJ=cSBXFKP[n;5k,X!HyhaC6k1)|K+Ge#EX;Iw<=8Z/WC~N<U/>r41E|b_06kPB!Kx;0EbQ>WwJ`=g^a/7vfV(jbC7kYuaUl5,0PtNvNLap0kf4TANHG!GOMt]AOOdZ4WrA?PZlvWuAcIaScLYAmE8<ZLuAXCNp7yZ"IC=h=x/.NtRB>m5FeVzA#CZR~PYLcADF|Lb4dA"ID8.o0WNB2Ky:Et;*AP}}XLgAfJ*BYLhAnJW!NcRAMDz|/`Ft*B:yMcSAYDF%7yRAcDVRZ4mAtHD35Fe",By6wwOt[B:OxdGt~BQ$5FXA@D|5Zd}L>yk,ZUbpK16nLy%eKs3e7nPy1i]Smg4)/Uy0K18nxEk/ya=$hvGfk!3e!n=E{^m{mgI@8KC?bP>$vvzowYQV{nOFzsj3oILt<DhVoYiNu1Lt]BTfN/VA_DdhXLy&E0OtPCSma]0(LBptBEptFE|(LB?E*B<OWmVxHt}eF!c"REptdEWip`~;ZtqI9(WBAF[t+*;Bb,u2ZI;hsXkD7?ZE(?,7Ktr1dtGF]"KFy]GON~(^ww{GB5$gqysFlC5J{iD,H<m<m<=n/thGYY#Hh/pdsigc^?YDv;We/h8A8F(|Xr~eNYKGrY7D^d@$`XY"|CtxrP]h%ApGlR};<FtYAE&gj|{)Zwy""I*Bwx$IH,(nDYMGNuoQR(tBPc[/VRF*xLkCwTY@+5O<JOb*`JBG]vMX<I@<,7}vNXVFK.RVPcB5v+|)1L7x"KvzJO@L.C#W5dYRJtuc^vnM+E|(iM}CJYzPa4u2^K+CVtfTv7+xATpnAu(FXDNc=xq1C?QCsRRlxwg4tBptSF7jtpScSBQJS6q1bt%EO!:i_94"=E@AB<[h@AOHrfYjsiUt<DLrUE^h^AmHGeq1Wt@DG:i6:hAjIBMg5*:hXBNK9%ww4(yC+QFBK73tZEy]hN;hIB7R{O^95"aFnZLv|9g",C::hN/hRBBGV%A^3(1BOaA$/h=A[GN%{x&T_>5tuvXTD%*[D5dcWxLUm0j|x?;FAH5u)Mk.+[})#4]I|od`}Lj7iueOGa)nG<CiJuTP&d08Hh[F^u7UY!X7~)WGCvYQ{i)0t?MwxXWK,er`;,BDA*?LDF5o*5ti|y>NqD:4c<z+DN:DZbqNSjHXeK7i`J"L]FKZ_IK.iq~X;L!E:lB*w+")=L>Ejq??qN8!zLUF:46lk+quKmxJ3RWzMD4zOmn+&udd$YUjpX[P_wf<@yFEO[f;UjxXrR3X4R<L4J%jR$2kytjJ+GR2p4*wRPx`d#]4/En7XLWAeE}4vW1ApRJ`vW(A/R|LwWSBzT2!wWXBYUvtZ4Ao5E=!}wxW|AbF%P8M:hP)`B%PS6p1*("AddE)p1NtVEVVgoVx[h6AUF~1),2(kC3K7zs1&W*E&e~1};146uuOD?+e8;xnjC$j?frieVaAsBpN2]SVsitL`,n4BBa&vD[vUBLO&mqT9KN!+4gX/>jP22+G<ge<MUBJ[*BXqt*}:o~;}Q[1[*DXmt?adS~;BV=F[*_[O<Mg"KY.dBaBE2/k_9>[*RNkUuawUTK0|e;mxN{BzC+Mu4BXI*qoz:zPQSsYi!_4uii5%!WhLnSMd.xD{F{v7[^9b9SFI([dSO.$Y>q;b*3<~Y|miZ`EtnO6ueO^ywqQ@#Qy!UF+"0v5_mjO&4ic8#2:ec^PTHKhkyxr7DmUyC_PF$nf#1:d0Du<8fB?*|LdAkT10*M$A.RxLio,|BC%|RWX>Hso{dMjP7n?8Aj8[e$LA9(F20q^.&m*R>OdB8Kg[<ruzHH4{<zec64aw7$,ROtQE`Aqj&S>9@i8Xs({B8Ae&pk7O_doM9vlS5xV}N~7Kj:F&6Cp9UU6uKC9kyd0H6yO+waYIri7NAXDwPOvN8aizSH"pAi!ZjXdG8iYvO4]VPdY8?_ISZ/cos3.*c2.yRT+Z&aO<aCd)jW5;;gP&wV_+V<a7ijc%pRFliTcaOAS0@J1ouR>ju:]zXnB{E`Wt*0$%KP^ggL<%n.lGh]0~P8BkAi8)uk<WBT|T^*H3[~%PX?KB2Q3Cj753L*qQ%o$:W$d+:_v+jwldx.wG;]>Kx8H+Lv<lU:Uxq*;DggkdU{j5X8k[IJeyRX8ahkQ$4S<!rW+~7_!4p^%$TpXn`/v/KSe~NT3;opq&BPPp,cPB#NXGdj"NBj2(#y,}7:j!@Z5)im+WIB8j*|./YcEs8z_]=_+*F^IlxisE{"gjLaqL8K|u4js7$S_MXa|Um8f}.8^zhq[K83$+KOrQgXa%Dv0MINp{eeE`]wjmFSxtq!*4/FkQ3GAa|5VXA:{xrQoS2$+Y7iUn*Jyj&|If]o,3jg7UZILD(%C[K/%`{x|FEg$Ky08MjZ#77kdj4E"OKqu:D`|tp{RufOR6$mLD8yQ|fpGPvwH*7mX,(@Aaf8k,CDvIM!8N|T3"UP0Ue$1Z<&%TbDH]f<!Tg1p_&i8K<NcW1:o;$2iQ3lC(K>rkMNNdZDn7_pMS6:gK3:rb8A1"HAvz3>,JrC8K|JPW1Z4rEw@D8,%Lg8^C(|AQK|f8cO1mey_);XBa1J82(z9"!Djy8J?!(M8[CA1xW5FjHa[yqkhV^PdsTDgd/B8+S~lZ8OR0RKNO*Kjgg>TN(/UrGI3k`hGxn0|.#V$`4#"S_C`yrv?17oBF,IL@],R/ikpVR)V@V5;oif9<hRsIKvX1P`)F!DI6l`w5jc4`>O;+_JpV@(&^b73P^;Vs[Oyg1>TK?uuJW?SK&^biPz$t`);4^n8Dn@4DF"g>ry!58^!1$SnzPk_Qr*]dUK|3l@},?B;S9Rr0%]HxP5{L;0*`_472^[wyh1wSgZ!KioQp,x,ta!#>=uL|7c/dUK|uq73+>`P]!sd6|fH*=6%M(xC&o?^$7c{Hp[HMLyI<.:`O}H_Od>L%AT]yr{bDe"@/K%=Ae<&U!78K`Z5s$XaZ?%UK|E]hujH}z3.C`45)W7b~Pksb>c=YW7LA_7}h$>^F4]^1y5DJEFP<`0W=tsl8B]W9II7XT[gEDtj/Tx.mwX68iU*E:`hU*bd`hU*Y:_hU*#5^"V:mwKxfB8NC8f"EtD=.0&JXTC9Ac62GW^G8N/XhJXT|u7NdbkYgRE8W3)7MyV7*K`z/G3clw1v.GPy{oFr0Uk2FZ#}ZBTY(<*NjfMU#2_8ow6.gr1HcR&W]l_:0H:nOf|uIOf36bzc]"IO8NcKQ3&SEH1/}o}6Ap^zkD/[d[;76dU/lwQfViu1r@KO2<r4JpXxK5B]~5l:Vcw@;;+6IHOFH3:SF0sDxbVbP#^8ugG36UeUL{SY+Bi4D,2N1f][!23#7NcKQ3q2Vp|N][d[lwkeI={qMy#dr@9Vulk:LpJ;{q=3L5SY+b{(z/%{ymrVW*K5]P`+grU]7;wc<<Ye6%>(.kPJ^DkJmyY57^BxkXkgdc=+EDC/7HP{ovV9P75<$y#7E>N_X+w7A;Mw1vOF&3t)>*pcbnOH+ZZl5V;$6gCna`aYoGdJrk3ex+kgdcY=`5lvt]]g5UgL)SojMZ$nVOG;Y=4nTYPFi?Fhs!Ub<wI}G9mn,"[N_X?za9J+=zgaKr<e+?y+#h8O}u;Gn28S|;4Vx(}]f)v!zJWw<])eBhJ.O/SYmpcxG5?DqldT|>(z|(}eUs}Voq<tq=hn9k8S&6c^+"$pQSf"?*gD+Qj:7p]uz[@V2n@+>w,6[&:u.g>c;i:!vLk(86l+W1Bnr5Oo;WGEu^_uDRj$o7.Joip&wTGWx[1K[EOwj<`Nt90KVI[,wH"kP@Z~VwQl_]S?<2j)ps5_S&0Nd(EvMVLl]8!7sI{Xy=vyk.]265X;{Mc{5?u6=eTG65c`7t>G7.q9Io}d:5[pT=.Hd8#$BRPOx=:#a^F1zK^6/pAcfS<i,Ki*8Sn5"7VXR?E3Fb>$#f~QOpf%!tkASg$E<z/D8QzK>Z$y),QT"p.JlOi]Ir})SiM<q7vHQfhM95v>Gb3[#9w<.U,>u?W>.z:wxpUZwW)6%pFG*4~c&LIHafYPb{]$#p:/#pE#9Vh,P*@+%(%jO2m6XSp1uWRn#6q|315}Gqnn*t3}TtAJT,%VIkL102.P{kz!^ddo:DC8zVm*x"t5eX,@"mB.}7Q^2`DZPQIR:lT$9N~^0!hc~qPC;[4$z>cCfX23k>;zk4F{O2*(GA>ic$$<u0![v&Ek{>=MXLy?JY"n/Kl>mHnm&qH+JqHSv6xyGP0M6JXLz)yjbzmCJV~#6Jh/TZjgR$0m2+?8NgxL*fOgd"TJb$1)#[L=Txx4nmYJfDON?p!k$#00I&oOj<}?rvUbk9x{b7L(!+f_8@i+PqE{1B]?WhXE?),G>q}+GQFI2^ICj]hfA|j+72a{BWWEJ;S~5B_>0[MC.^hSW2c}UQT]0mL=2$Cr0iObQFbM<g4lh>u]g_a>g<w=UTt@A=))X$I5AgLZ@Sf`8u/N*=dA6:c1!+R]ipvh_)@H><o;F!4}x1)*Bz)+s>**@zBFf^rzYPJ%0kQlQmpHQC#4;b;tZibqII}h#r$jzWOgl^xv742X*:tmE(Kw9pO:`krFs/r7gqk/o7zfTfQD&H(g?#9b:rTHt@Ar8o5j>6`n^N9U#4bp"[iOE#(*83q]K{h9QK"[4@LuA@e_<sYmS!ibR!"@4mVT_*ljT6O#L:6vqlz<F],PE{Ah7Y`gyTD42.gay3BOG$NgZUGBz^t]_+rvFQEQ[(BffFL?M8Q2khq},|r$MVGi0v<w(KXnRt,P|y[YC[7bkB,T+MW+vv}nY:`7wii$oa~+,8!ch]p^@C=%*S(}D/X]Q"5`:7{p42V8I#*jjoaUtnWuSHA+5p.]7%&LYII|7~V|jUF+I8j*R<*c91+Ud[$.`#H}%N"G(=>?W8u0o,IeB8`37erip9~c:!l/_f+jwV_YVYHSmZ"bO5!wQ{<naY=<dY>=E/O5Wk1wlX,T!BSHH2?%9s2Kh.`C8o=^2.~g(.dUuL0M.NNV5rAw">Ol8Hor?CU3}RN_X6YN`*HZG&vZd=r^(ons7U+o<m&bA;R[51wihZyk0M63"L+52^P3rwlH8~Y>Yz*DdcA#}+O4{S3+z9Y]c(qKITQ#,qcPP~)i*Ll>q;_)jovi!%smwOb3F*jUBr#_yZ&lqi(2==*Idb_Zr]gM_e;e2.{U[T*g[$=&^Ze@XB(&ZvaX^99>v*I%71vxF$$uksw=5@&xu!X9$Ex!|9mark^8|.2}&ojm>d"G(<0yLPmYR<8H(<sKY`$ERznBeJ&e#I~O~njm{V^]iO.znOxWD!UPN*=$xf"*iTV#(,PvM8UwK/;<j1.sS6O#nJ}}dE(iSj693W%.a/0<JiJgn?aFW7]6deS}&_i*V}&_MEi0rS>)1K(/G`(]?)~O?KEl9$f})77K0<1KD]l7=aETI6~q(>mykVT9TH%X5qzBX?Wp47>YCppZ/EvzR%Q:%GhO,?ScbVZBvt8;%Jag+PLz=X_36U2={H|R2Ngz8na&^[xBwb!M^cQM7>TM9V]c4tYE;M6`D1XEB{3Bz&JGr7_k_]VVaY3m]<G1&b>/RZZErqUiee<RF<A;1R4i2ta{Y>hj[a*HNegh0MtO]&`=V!+lk+1mXC5@#{FSW2+S/)MsMUzVHRbV=f//}[}1@b.Q(y!kOZ1Xf~!C41CJQ8J{dHlLQ,0]Pl|<BV|%8tyG[oTu6Oa(qjA,LxjHmq[pfJLoM?)GN49%d0@#^<GW|%hZ,ZtB`*J@xgoL~6/nt9teDV$mEq]{{Mt[6Z8GLb`<#6f307]W#9jzJgmfy]B&jEg(J~9||WyG,{},QVeNE|lcPo@y)+Dr;%5R"Jd(ad|>1r82k(@nx:*eva@iq/0;_2[U75/{lj0kY,o@/ni876Hpyn+36yl9y5#kU;Fkp]t;)D@T|bo5)US}w*YTkTX3;m?lk+CJl3HJLY^DaR+Mxy9L}DyJtn)ijqF%qptpBGS4n^?Bqla$I{&.a1x<@gU*]Td).|yN8mE8e%b:X[E#~Y",f:&H7&iU3V*A]a%T*!mr^!NwGMA]vS@]_^~9xU]it_od9e*lt[E=)coYNFEil32<!_w^p"KkwNP+uYv{eO(i$SOu;9vzw.R%jtKn$eo_LQ&YmY]KvYN0!HKV9nb#ycJ*EDwk<wEoz+T`k[tm9Zb2iWn]Z+1S?MiW2ltvj1]4A@E{ZtK/P$++CgPsF1F$:_YsS<HzDNg?|wV.d6*Z3i[..a_uuk0CFY=JdF[kbDgVOSp]Gaoqd@lUVfwWb//YR/M13QDq(~c^D[ib++@6dSk"R>v5SNO@6/F0h[1CFYDn0Cl#05SNn`W^}1[tA~FcTYH&:Nq6)![lJj0CQ>tQTS1P7qErzL3ChDh<Q0q3?:.o[X3UNM29![)?IXla[V~%m]D,uQ,5S""$V+?H^:brt6m4W+8~%GkSi[4xy/Q+bKT?1>A2Khg/NFT^#Hg^MjN,/GTUx@Pa]lr[kP`|bKqY&SK%jtP$ADijB+%7[!sGXj&R3{~p!O*A/n,"g)ED(7<TkQ_lgZ&u<:<INX:b&S_z|L/zjSz>}5q)B5tTUbN*s5)sO@abRuf:|}eajyG5r3G5@wD>.1!BDINI3"eDK/+r;1DL^<Stl3r4M#uVn"kKs4M#]|uhzgw,%.J[14~crJ<zNm+Hs9vz[]w#)CXD&BV<:FPYyrF$Vi|vD$,u}h6y)SnDZX(5Y84bbml4^?@IZB{$c](H0C$cQp+toDXlzb|bG,Dxv?%VeU.8P<Ys83r}T&,WFNF3Ir8]VKB2Eh;)ih.t~B2,2`8_g#TR&P|[9f;F{LpEDQOwo(zBz&?*#Czac.xt&{+k[&{o/fxWG1KzR]M{(ZqVx4@6U$]TN#54h.a^l8Z/2_O?B&Xsd9"4Cws,q;ezJo1Y_%=%eD)+`=>8l^8(*NjNQDA]r;#Ood{<0hD)UwL*i_LQ_M!Og>?#_|V},Q8p|"81Qt;Y)n_B@/oI<YxyQoDKNEGDPwVQ+0.rqFqU&Y=6<HqU&Y;0:*zv:f]Z;xLyAok+UJ<wc>ZxS0uJY,d5+nhpc`]6n2[0Q`C~vvC{Nq"z?cc6121P&:a8wxjkTHe~bCU5gVkXQZP=|bUoWnpjZU(5aG{Q5xI]"duIw4~|dl]ldxNMIz+Kt_e.!g{_$&Rx"^FL:Lw*OVKw(<*MMi*fPV#57e{qIzKWmZ[k3@nlU`d$|i*7LooZ1YW@h,ZpB>M^Br;qTT:{jy+5"CfZ0MHSy=Q*rfQ@EY#c]k*GH0oGVXPDL*~F^j@i_QIMzumzb]FZ#=(W(9y#bjg1ZuAh|zGxLVt9SzFzPEp.SYcWPvay#v7V)?"WMEEuf!(O*#IoL8#ym8hxGYvj&Mg`FHGGDGq7)Lu^B&fw_kh;/2"MxG>iS{JkEUzuEIq7Y=s2n7Kn.kF%mD(=_dM*BUK(&Uzu^c{_nt0tMlfSbm^>2XUp4nE5NSL#_p<cqK$7~|~=zxwA]%:NjZ6B&62._EcJsHmY@s;Ed&vO<wth1X_3uq^u}$A*,{>%7]$p1wRxr51+zPmLQ,e00>pu.FRXi}})%erL^s,@GYh~L[y2=O==w%)M@]*lXbc9g4$ml;WFyfqG"%cNbYq/prx@P3}B_3AJVU96z99OpS28Xj:XyGt8Qqrpk8]YO5b3"B42KgH~o3Y,e%ju!wA7{o18io|feT9L]Z|jM5kV_p/q:/eN6,i%G~A;0!tcF6;VEX:g1_e^wgeAPGaEkZO@k6lH2q|5t5#i%d)PDyI/rsw:GPI:Z+0k@NuT[v>ENtZ.5wd`cT{*h>_y[O3prtU$hqQ#cRH4@$vg1YRzVObVKJg^VVQG2sX#Cj{je`hp!)(#crBcLgm7d8Wp3q`=o]~>a.*54MrG9P6YFQf((znlUV)KX~R~>H7dlYt54m3p5Jm/_iu,ZM/|)eGFn;%%]pwcn*=Ug%39t~a+Im4PfNf@UgBxHd<+B/}?U`8N2|dv~AZRmtP.g`*kg|E;#XjeS1{m$pEIXM)m3O%kh;z?W[91EZ_o,tOC|9o;>B,[x36sanWsA`Z_J]5<g.f.K}w<<^cT[U(Mz^B#/<YVj`,3J1Kvn^AD~]$Dk`0KO%3uO">iQFNX`;S9Zu2xU$$)8hB#"bs2yuh|61$@zBQcZdHg}%*np:F]9QiLxyoZs#()[KlrnuC5l?4LO&=L[B[Kiua>yr^_3yi1P<aWAzPD,IHYo8$*D8+Iu^Tf!*Cy?(1v+j|"1|Iv(<ebOl1uxepEXI8:(j7m&8x]q$NbDWsb3]a^Q=;ya>Z{2cT_3>i}k=MYe{OVu88+_%r|/KkJ5EuQqGEjy~+6`wOkI#s$x,V#s$)Onl&;@S[_f;b.VV<SfKcfO54cC8*MwZw)NimzO0J|TPk=.E#&JC+Y_8;CYr4Uj;_3Q#)LfCq*5],s`UP/hKy1R~n#b5#/U={UP/Bp,"JCdG5u_;n2D!S1gZ[]*Fem2gxg?f:8rp#oTwu=p^GAKe@?4sb2jluFk),gTLxM1#VG7V+I&N/EM9MzLdwxGSpL0qoB5+&r)soMIJ#:yXL>8:mI@n:c+Ksl$7eDI9i#ID}`Zl1)JFfB`44ZPTCxz*.o?0fE$4X_zQNs;zjR/K86OTWM0JK=.(i"."tXEiFRV|)Y9x15v_5C#ma)](erGxn{|%4g3~JX7HhG3,h]HM;:t,mmgRX3/Z:6fNb$829=)@ws%mU1S%PXjdPk(F{1UXRD4v.y61yuj!k^,3krW$U/xqYk$<SG[tPTzuY6m5V;ya[p!Y15ta<Ifv+?7)(g=3e=Q=w+(ec*bsQv5pt$o]ZTlyCbV)C2@SoB|oO*a)(gwlZXz4XG|o=gS@Z1oSHon(*/<@i:y+c*e(:,;r~;{+gq72(BR#V8+^Lv^FZ:{Pr~z|`9y95TB7zMk@VWYl!O6}O45J,VhT7Gr|x2w=yJZVHT__#sjCmg/|euRBb1mWdT$QgYz*G>Wd,i&61cPDQZHOc#PTVx(/8F.LPjuQ9;Mj&Y=8;*t^b!/znDSe(GDU9w<[V#89krbz5jqGr22?Q,gq^Zzpfb7%5Ku7/l3v"bjdr!{p.U^7Gw,V9z%{R*>5i)hh?t<L<ncPWEb?{"_oN^lbc%QnqZ&0W{{3c^`=hYz0p7z1rekgbAgZ)E~^v&P?YSK0EU`=zbN4|}D7Uve&)m59<Vepg&cX8@2IV$Q}`yT=A8Nw[(Sh},s.QS3Jh|<m{Mo{1oY~CxZ;0+CtPTH{EO6U!;I8~J87]IE>j~bYW`*ztvi|DK*&MIPWEr13)6ACV{~@Es:Q*?rS3J>s9,g;6v=2w&1rd`c`@.`Nnv,oKSyr//B>G}`<dV=HweA/J(0A4L})w7^K:?e@AV#/,^|j[?zBZQXy1*EDSe45!!lP^.0S(O;O;@{|Tm+@q&8a]_8^a^E|Fnb22mgnjw1yaYT+5&eF5<77%7V+OlQ{nh,Mg4sBZb7eylS=Bjd#vkWygwy=GRcP|%6Lc]vBJ6Dp.tI_]nDMBq0QI%2|t=mxJ*7+sgaVHS49j>"GaG/,yGo6KCiPau5q`^^B7_`5U0AY2_7w0ST]hu2gC!;o!9n*_q/XA%9oUlT=rh%S4?Tpf.&mK|UY,/!Cw_6Kok0pFyvV.c$1jF~<Ybh.Hx(SEr"b"<~<XBN.ps@U!<]!x*hF.{R#q[M,zm?q!?f5OT?e+iRByvKab!"LFgR!/_e%C?gj">y=ruXKq:QvyGn0XM1MV$+6egS@I&hwCthhFQI%16VI.r>CgG!9m1jZlW64/M15|(8~`=TYZ>oc?8iLDr6X?[j<cOI^;k|yEsA_2!ok_d;fi&/,=8Hp&Y[b#Huc_[,BxI[HJrWlqXaY`+2~%*KFR*$V:yx;@Y:#"T`{[T]<+)(7py0Tz~X17m&I^<NfU.>.e0R=Qh*$kbJc:]LN#9ui5T0rTBo&O+Hx_3_/Qvcpt<f8{WNn8aKL]R[21ttSd5WM]KSC$etP#2&NLmFoB..]0,OaSHC:sPn9^@QjDH9k{yr]??_SGN6:m2%XG;!uw+h_+e%E9[%S365BeJc:M^y+dQgTE_M>W[T<n.D)Z`.)d!s`VRjF|qb#9rR)4.6Kh<`x:]<.nV,A5{PO90?O(`XD3f?jV(Vh_Jd]D:g^h3^MJ~f^uo`|.znO~4PVovF7J09.5^IwmQnx$+QZT5uZ}p*)g/M:z}9MezE18>[>qUMSMi"o8txN<f>q8+7F]IvUcyu"T,8U1_f;zyRL0T(uEAXlwIV$DzM&Qq8hSHhcib!LYFT|(jN:v6HQ.~,^j#d;5e,Ib7eX)mM>~o$zL($@GYlsp*/rmhXy%lL?yMJ{CDM*,)R8[jUr,d2Qu_W/:ROb)au`17#3p0l8=Z=HCW},bYC`)S+P}yFe1f+vi/d7]6T+U6o#K8NAz&;x*7Cr&c1|Czu:8O3ut{.$7qL721=yUCH`%FHhMrXzHPb]#Q.L"O<@1q|yu%PN0ai{L`0#ml5C@5U7;+[m%:[xG}W2ASqL_MAnzji$H`Jg+LV}Eb^2=8Ym"O!PY]kqFQwra{Q:,ED2iGiS)kY,Vd?/GOi{GMhuX,~IL;.zoYHxp_r]l5nuEd8X=Z;T&./Y(5X+XiUH*!3kW(7PaJ%lF/1gJ:;by!Wwm/l;]+&XTb16SlKYzAf6JK$4;NV#@VBHKLL@MfuIAzt7vS!PiNE#n;k{@oqQ]#F`#Cu6+l#{t[k8TH#yh#)j%vBrK67etPa$ft_Oz!$vBr?R4j&[!VfP)HFIk*7pR#NyZmU/Q:[GoPcKnh22@WCNK:F:nsA+v6SB`4l4/mq&0$I7sa[[3Ld{^"l*:*z8}EUJ7?7HV2h9x*RFUJ<zY@/5|hi9$n_n*2+E9]w?AI!?iw19/S1(?6u90)n/QF1mBqJZ0gUH)+/x?8u1W:caA=1v7~3jE_(HI<g]7S0Yb7n)~#?pGa>KJqN=X?|>#&6;[Df@|la}bZ4B0Fjbzs%UDTlW2PW1`4SkITK#Z]_.uoIqNZcWc?z/ixf?7s,,cM[/tQPt+xw(D#<[q|]&k,cv>0X+,JmL1~x5o}Fca?ay5jHZYR4$@kn3J]NB=|]n|n<|/4WVxck3*S"Te/^bdE*50qi0$sRRS.BA"=r,!VlLr04.yzdVzvqlOt`y%yoTkU=}iy<`y68_ids,m%JfeHb4Z+o03+3+g&XQc/j2$3|7;`O<z2hq[pPTBzAMk`}qvb9c_CmYB8[L[*{Eq,yQH6ww<Js5[7NZWuRo"}d&!.]J=$32%c/iNkz:6oV9u..<r_$RaS,qB+$pExB?%I?iOhHw+K3`=8D1(vn=k2|>^xNl;YAhPFK~6E@4=7)E)+Qs)=v1W:B7B_QJKs`5l&W[J2mqK_L;ngr<Y*pm8vRxA~qQ26o8x|uYZ>m?.&SeE(g>:{fz1,2~z#n]Qg5~_g_MT$M?IE$d#CrGQl,ph8)+ibvT2ptIaFRkbc:dwV8Lo{;f>]:QC&NZxsR(K5k"_?Hz!{x}ibe(!7]IyoqhWy%l:g+5,R69?eY!/nj5=],,z+W"1M$52$m#+>z[A.h[P3b><VrhN|v|]<,%ox^._?K|DZbzG5"[Gp~EK]}mb2W!U/bgAe/FXN8KS+UmtL>I060LQHW,X16pJVxr6nX7r]7!WOR7NW("[Z8sW32X^BUAGu9HPv*fxi5lDCzn$Dz5zy=R2ov4gS1!`f)]7i&;6Wi:Lb0NY^XQS{N`?t&C(f9cr70Z^Zc7hQD>6qw88:x`;J2_)<9/2Ti]HuWqaOq:ZZLDbyC6$v(Si+m1;tbvTE[$<=/[5d]|G/yn#v`HpLI6A=^3W@O[W!.hP5Yj_.5:N{UY~;zERRG3>J`rYf+BV,](nX!5N,iAS?R6ttVh3mN`tQ6(?8qG?*iCGX3aKfyC;ggu,hrPPXx!5Y_U"?YCX@wT=>t8Crw?iAMl~,gSi{QX/[~|klPg9Mg]FW=|v1Rp`bZn~1UIN^qu=zDur#bwo@q:qyXI#!q8{8kMcpZ%e$Qnv]FGWwFn/}3wfhub9EMJP?CwdhAhi&H&A&B>ihS_"ZKNrX=gX6wq2N$H/09r&(cBxOlh>`X{Eb0;|={nr%@IE`>cdvT<LKs&M0zZPxHG^&2/>8~/aK0*;[qK]4S(li.!1KZX..dB%[c_JR$;B#nfNRs=aiMT)lFYPDZLdGUQq?pLcV,4aIyqG!bC`3N^;VkL5y0p|O1R>XVQ5yDlEpMPZ<x82a}VeY:tLlJW0iSR6?gV~//)N+#zy&3wK@*2Plf?<=i{WJNm?|c8bPUW[bvoAe9.`V>V>V>V>V>V>Vf]KQ}de:f=bS=?wv"=YRc<S@1!/@li;.}C7`e+X@n?s<dBG|dx9PK3VW*LgF&,4KTR45NVW]kHG%EFI_kH",y|a&4dO@L`/1SI8FW;z)kL}5=a]~XTy2`h{H(,db;ej&xpJ{{aK(fv>iGxKV#Efe@/9w=a]>ylt%qWND*#7:Gna73:Fz(7.%<G=oz!l+yc],p"fuPX317K+(RR)dO@(|KT<fn`h&_JwCZbTDuC0K*L~y^@liZO,||XYFYF;k_6E5lS4jxXI6QCyrU@3R4jli[PhEo6s>7bXFtq,Nm,h|31:!(!vq]*"b9O&|sND{K]/Baqo@>nyt:,Wj5vl+4KJKXd_ic_7yh+o0y|31wSPVR./zR:JGmCq~[*)?G@HBV>qmJ(]u`kCgXWYCL:[g>6QfqQ+?mL`$F`AFBYXp/?NmAMT@AMR@I`L?uN3`cLSzSI8lI{D^Q+.({oFQTce_LL#Qep[3}iW?|>Y`F/[hV2r+&f9)8`QI<!qXN_GmXkl&~Sg;aZ1#J:]6g:kafso*7+)pb?SfWy_<_I7>rraX49,&hoo6yyUn4mhf(e]tJysjWbh^RUp)z`nmfhMTs$ePfd*p@wL.I*&N"x0Wgq]0dKpsV`a+T@[g)E~a9|K1l+m`oQu:HZc1?Om?%qUII:HZaLcVlir[ub1Q%yh+.%s0+}vmRC"dxO?8fwOjxGI?&r%Q3*Z".LGU(.A?vp,B_6{6=Z>m=jwx<.h|,}]pYT%+s1t+loc<AYPZl~tC8C[YjzIN#I/vWCEv#XKI<VM$~$8_OjUF^YjRK%Vmp"6mhQ!,_G1B,{M1?6fiB*reB0vx9230*Mn0<,R%efLZ,MFCu4<PKYLVR(oZ~w0Qc[j3y|3V?F#a38;@I`*2fl7xc2.ugat]>coWs!c7w#G@BRV2aIHy}xwik@_)JIOPoSnP]IYgi77/XP1IGvC{O^{e}Ik;Vi|$S>~lV*LS80FJGyv=)YP?ih`RS}WUtxK$Qx19,MNUSP{}nf9N;O99ZdKOLA"7}DpZg0xr2Tu50,b_=Jpszr}()gNW/jMIQ~NmEo~gak+izZ/R}~z,HNpMOb:y2SUXrB(Ez&m5[3}QAj)a@{Kc[fp5dpXz:?W#&"wmm)}+pFo;3&|@i9oSMxD&4,YEvuNphw0N0`/$gR~CVD}5asjyx<ko#oX$Az@me3D`M65If5uCR`H^mE)FNvccv88(XpomkS/FOu?(<>3L{C7S?DbS%F6Y"ES@979/8uF%9w6k89]KulPyuthdh8b<HnO.]i;vNZNmNVDV;x<q6b3bsvy;/L=CS":CZVl~DgRa[nw;yz]7BR~L>?.1C2*r405Yz?u9JFb*.<K@(ge.C2$i>bNivF<!`V}<(5RRGiUp8gYRqNI+lBJt:CS"e+6?UR;l}6AMnM/thZWO(yY*$q8,QhBH>^iK:)^bCFYw1pz,K<R%i&?@QX;x+iXFF=,i<{h[5~x2L$0*gso0SV(E{pYhD`d8v6g37OhA{u0L#k!XYkTb!7I;isZx/R72*<fmPD0VD8zlfLB%0GW.~L3i4SBhC!n_=ZJuAr@E6y.+_d16(eRXnOD8vmp?NPT2Zf*)<^d7X37AzNbJg|6HVFbJLT@kZ5io$u|h,G$q%%Uo#nytw=cQ3sOK`2@A`I}4w|cfIIu?(}nj>nW%rSNs!_PRKau3Mj9}v1&GByPVUAK}/,<8}FS{#xrnE`<ojF(M^tPLSH;"aGq6bQ3BZL$ddQW,I%TX]CofAP?0?C<P)F<&P4vLUVxaZ[]tu2>q0p$esO]&>v]&D8o]HeT/E,1t=DA84{OfgxcVn9i1,S*gmS?ko[kXfweT)3O{du7V$p2VKMj`~peMT~OCDO7pr2>q(SrmAP#vBHF{/Xe.e~ulP0J!4]#2G=Mom_Oz&j?A*u;e|0J3!4j1s2qCPe,EY7#3TuE;#X7{T,^FBw2goJ:InO`O!XAM@)[&~XD5635<?)m+?U*kMX`GY!<FEOoy"X7r4<zm&8Y*q&m2<!"/mNBF~:mNkssCd0[njC]{Yb25xqNmoqLLy,U+A~.@rx"|a1ft,fpt2ywhnf//3w[rA(`Gd+lU]aT$R@X:z^3g3&>!?G.c#IK3RL7O,il`EJ^<rgn#F{)uz*=%PlNH9SZV5{L17Q]R%KhoN`6LYfV1>dJ]kya*Or8A~bB!|;<=U(4x<e9+z6`#n]Iu[cCoaTA9JF[6jC.mSI9]fmn9oScoiGG6kHyhvc%tPlVy(fjRb7p2kmT}:x<L,+cvf4@`;N|xPVG8i#/gcQQ$=4X$&x:G9kP89`L5SyH58C^COpcM+Km`4UN`cbPU%z"mu&L2.L8qlxRq;U4?nj~Q696=q(h0?FWwGk:LUM43@kQ_w<g.7de6{X?{w3[*cT1yw)4E.ryxBq*$RN^ioO(Es4gT:*>Q4gy&@Kc{W)}k[6k.&=>Wg]UCnR##r~[h6)Z!n6<gwMEsp])l;:TGI*fUfMaG[Ct7N|c)wc`+(Fd{z=n8c:malZ[]x&cdYU*92;DDSs4?Zdz9dH%$WBNu]]$l_CP?#{|n0~YXFD9pg7Aqj+W+*fsU"lz]J4>Z)]){NM(Cnwuu/XmMtTQ,Y#1KC_+pO*aMk"0<|2>9tiwl"j0My>p!|2O9%mYm`r6s"Y,n7L6~Q]uYO>h:fa_c*21jV{TYLVPp<{v/T>1<%/sO1uS^V,rbyPi]ErJ8C$KfdlnKW2Gu%+w`<F5bXp1`DYN4|}mankv+JcOgC5vbjhIz(?n3!={QrqS+=tIEf@!6mO1Mx]oZO9W2aa<.D*`pZN&.f>TlFW;7XNdydVm8j6|^i{BL4bWc=a@G*+(SK&.gxuqm%ziN8y^l9IXK.fL~}JEr.YW}DK7W/K^j/E.l6N}GMzjR>|KIPst+f@}!.RfvE1x_i]8ex_t%!W3n1O(bHtfXoCQDuL0Ucc?bb#IHNXq&Tc3_BFta:^M`0![O<9?gb/P:;lhCWs042/.[Xu.ybQY1NUNoL`r9m`fmrV^K)[zR:?Td`4s,=X=+g,F0eY=Q=,6>dy{VQ7d8sD&Kq@ryJM0/;ly,cb=n_#/mGUIL?}D},&mwUQH=6;@KWTi*{jT0<wFMF2y^zcj&R:+voajRlC3j6Up<{q=P)[8#*Vmw&uZ&+^&zl#Z+L@$2?ba+&~&zXQ4?}!*GjR+vdrSogg"2vb<oJFq@QT45+a+iJ|t<yz.hy*g.FI//?`|P{fE{1BJ)L.sot/tc48>JULGr<xhQ:`/,9S`&I82Mo2QHR{O|l+yxf5k>e%d"x"Sj59BDTET_e~SRhO2_VS_M$a2b*9[NHYjXSZ(#dM<C)vXxA(3Ej_YRN_snNy|}a+>7(AbK>cznAy}Tdxf2.znv5&*;QWbk,&mpIyi3oq{aijF&<.@m3`LSpEG&or:dJnRrfwMlc&,2X]yh+F2V{<%j*;w::=iO$eF.HW/sQMf4$%hP@5K/.&SgmY:Kl2oU]QDop%Z&l?#&6ef:wy3bV@l:h(3.Xf=2aTNh9a$9Ja*;l^Um{+sm=EI=qFq5j=&8kfe=M*k[M*t{youM(5#s{qG+Ab^4*6|5%|[l]zi[)@{"y^r0I(1{DsX+mhHSHS6Jm?Me:dxyZ8G)V7]*4jY.3J&nyrDy[Kjo>G`#^qKTUiC[jbamhS=gd#O=!+IFO$.#JoT`&b<~[ZW{B7{^J%l9&67g0M^xNZOo?mdbgMOw:#GCO/g<rh3(P,Y4zm0aKLXHLZ*SA6PNvZ;GW969`s9!m?{vPI6L5L4MnJN?g.+2?73P##b_kek%.L&A{pe[]Kiu&{^v25>;LERu@F>v1*bA`qx<ZF947u2Uzo41^Cz,ocZLX7O=T._vr,]=tbt[qD0n(NK4VK&o1^tV7Jegtl$<Vi{MEqkxX`7JXgjo[=xU"Flv{zhO][?^IU,W=&=h"J5qdG^<YP}e%mkm<%xeFoab7h[!joF|y/U{g.4:;+,X,}{J"%;gv]bp;E:CC#APi^W$]%E;"P5."l$p6hb$T.&kwC2#8G%mdz:r72l();nmdh<]vmImdSD][!7q+a>hVKbUQ(}Qdj]}W83(Q_8Qhan/&#Y8YwcX*?~o.5)H9xz|&)}Wnk&MPpP0@_y4E3=nsj"1y4>JQqGT]iP{cP"YfSXo3r%EF?{JF7,bp4?ol400A73TiZlq:R/^>1Kln8&OU[M3aJapBz~qOwzKQ|G:t	ch"97vQVq5*m#y,JckT0<w|heBt?kH)7S+]B7V%LGuai;U`WS;PW]|=UEX8LyN<8Q(`d"T{x;Il1i0G2U/pAJB@QKew]AAgSXL{ND=;_zh)k[/tQZc*UuXhCR|/h3kFj&:gpp#KVLZCW,cjil#1LHqwE>=TBI:|eUILOM&#zq2yvx4Vg(5{>X>pdF]=eC~x;4apZUZP_vXSwy%6/u38k[TI;rwhZNMGjd)p/3`uB6PxI3Ed!Oi&k<EpGQC<L=fv&^O}7LF#kzP7DH}X/>8A/mzMv`lkyP=!)[fdj@%GBR~Z3vL?eUf.cZ_Y:SL<A,rQ5l"ur@T4`OZ`*(S;qRdsTi:awY=*#PY"COwG*J|{Id.*^$xrnT_YA&nYfWO4G$HMMK}*7*Q2%iR3xbpt%Co0{cRT^nNa)e]8#Ib3sF3}XRnx+rGfmyM#5jIP_<#gr4H]{5XoyI|2Xv5Kwo&<7Q^Gr%!fgsG@{GRCtpxa{W@{Y$+R=#5_^sP2PNfCirU/zBZD0rbv5Z]*o"Uk7yAsc9O%d2cyXr]*?IeSwd:!A:OJY>5nEnH6E|	LDR^Gi<oV]P3Aex)os;sT_kbM=;yC>TsswhZBX&]UXWGM*J6w?sY(b4^Gy%2;4^tR1{$*Vg:M*:*M2vLxTm[d&O@.r_4J{Y[896vd+Q~ZT1KKhaT1K+%mN#CCKiW(Z@!0M7W`52gLQ(ZMWDxilgbY`[;{|&zW.5Kz:cFLW]+?o^ktEwb^$X.Ly+i{oej"b<EMqySvKmL3~Ll,J45GwvidhsC,{x2#!09vi5I[P]wO!zP2)@WO30_1id.14_b5%wxd`h|qckpT!_**K/z|J~5@{t7zf)d8g15=[X*5MtuDIi*=O$yt%IhjL>5.CM7!C@:L@Qq$n:xwV=z[7h2Fd.f!t)d:g,iN~~c(SlQ:_SI=]V#7Y<Lg^cdPZj:aO=5E/FLG$cH#y,|O[i/rN.jdHy*CpMIJ:&#zv7lbu@!z6/=<DI?Y2wGI^^%j866rS156L)a9Bw+3lTo0r)Mv:j.s=MfAVGUv~#/[LA{KgrV!PPe3{yE"k,YCiRTw_%F3P^9:imBYMAg/H3(DkDZ]owfkaIbx^L2[F.jt&KJ)+7>]zu?r#]M]uPyuKQjh7C4hP_XL+zn_<!8IK)p@Gxp{[6ML#wXEq!_h^KGv3"U[6!Nv=3u8pk&[2r,MD|w,Q/({%B7E/Fn2E$`h&_Deix7WF:%qG1)2XZ(vX^*q=$`e}:WdHz`@lW@(%vXnF7I>xl|`5zML#{PpjE$PY=YsEt~i{bXO*"7H!gx,38x&:9m:t.U"Fum7IFs6dPpJC:=&u}UvLQ,!_GwQQY4Q`:kSZT{N5!4|Z8r&_7vhLW7T?dF#w&uu0j,Sti+nV7Z,:%oEap*.f3U;tuVAl}`=q"eCNDdJjdPr^C{:G.l6b@y!xb/!{%eTMycMuBp@]4K&_LnF^P#M3G!q2&)6xnFhOG,yKkOd2]3#/~Z8r`+23b5458%kc5)BpQkLf&:|BR.LmIWBzjw}_XDZHQ^,elY%N7$+yk^}Y:aC1gzwV)`$wfEM_`U)(CUL),@l5w`"6sdjm+=]TQ6Kj&fL@dr<_7vcq9vBqRSGr%`drdr#NG?aF`$7K[]S[yUqEo&<3odu~~9%3gU_qT[dtXKG;$jW9rHx!$KKxhwUKG6Y[&(IyF7Uvy+J[xrkQ4:{y&<ShpeYwctC^WekUlVT9*Z_Jrmq)lk|Q*y^*S@ADE7jwk"hjpI<9@[vzE06#55cb/{tV5Ty;D%+NM40uRM;emL4V7ZF)1G`1b#9;,9<W&UJi1hxry:+k1P~}*01Wzo<#0Wlu[cAkC9f{8L{9)P@S#.nJBNt)f0j,vS19+#iOnO[ttbWWw|l"K4J3u!yuUO8=FX"8;m)s1ob}2mVCz&BDLH^Tpc31D?P3RebwdOdx&qPucg9G_^F5_wLkhqNQzMZz/;>6{o0@}nb`/(PO}p6Z]lt9JOj[G,H0=w"y7dk7iwzt,3<8Y=V^aOcRWWx4S~k>~GcD=9S5>;GL4B[yDc&N|E<fwDgWSa89mmSx4m:F7ZFQ@^5Q.L}N)a$GIbF3#Ku?,a:.uLiNQD50;p[.;%l]i%|$74R|x1zWkad#=%]W_`ZL0^oabz@:huluZXX]_Tu}>/WWB@qF5_.E.+dswAk!,754eD487tV3|yyXL^VP6}o]}+vGuTGVjRvVYiC}pga,:`<"r.tDCp<z,0[F)q]F?mpE@G!c>98as$oD^yDN87,=(3C.gTA?p.rZDOg7AK_Z(5{S36X<SvT#*G2?Ftgku.ii2c(:3S<;cUv3nLy%eyn3]`8.=`Y?+y~p7OA^YGVgk*X{C;eT36`9Ih4b/ELFG~"%7UIp*@+g+r`&*/f#^Y|CtV([uv4=1Xpy*4Poi<7czMsSQX`KTzIlGZfc/[/$sQhyBhr/"0XQz+,@E3/@fmbzL5!r$UR%k#f+?o*MjRBqY^VULIG|}aKx%o}^^?dSI`CLrKfGTM+!fSu/0wV*Z&a[jyd+L6k~cF<zvgM{Usbz>#_4!dK@H`*33_0,F{T*Z&8;1)V+z/T/cF+Vr/myq4kn_E6"mnzDu?<>zyC1ALNSjdKjmH(B~g{Kxrp5pL6,Cri)eF%UjL]rp~0MMB,x4d%~dy{IOmyGHnVs|?/}Z&H|gsMQJ]kDgV3,K5!t*V1LTYqD8rlV8C1,RIO`1},1f5maKnyKgVH|Nh"cs,P@2!xYs,E2y%!Z22ypvJ7mjh8]|b=N=|bKOwc6kN@bxk"o0M<6?=$KIr7b@b"fXFJC.zHF];vJwIK*PCH1fEwk+iKi1lhXeZ*a6KrD?/^H{CZfjRc>g/R2R5jRL[]+D{GYkD@pdK><7nTr;gDe&8jo47U.5q3n"<C/Oi,W.XP=zTRMpJOgI:6Zr_?p@c7HOpw>~c*/5Z+i}6XF*/0."+{?v3#!o]CWuE;FiNJ5q={8RZvqfyi2e9sXR"*r0PY{<fP6cFweT>A8.]xWG#KyTYw$,Vdb(TG*oa6_E<m(MV{)+Q4f^1O;:urNg6+T@BSHIN$d_;uIjZO=[O,<$]UT,<MlB_L;8[$U<?qcs?3U9o!Q8v9p~%R3Tg8z?}GYV$vPgZx8#<=wC~O&R^$&99:WjxGz)`qd!y`]n@.#1(Aev!5D2jRS2Ktc@M%!k8WhmDTHmJoP1Ah#<GmO)xtD3b;WbKJ:wzKh}RhpQtjl$I#%0W#S0Efa=$dv]grtMb8^MFKwh=NF~Tz9uJD[tlG)SH=eaHl2b_cO9?!)]H3W589QmY.g9HOp~E^;B~8X1sZXnc{fo[n*=U~+x|^Zw;uK~?5caYK$!})4!Se(Cg=]#xa9;#W3c_:*]$%3O)}]Q=~9T*g;;sEZ!m/Deiz{m[je$UR#nN]tw?V+}eu=b4,qfwvm>NDZCHgN{MNMs{%kfKNr7c7pifnJUJ=7`Yv:;gnU0>sF9$$p[a71c>`*YWY=$@:<"pj|;Bb:2n#YNn%5A{sjEHi{C.(fKMt7w#BR4t^8iGNu~q.a:YmIqXW;_{.8b$cY)u<d7bYh~S;UZerq//(Iapub!x=EVlyfk:[[77562c_ndiUB41}dF85=z3#FcM6ksxsRE9kN6y!.kpPn,bbM1`#l1w}i(6ym7&;i+qCodi&Xz_q_6>z3*7``_F&<)M&>Xcg#sSh8C!?4Zq8*ckTYC`tsF|+lXwzs]TI%9o;gqEfr<xG;nd_rS6G%:wPvLl0BZLBaCU$#"Uu4!;`L_Ms#Dwx#}<Y=8d0WsmkH060#A&wLBr.aCAAW_OLb.lduR@~V4BdZ4gxub7^cIM+b:/9#Uptn!m^0xNVX*L9{./O+WF{C1Ew4;y85Q3#MCp[d1*cvY2x*1%^TWK3Xf:AkWykwD3Zz"CzMoXidbd@6JP@kQkT0<w3nSGu<EN&?1Xkgj;>h0L/<&B$7[&D#,2GMgVDeID1R*h8fz)Wb0M$e|j+b(yw`S@!E*LEJT0DOw6N`+*{(}ksB{M86e${(i^m}]`(BN!w)lqLVqouHO/7"U28N%0a!g|?JoL(r:;u01$x6oPt$)M%B8M~>V0DcrDl7G5>H2k71}631v(sIJ7SO2v1+k&^C/R+K|pJV^dN`=An7"8/8:dYV+M3q+KoF^1Dl5S11YQGiKY1>gdVKkz+7^*%Pk7PX8G)f3_LyQVgd;B~7=ZNNmy<Rie3)7j{"p<66A^?g;DXKsYb}]E+fQkSg2ye9tm_*Z$N9b2(J=)0Rt,]<;JEJ?yNRI<QtPJx{Jk6xaF4/U/ej90~#CZ:R>RC~cY<q"6,."7CM:nn%O]]N%3_UUgw=5chRQ)}q~Qh}aa8zOZMrgV8btN~/1fw=<CkZ2@35r*GoG=>a=V#m%40"CE5*npdQzKR@K.|d`*>!#40?F=5ip,(JeD7ZKTPYsO/R^m<vW&s!$Rb{h!5jy?=[^P2HQmiF&nr6qG3_r,TJ1KoMFf~y`4QD8v:{Vx7~P[KI?go9%d9;2?RS19gLYTNhbBEY3RNV#v92#tIATvbyx7[?t+}gG"BRb@@Ieq;x,*fflG%&:Lzy2WF^)eyCH(*?:{J`;9kqU2^O<{qUzZ|=L?.I=M>X4R`j/MgJE7d)CBD#3e,8K,IwMch5+>HA|LoiISeMoFQ)dx$Y5X|Xt1Hi0Q}L;IjAyFq|iy0+!W@!H^IewzlEA0mx097B{E9>?G0KK:1>k{;huhd%t^x1`<NjZO%}/9Q$Vbi?G<LPa~AR_dG*)$q_6>e5Uy#zAD@t#_G}rasZgY78iE<5bCyRgaIFAunZt~[tw4utF;2E7t,r.?kSdR1BPK&<WW&NhAw!VJQ+aymWG`OKw!jFimc_!5/XHwjEL<LSFqC]fS%<54?oA+#qGa}y;*PZuSfVsY=&79>I?5,/eE_WVV1k3r"J8?;g^TUB6vuKIejc1YQ81cEj<)^h0M[a,SBe0z9[Ib7is.E`G+Yv`6.o8{zcHsGrdXn|;fb7RzIDF%?woLpRmi,$Igw3QJ{E0GwBW/d%YG1KOu<(NZ]k2NyF;GPVJZ;M<xaF./v&a!1KMqAIcv&k,0v=vHPVPZY*fm8#z+2WR>(vK8f|0nFQ:FA3b_ko:BAk5_<0UGnmIKHZrUsTtf#nt]Vh+UMT$?Y:/Xf@<T|835^=7tsMp%0SfS$~9^o3&YO.^1=g<^ISYP6/Rb$m!q%Bjb@o87^1bU;d9m=KLzubVhNe%y5j$@?G2aUpexY9402W?El#O3eu:k|p@Qj64;KlR]Yr4JThJ{.e",pRQQW(AEPj.|rF|#a9m`xE8M6?Fh&_L%RHv^4OHBFdc0j<5,Gdc03lZX;uv4m`*3%(Z$ZQR&Sej@c62Sp);*,l!,NlP6]=G=Ya_1KOhE<5A(55JM_M[SN*J%<4OL)ajdnU{oM@!pOorg2u_/vd,UO9^*l,DiY>>ldr?!OG?o%}UCu#u1zTn_gkE~wqt9/<^1RlOZgXHiIz_<n,.G0C1CSgPcS1bn^cf*NEyPwBVF7UxfZ5.ErG]1&^pFO!D@LtGngE~3Xe,U~/2}GD$zKMoMiD)acyDI4MnJt#[u/[O2fD9L9fWE&G##/<9//2fV+Vm,+HVDmA]&T}Pk}m:V$+0Xz1rL+V!v#!_]_ug!jNZErGVz9rlvDIJd*^UM<c!oT2EgT_tv~!8PmS=Z,cXkgEcGfyT<,%<VD99s0j"B|h}>!V;7THJ5pgB*|jph[ZR~[ZG]swPtc|j#H=r%,H)a@+%bf0a%VQn)i^D(ljV](2jN^6.M[6U~Sihjt]R_q`:Yj}9*NZS!=tWuC{2n#E$/TX7%TI)u`^fH]IZMB=h`Sy0+bV,B1KYBYJ%::*7v[k4T&I&_nuT_+VL|SPd8=_1JT>=;m=%CXg=Ep5>;6JyRrdeCHY*IfthmI;^?AT{<sVK@bk?iyf.c2$"+o]3!ADJ)._`YH6MP}^0k+kh?KN<]0kQmq,l;p5VaN19Gn.pAmk<3P::*5<QjJmBIu*o;,l&j8a+ju,Z3a?98&fY?@041Q:0!)vej.{Z.|@dqfvNk+X!S|`k{Lt006KU,T@i/<vayE]oNe[5D@kV+/Y//DZx:OzFVjV|(HsNzLZ~%)`f*NZQf7mEzmF?poZnOo%VquczD6Nbz=z9PNHZ+L.gHWY+*?8kQ7Q+aLlvYs[?3F&x.$Dy.Cxah4KMrh:1ozN^OkKC8JnkWA?k=s@n3IyNfG?hG@jhfB2zmx:&1(z$r#8~fQV~g33+]OF^m{=`ZQbM7;Bf.scY^XlDM4UTDfK<:(k=YU;~,&%#5cX.2m~y6,=1;N4}wQ%,wx<2!+d,oGKq[y&/6[YXyH,=U./|22&aGBqj"<.9o2.k3#K)%PSk%W=n$Sn.mtL!?v<UpBJ1bDaD@_yV{O!:OB8dHLV)SWqzD?9Ldb7$LAg(vpt"CupDGJ!y%"XS@*bBnFa7%>gLkyMOiulRD<5z~aKJ$&Y&VfNNT$x2$cmQ._D3|P*Y$^Lvm0B{p1;QDBq;Gn;.g|>9lMTXM_oEI.tE~eYd)%b.V+puZP9Kp<kDG6KR1=5I6URbD?8(?SJdqPRc`/$j:L%mTlus}4b611YF{8uP.g/y_hF2E_W^4bL}aiSNZT_7=<WjFR+bc$FCd=>NB~X2r]Tbtq1y3.T/(gw4x+mb|rV$>]?kM[r9pqixINw~x{QB&.Jt/0+bI"Vk:[wK)Bx/cdPpi?f>$q[*kTZbqc_f53UD;{_p=g+B%n9k1MXd%3P7!ox"yKJ_=J#wL"!CLnu[Z,u*/9?y1^j6.n1:%?%^:lXLuJ8qxv=(;7pE6s14O+?t_kkEY9M3P:57S<ihxab0M>64yM@yTdz)}2?%M2HQ%r1C`4!1YJug,,:IbYQ:Q@}Fvm+M1E9XNaQ?jsld9p+oaro~gfNF+FV>xGE|&g|/wl[5cN%oIR:~2;RxW#9Y][TSw5dkOkCsubz)i(if>x@3RWmcM=jgmKoW$D^:oUm=ym#[@{P8FHJLTx/l|t]qo1r66jRgms<oUZt1M~J:iDu:4,.l)@8cJzJZtJI+c`oSe?EFCBU/uGEc^[(fDUJ5.=GUJIt{JEr{!@7RvJ6/[xg^vIgsI2|vfdChJDCtq}b<=uZC)qUMS~QOo_nkiy5aFcQ+kTZa9@o%n0|SZC(>s8,CyPVn0_!$/#2zSz`<F~c;yi1+/z@[k$o#I/v^rr`*xJ69_Bp#Irkjoe.G)Om[L@RU!Wpox0Z[?f?dS7EJ)3|=xO^CCoiUaDLMyCM$L:,Q3ZF<[mi2Y>?7/nH&_p+6+/Y`N>)X@ni;5_n~y7KTRZwAqd<|(V`m+0Xw/;bT0f,xue:0Wij!n`;4n3e4]vrh`S6k~NDD_^B+(BuWJ7>q74c!:p?@J,t"&O$<&%TDR#e*pm!L#K+B(tBVGU,oU&W9[:KIt]+Pac~PC*X)%eH3Quqf,ya}xCRnm=Zry+$X[|>Gr5`mi>f&QjR}^d5e+x>N;$U{66#[(It]+A78~~t24U%UiYO1cj&iNX+D_@)S{iKoS%pn*bCoa#n1t(?<i"x>IPHc<6S,E6XMh6u77xig7!7(upPK@CI4VCw)+i8de(.HUUJ"FU;U4XN96cYu`1t[&PrNEv(M`F{q]Zo~G}5!{377`j9`2ngZU!p}p(N4ilotDc!Wqo@#>|EX@mi5uzdVj9v(]2dBt4*PC:4k0FUhqhqu5iFq;HsHTC;`DN=csQT}7SI+):Gj2@t_Jxv;qa6L.5q*=1(2|=(|ETUVd,is@#&_@C=?TE3^tE53l"AaG~UzC0M%;j5ay/=pj5Lw(b@W%FFrbh=$$22YQGDJxioh@]/NzKxH~!rIEfTrF^3NE>GJId]s<Mo@r~LF[qL{0"Niu^rw2/|&m{V(K31]j7dxUzK`Lu(LWUY7/9=35=Vo[+[UK|;356eU@9tjiB*GO3rgAe?jCOCz,HD6P#Im^WRE"Vvy+wo(furu5q*(AxFLwFxtEHYGF&l(V:e(QoSaG.OUKFbQYAp<cj#/g]>Uj+,b%D{V[1Mjs*^LSs#|l(w3|(|c2aPA+_rz902%;P8s%B2^_CJkT>QFj?0NIkOS+*RHD~o2%.@jsG`wvAe#y?US"2CB1T!oj6hAS8+eFCQ>s;DEx{/}CvvIK~+>4F$Pld+v:p<5R=PS%9NAGb`jbAM?;mwEYwghu}<j2ADLleSiq9F#;xfaGfL7KbS9wSQg|Sfj1uN#EuC*|ohMTpi&B><1jW1ek3gC*@P82wg(Q.c!eCx`$Ufibvg*#%<}m0;_{Z!^Am8A=f*bu.6w._$4]I`H?.o:~R*,{Z&z2`aILsp?^;b~=gWYTCSI=o){t"#S*/C4&Okq}2("JB&MQ2#x)`dSw"kyKNDji7/01Jxr_=Zn_7v!rO>{X:,5i2`J]pwykw4)Kj522gq}@18SRf0Fmr<quzitk*{P.&<`FM|/jdKFrnia5rwyEqbeymGaV2h_M(85K#[&1{K)[_ao{h9>Rqt+XZR<n+X]W)?jNQr!efkx#phTfD1!lx<^#hQIvxv3DgDUyHVrO{M|vNoJWhlgd8fvmLf+iXF,E{w>,GvSu:)`@mVp5G@qonnY9O>#W<nO`zB!wKzzMVh7z{k1,us)?zBTF<U@k});$74zjr=dcaz?p_QR>v=#W)4:uUy3Ei|li`T/(g_Lf@k{q{WO:ym{tm+~gB8FSAYo&bfWWcm(1}Om1C<3QCKH/#YLblee_fd!Y6f$zQ:@Ii58~[3zJFJ8riC#_{xJZ+3~*VJBS?6aG~v`=yrYe?B+w`$g7p;=]SqjTi@hQ]CM?10y]:M`J>wKz$`|)uIngb&{W(%#N|T0y9!z7tX1,{TyCM?`SP"a{QT;YM^~~B5G5M^`0azgRV2|$}$roch[D;y&vp+%<MoR(*~SJ+)?XW@UU`>n>4qhngF0xL.BSKw[kW@l1@ke.8hn1f=T]oYTYL5ngH|Fx*LTY4iYQ{KGE;q5N}G[qmWr:fs)3*p?rr@^y^U:m+/#v?O:v}cjyyg+p!$<354tkRa9(vyRLx^;d|aMIm5[K`gU^mihG$<ZThX!G[)@V"X$:Fo46{q|vj7KjpjfpJ!)%HYM=4H(fPKpEvHui#LXVID^d4M^gAp,bNZ:2OYxePH)/by<Ip,I78V/#)/4ZI+LK|a0m0jmBUhtttlQ^k?WkKe?MD.YT}VbyJ%VJml?hFrM#z3"CF_nvZG3vBCkx{;%?c:Zae/PueLxy3wbtqGhV.(B8X)@Vhl89SaLgYX!<lQAG%LJZ=!iTNf_wmwhb(twetVR;>dMmfm[/.DV]lcahsD,)k{gG5Hun_q#AnHun^9%N`=w]4(2UDN1?CKXBp#;P}.{aeJ""I,KKD@^C@/#yC)aOW"03WOw]Ge9![BrAU7YOzG7eRf}w.H*?@>/oZF,Xf&{R"&{R!ehX`y0d59DF&4j2QHdqKyNfuR,cy4h{(Rbb=,2.EL1)xt:{LQof<Ofl<tf{l?_{}#H{p;TYpP~L]u[wq#cr%H.a19Y5nfj!o]+VheEiRTx_,^yz.t*2!!f:!B4B`MkS&98GB{_qPSu51k%{62PX+?#<ztPloyYTX>}3Fo.[xUg^d8sD"pL`q9N3HT,6Jx]dH[nlyrg4@_v&,_$Km%I=i$PT,n/4b/1zfEXq:|9L_IwBz#NQ]Dl=Xi_H7G$%{<t9*;a[F1j3!oeQo#7o#qL<sO(b%f[P7d:y9RdP&w}Q#Gz?6)IMI7]>O?A]e@mYcK=k}:PW[2XhlL8~Bn>E9ZUr>_6y;sX5h4#~R|fb_Zqx(@ZOIB0_;>$IlB8c@pL:GNGj7[dO~7UMdZwH+4%i.jfM*^V?bYsH8m92I|a_(ex}i8:w=#"@(]3Oz`f{==y~?!7i6XL|+ipzol0;M@X>`Kn{M=LI^K8N,iomjlW#4r%}P#+!`W|w^v"c/hY[)]rM2|GM!3$4(!QeuY*mBPY5&`xE3%7Wg}a^CjEHe5@fLB>ClJ&cQuFV&|$:&vQDP?nmrT,^zu]28.PD.V]pekKXS}(%RX<>u8[G`dG*oDpr&$XrRjAgiZiJ`<#+mMRh]Lwl9l)5#xJBkM!#Xin7zI,^e@/)MgF%L_e@Eqz*P;8u)y9,D^:!?F$jt$pN$5R84#<d}mMukrE;r5eX@NnEW_GAC2+yMR_kh;J3.sVa3u5~a$6X#9%5];wGI;D53("Jfy(vp7(*L{>K0;"d_^Qnt&mv|)$eXRcDt7hb+=?jmB{pb!Z]"Frm~kI5eSP>gT{FUN^[{xk$idCwrcCD^[ZMo&2~{C^[#m0iR{rH]C#?2Orm{T$utbozE5?37PfPnmwW~DOuIE)d,]`[4],u.&_7n"gq8W]oyW}}`#Hwq{Y>OlOZrq{6b+p.d*y3x1"O%>zud)Qq~0%2my;Ke^P+K84mj36yERjH~TT{vknBBDiNC9J>^JTHEDv_;wL,F{=z@8]I0fg?RfN`np$3!<@cj=AoL@+:vV#G>pRJDYt,N^&.v*BzNR1`PvqlqzM.[S^wz??zpNB4]u+0k8Q{TW.$WTk9Krl=!.xra+Vy}o.KyG*=b"wkiqOA45?lsjXr%pBe8bq|]x$IrEuRlZj8%2HtO&pblMf7~)]8X=#aSeWR_@z|EegHtv1EBquF"uiHhd5[g^B|2uEsz=OGH%LEroHzgIUJ?dZa0&H@K[rg/5L.gPvSGx`U?]R.EM{0d.@G&82Zc;{hQnq5jN+iu}gY.&d@+Z(%F#sHLm{.T,#7KbCJjMI~)M;e=:`@*5?bT;c@Q^wzn<X?8?e3l0v{3JhqXQC<*gBR$1*3Pl`EO<M(66_T73!_1U1V:x@V_aK{9`|^|vc>dKmg3m4xuYE>0+"GGvaq}U42`pTY$:yc:x1pS!I`R1k(mZ#I8hLwNZRy6JG*SvgnObZ<QE|ow28&7=?<&!rz<zA&FsyeNg8NWkTYG4zCts92"<4OZjw|5K4fll?kBG^[k&EQt3}SP:IljPMfA8~1P!Z2Dk5SPssmygFiF3f9~&$?EW~/Bm_Ws1lNqkkwZG(+gmCcPg{59eL166F3*FbY&QW7GGz5ad>:H302B;(61cr3|5D=X#8F^syOQ89#!:MBe;`86g0MDG7ZvuVz/F7ZXIkOtTj<1>Qw/UC%/{,y[<*R}m@lY@$*j|o@YIYvLo#Qr9*yn8<[*3wno>EN>,=*^e}4?2%;5/s&3tkw1[bdVNIU1R0@g?e+K&KkoRPWB|VW^+VXfvv$GZ&j%S:s}5T;1h&oTX+75o/e=`gJYD8Sa&=wtn>E6q@E"Llc64mYpjx<[ws$`tm7Wp99J~YGA?lwPoL>T*.Oyy6gCvn]m2+cGh9]4NicQje98lQbT+bKdd3QOft9b|O[Df=Bzl;=<:%@wuDYde,yu63(D.,z1%YS1>|MXy?DfK`i9(~I<Ext[y4:4URq.t>`+}Ag^HJBi413fT26A>:SC+m/T9LH)u?4bxh#BQ0E"t:(f]gI!)zEB{5|_c1ot)2(Ahetc]i+keS&d5dZNn[vVKn0baqKCftK1DX(Vr,O)QuHY|uq:R@)tt9Z{lNohSKE98U>2ky6_uFu&NcIC!%gFIn9WI(_16DZLZ!&ukWybrxMu5HG_qSJ<wtb/g`4iRL@[?@W!{>W(<Mlagp.#V<nC5!?1v7OX$]>BEWA[ac}bImY]uuYMGFt1L.UMI3S5%lBlU<ci^%?gD@.Q]aS<p<w9%/|d*Fwh8ZG[k8p"`vVClqT8^<w[9#7&<JJ5Nw69H>ZX3e%ep7m9~G6<px;g8MV<SyV=^t@n=o}{[&;I!TtYPic(bGKhJkaOT=<yaQs=`9yVS!I%jA7<;#4xq0AN?JC:Nzj*=Nl5sKgGu{]VmxY;h>7>GJBvtk7pbkEQ_$<T.z/aOe{hnr.liGQ%dFXK}%D):A_i]sJ=7GB069dY*l1C&AD*t6OG#PjKa@$>gqX/Kkzl9[f!cYH>cTKUgrDV..Oida3k]`t_Mp6>ym/BRSAv([NC"{E*MEim!<)2EwsUA,L@*FdAH]ZlLmXRv[FYAAAAAAAAAAAq}eF(rLo^}b$Y{REhVEO|K2x)UtbPJe@5ZT|Wp;6bRiQ11s_y{NV/D9q[OZHYZPy[v2hFXn/t~N[Y.0QM8{{/7#ql]iICIO{{=b#1PWrb>(/?YP{8.>s|RN0a6GF)5y6BE@.}lS8wq=Fi[$MPE~fF<wBg94OoHA9g&()rv|q6#[}Vn[fVl3V?/1|"I(RZuj$nRuE4<Nu4a[c!hxo7tI+f4s;EqnkI#7TA2CVt(*rsI2.eQBVy@0Plvq(I[7ms8QlEI(M*0E(7SDV_SQgs;L9h~C#Xn%FQrCr7`CKRfb$,F=bDx!,2(2UeE]{0oDo*`U4E7(m5(*v>/NY16m=L;*n3:Y058yl1_Ob"5Ja|WQ1p%xH!4eL908_e/wJ!Xoc5"igcGMvZ94m&:Ed7O.YCxt!:^J|O.ICt+02z5taJP5d<$uRIM4f`vMw=w5y>!S#+["K9=*|X*W8##G^zh5$;yR2xK:pd%4~NF0!+mhYEJ$SI;?3z:<|2Nd,VH:Ju|9La=_H(KB1Rf0P@9.]<6D|~#9I"5P!8dOEMC`e)D>H}R7a]u|g{MRU5>YaY}]M3r3/A~<loy#ht*^btvZQw8n4tupwZlx%dXs(!^a<jQ].i4KAxO>l~KU%Z:o]I5g@qU1T*fYi],bE[!zw..xS*BtGkS2<qpp2S,oN&rVz{9.K$XeVEY&eW[sgon9Z=;,=B~5^ckDqL{T}%N>a1FMiMUor!vF[q^i<Kp4XReg`RO&FI4IPppNHwKNV#Q|1m@"u%HHrcgwc$q?MuvLB9xrA1w*vR]l@3>IF%>:?kAUzdMR.BBRfs@C#zPWnoO%">.HmOI/c`d#FtO/*Y`O.$%!07LaFExniXHh~?/QLb/jm?bgeC^+uDWq/LdDMHa%l?p@5;wB0|%``NP@%y~S[#@3ZgjObv;[^X3j%@qr}+U9+lif)R?KW5rN8*T,B#cEf4t/$JScp`m[>Y_?(xL>^p]Z=QZ6ljFZ0Dz4T=E,9ifiX%]oN7gDu96X0(qP0<l|}ZiUHxbf0Hr;c(7.W^KJFy&*Q:13D:O=G2=LXukoO!L+ium`|%O"]a=3YK:Txj*xUdC@WxNgf?;^x?ktJ2i6^wD3@ZZiiIEq?+eA@v>6xa+KjH^SDB}FN8,^Z%Om9}c6o]c<k`B,,!y4a{5+LV6q}va>c$/eu#$ju%F[(Ad_NZ*bR!;;B!_Dw1u`cGUC^h22]xVpnW,XM_Nyf.hrxUEE_R*yAE=9zB4><=j5pqL"j%o+wxjq1`h]{WL|Udn!pIk,N5Z8[W=vUo[<8c$[lON,3@tsXa*Q5[2xIXqcI&16Ue6Ezqw30[kx|Cp:<mnD5C:3Ig|tJtC%+6LsVu"$WcrX(sR2>g|gb8I`=Tj],[AmJz5._4fQ*Egru56@*pQh~2Xr([iz+pUkm1yOs%5vz?.`kXVyreX]+rNxav[qR1F!3z(vQcvK}+xnM=V(GAlba0RS_1}H89mzhUjTJxK7/h/=%r8)yiha_Yyo.Y5Oj`.e%)!A{vDStNS<%hL%;Qf~d2I{DNKZs0V..8Wb:=p71Nt^NkF@}kT7|_KccsP3eieO^zR,4x9||*ZIi?3"?w3dhcRxBzQ7&.!F<P^7`,|:FyUUFpb)Upn_5%y>_/QKPrE6d!4bo)_crtI|:a+Fs9~^62KwMWrlWzl@^Pp#qvhOx%,&#g&q$tdm,O;Pvtq{S4H`+XY/]HAtFgL~8*>pq.OvL`l8P4LQqZ`Z*l&9xi;nY.m.}3:L_~hjM{lAM59J4wizs0pM,+.F?#Mc7K,Sb"5rji}&(ZZqP[.$XD6_;p{wF=gG^+{HbKAkFGPEtk0av@.h:zCUdsISIw<]U[r&e22`%kD0PxnA;UtYQnPkIWwYuC=.=xk]YUW0].kj4Q.PMXA0`3b*|/&mYdd{|{1>PMxMghI/^c@3BU51GYaq;tK(5/=+*Y(3mVR^gvO>e`Lo3AYNpbtEN?QvQI`XGF`1$.o)lneu|hL$fd&D0u$3r&RFkvJ1hNw)R|]{IGSh4uTSwei$Uv}q@^o}?7cX&K>HQ0+Oz.1&uFU?~WiawevSMvQ*(atO6J_Rtck)|uhKx]u%JY{DxQI&h/gL}mP2a]]M%oV.o2&8u:tEW|E,u5EZG0bha<o6l@9w8=S3=)bhv[$mSPx"sJcHD@O!+2h]]k$D!,lO(xIfygYha?Lv;GasBGA!XL^Uq"S>?rhCP<J4}R{(@^g1WGjlop{k)PVM.@=9`Puks*_V?QLRoIrfmCt{OW^aNN,tX)TSl(Mq*=tYre_.7k3vP}O3prI`u+bLX?SF$4UK0j?/tilr_:FEldysYcIgy!YuG)(T+TwuJ0~;/TP:]hSMbLpAjW+m4aa~Ap8m*kJO)nv}|j3pCD;GUVEL:q$MsD#)}Wh%VX7:P+Q.dOu"*L=G/HN3i0z}4c67/co6KQd,lj+Kwi0a/qfn*#&5i3#NlSj@_Jad"PcPP!Ah>*xwo9kx|G.n.zBKkKCE|7Ek7UlWjm>2/`W#*;4{/Bc|R;K&grD^ReBk~Y|S2!:Eh6q2rzzAgmmDGhw;2F"v<4wfi~[Qo"dpE&44H1jCIpIb4Ga)nIvKG#;zK`d.6KAD$_1"a*pb0uH!gy0j1e>;8(IzQ[WQ;zV*v?oTlG!p@~&~c|vc`i?L:?lA5%:Eh+g}/dVg0v#IR0JVXTq2wB!x0Qu,GD{GDT(RZ:Z5Mgh@N/sMX^BcJ#@b//(71;ekSi]G~Zu]r#w+WDQ2z^oge&~=CF{*8y.m@R!(uI,t#6/3sIN:O[SV}:]BmeJEr_Es,OJ[e(.I,[aiwp)!.EhQ(gvt5zP5@*WZ3v}.qaZux~UvNnk%qmL1)f|;1v%Zm/lG9=iW#ggGnax6Z$5huu["t/eO$9u^G4?ba}3TFqBNmEq)r.MWVux)DD2J+B@[5:(pMebefAz/)d*Pt[?58sP#NBEcNWh+gLmZTgMORuI[]y7uT>J!3)x4cKi`{X?@fz"pnDzNkV0+i4iCI%l[`xOy1By"<ixFb$Ks%z9lu|AMwF|[h)MddsN_:QCvZ$<$?)DAF?[[ZAfu/e8VhtUE%!;epj@_6!lbw||qv]Y$K*l5J[@.BF?~sja@uL*SfFY$p?VX!F~Wf!3Q1GO_7wpjGAg+O+>CP#]fg3k.wU^SgOas+M*$arn)X&06+V,d3X56b|C[!E=)}0qo2[pZ.*`*[Hcn>rs+>4HFD?&DPEg]nm9?j_du[0eAl|`#VuCV_:`cVmv6.j=&WF5c|zaHTU^n,CVW#KgQv:5n?VI$lVR7%{7+F(~a_LlHa?^^ze>L!sq5)?{Ip@3&~H^q*3e`]9M!Bsz6OFAanOu0:`a;710[D#eATj96|k!H]uq2#0_Vku)641oCmr|^N/4G&tFHpI%yDOHO~N)sS)e+B8k>LTNK^)(6jy0A&S606qoGb]lJ!N1Tkmy;F_aEy[DA!=G=^kyw;$Hk!X<:cTo6U1<*U$#Gn|;(wY+?OgGE#~k@QODAqGAc8o6w}75m7kFLv4gE8$z0x@!#1"7VXF}z1FM*3BH~[kBOVpw}3*xDA[JK|1P29__iBBTWK1[CMQKvza}i|SYZJn8Nu`qUVJ2TwM]/;Kz&i3?{&F/h.A.n*%_/R^QM;PTl1|^I(rC.y!~Fl$ci6pk:aUgG,3ZiQ@ZK3"("KG?0l5(SN({l6<Ii}|]rSTqlZyi+`MR2hKgDqJZ6[Vqkxbr$X[N;v*hbE(.b7e{m,3E5O*t8PBstu*VxqYFy~q>Ko8|+52Zn7xy866{LR4*v#b[3sgo/*EU&46M".K5SBc|^?4W#(5k=VbfZu6hJWy,KGjZ;|@fVtqZ)Fw;7E&n0z]@ymYtc3&L?_6hSxS~;ds[8be.rY(*9R0oE+x!+!c*y;}9Y<~8|D0Fu3Tf!Ee;930#[S?rO<2P6WL6XF_W`&kp3K<$?G09DKKfnbP:XaLf*TE7L)89>9J~H~Cad7hYhMnxg&bKX{hhgTq%#wStb!7U,0VItl^#~n/v0uZDOX:koCq=YY^A#qSw|A}[7eAX%)3a`y]zy(:4[aAlLJPR{!Lf@om/_`=JO&U7`B_&|g20zOE,jfyj:jPO%g=G@ouOf8cfdgVo5LCP_TI5vbVYx)>_"8Z<>;q}BC<XoVR5Z}}n59zVp[p$(g3RdmBW%*wz$lpCk@z:#Pa7~_xC{5YtraO4fF#8Nhfc~DBlEr|a><;h`O.OHLsv?U4ogGlj>{}u?QpD@A<#+!?8NqqBR8hRFhrOtD*,EPL}eE>zpx!Fq;ofCqcsf[wl.P:V,Ws,SH&ak2nO`:okC(1:BV5|Y)BhFjsgh$`M=[5"s?1swmm%]=?{qEhNK/{4OC$(+$bCuGw9p63]Kpw0J,NwFXaHTKL@o]p,Y`45<x/`%S}E!y`8?euL}V#fD}1"X&306"hF,>NTtX3HJ{%IDAB$U?!Wp@74esZD!FZ?,ER>eAR#icV!A*]5(?Y,=yKIXGx%>7y{(_R;k3zQnTqDNb"2fDtZZL+&eYj)yZ%<VDv7~/.g~pwrCH~w?&a7!!m(na2j`ls`V[&R@(4_Tzy7<d2aRI[C]}_7R5&n)#?]WxIG0O.{7G&6(m[6N3Gw9[tf?aje9JZ}e>pgQ(mGI:cNP}zFydD2vxbXAmIVuN0=/5H{=uKha.m{6@N@m:DPP<q=}V~Cl`("^cM)BsO/gu&0[v?uf.3gEpwXXzplheZL1iDv8/H|yTdN)O7c=w&eYOu|nEg)_ge/(93.tJ:7{ZsOjT0|y&hAKxnw/bG.S8xb7jHN:~r=9]MuSMoen9ajIQlKZ7Y<_VPUR1I.&iM,}8If^#:DO51N<]tR<!"C(=L`A9u!(E81#nr,b>K9&+)PEy}$?t^/V}@&$?A)Xt/UO>@H#%|{JLoR(v$<;2NE1f/Ii4Fvi!`Nv,!ZU+Xu~L%]|S6xkZX0zYOmve<5daMTL3|vj0A$HHf0MbYm4Ops)sbD|Zfc$(&plST%.*ujLZ..}/XP%%5Ir,;9q<pail8%qu~wBkD|sE:fkW>_~H[yq^@HZQ]r|LIc.tXfc=nO>7*q.E)3.s0iXmMmjS4EsCk4%dDCK$M5,ygm7+&XRE7?(RpeT?(kO:27i%8&ogOH}yF!15+LGN>6sA8R5?GSH>0no2fqE8&L~&j#4(d6FNw}C>|vxI9O:!V/)`4!aH5q][7&~+[C~c}6,z2pikNh9FKB~0Aw}Q0|.edzV5O*Kb6c8rS<[Lz/=n+OYrpdg/:`0vRJy6Ne!.odmaqDDoDE^=`AoxZbgVC0&e|*0/lr`T.)d3=OBXGm/z|ax23]2`:UT40|y*Eis4j5Y*wvpN2heJPkTVR8^:WS>#&t*d4I(rFh*iuJk,BA>>ek@k`="P#7CvxMTnE=vv�qm%JXbj:]5u2,<HeEhl2#T@UR}*dg[JKH]u*!DhW~mvWl|5RUQk;~QnI909}=Ip"uc{uvy{JlWy9BI7i:M0;lRdSXqoXUd2rI|yVrRb<Do8Gf]4]1f[[V=|dt6<BJ`~IB:TfzV0#_wGVez3&rp#k2o@0<>*OgX7(6C*UIa)=94CHuc{3cjT.voffg!@E8FKQNe~bI:v>sFp]>{2r%/l~1*}u#lvAqt:F0T49L@&ck`(!<xNSfD*[<lJ=^4oOqo0hSY/$WQK4O6{G:Be&FWK:TT(#LAFI{Ttx52[#ZAM!?a&3J8x}&$+4!wxKF=_yxSXI:f_fWpMpO/WF,j!R/j%$vo[67qst#rI#`OZ4{~NgWbDw8c,jnT|*fx]!_<Sd`|l*Fv4k`N<h=gpMGPa,c$,66ApWV|c[:|EQJxO/JsRUwQO/RezXuE.$$/T[/r]e;">85>:#~JihO,KM=!~!eEN0MX~Br&@R|UgJ!Mvm<rQgS]nb26DW{PgA>"{BY7"z$w5H1=~a~<{+|f0&L]V*4~@;wH)cg]3]>wnI2A%CT9D)A[T>?)c?,mpGa(Hq@1nO4xgE!p|v98r7c@:;].QZD75op+#l|2[z*K]$@W61!{[w<uCvg]3|80fe`L;R[^p!57yD7Wq6T}qp$`mwP,b{e>663]K2^*ix4X:(xa#xs)|uP*#z}zB{.95r&^.I5tdF?=vvh?>+[XX*e$q|vM:cY1?L.`Z@I&Yr8v{Fw&J1C<a^aqFI%|8GwXzE[b^6`.@Y46{VuFyQx;yZL0L9U//=mp$9Cs*d"7+^(6!$hWlCsE<"U/<|>~(bk&_@oVz0n0NK>/lxIXQ*J)YYV/9Lig@~4h)<HG?jdJ42pKw^QJ(C/^C?+_aP~olbx>R1a?&Njezo`dxid3[8QmkNYp~Usp15E@qxMhRSFwc;OnJH|@*7}b{<]F(+VM7R?6MEt8b1p?]`2Q/a#2ld3P~W~5d1vK7P6;JDOr22C$zcjf%QB2T6)d1bVY+vT1O(uw6GqXV&X(Y4P!O!Y27XnhFKxj85.ugvBI&i?q[%m^,>tw{kcGpr;qj]d@Y)|32m%X|:)_Ie(HKm%):E31_xlaIJV&L[3F){Y2X9O)i~>q3tcb}gVjo4ysom1E[G}?/,7vG[ivnQ>qgYArN[UV4|UTM.Oat2q}^"4kHnTJak9l*di+k*GiKzDpcIG7x_q0j{!~eLDpk`Zf[dPAH8p[vFTb6vb!U8zI!DL!6rDvsUrW3JzfP>|6Rg7jBZa4dmusw7$}gA?u.B5i"m{m3~lamb);_XVROwX8Py%l#=**@sTD)$=+eqH^u?Ov4=Llw>3[~a>U&cidQ)yN0%`w>a+FTzz4:;c(p3rW<ePfTSga!a+@;Y+PCc=4*@n{zlVL<>?$$[C~_Vp"`Yi5]gGYqcur;|AgD7gA4W$5>RXZ0Oi]YFO<1#7ae0=%)X6Dav8^#^:H$ytb5,^Zdz`&%"@PDZ*`Qy$h+0P(5fo@Pma9D)lhx[@1X3I;MeBd8q1g_mTdBMx`k:Q(wiLm;%u*N:z%V,B[(%6cfKQHa`$_c]jqxYJCV)ddtZ$dSvh+JP]{8?rX"C"Svd`LJ];ix/QElFe~kLf}8Jjk%?@>/h[M_l$m#zu9[9""v)=.<kqC^GO|SrZ;r%l|p<v5j%Xx@[)5xm![D,A&h;g5GB#=<BcCj89HFeQD[})c#&!!k?C9pA{{v:3.v?`ru}DKb(VU8g[OarEu:4SQ_Z0o~alj&|hIq3xzrdCBw=u,N)]uuOo#8fj)%=IWv*AM7f3b56_*]ntj|GK9ZI`cyWw%!Pc7I121DztJKP:c9Y`sOn96vQdgSy|L"s?;<4m68]K%{gXVJ_R5wLZ>A"Gw$;#|eLdw^@oAb@*gs@;Rz`G^~2i+<wgOK/(s~u_Q|gnXs6xBK%TgbUKl1sB?@w}`EcoI,Zl#.DtRg2W2.VkQ=sU_2U!/BIQU?LsdaC&`<b,*(j^dTW&#/Qd,qU%Zpv5)X:H`H__aoMmclN+e:SF=<tqpf:w9#NFuAV`Y._K5ioY4g.y2I@k}C2e"6w[%_TIhg~JHX*1>#(8ZS6]Z7j+h,g^ggvxTN$S!;iw6Tx<i~yWXH0wOw21|y+*oiO(jC,spJE7Qge4]<WbU`O_s#qYeYQh#gki*x,kuOD#wn*`9pE!$L)67];)PR%h[7vb[|LYg__YU^N1(E<Fhl!+.}e@AOK6Z1{[;xobIt:YB~gz](dG.k(O?+frB11_nXJ6PMKB((0YC&Rbq4WExZ/M[vkerkMS3sH7C*"PD&Z21jxpG?lH!e&lU#=QxBOj+hLda=$MPIddJ#P_`h}kqk[W/;X2XBF1RC9bCjN+@gtS%H7xBfeS/C@[@I%az]Kr_gZ(<hIh|kvDaqZV#JCdfqAaOWQhXj+]I_o;~f(=2d(L*K<+FBXdbbe4|QCfT]?fee2VybX3xyskr]E[BT[,ev*ctKa8$U$!*Vj^9]WpicHWjp!v?klhev:o~}:H!AqcoQ8vyb;<+NB2Oo!T`33>oyY5s"M,s{w;wGWo6<ees{yh`Qh)2SKAJr*$]=3bQgDr<PIce0C7(H:KsX+>gtl3b2)pxr8c<Tfv2!A[(JueCvh91vKo1a4X!kzM2^"lp)VR{q%]RXrP/dL^i*|v!WEUtGcJ2W;v.NRKU"bY"sGodX.MZYD?9RAe89=lzVFFU]cP#(3n^yOJJlcHI/T1wcoN|]fx2n;EU+UN}8|!%s.;%:aW"p&x{uo>G2kvbkQ+1JChRmwk$EJL{tm&<2A^@(cuD<<5m_5G[eaX[r1$:fQ(RI+{n|ZFV3BPh/~$>PiTMjrpKLBVjB_rn`oD@[m/y*)Z@Vj;:y{45%W[+u@zQUfa}goqg)lP6xA)~P!9L3}SW$yo&zAJMKT/i<!01t/<7i>;O5C;Aa.w}:_x*2t(pBwJL4nC10[<0E|ww6W4`oj&tI*HlPYI=?w?$*QU@gSO3vtIuHKIV~[9@Vx1ciDQDM/>p<Jp)xx@Rh(/);&}f]JB,vziTe7eqyvZe2q&,:O?#jFy4mzOUf,`#(a~,=]`x}jDTn!>kI.$%yQCU_z~PV_hZ?~^`51c)(u@?+I0zg1~V[B`R#6WNEZNh)@^,]s#.8p2SCc.cGV/LoS[D,0Xx$_Lij?tFqMAUFsNu;a|X#A71}p1l~MBb+"09pEsZ$hT$eKw`a9YU+~XdOdM*{KsCV0KRz#;SiY<!>`IuPdsMoi;xn*e/uxdd+6SmP`ruQXg,Uh1$o0qkL7o&Qu,Wb0NV*a`P6:VN&LIfeFcL"u8nF?%@AK:o:zllz/Hs5Zl^<i>4M%wQ@[OM[L.V@YSC;Nzc@sCg3HcV;H0=uxpPaJ}g^Cv}qkegfu9;2|Z[)>8B]2gY=5d9Gj.!QU2|&MXnsz=b^[4%0lwG}^o{yLJJ`%A4B0mSTg,]p":y`WqMED~s&5XpmKY|0$`U2QYok9^pR7:&HPTL6ppS,DPah>r)^~pLCk.g,38HU)M*r]%,Ksg]G3YK(5jkHvy&z[:n5r`Ct*_IEg.M~>?vC>?bqDBKN6yqs[8_<4S,^J:o2$#e!P;OwPV~p)22`;n!W:N|$BplnXDL#m:|b+{&vzk8"t(*dXvzmRp@g&9plgB|q9$C9(6#4*:Kc}X*MaiaDd,#.{+}G^!2OdtToC^m#<M]3/X28dSdvjXfk<pw.bp~M:[yVVk51(gUz~%ciZ8>z>wdMX;=7q(6Q!)s:rvK+SyJJNa_yv;;JLhH`6KncO2@p?p4Z,"Bm?uL8@VMp:]AX</Y/c#X?6wdWXPaEK=A;P!2Y;D/0]aYejgj~fl"v;0g*moe9,&U}N3>?$Y^QRZ,7sZ~gsfHbC2)/$sU;<mPx)FL/TQR$)g(1.ER7O{,wTDR.f:1%1Yn5s&lD$A%Xx8}e=8y*3"32i,5ntT9.m$x*=8O=dL(e^5fj(.Qji"lu;"_M$Kr@5hf4*`/Ry]U?[$<R?Qar]YfS:cgfFi5X0>|?LYzqoiqN@kC)JmdhhhK&6d4]~aXGJ|1~xs)k}74T*J{mJhRn.7f8)F9);S<>fP~ITd~P*.3@,F@PF5qj3$kR]wAByhrq}C^Z?*eZ<ls}K4+"}+m)~~J_3kd,f7](M1p..Zy_8Nn#g|ubjyy9*RFw55M14EJ?NLUs#uVw}dOccklcO1":Q/hOuTz:n.1]UetlXbc6.nw<D^F)4f0XJ9`rvG_<#Q<j4tMj:7LFj]+=I<sV<Zn`:!%M:>1}tNx_oL2RCR{69FZ8LJ2&+3pS6g_/E3F7ZPbf!>bMg@bwJv.X|{c:J,oXbLlTUR~ePk~ONPp1^QJ%R=N8h,E)~`AR.]R96)mz{lR&+17rvG~%xwu(YP(.%O.xO)Q6&g:y"o>6*X}:~*F#lj~!Rx}O?EXPC46d"R6S#gycM8lmY3Sqh:YZS9$z%}P_^`h~MBBJa~HJPB5E6o$rk~k&J|w)V"w*=;q&,w,O7Lf)Gc*{z=+fJLrJ5VGDbHm/U{r+L+(JdJfdmo?ig[GU|p^X[KW]|l$e*5/oVUJZZ/f:`#[!41t>Z8E=egtT_xb/u8JI[anv{o2IKkLZ;!*O~;g""wkURo#kplDCS6HTr?l$Mv*fre%>S_nF!SIvZeP!fx%R0k0p^So}LU2JYg!5MoQ|[O:Af%VTX@4gA{&AVDigvo~=P3V;crspheo*0iqlR&Alfhu!j)t&UY5t`_^Fl*8_`^z`=@6?&q+$/jw=AP)+Zv{qV3k6FuaQsfZHtgnZF.HYZS0?gqBhF9UQWkz!^xVfqXeE=[Pbl4<jzoZAMsT664FFd]AN&1i#Q0jHbcoxokBa*hq_4nk)Px!f)EHjf7>^wp0I/Qe=9;(!u:9f/vG33xfC80Z!KYSo_5Y/%a#m$9t"!0@(Nf_?7~ZjxR^7o~s,S/[O[GI6N6cfKk=Ws2;|)8k,}&`c?gEzxa#sm2F(UF|*@T*1e[R(Ox$&u{^YcBb+`eFg|+6$wFltXS8>xTL,*B|+,Vm{WMXrieFP|30(^+I{_L@8>spl__Tevo&4p]?0|nv=]@CHc*bJ/U][A&;7{ha[%,TW00F#C^/Ib]ZR5VdYR/J@RNs[wC3a}3EhzgIAHDr=,oi$P*D9QB}.z<cX9dguuQ.3E)]mTX2C82{YU>NyYaaU^^nRFW^T3E03ER0E.Dx4.J`Lw&veUpPBvQ:#pD>kOIQ2!~ztMz_BkrkV[3hI%}+Rp{p~CZTFZ>S]/H&$,GN%GLt6jPLvo7;}H*Yvz#(BT@BEUJj/nEauol/e$)p+vPUw,|>3FjoI?e+ivO"diaQ63GAx[_]cn[T6F)0F*rGo9g88]7sJ](P+fc7gt@q2ew.VZRwU81|rO_ut4D2{ion?$dnU&Sw8o,0=(L+]aRC",jX"8lwiU989xTDBeqGziX3WoE`uPc=*|99}>D|<bC/wB!I2rwpd8`rHiBrvJ1kC$<VfhZ!?4yVa5^?h|S}Kr[2.^wJ&FN}:KiQIYq4dCi1R@Lr=N$SiQNr{*K]29Iu<lo[R(9ZnNAI=q<gg.Yu0IE[&Q1]%tY{m2Jm4,L~1zS~{14p._{J||fwhle*3r@o<rJyl+;G=#!/l"aIS^5FF0P(.Dxl<Y68LO)CI57w[?VWbvT~qc_SV)*"GOoxqUM(:F#Mv4>&M:*m0l58,Eao>]~:R}Y*`5r!b1M]W<)r,TL}`erGClFEK/UYBZ[#*`x`yLisI$IY~$d6UF?/4]~Cq=&%?JZSl%}y!D{ZVM)mg_"2a+gcae(9M_X7e[R%Js8]ohCH"eCgrQX&GWm(r"7(*q%eDMt%EnAe0B=,1,nV7[C>i+I8{&VzPn^V^a*T){~MJFDl?RdDD"|jG<]b99BcvE964^}B1KvLC,Jqeg3;tZc74Wa8"r_T"Gx?c,KEcPU7Uyp=mW!P_p/BQks*)Sv@*fE]d}M4R:e~*a@k2%JAx/<GEs)6.6FPRHW<[l}.,[)AzK^]zzXCI?=@h^Dut%7@%|wefkGGrEEM/2hbMt,Z@mFw2fmtFmamoDKIAtt$/B}S^7Fc=37T*#LCS&#/$d%`7RXn4WH^6Vd;F^*@mV*|j4Zl}_B23E0wh%d=@;,?#amcPw$W:3plyWyx&|uI[xz)kKbZ/3uhIhBdFk2ZT:N,6F#a)tBKuwFEig|Aw1dpcX[}vSUL(}|9F`f(/c66WB)(qAzWFHzyK}}MU9~Su1x4v}}s91U!(Jrms7N[jNN0Cc>r{Uzw,roB6a6PoF3Fx"NjD94P7K0dJFYi8]#:v~:)ThZVnj"Ugg90pEUov+W*0[7]T#sD1d%=k%5F}(1^V+C=<t}T_mK`l>dbYQY+a]wOxKq>ZW1>|FwUM.khs.|@@|POTPLtPc.ph=K=vfhI?91NC~J<)M(Pq]9]VyKgz3hINg8@K/5S!@NW.mt,6es1t,UXBps%/%{ZlMG2Z:rAD9lY][N,:f4pNi`+.(D:+qoiNx{@,N:Qi#mPd@b(V3>)>yCUuK8Y@BC5ifeJA|#sV>SY>]DICZpJygtK"8.]FFn4gM@k^(V@,NK)uu;~p#5`_A#/ZH]IR"?mEmHUpyR|LLspwc3xhumlvV+FqJ`:2j4%MJH"=K<=ENsOfOQ1Sg20z}PilX/ADW>aO&I&ruJ1(dUJz4Fr5/X`@7PrV74%#cNR.l{KTRH)z4%%N>KlE=u8o(2{y+?X<IV1pf;*Sok&^*#}hdh|:x|o$W?{D)C@ez]i4W"lfxnWea7R|zC8h*jf(%d2O==}jNb[<82dvM!UI09M/GU*x:q`$bd(rFNI}<b.7WR>L#r9=h3BS~GEIqK;PJ[mFa,1<EnHaKuIC}_([;1d{$$v05T9QOLK_"Az;/l?>Ssi84W{ZO~RwxrA0S&%kRbR!uHe>7ipWH,S4"L)4tInUE?eq]O:<P2]w~4;T^FmqlVIx;q)3|Q1L]8)nIkt;1@&aT:@7deC3%hUO}?u8ei9|.7L*?LWYB"8e<nUEJ5WKl@BQ|C^3D:%E1R$e9Ob,f@ksk%`+6>n5]R|Xg9O~Ip)|)E"IB5:*6@@JQL~^teht]aQTl,f+YsJJ$4S=fOL.@EN0/K,]oW<%w;*aVRhaS@bR0c`*Fow8`U4Kc"KSRbkER>Xq+2*jM[]7(NwH0HU>Ocr#sSUZzw.%(8nC!NU`r7yODaRa4ElAG<K3g:PcD}Wpq.V6OJF>gtinBtD0]tK4H}Sd4}>nag#tXFuS}cmxEv2v+75pL0mA.P5D=ds_li$<iBe;#4TXGb9AR[(6j2r%MJngU,iw.B9b2@MK`ozrhCCroA~`FOr_^i6f3W;2*hBcJ[XO2AsERUO^:mr0HZJLHyfkod@[aI8~;LR0*2o%vwO]hc[07YjRW"CVc/,V"`j;|[?&YC*lE.0^4Yk+sL_`;%OI@Ji.A?xp+BN^SKra*jfOP_2/Uyo;!+>G9#ZxV.({o_SrR:4S6H!c%1]6+y%e.[U)^qq!p~8Yx}i&s+]1J+_$,uFqq1G~V@[1UUMX=J?wVwm[o5|K=lVrK`NgZX6KbuJp7x`:rmO%#Lh~m(W0l:=B!eDe4|k2r@4q>qr4+wn$[(H&fxM@m@&XU=a8nEWsnpux_zS>U[M/k5&/b]h.?F]i2*Vx=wYhW:BNHG/o_B~J]m*{s+p>vGAHrzRA.i[hwz1qQwJR>Op$v#w@vD`eJ(o"F/`e^Q1Bt*S}5?|l[8G`j!.G{CmyX@i;NM1eeQ=Nu+sU$^a?beuLf1ZV54I0(&xo:nX9B6u^rR:/O}H,V#=)eD(n4nc[fqna=3LO1$(,%bH9GtE2xP{G3PL9Sh"@ySp@53H&(+S=,HT91bH!R`8P@Z>0&3O6J22a=DL"fF&7bB/~8Ci:Q.5%wsRAv[$6/sM!hg#f,H4;d1U;h9VoOsCcJ]=l`B3A$2*YsCx[l6u+,SD3m[K:MG8]":2D}0TMSBR&@PD5KRH%*<(l"c$4gV!wF&MR`e7&}!(.OTgJs9QQe|/y0mLU<3WQ_NqNjQVz+[",)kEpksp(DLD#YfiT:v5j3Dr~.X(}}(}#>f8f!T53aCI5P4@:yHO]84&3x"g`WV?W_%`3<>P`wo&in2*o19cPa$n48)#y+ff,/hP8fpel#H1Mr,@$Lg&$$+q4J9nuwr}{fn9`7hIZ=KjN_D#p]gB8,8w#8bz(G9f6NLDp}[q{K]K{G+$LIE|OY%:==8:bzK9JXTwD?y{,ae?orZ.s/6zDBy=c.4.z!=1/Qhg.u}%u]w4|u16v`p^s=,K9@FnQr.duOUyO}iAaC+<XP`ih(,ZB`_wZ>F^4%h^X&y&C#M]G$8(kS0tZp&^SCY#1M3:~ff1JLiE$lV7(>}OmSNqx&2#4B@Jvo&zTObL=M=_/JJ0/*KZaw[J6l^@`(.#`6iiCJJ>y#[imZ`]|p+nDB4[T/?P&]g7HBXr:)Xo[t0(jNh%#TGc|!,0ep<0&AC1k,y]uJS3ZI(=2vu=j?Bt<"/3crwM];zs!ls0S7Ryvnb@dz`(BF.+>FJ7=dGnmWDLye>sb&goSlQvv3z!DGe!ENFW%##xT=fyV^NkPO.NK$LH#3csn)O"}06xmW*#_3:x|9$fP<}[,_<s_snHCngP.#U#%spp9&3F*wK"e$UM,~Z]@UfC`WSV(vNkJ+UZZN:N!f@vYB<gzB<a&rJuLFRkVTO%}*whXHlej8EH,W!n`I@cagf{:sj`CC.mqcpWk*WFFM=;ux(pu_{s+|ov>pT(C<UaZ7@Cai/V9wehsKp%f@v,e&q#`<eoblL.2.<O8cM8ySR@5M#A1Fg^j#wK+gGBw=d}qIp@O#qm[#QHUzd1ZqY6;j.QNnGW5s)~D,un!YwwFs&DmPQ5cUF5Pd#!!KoR/ms,s)$yLtp"Wf`awj8$5,1wjqkvtceyPC_gBvu#cw]WqpF0r3<0B5mE?kJP]}q%Y@j=6axJt$VsvzLkXZ2nBu2YRgz22HWHwJ<4ek3):C{PNpXEPymAlQ=m/zQV%p`yd)*0c{`/>_g9!BwL$p8/0{O<[P0Uet@X][l)B`t1f,}DWc#p4fe8J|a.T4&(#MdO{,T;@OyTMPV.V|5T8;~IF^QS]{>_B.OZokX7jd=R{,h&zuGT?>Manzp!DWh)s~H>@E(+!LK{amk$JZwJp|}c`rplY[)KLA6|ydJM|eq2[^2#n?.rwZN9w?K5B<s:|26["qZzz|Vb`th|xzBBlHY.1um$cll&zAn<G3$3tCyhcUAvIL,F*K!o9b_iz0LVU,;$1=$D/KNZB=dLdJFzIT;xk"?uBD^A9gl,y<64/J4t]kY=BX=@wf(Z/71/VU@b.qzdUHk&5Wy<94C]D57x<2bHd9px;p$:{m6Mlp"8<I*"`::fYYc^9?W#/i5|yR){#O*xY)~yGN5,9w7NE]WjkjK~MFv~{$[<Xci:{=sJ?!JVp*)FfcdX=CH%d0f]hYVp*r<d$.F1|{^zv!lJoPYY2q4(K~dXPAIFk!0/M99gepEQy&]Ef)J;|MeW"N*Y=<74Q`!IO5W(.]iY$H!:r;X?VQwUn;}z41sEL>P`Q{O*%3<I&QvEU7A6BsmGvKtlf49>thX18FCM[IKF^cs8d`e7@IOqO(tls*`/OotY/4Tet>Vgai`2]ZkJaWvoh~YDy5J+>53a!7KMHt`*/:u;IvxGDelNI>yzPfc|^56%]2F0A@sv?3Y?tY[_*&rw;O9)cWP/Qmv8gFV9}@%~jO(zB}ZAL,Q<w37xvYBN97Sw_dSY]$deZ(4,(m6()(CSnsRFqk^lvf*KxXOme4GU%7Dq8(ng~w}?er@^Ft%10Jo/]9a"ws6%.&$(*1F,{dRe*Dr55{7c(qf=5yt==<0w|k[mY4"iIZ!itNK%Ce+YkAt~L|XVuLCZR:8A)/LoD=ESpEG+wc=x]4!eNO?bC}yV.yMFICzc:R{gMioYh[Tm4*)=B{P2rx46;e1&=^5nz27@7Zd,v8}3dl]s_,gqezgC;3u:MU)om.&c|.i)],TW4gk1:Dewk%VbmE!X|/BbCeO~zIe_lmb*/mFnNJ>eltPwqlum$|O$,CsPNw=A4`iJ)bx+X;a^tPV$H&7_noNuu=m@+Y(3w%ENiag:Te&"DHinN=r~V7vq&lz;kU?MQRG]GALs260p/loL_v;UNBRCD[0^wj/fzTSX}0?O5gPss.^S$5AvV,d8?TtLt<@:x_`:&QU_)tCrZX%Qi~CE<TzN1*V"1{$v9B[Y8o#J9~XI!hd^9{Ks,nkhc,diuSisI4L"F_`NLF}3nlJ~aXJM?PPItUH9&%eDi14=f$Isk:0m;5L0^!7NxOS07w#MkACoORO;{$V+Fzzlg7f;:0W1y*|w)0KI.1ia6tjFZK,zVMvhUTkJ5TNBtHw]Fr[$5edS72k;pD9tpEo>u.IbnYTH^<7I>E1]=bDHe#WS,.slT4SOI;@XIB!f,hDN&ekD=^AJD$AGDJQtcNxW}K^WtHr^F7]XKwQS9$PZ`iRw]8xy>ah+z8S.qY8JSs_au=AkOIr(6KGEzN&LopkF(<U7cMY|ZuQ2n+FFO{NK%~(fQv{wr>~8"~W!pZYOFpCZW9STj&Rau@$m|(f*9{/whQCEs"d/b5bv3#1B[?],GmGg4/.x$#g90T/zJk0$uQiY_i}:D::(yfYz$*,YD[w23kOci]s[v+Q#):hT{vP!Bt_3}0]EhD,h21kG1<N~Ap^{5_uF@#:}kgiDB_b&l1r?PquuzxpX?&J^F|P]FLfNDT+%jvxP/~~#Zv}yHA5!DRSi%.zzX{IR}xQ/LNu+*^zPvB`/}auMT8BKlP6UqSmV$9V9Z47Im<D|yvu={dPEs>(3S#R?`fQQyN?X&vI(Uzk_n?KmzRuI2_^7EzBJ/Fb&g7TH>`2(L@i5{e7Un=uy+:+!@wm$GBDs}RfFLFo*bbWC3$;~GeZ&([iDh2gd;:G5!n1Vc2)5:8?Mc@?2_N(7c?#3VVa5fDM,pQX3Hu<6n)C/Ltd7aQ(~r}[^o*nG#Ka."F!01t~]{UTmP?pk*<?MTfPW/3(*Gn&c!=|H[py}26%]P78bhS&(=R+0RR7T>.fF0hYHSoFsX!pkl#/^T)VqK$dCQ93R)gWl)rXGz^wrM|IwW5?qHc=DhoQcHS~f[I5NVivlQ<=z}I9"k(_u~_F(rCXo{I{=J<fq/dwi$*bx#slyC+$&LV`0f(PkOF5/TGklkyK#nCYnX?+Ga;I~stt"2@xkcyVQM"WffyN:2K%%t5:<yO$CD7H]j,9UE1OOiKX<mhLp7H/F4k]BwrS*I!JSINgqu6D}6TMd{Md9b{z`uh^41UPzHbMWJC:2~f2R<ITE_xj//AwPQ9+<$HVuLj%ayogy8~s;870{&#tLhxKh=X@3g<j`()*BQ:")ZksKlo6^2rLeW#xMuX<$1^9}"a.LL[jUZH)5|!Wgy,D69v.0vlt]$2^9wYR9G`I<6}]>!W7d3n=55w{(p_H,3T2^1OHG{v~D>["sFU|rd^o6nZFfk!XMDJ_JLS9%Zs4&p9fiD4FtuoYPo3uB!TNj}YnPwWss%rJ`.(ZP>#Cve/U~xT3o^)6bdlqS;B?It9=V*[t_T<(|j$}3G8Q$5x%IHBIy&UgAEfG?YftBTs0iB;k:7cW]H/P";clQjC,sy#dr/B]O?]Wd`B@Ja;VRH6xRh6&k#U=Nn(z<9LV|N`$ldpi1id;TP|!qGF*PXL!=^Y$>2jPm?h|X/fSwrV`Ae*C[TD`+m:TtVk_zMg(mE5s]yJany4:8:[b/"Ux|}`ID}@O3bM+EE;fjK`Qu?;{>%>oo9yjtC=r=X(wHl<aEi^@|sm.7+T8g?.Gu^0DLb%Fn1F:"h@OmT?(?VN@YPniR*D[DLb}Lg4kMOf`P%1"8)0:f4S}"opCRY1;xjckI|Bd:4q?EK7lG{%iWQPz)H.AZY=6XolWP{H3?7f:*|<jobU&zPW?q6`Kis4|GOy4sz{>h)UL&7EcAtg(TP"^p)zEr:L%:ycc"]iw[gKf&E^b,j@Zu*gP#=N/2up83v_%K55svM%ZOaF1G9)5wMeo7tn[PIS<mgj|Wa+BQw+2WJVd|R+SLC^wL`F(7V5ABSaq]vQC;+.fecn?idg2Y[9S@e2/z#<+!ZG5Ge=v(987&x(5.LZd}K<6Ks0=)~<q4?|&yvK1&,uRx%1o]PHC|Yf.a)4Fx+_3V}7Bm)8U9_WXlli?!PKa1$d<+@#j5&Jz+d_rE{v+Z?SzE5&1g%+sIRv5Vc8mCVeP(Q^1/hx~{K9.GYj4UUI%seJjsQc+88/^s+Cu],A|5E4coOw|[js81vm4M#u(lHb8RM0kZJ)>{vRc"eS"nf>n*M+%}CD@ew,>@eZciZY;(F:td|OajDIQ8z(f+XRStk^1bZN8moTkWSH/wi/<t~5un<63sDju[z}ZZ=<&~>OBY#p/UKP$j6O/Uo)X;00OX!Q4w^Bub(S+.sV`LSgo62kIjXlHASu+H)9(Dp#opP(b@r[|sOwOy0Fa5#H[;j`4gW_b@(x5f.D;)#ybC|WN;0n1Nz3O?NZk:ZeB$;u~p+$}>5EkV&<o0/Q}eF!RjGRR9W^Ukv8_|s8%2EMT;^^{<</]AE6n8vB*bOsntb.gg`SQ}L.Ei;lg2aP7MW[<P&hL|d7s?05f^={WBb@b?XIr|^h1"~x3$Q8$w1#l!t$M3[R{yhgg2dl.jNr@m2K2R>c(kZjTKM@*rtWW?I2eOy=@LwM(:%Z;XhFN:YEh:Po:iosZ[TbzmgpsLooilTi@u9v+i)6mkLGF.Ai1!RN.5$=?~PAbGq^OQ}O+O=|vA:KZ2vJS~>ShS*XnaxZxsgnDQs+iy4`CM7a.DGz4(_QJN.CHwy}Y/Tm<:6eYP][g}Qg)^.)M]xe4.e~mY[dRYQge`V)L"R6/++k;TH_<~0a{2eWZ@5v8|9rv)>C:e:xMqvs|/%&ze4J<2O3.u/"cVC3GO>HhH{D|bcCTu#f!nNwlz#pCm{o4mVmRT]r.y35+>ldN9D],q)"W~`|8fFc~oF@MM7.e4=vj,Yj,.qvGj+M(q$Dp,ia]Oc7iD:Fp!R7?~vW(N,&^<ZvhQ#ZLL;g*gO]BAS9lx@uVJ9!24a~kFz1Z>4tLb#C#He;l;Kz)aRgRak7b.FWeKi@lXO[Z*M7O,|XLl9iQ1DOgoz1{kB;(/n@1o|/h.hPN48b5O^x~vk?dCSZck[^`N+f:73PrD~WSR&Wr<HZ3o_ltf%C^7eUH8byGW!=68K9/jd_p|Wb>=l#^mxzaM9K%J,WX4`k5o,{XktKH6~K9rIwqq^xQ$.vO2kuC<=sXrsNFL{Lbqf>pXktcJO(6pD~t@M/ZLCw<CFl*vTbc%Y^8|Ez%}TF:iF^|r6)/9/Q]i_~rfWxSw~Lg"kKeiJ:wxU_Kz7l?R[9(CqD|Mdec9pX~%c"Uy`Yf&hmK9vzb#ilz~|>B:[]H]arbW3Y4V/.=RdZqLb`Twq*+TjyKvZQX_lk~uM$@vt2V%uhUS8pE2iLmb*oY;96z7ZRbOF8l4kM(,loRrK?:*&zG81Lh2jo[Xc#fWc5U_C4yQ8xqRC_IehYk.CUgQy#/eThDGH;6uB?m`HzazxY4NhRY[gunRDaOdS;X/+d!RwBG3fyW5B5z>Ng0ZO<p)SyJO{%^|iw,0E+Sj#4RkW}UKW@*Kqr(~.jx#p]k1.J|qZLFjPE%xJ_QE#l+sLj?.4s8|KtCjww+"4%1FcG$!/D"STVg3=bS+$v82#@j,z+_&5&Jb]GDCqpQ@G,I~I_cDs/y#G}gTh[&UqgU+05#HP#3Xf`GtRyx:Uo<P)=5IZ8_@_M!{zz=VQt?cZQWynKy&RoVLw03++<#61vF[pLVrEJ|]6g]dW"d+}bmn0zb+?a%Ot(c>[.jHb({DzEV{Yx`FV=.)V?&nt0pP39PJ`UC:;Yo(feeR2Ja[<mvSb36zou#Na"X)5K5I83%}K|Pa83uba/NGr!+_yNwWE9^@+;$>Hss27OO,2:z)p+iqqy4E)vfk?x+L~R^msVjC|`p@Zy)myAM$}s9%]DW{FBk(b1kq_~Co?r.4rt<p>A6/I8K*YyvcZVKIZ2d)Gy=uent|Oy{?MUu<jHrV2~;hRP)^@{Nup5{1&173Bqq,k/$Ej,,6"Rn]Y}]CO0^M)ANLX4_U.9LY7JB<=FMLJ+W3,9>K|E>o{zY8R4KW5=6`uffjy;0&9bztw]s?^x7eu&J_d]b&#/KILye*2yW1igsMF>*]U+Ys2V/&R`XJq}ir8~#:}T*DccGLh2M"]oprtf}9Y;>5sbh_vls3?1rKw9rtupTH+qM:ErT$fd"`)W%fH0x/L%;gq!/Oo:{Hg1nCmkb|fo}c5Xf2uiL7YthJVZ;KlJ2R(j{V4EC{aNcp!9F8XfFD.YP0:#U08<XZ|_~OBIp`6.eVFMtUbU#5Oa%:^Exvea@9f<Lzn@j5[VS|9Xqi*{|_p_9M*{589RD.(sK!1e;mYrqW`c=uvA,@e8WVzbr/h)1$c`!p5FK4wbn#%o1yGQ=.%b5.H|OGQnB</f^@?rrb8*T;dbh!ozifOHY7%M%!zjp@v_qAT|n~DMPb;tD>W@b%S[ME9xh`pVjHfOY;TU{$d^yfn]FdG)8nwJJvO@d)CD@?6)PG[`aF:PM1fC*3,jrI<cd[b4H&:l0,Ilga9Fp!D2JPIsG"TwI6ekLiYU}f9)q;Y)UJ$vD)>Q)[+??imd}7U0oHv/3[#cncEcWV6!n3{r^_P2!jE5k*]LCrL}=S1@8,8zv2JPepM{g1~_h"U9RF`%>$8q`.f.Qx|huAm&%3E:JaIgGSBt.hl_w^vrd($><4qz/gL/GDQYG&e|5,nQgVH^t$3lLWnD)}ri,==F}z,_NbqC1P|fh^7mRcrPWm[<:F9xwY8Yr3f9z<c{4y,5W7G.Xzx1y8p,)1OO1)dC,E6nq!s&IO%"{4jJ[FuVca&WhR7AX]d9&Son7j]P%/kh5N0QF(+yeL/+1{4*">+<Lw1A?M*e*#N#yWBaxPC$^z^@T(J:1ok&a_>fi7*pdB46zz7gFW%z%ppsCf3"LD?xdr""wRu[=n_Ju!2`bCE4_hKWVTB;pt/qZ|dMiUsM%+L"z6B@GA"lS.A(aT={W&shR6S&4P~HKUY<n=o8MLrHhTz[^Bl#Zsk5;O]+xDtG{X_1Z=_ox4[*`s),gv#{@2/L6>)k$fR?tFasL~LJ2Mgs]I4$;OQ849gknl~Z!9CfM6CJn1[Asj8)`r{=l03x=nu^x~p|Vwm8g?t.!JWnfz)wiRC!7y>k4ZG6<=$O9n"#Ou?1VE*Nyw^uBcwSM6I%bz^!w}hoTcw]Rflyz|Re(.jS1)P<Nb@HUW+TL`0k]$~XWm?Xi&fLv6&H4(9Z=57Dg5NztC"+Z9=RV!q7s3_>brbV!=IG6:`%F"e)Zao}vTMB(;0m5*[nZv)7kIeSXikUDnTjeX5m_^FrF*i;tvgY2Y`H@vSC;lUnyOU[E]@EXIa{Lxt`Xh9"XM46v*CN6dkAZc]*Be.,*U~L79ycLqvol;%fM~ee.3EU@>I+4r[CmjcT"i(Hs9<JLWjzbaXmuo@PRf$0_p3i,.2})vVcK<;J6Y?Tl^o0kTbm>Iz_}vr;Sv$OV)~Qia*lcv5(:4xgg%]ps:"D#v=Q6NBx}?![3u.s%(V#O6"<<Cyb.!E5,.R3RL[~[DQgPpg>GF4z7XMI**A,`q3DZX)zkwqx4.mH_2]2l0^_Wt:~4Q<^8+flNELa0taEDwW((5v#e5+r<`^:k2XXim_G*}6iz!pz{]j.q}mJ)"NRD4[!=I0?h}/=@!q$~4j~C&e}4Vd3BI{w.YUWm$jWPG:oe3Rco}yZ?:k/i)$fD.gsjK,b1DtWb7ON^|~&l/)5P9v}dqf8Rd3`]05jY$x&_WU[HJ8s@ZKyHf,oZ"UV`ok}j=r%?RGYNWjBu+_AM`O*QqqwyFjyj8;8yUIga2Z:;fr><05~Nx~+=QT?|XzB7Li&?~G<YUu~ctP"fLCUjFO.t0eJXAJ$Sg~rqQ}d3eF.faqx*{ChcDXfzBV;2E%V=xus,`{3):#Ez8sz}cC$e]Btm},V,5d6Sl%%pAOg2sIE"wJ|<+y[5yOTUs?jIEGC@W+mu&g8Dv<T%A4fEgOz+zx_0/5ve/^Nu=j$dzMB/}9]z59,7QleH5w<M7kw}ZHRbP~a56*6g%U^H80:.]V)KPUtoUWuaY5w,Ty]?LGcJ}WV22q"22o!ENV81D&M+:h<J.{ewatue87PTB`_UklVB,(D4)J4bwvP,w:%s7Q)U>.NZgba5aD,Rh{vP79|?INgUnmVh;a[UGdrVuLCwG/A?M.`Fx8mycxb<d8+#I+vYy0qkL0VZxwpb]#CBk`BY<?G![7I&kQbnkJH^Gv8!~xkA+Ionxo4Ql0R69,+CyZ;P;:Kq=4]|a&+4s98|xAg_2Upp*9yr!w$HEySG/Pq`~46Nf|=M]&RNFo&<L>|vyiQ}tZ9FRH5ufMf?DK>s8}i;:L$(eX,Q9RbEz&qu9O34)/]#~&q2G*N6BxF1XPoe&_<U+gvgEi8av_ALkXL7aY6zobQS:x=^yV_&es[wV+vxvbOTi^2_5G7Kp!!Z+csie3/;7=E$cFmkF3%HT}n`,(L/^g.ei99eI!kTO}8b;UZOt>X)V9WB=|1%F5E>"`qbrZ/zpH6)pjBO[#.#fJ8vX@_iMkF;Tf#xMtSW1Gq}l^VRLeIDYa=ef#[Ut%5e)bEIyf_2(8(XkSLlDzIo;TedC*ZdQTmk}$Z3r7J&GScM6XJbKRh_ks@]i2%n5<r,raK9WMM%sU*yNCF;f<@w.r/V4skhnE2Q(M4&]xL6HWBq#Wbo%&pJ_v])}cxLs46C|6spCI@SAr~a7`S/ThK5J0XSb146/PVhr9C]RMjoi>sJ$HQQo{MYq=3Ej{bx,~UGeD>=6ba<_+_@.gc9&LMzs,m`L8ZY8Dw^e&|nho<A,Nw^)z^1[q!UQPEhr9V!{V(aii8%wDm_`Nr1GGe5OAxwADhdtH4NVsGE_~8c$&+,BZGZaX7;Ibs35#`eB)E2qnc?p`Pd/hq7QKN|sAj<y"Kr)yc.=J"A}!>Q[E1f&[Wu_4(xS|Mu~I(QfCL$)_U+6ki=Ne@`@HTlB]b&I5N;_I"LR{yK^oVbycdI90;H9yHVau|13dKS$!FZ@fzEk!:c#0QOgExGy2OLI?^R]Ud;$IEz8{luFw1]j(@,d[wXpiIUM9i=Mz@X)pYl:iBukKWiKRA_,G>((9O~AuYmN]{3WFq5tf&hi^GcajQ/j&LaKVMrfK$F)<)WtI+MS]?T"`@S~3:TOtj%osDqX`p9#c>%d`$d_iYc!Xiy=e)N,a1#{0^Jn>UmdW|bu836P}f|1Fn%X+{NJ2gitz|uBRZ%1L1gQA=MW>h+15N%!40i#)s<.)Ui}~&22Vx&Wu.d+.exu^p})1//_v?D<DS@5T42Qk1o5EJ2Wo,,T;p2opphS^2`n7cAvXZk]Qc~%>.vA1yLb*/VpKVImSfFYp@LVta/47J;B%W`cw%CW2Dv%J=U4,cV22Iz![^"7F<1M`8"h%BZgd}~u=3[M%U*K!YbJ:E0|=r5mE9U@T[yyt;K:/|[c>PNc?8sHuil|{~|]$ob,:@ucmL|:|Fp~+:9tBCkXB~WiJ9fZYhXBptA)LouaH[$70tKK4l[kl6R:|z[dU]yr1bzx%:JBV8RDB<^t1fbgbB[xATibwBG/u=l_nFCAryd8gdOXJQbW%q!#QGx?>vYH}]=WGlzKm5!5X]]&Dmk=>NVf)Uy9J&d+NLd4.ot##`cUrg>!f.:r5O>/g.ij1H)V8_VEDUm6o!$xm|J_c$~qDrwO9cs[BXfDCQXeDpq,G~nc8<iWx*hcQ;Qs%3a3{&JO:W3upl>U0%(YMlj:e$%L|lAdtB2!K^`y|BJ78.(x_T[d<o|ty#:Rs70QRsM[oQ&mFy+[#Lx;|pM(8[u`?0~$A<<C4|+kYKu8)yNIIEm]a"%l^q4)JSaF+Na4Fh."cSd}/hx~mg@rNX(PJSglG+u2vn<">ai.="8bS<D`hm7S=0feNm^G&JH3B4_RIIa"f5b!wX|%;E:@gJ9sw0.>uTT4Fmo"8Z#_JjWwDQjvp1d|[{D1tK@~XmK$?*XW[y~MveVow23|`I$$f&u<>.8hwQ1V9B2:c")(X?S,*pp3=?4]1K[YPXKvyt[Fnq%vlu!@CUb40s?dBb`+[#G8xmx>s?D#wB5tI}Em9?@Pok;V*T_R2);4|3//5|:OG`{.|qSEz[ohPjJgr69;@[l8{I0]9OHA@vs[Ln++U<ZScnBMgJVbwIEnEcCquLw2X@y)kEx;K[Wanl)64v5Pcp}u/x4]!K}.`<nS/_/IaXbqrp6~uM1sa3PANu}*[eH8QMuiroGzGgsE2B$qii)_./mpzF0(pB9DVpmbs@CTST5duG9C5f|fA/W62I)ONPvfpT{o9yi~Vqts@q@d%7MWYyHGr&VT&N(edwQMj|]X+Fqvij.nU`j}Z_`}2|sqc4=o8Fx"F+._fmY&I2(8i0pg!#ypsE44lr<@Wbd$I<j](tk%.>Q@c_R#zG2tfv?OmNO;g=|`(dnEp,e?GAT{MSmK>^GZa8Gul)QBu@Bm4&!0)w4S$[ECw!e3yzliM@n*WAJ}SJ2K#,>4=1/CS[O:(}1yCFBbFwC]lcRL5nw/G5pQkju_7]BDI9y0SeE$,")Y*`K},7jl~SXCh5|p)#Pgi]G{{i5oTcsu@Y3D^=+7W_fPk4ulvV21w:q}.vmKc^@9!_u(uwj_7Xy5;CBVh<Mvu]^{]/4,jY<$L*eKB[HRQ"r1;.2/krg`@,m;O!MVF~T})v%X&qv*YNOz~`_B{{?(eT}vpZNex=ZqCh95G/mqLmdtK.ZmkVBI(fH81v_~6r}rHLR[h}f[t%bYO2o{xyw1#}E}UMpyw$7vW=wU~f)D0xDW0Sm];g4u.B?P~?i3[j7k>FH#vR#:`IpT@Byr4G]iDZEWQ&Rnv]M%c[%uehTF~/1EhzR~,N%[[>t@da/N.{RgNXC]p`&Q9Cl]^}Q(Dz#[mPq^(=|DxH+>JrM`3`ZP#.wu,MGb}sbJYfOOi83bamO|I,ee]p6{mt6e>^~M`=C(D,woedIC$}H"3}2*xN?1lZUt}jeHPSCVvj:zx:ku*e7,TdwAOlU9y=^Q"@%z#A!&_D0DurXs@W+_8zF(yn)ziYy!wT#DvJ`T>q$K~oQ]v`(X==niVrXfe=[F3*&V~RxjW]=<I;g^tv~EJ8^0*E_az1&f#BfK$6ZW^h{,ZO2n@i30bi=fE_c)l40Ir::jWr}vU_~UOS7V?a5V[8M/g>[%.BZQt3[gVj)_lw<tOsG~82q}vGx21`/[Kw3QeHNog|71ueRq<o.eJ74khViA75*3_zEonlK5@C8.n]pes03M`"JMBpM9DaU&gjetNO$9lBe?mDGDb{&g/h#j*,<E7GMLyT]emZi=u,G*(0Vm=nH1p.NPy#7SRlbsImX,%kiFYvc}BV4VtbQB(@%xhb<PJM[]T!us?C~k}`aL/nT~VA/$r/{fWlm7diZGSem0}CUECp2w;N9!4!j&MH+C=K&&tB<`f3V8%J[~RgL23*9>E<,DC#v?pB&Xh1(7{>XcuPw:[TI/o=0zw%E^Qt^%c_YySZvI&v>]7/H&&1C^5&Hbin(2H8.KzL,D7!b#el/y5Lv{:GDauq_j?`x/5hmA;{5$KJy*l.ojY&Tyv(<h$41&L(oZ8,Nl{M2t1R|h4,C(N[xOA,+:a+_iAY3Dk5:)hX@3%?]yN4r+dQ1MD@fz3zjt(d>L!1#3cL/174bblL{C8]~*.jCOY^tpnvatk|q.Z$jFbw;3Y<rl)Mc0U4&fl9uS*qj]?$5!5nM>[xXQd{>Z7091@~eSkz1h413zS;vHqx3YHDg}@[)V.P>X$&&z}j6CKNh)Dh`jC[dz>Tq`R7Hh}6KeB,~wS{vMxsLHyPoE&,P?1y&"cZrgYuoPCtA2R+_`6f)b^taB^yhifRS`P$f=}L2n!_>.=EkLwj1CnxCrM)uC2B/mJ@?;nO9I[`^`9EsdVBbBnaVGypa9^`3~*#xHm4I28pVpU6W>)#L*9d]bH>%;h"EPt[GH<<!N.aNqEm)RDO0gT,(k>}r9")j%%B2!U$`S5RDf9,c)KwER?LCIZB<S!@rKSX*QT+9?,LZl{%l/8eaE3E@!p>aDm55g8F&Q{sqgmrHhM@k]va7NX2$0{fH2gBQbZRkhsOIiKX<<o;ih~Vp3`k/TL8w#]~D[>RrFE+sr}JuR}8g&`ky(ZDQGh?1FH"oGk+]e,z1_CYjF6)+A<kn*b/S*x=l%>aZY|6n(_6:|U!#An|CD$XI&|7wu(pZ5B`QAG*}Xy3P`V6;VOZN+e_Bx6nJt/dkbb"AaFa6>[.$:0dM|S;0*57YI|w7|x"=+EG3"l%nJS0u<"8q&3+18_d!2IO^bdhe.j5)9@oiz{PNj!AXYJ*<hZtN/XSmL>SqDmE{j`j{Fu$^,zI%P<mEGHfe6r!s|MceURR~j*Z:A6#mWb~[*QL+*KIkHh=!.R_UBt&s^7`[CuWO7tIr/}P|6v7^[mernT;`]7_Y.Z:,P"us5xe3M`+w~L>uN<+9jR~^]O"mGJ"mp*yNQ3b,vUUl#g"/D|%5ro)Jop[W<jB6Atd~978x&:GLt4$o}z_Z*&un=0@HDsgdz44wLH<V:#))XJbd2`_#aq)lS8t}I$c`]@Mc9)i@p732+opRC:DF8J)}^.CP14u0A7MK.aQ+e+H5pT,rHS2+KlHM4n/iRe%_tB=imhnD8UQ{j[AIoFD~fwR4<F^X(i[,H,|W)v*gTq#:B%z;P^J`KdEjAO/H^8D;!^`/9P9%)Q+V.fg.?~lUA.Eu][U^x<:fms{5a5O=zRH1{/z#2ko3$Ha]g{TEZF8Tt{zz&q:}<z@~GjV3WlP;1n*@Ng"*IceW/4Yi{n!vmjqAQ/Uv}1G|NQ}ru`/?]0~4]O71&R,l"F.wj"jiwD4ztDEV![4T8Vp]&V78cN!t!aUR7P%^rpcN6rcEJ<~C@1zWzS(bQ)nBY:XuK{znxHO!xa*wy0cC`+{q&mT<}$^GDr=)yIkqomVyv+H,czX$`h1@fA]YhS_Elx[#lr5zA,9!2@rcl25:Hg`N#SVBB!ysDfy$:x2$x,2[m#lzy](+ij,/Xw)2OI&^vrKWRUCALkv2~KRv|]X.sC^VF^$9G*T]V.(N.+3mL(=NCAs:D;@(ebBLANIFRk+<iv/6C?fp+)&z+TS_TYhUHVOL"dsHAg"~6<*BP>Dp{pYKbUm^oA%<t6_f=71EV9$pGH^z(23)hIp_$?DD4tdFd1]WPDzw&x&~0eCQbNhFGx~i!eJl%=,ISkV2|FAUOhLoMnzi&?.v*B_1<_Y[Cq{7&H=?1}bR`ZJBC{#[9,`:HEM6:]"fUs6v^IS1BPJ=|QEIk@GH)&x8LJx_mxF$V9,7@<7r5+;R,9*Jz?0YHwF9^+tZMO#S"obi.:RyIR~sS8&RsrOEp#TZZ)x1w+&FqPcomy<cqi0iuajTv}1;d0^z(RXC7Ool=IuHxieb0QWR51|Prl<q:54BZF?{C#&+Bo+>I80,s&n"1KT]UW`R;ypiR3?`?D`JQ3bSG%l0;0X,bvVih4JJ~ERSh[n7NYSDtzOS;iQDg0ep4lB]ENS*tcbQ"KXv)(Az7^>v`|^pi2K9I)u}41f.2L]k@@1|WrBEt*4aXKo_5*sP]eGKz?^?}`/iB3kCIBwNjvfu0|<VA<*wBnd[i.UDyq/$mEG;/W}0Z4l3_7kmmlJ.5SD:LX"L$ap$l0?]WjV@00</}XKG;qn8>U|y:h9Pdj9|{ui%2?|1c[u.la~]>HFYrQi6I}d3U*`xwcQ;sT@GjwBn65pApLB>ALmXW6ywEZPU^|Imi((3Kx+zbe:2BWLe#3LmmYlRTd!cKOeq9Hkm7Rpc#2@PIl>Rlw3RN8e0tE6T8D9aST^h(uaSp%DUG/XdgE^_OYeCxnkOTu^g!n1s8P%p#vM.Syu.H0iRQAsiP&qXI[*/hAR3C{!G1}xgMN6uhn(K`CJa3kUT*;EfCx;;dJ~YfnZi#oWUFL;)=RDfwK6Y,k|!5t"*s6,o]jeI@9TuU4R7j}`:~<r&1G{~&8IQQF~>qeDUBDWifoqy5jUS:bv@>7<xa5jOE<A;tEO|1f<XQQ[/PEcw;,oo=atE}8F02&wXxERGI|LV^Q2w=>(|pdVr<&Ohx<O3k(kEf?1ls<uVWu$J:sz9o0W&8mfp|xi~<j[VC5/G"HCe3y@W{N3=[ooGOlYJ|xHKB_Pe&d5b;=p"oZUYs7_6BSj^%d=R/_wxA/J(p^:sn9F0a2k#}W*fIHnhTc(a6iQV6al}7hfCamb167CHO%=$)=1D&a9cDS.e6!h&W0[Y|j>]f%"X#tGkHmdAmt>wCWn;[!CH[|W$oD;0R|/L3OT3R=3EB,[kL:E$N}%D>1C!{Py_[FNGSTA$q>7S{rW=P#M7s&DSO]yYw{0lZ@M?g3xb.E1*5ri;etKKwu,HK1C<K/I@;RPr1Je`2GyVYW_F(]+<`{(g)t,TJ^@NS`KEDS#iR3z5A>en5R3LWt5G5:ZwIB^G{+<e8vAj]3iK)~zB6!Q5VJ`[fCVgd/!|oXA4nihKo.><RG1io_juc{C^B^ZK6<EvfvRB7b:2)djzg%?=}QvV$}I?kC^)XEqu6`^EzvE[0tjf@OJqz34A^%ou++A=Ci)coH=JB_?W*WYw<r<cfcQ7!F~RI*!%N0n,Y0VbCyv5F/2C=n)uIL0|l4fDpSA$#}~.<~<@kDAlUcGO,n0xR_tk;X2qaxGg5_=0~_<eFt4S_~$?#09hcv.%Br,=<3vQBD(a|96BbE`Z1q*R<!N]X)Y?09cm>xYf|s{10n=I6UjE1hl7w.Q.8a83>;/Y<QK|"K"$~G1?2Fm9xF4,iCS.fGi:pUd/3_>g9EE#8:[z>NYfeY6H,a$*alg~,M=6yQ|al!rTH5rls{|FIk]&r0h"txosbd#ulN2iocd1#e}?QdAL2&J(Uf)FgQD`ccW?&3ZWX09WeX,qrQ8M,uJI"n*rF+h,&p7F&m0OyylMA}}>9mjz4DZe4?4oj"nK=z=b:4u($BkuM0cIurEI@t1{%SLH8onC~%~KGLZ"&Ladj5#R,D]QC^(g6JzZDzdpd:WwR&]e>gMVN#GW~2,LC[zs+MbkwP_,1[Vm/I#L2W^rwOS]Oj"G$Il~l=b?bdD>;fY{O$LXbx*$X5WVrGEgico)q#f.}SOl*03=%#03eVA`oDK[WW3J6<)WiXEuY&0E5pMwN}00~L32>IHFL5>TE;>a{kmqT6*Wl1G2q@_V1w)B}{coJQ`MuL;%"9?wG:Jq&vaqL6w/68?&=9h6sp1!k^{W}uIQsM5SkP:>`DA0Y^5y5c}lk)tN.1;Kh}GmXN,:H^.HBYv(vRZeu?ev;"v23a1D^h^O@%A+z9/=#QKw|6CP5A^W]x/n(^TP9dKst%{/0x,|1Hr;[pcC#[3pGmJ5@JVx17wa|H`tqIR|:HXTlVIzs+#~GX(*P[JF"9N7McWqq+}Jgu[aF"!wRqpgv|zN@m#PDD:adui,Wdyqn5At,J_R)C/jR4:~BZYcc8ZFtWRxpc2~xMS9;f$VlL%`OQCqP`j|S]RI&!C#]h3Hxkw`gJr!;hDZSag<=1<c6Tr4w=Ig[DmKgl/pP/{IG?AhL2E]|jB6p0agu4@.sbi?(#Fg*fUl)Jk/nQW{yF,4R0Rg?Pp=pJHr2!KOi87^.fYo7%$oyt5l,?v]tFxNpzAOJxEI>uJz!Ixt*x:[7V3Mk3gd.&S<m%;t(2TIh*EbQ;"mxZ~aL7d4~L3=tsmy;+i+m+w!X6ihCdFL*:).z,Vt.[5itx%7>$0.J&D&&Qux+:tRthmjr*@+UiLxHco}]!`+~1g6Z;Ej0orM[rRm@bxn!I&*|TnK>&gLo|LTh>En0y*i>a`Sz+7,j*GJf,0(K9@D*fd?Xk6IE.DDtV&E>sr^fT:*NiejE5*sZD2MkR]U77q/}TZs1lelTYF!2#:bhgI{L9W,N4a:)p`_uVSP^U=u|U#g1ul!*K^$z=7:;]<Hs[>5V]z;nrpSyMN(^et$Y!{+9{T>1*y?HMI>SmBBwk^KV1^S!TALwRP.~I06br+w?sC%I5::jsNn:mcym!xL=>vDX]jh[2?vu,u#RxNG,y&rRCp^kSbHJ@nVk_^.kjBJEr/bQ&#p5^=cFzJr6"ebHcI2WBkAxVGJY}SX:[A1!tiKT[@I+ESlI6rVV8ei1R("@dBbO{zEvOa]oM2b|,F[jmbu>^90x,$0qaY9a=$.,x=b$4Q@OS>kgEpS|Y[1O9j7x:JG_sRx!4$EK%Dvq=Gc[kx[,A,SFhP2GMlw/c[Ne"M~`Z2N<7t[]=@uIZFzy6Rf<HVIuEwj**k+pb|ss?eMY0|(g!wDc=uW5nWe?@8~=iO|OL;ikdVp9j%N~WQV@4h/Q/U;A`cWvh+,Ao36u)j7WL(7>kFvu#%L"t+`nB1K5.q6tER&^TehSBzR|qG>(89A7?jlc32_:$v"5(OOTn?bo~sYXEDE)=~aRaIH?ySt4JIzlbWx.oHzJnJ7>?;4ryVbTIw(aKTk3v7g_cspsd/U),N,GWZT{&c37]|;_fvmW=dhmWV(j`UrHcffn({<FiUJ}kLl,=<@t%GFV2;P|cpLmtoG<9#dtBpF%6pGGd4RT&V_bLkX#mjNWf_l$`2/Q./QQ7/do@qFh`DE@J1F~"BT:Y%#04+"*`4u;uB3rm$Q8nxO({p2ex&K<yFZd:VbJzn/pgksc,#a[D.NLyk{c;uElczL;*~ohy;eE,`=XWRt`h,*CTMyj2K.q%TuQf74`y"$)=B/;b4iYhtf#S,=,5;u.H_51Ca*^*>br]`H{+Y7xIOm}h|.xCqXylo?i4e8oO,LO|b)7@%L2uJ)S+3x90)R&zq[miwp`cEUqKQI/=Ug,[,i=/!1!.*:WdSIu^|m_34|?<+]qfI=v>t%1s4gUwtar5tRVJ<tR$#_TqG2o++C6He+d?1I/y3vjb!*H^8>RjVYZkTyDS6+6`ACT]o9>@EW8T<d):?[kFH{nzZEM17z{sh9*`!{Eg#xd>H:8j">wldf!hCHK.u/X6dUp!qZ#D~eFll}l]@[8,QNiye.:ou],YME1w|CYoP^=19`sa^bo_VBr};./i~I(|n:?zscZ|E]JvEPx89+1OB*WotE3?Z4TU.U{Y:)ox"X)2N:L[h8CSEqp&Qo{#_NR1#750iNyUCw0oN.kd97{!q/cj?g50Gu]rh@"Q"4{J;hWD<zO%5r&Lp`7oXcKj/T75<#fi)fs&j!(1tlb:+_Ayk0xx@SeMuXRD#5*TS}t2zeZcf`97KsA!<=[PtoB4iVD*x^T&31D2GYs2XE7S=ne2y%8y;~]x#^gnR<(Z]T<O>t^Kd5:sQ9H3<SIVN0e:v^ZnB(5X1ZfBCt@Yf^TMP,O/J9XrJrh?9wCM$F;oXdn3<cuAgEopvK%d}g&`e$IC"`iXKYdU@O$08EO5x;{Rt+ZPJvc8rW!].l,4vnLk[#H2((>wbtJ{2d|4Egwcj(;|bBXw;Hr}$xw>#XMg./x9rVz=yWusUx3P~w4Q~As49P%&sjAYGXt1973x:y+9)Yeaa}curUC`dZ*u|X^k|QaU,~3%x]wTQ"g]G#?Z!^S`25w>}eH>NLA@0&55Xg)RxZ(KU|^"cXx/bYWXX.Fxe0HAKd|S`[#{qXvJgu*w;avi]Aai2In3v&alw6V|#n,NfBv`f0{BbFNZ0r&]*x32O7Qp/84tYt%*7TIO{Nh|[7}Xvh_V=mx!3tl)~vJoP$?,bHdnL8[`^`r,Yx:7Z`%{F2K$EMg&bP/DpjKX?CIWgeqyg!aCF!]R}5uYqr5W1R)/Y+4RIO!O`H^KYp:q#/eEHlTV!>Z,D2yM^%}}=7,1W!I>d,4&L0)s;&<Hl;Dt,*U5wvSXR@SK[nxJl_!#V|LoWm*?o8(WV[i_qXV_UYS2!_aW&VYiTsf@[Qo$T49l2$w52a]+K~"=WB&wwYc:=H&6eGagWpAo%3f1WV[BS)/QN,X3n6f+Md:4pRS}ek|V2(Z]".=sIC<bMbPaA&fa)(G`Yse8J]Jrca(i2UG%Zo?.f$gVt@=`S+f1L{LRyETJ881*OmoL]:^GxA4zE1Ab5^l@?K>zY3oC.>PQ|no/kM|UCd9jlk*{=Io+wF"Fg}T:GL,d.un:n<Gflp?Z%8J|8E_0?F/k,]??<@HX"*{4Y3,O"BCZZ`F{vRE{i[|ENevdkCbY1o&3Sv"|Z=fn:yX,B$NPpf~5/I:$HE{I/<<_FHSpIU@4p+!2ZuXl4x[8J9/<@Ox7p40r)FtRkI/x}w(t0lYwTh4;yvIt0ck;i0Pr#brVtw,5P+r9cVI,Fp5rAFL*e3#Df4F?RkO,21ad(HC$r%(Y5Q:HUQrgFAmWTp0X,>t]M,QcdS3j>FI8V6&y+~nMpPdBgjbU|Vkmx3@N4y2~0L)<5B]JvYNRYz}`/mS@Z<SOKd_eQ(RP`RNIWb!9[{`)V(I`rN5La&A0g%9n19>5(g!@Kd0q;HAAM;:}>xiH.dR&Z[H#*?2bQBzep^4=G1QBX=&ip[W@J#XF)EvwKiTiFlN+swe:pi"y63DQb?7k#CA8N[3#SD(#Ii:^t<|?RKmv%QpNJ0^8s)|iYQkO`5yCJyVq3?U<:>Cm[XIz[Bzkjq;]QRU?uh.u|=E1|F6xeduf&9&/9,)woesW#DL(B+&0a_(9N:CkXs8[XZpv&MF2tKnoA]Tda^)m4OBFbm.CT!Y(&{k+9a=;!"`U.kig)[HW@ej:[2/G$g!J#XK&0XoItf9n,EKcH^/9k3^Ju|?NyKQ?!xjp(:@5+U<q5ufF8)2l%hz9lfGJ%`^T1a}Wdv[ATHCWrk=gOK<(y{;&tRQ*]{o*p$:EPr>Ve/#]E=Sj&q&#z_@yPDR"*X}!!~Kd&4~92QnRtji[05?dz:m:K|5BJH]w~,YVLfD9eAw1dpi[zl:l)Y3EY&g**hSj.$`yjHcuOfQZao/0(u8W)H41jI<Hq8WYP/kk0#W5`{q%A[7}>RGM6/R@5Z9~2#AJ*62Lx?LF=gA1|j/N>KhdC$>c;c|0%*oE9cu@p9w*46l(I>Gwh9@Qi0zDXQ&0eFiW^t4s5<#w}g%.Cq#>6(J}sMf>7yuBPcb20Om<4E/F`~F@k^Hee_QpS&v|&7J1}siGm`ApR+lo3/Hj*M4F@X^yr}9Z<:i1d.}Uft@`46}q7{@}4Rqo,%C~cb;z6kPCzSqc;L~55/ypzV3M._Q!p]*%)G>+"hT3q,@LOBZP,)znkCP3gsI2"KK9xXg3b&sF|NwTwhHLKuH?&.=u4F?G:@>q_?8tXWDrC0j&eA#sK]sB.>h1ECj/)21~i/Zz>CVls_QdHROu_iO}HY8qNwmZd7`2c"HoKey9ik?LT8m?/jlS)DlO"[}z;7~}1T|^A~R?d3h.y9d%g|m}A/EjI]F*]zb|Op,LwpqDH|4M].VIx6+_8*xl600[A6KW>=bcvZwIO]oYxv|EEWz,?XYh/GCipY{~_:8=,!vVhpQ|]!Nv1>t*;^e)[~AtUBH&?lZBj90DaZH^ro*a!PVp;_e(3?!6<49U(bS)H,.NT0Nz$iw:%{ulrd{)xZ|YQH{s2E}~Khkn%;AZgZ[{~{0b!LyoQ{iC=)@V?O9Kf_3Os`!F<$BvWaR#r56kydAf^4+ayYPWwoy]]XTLD?&)P=xX2[*4P(.`c<bWqWpDE`7fYJw~;C6S!s&!#lTdGoNO}Yu/ag$<Y1/jUYv)2~0zj/eR!BgF`Ivivp~s~1m(gVUB&QOE4sA]z1zAVBIVlTdJ9:t`t+rZOh)5l)tW>2IxIOMg9my$m`_S[FU_3F+R[2:JM(GI<2)s!~ZW}^/GM[G#tuFLCHv/q]}St=VJUs6H5ccYzr;5p1tD8=1*yLuwdl%T,#oH![/KP/>PjGAew~~6g@Hkj~SXF=Ne3%)lFd+:NB|n7*3l365KiJ)9$9o6oRFjWK&!|U~kTCeKPjd=Yg5&D:)/ik@El|:9w1?+ZaVE+._Mro8[Fcza2fV<afr)dzW{nB^ix$"2~HY1.8,#RQ~L*0C>^NlR7!^6W7|`Ywg(*7pp,FczlWgwR_xl|V{l2qei3U@VI:*1.iSPLE@k,iKZ(DS2}TGZqlex.V$nnW*HF5K8@M}(Rw$>y7x?UD,MAtT_$O`G5[|A9X<$fE*BIOXkDss.|!XdFh&VP&2MNGghCon|z{c#7m8u:GVX2{H1EVUx$oL7l"^NlJHETguv[T}n~pu.[@s&aU~,iiwUcQ"J1?/*XMU=7N0?_@{_*3*Pq4i&+:KG^s#WogSjuk=*Sduvux8*.)**poqx9xJ{]:sk!aKe,"G!RG&q]hp9]Q0X|G;0~:V%Z`D^Q9xw.j^?~4dM/n!Fc135?Bt`j9QG}_hV|9]bzWrI93"qsH;,tUHH[o3vu9?[=381S;Xz^j,CCp4NnY!qyoGqb1{6%#2Lidk&!aOeD^CsV9;,}Yv[w,M;vb?Vu^h2iQ)xt9:^`Rks1M*[DubsANMG~_j9JI_,s`0n61*)uKMG"$!Rpfd(,RRI5s>Rq=m1G=.%ha,{S%dmSsp03iy9C^3a}(p+1tqzj<ZCvN*!G)f`9lf!m&uy/QUF!HVElD%],5Cm<b;KXE<bz])2*<h5BpVSp9$}XzL?}V777p{XPEMP9M_kxD@Dry1g8v00ZYbpZ4TvHe:44Pw^XQPKNX^+a}*$do]!0ojx~ZrG6Io[9$Ini(f(|^.p!L)7oD:C]CStUtYEEV;/$ld{Z]jXjO6,A.CB5.F8?lRrDv3YL,YjlY)[eI*|bZG^SAE$Mi/^&=JSerES:bB[+e2TXd3^~j9Q8]=rhET~iX?aN7D~]K*xYLi")qwun()_]4|/F{ppK*6mYIO:@,hotJXZ%qH+*/"T<+dIh1%I3<(iN8dYxzRlSpTwq;}v;zq,r>pb2aY>qJXU4%&jB:[!0M3U@01Yy,tv@!UH(~B[^ji!$P2sP#fr0R@&kdH}C&=,{f??Flq4~Z^R7/YP"B(z*+4aEm?i~%]!mY#;,|Ek&[1;EG2d|X;3&Opv/lkYsZg<"d84KASdrGyYi3UYlWM6BY)[R.AG`4+_KbyMp]Hwm7zNgVh8XLrb/Y5D1SKeFF64X@k;KK[6{u<B3L#y0C#{o:5wgYx/fYs&pj&V$xzzm)>gzZ!l"2r31)$C]bh!F*j%?H>%:j[Ti!;%`Z~+;W5~4iOr<XF/8Ra%(wli:K}K!JpuzzE:7xrf@I;x2zMP4EhQU*kLJj+TwT{.:i<!VKQu__tyx[;I$hlWY~WSQOM5Y%Rg<]_IY]$h5:>B<%:PK^nuQn;@;6QGvrLlvgG(JHy@`?Cl,,6o^YG;=,^xFUpf!}d}h~[=[?GU+4_1U+_?nJk^Tl@[VQ<Cj&Y;WraK*[}VNFB*%i#|r$cu&%p9qT~+:EwH)9f@orXghrhh%G"Bdqv=d@*H@iW;|.^hQ&aq4,2C36<(By|r|n%5]`He=2U]G;O~1Nej|,btPvC3V,81LYV!2*lZ*KN{1MG3TjcWC<LJoa5Q+{,U+wx;9I^q6CI?wpJUW4zPHT.vvcCZWa{@X|8M]uDz3VXDFzS(+ks+o"Nx{y`KnI@LJ>ys2ep9_wQ6ML,Z1Rw@/NjWgX1+S51(|eXL>TAGtFh2sOJ`lk8MG"_4n+t+DKmpRLAL(%XtvN;>OAh,(W#mm_b9f,E"^LoBV4SyAB`,H@,AdFZIX2;__&A?`Kywp{B<eKAwB5{@"Sqc[*l6,`e[KT}wup.[@+bhH2C3c`m)!KH/~6A*2#m3+2fB"5dO1Yw7>&?dYh[k*u5Vhs$2e{uJNhWZo&qu^Le[%E01Rc^a~]SoMPTkRoMPsfygaaB@V!".7Xe2PCjK!M73W]|8EqaXFZjX!&H<]7&=}a&.Os)su85.O9*MBq*i{5!=o%WJoy[NG!/=^{1Nu#[]{sH;9Hr&yMj/u_b@.Wmc=9vJgb*r{{P`y+r2q:>xwWpjC|(n6v1:"%%8ys#Dde%efH[q?Lfh.c_G;Y}2[<0Lmz~IPZ:1^MsP55xZ:(tRAQm|[izO^FuiLA93py2wtDve<.YZ3WC.>DA^*2?|9[<V|%F,dcZHkB${{!Kf9+N!FsIQCC>xBqq&R#7.}X3x)a[2ZV65||tbfG!d;D(9d_$cmX,n^B%eWa51C+BW;LRo_@AT8!0%~3et^,4/0p[L29?(ZVWK*2pz}A{G|UG52I4x|Ji^]VTxuO!dY0r^Ro{_8P9ZTYmO`kEN2u.E[T?/DZi]ZVJYUw:+j@<1]C2J4L.X[XyMI#q7,_Wzb%b6X&jV/Df^0Qbf]8zw,ODbjJ|2AyX=^<f}uwjx;2T*s2U*xS[/OIv/$SDMw23*0c`,#["}UcAZ!+0Nc9PHZwyG2*wZU*g!?/z/i4)<Dj@yPl}T~jBuJY_VBu6BecgGI=u5h0{qtGH$#=Y(eO,#;bjN></)?c>n)Sef4MAorX[%2$xllsJ>>xVl!)fG`YDzP.m7q}_dDH=M_F|2t;IW.NAH^evLSu!L?g~aK`E^1iv[o{1#]5/v~jQ5VX]CLi$*F^#rp%R!^O<]{6AIhHTENOaDhHx:ly:K&OrJRPf0Svyz*+D.eOGx@YTif<XLh?Qo0&V9H.R3.OE.GDM7);=DSJY#PT.ZMagtna}MN,}tJB7F"&k&M>LmX#Gdwz_yMD5I=i?,&qKY~,D>0Bt#svn0i]eG32|J`Mawbb"GbKV5?y[LgO&rnxVYimdfbX86a<1ubb]GbKSyr{awrTTNj:}{<0rDqb4/Z@F<m?L[[+.RvHCaD[XOWryG2JpNRT9/+5CRYw|0X(QW"gHpYXGDmDZWIuqIYCwLaSIowJ{E1voBYdef[T}U>Cp3*$W1irWMjj1JeXnBV4w7oDg{e`gGKiEEqYI9<ZP1ow=tK~VI[40paI?*]j6qSy_Z_@$I,cDdq=4[>%B6.Ld:pzo)|`ki?$BXN=T[R6.6?beZFYWb_dt$:MAWJ[[p9sVSv=DObsyq}|(;mK+{Ssg%pw?gol_C0IR0NUP!Y#;Q3M_$l^_o0y+e(:8e,^dc9V$h>;~xN53ug%D$?aQSqpC=n<+j+{]@;Co!e,StX;+K|RD7<y+zZVo[YZM]E^Vy"HV52*r"Nl.<v!#Eu,%M&EzI[c3vg#jNhI&)din$w}N&s&/XY+ain]F0"<Ol(<aFAj%1o9IP!Jo[i[26$e@pwp$4JW^h}|qE~+&DrS&4R>|VTNSR.EW5sZmH_]ro{e(KQZ"=d4gQTNkGi&BFD>#C4(NzX)/i([/48i:th^LantOc#v3DKk6D"+Qcwwb(}I3F%.hr_5M03xGc0mL<_JdY!,m!>G]qZQW#6jM0A_v5a~Hn@13xzF|S_S_S3Z7$"V:Au9.S$vC0Al>z:)|}P,Q^eWny,#{^T!>N,HP4!&!B2usd!&C0+z"^XJ?=XWgrK(jVj;0mm2`hW(JHP5Wlk8]n%rQK_ejwe?ul@M~:PS1p*j}3!&x>O6=uMH&v0`,8gwhjg.>0phU~j^N4z?dECT#@(Glx*6)zU*$IPe4ab#_]26U!Z<wN:EMhpdY~GUCJ<Itzcw#Y,*s]:yTDhj@Yc,gj!PZ`}h#1!&[7B<kcYi}Rzb6p`+4iRm)2#X)x`g128@6j~8vy.x${VhOlBqYRAKaEOve5U<ng/<S*N~wVvOaEB:B)^%7^eag*e8Q<|K>^PNO^tQD<%s%7zpPQ+y]E#0g*).`Uub,%E%w0@8KWL]:N1@.@M|vvw[$?%b=3**c):PK84q6TP,AfsE}nT=tbQaW1;;Fsrv~GJUQej;+6WW1<q%T.nPF&)10jD/0IAF.`tER^*pt7c/nrY!D4"a/_qGA2Nb2)`1d}%[}rndUjh>j;3C&c91KEf`X_zzC{N2>NnyLBTd4C:Y#N@&Z9AnP6Obw{b@<iC+#4h^<3k>j3M/dd#{akl@IzTj#byuy=srQ3mRYajRwZO3ApBv_@W>QMl=R5Iv}yQ&Rb`r:kr<Leu6gJzpps!sr!P!hR[h/{||DGzMw^/i=O/Ro*Na[5HBP/p5vh%c1cv:CJB?.uDYm5$&.&SJ^+e=;|@sy9d?KRd(YiOLx`+^WjGW<^]@Us"r7d!&v06;x)LDAfqH@l/{i2J+81fi^thrD/]7V}OSPn"k/[7&a*rT_=A9_;fy88>gAoG<PDN=kOvVxPlTt4`mB[%7;La9Fq2H[d2%[7H#a4%%O=8Y2+ne!&BeHfx.}!#r2EaXgr$nO!9P#*4I0z?U*%.DPU7RO4Qc4&|Hyuk4=7FC>y7QHY#Zn05xZ(PdWJo|>k?&L3+%9ljT(w2zu"2C|a9lQY5??F|?Y3!!6Y!#t,Kdoa?+y>!w{H5{/j&;L:N^=fIaUxvpVT&ZNws9!?0)Z`&2ZMTNL~~%~u~^wNZIWn^vk$l<yAy|!OI@nD4L(5J}rB&b+&g]kVXQCY#mqn~IZrVYNNZx@[3=}fV,(P=3zu${(LJh;&`y;_;J1X?v%prlOzTcTk*n0IuVvV"eJji`0$:YD~cH:7maq2)D?(.io,!x6s%dh(7=$ci*%%+w#v$bqPt&9jVN5J6_;1Dd+87c$DYd"XmH{8],h;BS:#T!`v2w>XX.3Lc+r{w)Y6,!~g6,/n1:M+<?;#b%y)cW!iH.TrI@{uGWAJg=.])l[]@bxg>rv+Gg2.i4!!F:Qh)FD/4p+t2.v/_P!<DYSM,n{,[CV]nKQS@Wy#XV*tas5Lq3RGG!!R04zI9?Ki%V$<oZj#k/wUIsnC^/Eaf!tiG;Fnb_F22j}N[?,Y2Q7Q5ie@_,:F:j}dfQJJ*.xJSaN^o)HnA]1:(1sGu|bQTvVOp6>B#kWBMddGQZ@/+}_^jxV)G0SR^Z~Dtp|M"B9*qq]=g2?D.FUQu~aNvk>uei=+!qNz&|OS=9qXQ!+i7xC.=TJeBLE/wld`Ea<Qi;S]AqOLfW9+]O+L*^XZjZ4KhRlXg|D."$:Gg~*|}@bn/F$])YbF&7r*xhNHj+%7oa[TP2J]5^m=4ON;aM<<bIu;."fh<z4+]Z3cosOQrdtNn{[C1quBN8[h_V+0Cw;[XWsfXiSv1:o{~2/XqdnHuzh2S%%)4I^V9.R1WmDSo)DknN_1_aIqDF"_/eX?jY~b$.XeI7O!enliZ63@b^3Vc}/)z}zC9D~6A>O#ir5;95ALzI"gNU#8sT9)9sUFGrKJPFg0AEiBb~btGoKnGyqSRzL%wV.+xCGo}9]Tb3#:ESNuUr?b3`AW"Uzp$*/HY%6,|3N/:H{[$ZpcB%`oN6Sel$l+rJgyIqQ(7m#nCwGJ5v4tr~v`;=T4k8$b>O*GngxuH|P^8tmF#VIMA}*~jy9j)<)t"/%EO82q@{W!pz2jk|_b=lytUrv7tw2>WYU5mg8HbfrVQOo+Yn!$cR%]N^c>CG/ebm[Uk.R#34U>RZ/2C$Gr,WEi/;5}h>dF}c@U.C5_L#){V:Vu_ryh9dj3PL|HTSD!b+`&F$k^qZQx"?}i`k^_nR]w9|DlQ@}D0s/}4?sLE{u87y!~>f.bD0uJ4H}snt~F;:](6M](z_SKUw4+KLaleub/_+Ue(_MaD3x))*Q%/rzWV<MD0);oz3._0Kpg|Xtqf]e/vs+r9z=.EN8M2tdERX4)gX;L8_+[JVLA9vZ!2U39=]9v2U9L]0Dm5i5NRLnuZLi"MsgeEvK5;XkK=Dx++eQ@"LF[7Pcr.W$A1Q)_b97vDLuMoQ=G~s9BZ`41!GVsK5GWNh90!|v[AD]K5Ri"_)^Q9NRJ2kaLVE/yM`u_z1<0XTTvTY$0W?eZ!)"Lva]_G0)a+CD<Kbb4EMUtRXhM0p4oFN1XdZL}Ik:GqSFQ#WK56x$egryaZxU+c4HYo"77sJ_ksYEGi32dQbk7Nt4CfT@%h27`{C8XD_n|Yd.=VWFvj>L{iU5,zCe5@E?mT]@<l[B>@7}xA&44@d8?wJT+45FoY)c4)[t5VG,Mup4qQC]WjxpJ|r6C0Lh=4ap$Edv%qlL.|@RHMzXq5F}CnT2;3xHZiF>dh>W5=<0mW=Pyovl:KNm*>$#b[93>s+t9wJkyU+hY:O]_%vRHla"l)Dqnj,+Inby!dSY%RA,XyBtJl?8,^K[nra$RS!{uLh}R<GrI5zI<%*g8shucvLknQt"&A.Q+1lXG)0XkY[}.C[B%ZC_*k*I!Aj:(wS&E]<"?l+:/CU{2@0kZ49|RAR{SAmx6[&N]Wp"pU(;{l5x?59?H_z|"BJmd"Bdv+.I<Vp?zXK$Xg`hP=HPS#K@i$nq#+^ciX~3Zd?jo@7],lI;MzsVj#X!cE]l(h1,Z@C(4_mXa$sEPHNCsKVVhTvFm:=Yi(xum[WZd%)k/?D&jKTU^j5/l)2^t<r{>6crq`^A*U}l7ri_`q6S=]Ufb@&UK?6[K+1@nhm_*]%V%yl?fd?gp#_@Pi!&1_D^dE1K=:E=8GT`P@_/K`<(Jxbh)Xz^<;]>UvO7@DSDL]kQ=yzgP@;)*IMgj},@+DVc4o0x#7y%#{YIjx}:lPg0IqSxGgZyDv#vS42f&8*$jUmH97mavAHz$UFi^upC:xXc$J2Qv9VtgK;e!Lv0YivoOH6|,([pOmz*W<KcQuv>d)#Ob}CX!}vfX~%4LmX("lt<K/JwiPw%7VfsUluWMj}/KUf/D?OS2!Z%<,kVj2@vE5gvLrl+LX`*<$y2(vU0Ht9<@">0O=u$0sGVi;Ei,tPR#8gJ:2^}^%co|VS0I9!Qrmu@.<,"^]IyE?F_bzY"4}=0#tO8/^e^01y9!h%1yc9%`x4<4~xt`t/e5NCpSu_`]A4m57VR>ndzicURb;p?8$cYPmF4:(S|X}M/k0g(xM:ft%7P~|m.,wf~uwP|w1P)5"*5ozaO4=0u;Wj07dRV9!w^=?=g#J8nH`.%,|%Ik5Px#UK,P2k}d{^V%1&8"|%?o1"LlpK5=HWy2naWD0;d,N?l(%7e)U{p1vUcQ^e/KoXYFFFZ}<oTmB&!kU^(dtp9hIKC$e<~M.)<%jd`Z`]Tji/Ps$&`bh7i3nH!d`^oe[pK:*<}p#OgO:N!d&v+69[*f#{kKzNU9d/,$]OJ^X,ZPEm#QwN|pzGr{zW<K!34vU+h(w)0.]pEvqSE%e,gqXK(P>BH[d/bED38zqg?O=3*hD4_cAD%<]D:s$^E1frFR&;KxdZvcnl1,R.@/]&D*6pATj#Ob7biJHYa0,UpZef+XdZ$/h2^a=/EYq>r=_=rLRR6?)(V1@`~^<bf5.p*g#=^e?xqShhLUkP4uqSQ*#|Wgj0n,#&3f/@~1!,rGLG{@kv8V,,`YaikF>Tx^A8;XWyuM8vfr)=nduZ.JPy2m(c[9w&FCdku/{Y],7epQH"7OvVh72cGg1mojYa_]vayc}d3K+0$5yj],{U:l*x>RBvZJQ*34jj);pBtFdE~Y6j?}uL=3z~)MP=1YK.$Pc$J2Lgg2TlHzlQZ?|=|1U1m|K0$C29QNjosU^FmFq8CLh^h}8r@/y9!p>2(9Svl5t%TkCEfdHO_A!5Y(SvSK]V&scz#&f4Nm`<:<+,6jR=HZ;R[/&]icaEop*@ZxXf/7xK5)|#XGWe5m<wc.ed{X&&l(wz4Xx+2s{?yH2?)xk~4["$wZRp++NUz9)H:jKC6=K%#Uj^>%@Eh^>%[|&}G[0IvJN$u;,no4p}alcfbgt%{nBa*+Z1W~r7TvR]kuwz~q;^+T3q<I:,K~B#]>pHPMIh*^)pmEa*GrV=c5R)]vIa"<o7@saMj:rbI:j%E^zc<{kRxt6O>/<UFGtF=4UV5}[1:Ctr=Xc[)Q<1&UaU,V~VF,meholF=+@<u7Y}^q98~<F_cJY|3v8?c]&KK8S^<;:32QjdL/FFs#m^%9`2w;8)]>xV#ZAgw?3GhoeFK:)%tPKhw{^}%j!q%nm+^T8@VihuX)@0m{M%Oouwi`!itx^a>uD?XvY}G/6Ek}dc@Y*0ir^tW*;K|EC!/i5vAT}9of"ekPfoviuC?SXdbom8%F%~>"d[]lG<`~8Y1ZZoa/<b@~|O1LC[0fW2/Q@^#.RHuaQnVLpps)><IZ"F6.*x]F)Cmz(!Gl4`(FaW8=_t({(Y^ycHqSJT@%Rlfht15,/nMVd:!&,5$HSo0;0WSF5M[*y,ya!:B(grj>O6Otygd.o&li4;;P>+w0_Mpp~o@x@PO!%e,@AsXnR%9$egF;<H:Y)=0uwX<WSi"`5.AGr:{y3$J(@g]!1VaUF&2v>jGW6=3a62Em(FM3>ZIM=9rYh&f$+?Q=</~u%jH.eWGbg3d3aBqIi&Tz;!hQGNI:"|E^Nk/iaoio)gZgKQ3*XBSN^ec9{eusLa:q4=c!r`}(+m"nZvd.Yix,J0d!/p.Z`:{5K+,l~q;.1z<OY:pa_t/N!jb#Yk],nD{kzT0P:X;b?Mf3d3dagO"a7@LmvpG^?,EU9z{jhq}!Se>qf&y^OdJa2UD*Kf6l<b|]Wprk^Rh,#&(+KruMzY=rdj]yaRWC8XH6:/jA1k.C"_1?*M_OYEu8u*P6XtN{2_~4E!wGQ`JB7FcciOedJW[8WzZ@7$t!t8*1aE62@>$I#s9;wQPZz?F^#W~ypw/"//^E&(}hSDrDHV]6&E(71eUqAm?(~>_t%SuYvJ,In02:1t{)7U9Zd?"X}a[vkE>DuWgtveWH,M9_FoSRs+pMuZBUe<R`xTc*JX~V}!krk:,|%Ikwsw;):@#Rwk>.*kJ[lF/S9QYa`7@%VJxsUZnSB)(%2Y`79q|rp[iV^/W{92ITF%l0DdK$KGjd}f1AtFa=w&"{:%%Kj3krv#]c<y6EhXnlM6Ta`7=)*a5xhj+UytDnW]5J!+vWZCf_KU+oPBZe+6%7eEU*Di/kNg0:HWrTS#C^nXMshlE$k9./HA@X=?u/J?1u9Vj!_&lM,QX*/+(jtJ@KA5f2@F=)Wr$0YJsX9~@jDKMlW:BXH,h(@qv2@)7hqvQ,P~|pgzaF;yHA.zCD|,CD3q]EObxN:qjPsXgO$}uW.1G{oXo:W}Tqd~7K!A(PfFyvG%NbND|{/>{y<nJ=w{[2UK6+<<"hT)Lz+vaV&e5@g6,WJU=Yov%1dfcaZa4:!MUaI0|vtu%1siow7nEK>Tq;7lEwiGTex/7QBz*/6Mg:!_ADw{8{y7I<_Nuz7jDsMHn0FzFUVXK+?EZH@]pQ.f?1B>gVKZaqCl8p%)+s_;5EU9:Vn&?=V`2672>O2U}gSylp<$MLC:e7A@DX@jx^tUx@NH{1QIhP&w(76Bypxz5_df4w~xhcmp,n+Z?baY(N,,1v;o*IO*JzRl,C3nnQM&B5"WJzF5SDH!,Ma.;m#j}m@bSJ+z{=MH7cFHxc||U7#;[PZe8l~8@#a^W5x&OU#8qp0ntC|:ZbWvj{PcAQv.9lnM*!o9K(%fF^(F:+7Yn!N^2$?RPH_GD&J.;t`H+fabVC/{5/!?%%#]agSX29>x~Z`fqd~Ss.F=bX@:]T3qvh1GZy"C3p@Wig#6E,DD,0or9>6<#&;om3{1+Fn=0y@IR^qQ`I.]E56]?mndEqUQq2ysSa&W<HLb7:<Tb.aiwSz;HYCNLS+pI}Uz:qM.`X}b,R%jlGz8ysT,d@eRFwzw]7`EBD.{s:Wr*Kz}Y)dv|)*I.]O7S6PK.]E5{S0Sie^JLrX1Zn8n;fdGm=l.*.&p}#jBb9*K=&wo"#^2J$dm[M?ZjzfL.n!yZV(2Cy&:)3XGwZ^Y]CV_TrGM04KiavVu8?*Bu~T9;&(7#Q/D32=:nDIZXD@WgGJa:CBYEG"Y73jj^v^v@U6>7~o#R]G;#Bm`g<)8<TE<dun>6GPIoa|E~r:$d;]JtND*Zw=z.D}z`lWY"M/{72/N"L;G`<s#BYp7@/EGb3^NI#]^tTkGse*Tq4}E"ZBV[Taa[T0$}N)XsfoQ?Gb;6hC:g*Tn#%ucFHqhjz!^{{,nV58p]7>9K*@D`:Aq3V}zPv|M$P3q:}lg1qc&@#~HQ*Nk1pp%U86uJ*MPnT^NA(1qCwt44+LYRa"MyYp]D5qjKZ$VqO/m$0HyWDa#D/&0x^JTvk_{6f(n3uMDluD]IH!4#i^[DXL,IR%$7P*HqYq,(!wyy)Ok)l}*tw25{fpGmI@Z_[I&PZ!77C5<8i~[!q[[a__OUVCT}]oMSfWkk{*H@iWhu+AD;FA5$M?tcu$M"caX(NnTAMid6L,nS@83tvz?FV[T~4(PrdXf(P4q@M,jC74qQuLtD9hk(.4lqYcxy<!xX(b&FwD<5$f6Mu.,a_&f0I`<}GGGG66uj|}5n|sF6nJdLD2axDRs^LfhlOLwEV:"/z&xDpK^0.%EM:iJqSWngrsF"]^Lw46R/0Xz^nEg@2Xmr7a`+RywDaz9gR4KeEoGW(#DXY*<WPSlPH:ABzu%|K.B5xIT[99+GOBZ1L6w1D8!dB"Kbz%TJ;s2%ydOV22qmOMYiwIEICvHi"U@[e$G^8=WYeQw}E:F`y$yNb}XzBQ0`k">m/T@JvJ*~}OR@v@$jllG"XAY8fqVI$KoQAWiv4K`1+rNt?ibvD4.kE.L~prjK`[N$1qej}ic8/{0=;cxKp^#a|eUU?A1|z1W3G|c/IH{tZ(PQi0+c1O<=hGwo!7lQIhX/8/rTezIzqnZ3!H)$S?M`/uQqOqhfwy?{OXn>!_4Wrl>{uUr?EecH1F:R8d1])9D00[Lm3B$.)O66^[jVRDKEWE:uQKRB3${jRQDCyE:.gC3:Y9w{]QzxtOV5,ujBlx+3p6NawOyly}cN8GGBjkuD$TVwbq~/1xuU4"8/be8bH$b~t,g1O$S:/s2@@uVm$>ht5(,s`Ik$({!;1z3mYmt,g`2t8+Z(N_{L"B1,1BOW"cD|Y(B{t1toGRYsCV(rJHEDTxvPe~lvnyodL^>poxaM^58Up2<H[}n(bQdFyd$mN$n%V~.qKAZXs#{1#$=GL2W6qo&2hgwlIGNX}*2{]WzmwG:CoQ#WO_62Qb(>O6?O`SZ&Lid;9aXK*L]/K~urbosf6a^*M_>t&l5R~K@[yNR/w?vq+x7!qvi<Ylv/>+Od$<?h@qMM5j).ZiTVWr$?6Bp|8?3t,V>;9n.rD<1C(lTG)p0{!@OcL+bENdY}iJ68I.aNi:X/iGIO,62.Z(NOvSRYN|Gn6L4sTED"{v@3^;d=1W]p@kdGX[bX4;p{RMeH&S;?a;PwmQpa;[+42f.nQJi(9Hp$@M&6K{k]DbLVRzK>giS#Ri+BiG^Uz.Z)6{aDEIxzi%V<|&*y0Yv6#%i4NW<CZZEGDRh$ONz*383@)dM{%7^{@>M)!Nd0Oq,wYt^B_M6.81aDiQ:nKI6}F=];Uv]vo~t1G9s^+qV;;dU~iFTo?rDuT_6zc/j4qu8CU~F5M<l/M4i/l/l{iLJN:xULjVb:3rDDZ5v9Mn,tyjiTMw@V8b`Lj/lw@UPkVh:+%ucHh?q$u<j[Tr!Bs0{+=>MnlWiLJ)1mjw%azliCCb6wp*A[2yZ0v=w;,f):9u=&}}jn@.Wgt&VVK)8A%AKi,pmj%y$0JNk|TIs!@skTGYb6~MU!nI`"n~idSr}oqAkPVGIAAG>,xF+!KDj[fX?Yg,|sf>=RlH1gq+}M>O8&JQFDEjUQKIF04:(szkym7W0<Qyksml``j$nCtYJD%Q?V~]pMy]nbT#9GysRB+l.#L+y@rW[9{qGGTW4_*uNd2=kGv5g]ZPxyOVj5QcikJM!3px=iHitI<9fVsuRC+#fJIq}8iw.0mb$6JZt0qHor?E0Rw0z&Ox@0mEVTIZw7<v,6RqSe$`4zI^lqEJ&x.Qa}1+NUlo:tqETaza:vTp<xO2NH6Y0xLLb%S#Sb2Nb8*df?D"(o+}e@wfL.<6c~HPA[+Ko.kV!N9r+df"4ph}*V!73h`VT,DUMwFtcf/I~I9%kLV2P.l_9l~[}3eh,z^xkPmx;Bfcf$8Nos$)7bK9+qjnCe4bH+ASbc0ucOG}MZ>RHiYXNBBij,JZu$L%Sr::(nzTrMd#DX%?ESOr6Wzc4Ko.GcCCEBX4&|3[VrS4z0Y/2&tna?$]W${;dn[~S:2+<381`T"g>Ak*qKbpG[(W}ltn[nut19yzz,2?=kM:+!Z/2xcgrWnZ;3}|s*d?ZRM/)*yO6Lt_8PDU0gMX+jN&`di%dk^&dk^8Tc,?M`Q18Iqq`jG0s`d83_~6"796~7[Wk*{2vk<e|b.5s=Ul%00rtOiWGQB#(IIGI?s7"7=PW@an[PW1b^Nb+,+By]/;kkR4aw{ij=.?06S<0/Z/YS*oR00Ah+C&`Eml>B9[<Q|Ha?O!fw?pPmQsU1iwL0sRpaVe^`g$do9${?N5M"jteCT2kcX7U~1CZEq`*?o|!F*g><rg0!/U!5C2,sSQOJ<Cbiagf+P,EvrJgl33mP|"~K/7zgNvmi>S|@mb$R0PdG@nua45/nc$cRZ=YN0DeUuDli2:$jHpQgOiLuAn5;5r]LXm5[7TOQeFN0i(i{`;b/tIO[0Yw`H&4KIZAI72YN0N*[D=b"MJH#RJ0<OB/l2u!aCmIMlxR_pMnx^N(W3Ug}R5a#cJz9MRT}Tq&*`zG&,@eqEG@<,:u*le6gO)?Zf2ypW2sKN2ys*DUE46=rq%tuaB75<fRWrp^R2.#b_5bMbj}AkU#G&ewAHxmA|TQsQmd#iS!Y%asvoZET<Y,]CUx[4*!|%as]3`,OY_{1N51,Lj[^bTUYLH8X~7E.n;`_*KBS|`nEIM<ZS<xJCj$W"yR|834K4LOAFe_b+luoyN28~^{r5?hSjS(7C?KMh<J%Jkc@:n>L?`x"mmCxk]*}?Aopum;h_52?EB%!%nI93;b~nSn4qJDv}:^6|BKZ`;j4slOl@}zp3IEnk_hM~TweVv<K2/x&!}Twbiml3.0/xPmQ*8Mu=b5,RAk4stV83",aZG0<5++X_%7r`6=V<rLU`913<Ii=D6biJTQG@Ij%7R(fraa>dE)XK?+[fp$n6(W4L@V_oD:;i@7z,@u8bVw^)pjALJCt;f()8_;^uVs4*R*SUhdqoR0~Vz*N^RU87Od}<Du<rS#I"q!_bA+$I#U+Gyulz.2(tw/W8ELl0v|$yQSC+kx*F0i8Y+}Olt1b5HC8_W@KqwD.%l5UUhgCyqH@OgEE:W{7&NTe7JLZ+Ciq+&9R.DX_>_)>BqShW)WN~6"j38Fi|?L83$=aYy@8k/Y2ZSm/Y`wIa$GEH6KDXexpXX[B"<*?dUd~~mR!Y=L@C%P:ZNf/`>"@gtpFm&G8f;v2i?RaEOv1)aiNR0IaEOv1)aiTfjR,(SQ/R&YfOIN;Y?uuMx/^[wXF67mOJr>s+]6y){`Q2CEMqA`Ja!^)%v>ki/q7yGgi>$@BzJm/YCxTZvYC{#.PqP0L6!&f>A@:kgOFpm#R]zW~y9h[:{vDyd2.aHCW2[.^~/Y,mgODd)/%IkwU4;KUT[Mn=64LPn0zz{c_SSan=eWTUcuoP@U!Y,LJUxDqx*xgp+rqx%F^x^/zx)E|^Z`gM}.C.ChhMS@h$ku~jew!&UG6_3|_*hq`,,bh((v?;*^a~_D5{hS>it#mh$c:?q|~;Cmk&,G&v$I=iF*&hGmAj"h/QYaFLYaR{vil@}w2sK+R^kMX*(4=FXw`1?Cy?T&<CRwoIwzr"rupz!~^$TjP4LPszjYN4m5OCNK+{.6~ZH**q2iFi)gyGW2KGHtkwIX_r=}e&>g_5Y0Wap*bGfMqp&%iu:5XHaD"_KtFoq#O7ek.RW3kd8:OwI:),b*HP4O,gC5R6566+1KDw`.+U7+7|1rm:?;),j|4/^@@6I[jyG}m|UU4e^aC,RMAp(`LUZrf3;1k:SZQ`7UEb9gW^Yu*)f%wMMJEbqQ!;1Q;@TrjU8%E.9VG2eI+r64AD/^ou*ATiGC=i*kD86:mr2*!pH2W^0q!,;e=&Ny=9BW33grYXW#dnD8I$X8ueGwJ<02M^$y3t`"fU#9;18QOUHo]!H#2*2ScDM]HQm,N^$m5x2QZs;,!PX!UwhVd.m/;_7UJ;eWF/;~K=WI%m+;wHO#slV5X}KEZYj8*8/ab2*T49I=_,6<81d!F!ZRhqa27xEu0p_;}?RM_2]TLUAKub$p4#@PO!H@]Pq%!"bf`&9^Y>83)8/.`[QEcFJ3o,n[%!SFaT=?q.NNQSy~Y$kMi]VOgc59rV~%9Nc9I+I|Ey6z.6[{JPW~`jZAH3{MmU9#pq^[.,@#)+ud|UuSe}%(YyvkWG8kG_D`Sy2W>eBqBvL>`._wDfFnI_W){.vrFy^@"Tt|`,eC^>Q=7gAk=xASjg/icd&xf2/,q=Sapn`h1Mkl>^0s{Cp_:7:SmCIB^vo}sq_RNu}?IP;3[9052rA%3TP_)sP1SD]v!KQ|&E%A:b$AoQ{&;]h+A[Hps%;g5=gd!,w,o,eF&y!lOybQa^][rYvPW~QvvK*}A7F@,+f3lN.1S!Y]!q&%bR1VB2%HIq"G3CW9pqG6EMX>u9qov}e|}[s&a__D7B63E=n@53rIIq$)w^8PB)o<h?A(5<qph!Z>eD8mS!()x(Yywh#J;E5SEO;9ohe>qF:bRh]%o:K%*EarmiMZiPO^A&#Qqu"CA.{Tpfc>.7`wk*2#>{6&GH*&4iC<%y/&+ei`n:yr~Ad0)i.j9&<`sAIqt~<Cnfwp=_<j+h5C8>U`{m>qJlj8Hz;$jXO^vX/_I<)PrckB0sgMTu@7oHuprX>Laj$o0^mg:1YD(,mjMS;)$m!Zmk;f;inl9l;yYxq9IGYKEG#lFW&.W=s,_3|2>Zyi(pJ<(<8l9lyv6zWd%){1^$ziywVUdV{`K@?1Ex&5G(,X=94:]}?,zusP`Vlk~prH2q}IkEPtO"0wKdoTqp_!s>=,Ud2jsQ}^Lk;SN:T=?@*Q%VhoB!ejw6ZM(Pm,`^%.m3{.R3<)s#H!=@PnD@eiu^YT%LJ/8R4Z@lgVFmTUy1`]mEL@22f,.4rDmI<G6$dFKX{mNYV9s0KD";t/cZkj=gaPzRPdQC]<9s(DSMo2eD3w6.hDp,}q#}3a&PYavX}*}#@{n,Li9+k@R1&fgq}!!oan27$LhWe.VE^GHf?e"aMNT<:N(zJ0_8B#_}EmaTI,o{M4m|9{|!|VC=|8Tdjd3UM?q99!?}67TQHcdOmBc/xi+}aU4lECB>d>gO~ssOkb~49)d"h;zISsA4WkL#QX4<84D@rfal"%YE|!@O83xj8uIc"0{WE^_Cg5rm3su41|7xJ^+Dm5C0%u=4j+8P,^x6%w~W|yfl:^wpm!syA:Rj;X2JI?xOU`??/YSx&!clh76WnW[$FGE<fHczatuM`j|!XvyXF.hop6`i@*q!(1xp8t]Fq3aa>|4SRtjB6Rv#2BUq?rt2XBKv2i]{v>iD{aYb6tcM"nI*VBHOt!]V)4l@L|~G/oaB5Y*7i5rF`C1M;/L"ZVfY.,swJ:KpV(T*btOaPhwLY%RK18&T[eOZ5X<(mCclf,I$swytofQ:uIB(GVVR^`1NlCfAA<;XIB}?l_qy0LNN%FpW~_:ia@3/ol|PLjOLLje?!(7shErIPMG7LI_0xT@SdJXGAB8v0zzqJFo>)W?aec*x671=F]pEV]COfwe:@%vJ|]_,#CZq[Y^[{=VQPO&jeM${q$p<xPZmo7{Bu6X6q2TkQ3h%P;``0Ca=%g(9A<[mumxezcqS1%C>^SH5B&q5w]E4+GR>DdT@ZH*+&%t6IrD&_x|p>J[pGb.BFq>;b3OuA_V%U%R%[yH=h2kd`ZEN)yOx]6wZnOhfR0GfnyA:/(8Jdwf3NHyXBm7p|j,{UyL.LX,/bzyU]L(@#W~V$&")Wh6g}n0l}dzzUy6;4jj^?]v?gGn:POmrqx2%fOHv]m5D#V<KVG1+1,bQf~5zq%ha$%=].@,Y(z|!>luZm:fEjwn[Q0>c9V=rCT;10Id9twp%SUZse~/5+=_;R^L1V>~Nnywv;6GEHfuw:53qTR_r=JfsoI}wsw{3!:`oj25S;16J!1^MlPz)%Y^zg]8N7.7kOWZg;{y1=S42/5{mTkmI;uv+<.VC"fuPVlnyU+f6%/U^HPr.7b!1g<BJrjyY;R.,}o91oUtf,1(oXNzknNL6RQ1HwhZ:WV0jg];Tagms0v`k$&oC~q0`w%pNx*_O>[tl"k1>^`)=rLmq.)11<*whmMRDLb"~Vn~60$^Y,cV1_%i(3f[@~1?*rGE;x1ZKJP6)~*84>J0BI<~[GpRbt9}p)=:m:]@y0),"|r7?[FZxf8?m(IQLTe>ZG6%Z!,^!v+VdMPcY{^X{4KrK?NUHS_)w{/sH"tS)1qU+?;FMJU+6q6]r9rxE7/cq>dBW!9sFgoqUJkf6uSuU{+Clzz;,jdI6f2GWMW}1|V^zOa45DJdT<qjO3*Bfb(_k~plKFnX%!n)bK_ik|v}6@J|SCZ4qibk?y$$`6qc9L)v6eHH?r5=6cjj^fu//(S.N>6Rz4gCjXJb>Ss#~m]N=0m{bx|X=7oGk8Cy%u5"7;u4KxU6%c[u6u="a{o]IUHz]!*yC?`1E_@cK5=QM(~P,2Pp*)kEw!S9oq/)#Tulq2.BbpcU9`i,$/HQHVVd8F6gyfr:S6ygrA27o*^RFJ?N=whW2;J~2%78)?:sHPY,goadA4P0mt!mv"Xn8G!J_BX_c|:Upd3jlLr@wftaiZlfGS"`7XGfqC"Y2,1[/@JxU:[HsgO^Tq/hYVOg5ZNIPQn.iSNmFga$cj%;<z$gTic@{6Ip3l2]TFA!)~Yp,B>lTNXO7l`![TQZK]*iM8=~%MwTJ[@If_^)##;O1VJ<L"g:I3xiIpmWM$<7./eVUXXpDKy:.A)!o`&~rPEW22vBtSb)/vO`YIZTa*zho5=BuZjAEJpZz}==>>y6Ll4>y<jg>8S<`l0A4~VoUe*0xz,8g[|B?ldHSDd;pJp`LsC|A,$4!B!5i;pJpQX)C~qiT^Yo,.x}{=)bJLb;)>gz%@/d6k^6pb"1tr0"^h^GhV=xX+>ag66"7_n}iDQY+%vga"Dwws7jvbgZ[)PxaAD{UMtLoSMuCgAMA>Ald0DT3IG{WY@m%$y7i?Z`Dcix4Rj4QIupL%&QIo96C>=:2XJlwJ6UM5FHKy<Y(P_I<iey$ko#7%7lP`[@)G<47*/g0kk<Kzn/x.o_$bC010zEBcC_eK;YwrhL8fxj*f7}2sRs8_(6u;M7UtMgo7GOUqIW|o@dx1_8b%Z=rpx7v;6{)kif_[,{$|:)+:]>[ZL:wD]Jk))I)UX>(uRuFgdP0{:PO?Goz]}|{e3vzDz8bOC8b%Zbp#Zb1y2<i88IU_^oJ2]ec2ZVXaq=)1r4&&Gsz}#BxE[HA9_6A.IdXnGpqBOTvR0G!&q"9|j^Cu)KhboWMq6,m,n0,&y6jSC(ywh*t5zUc_C<]vZa9b?FnsB$7vO8H{Qmz`i$G_%Z@sKDo?p;NNVeu^J|H90+NYY0{Y&1uH%,e(8pZk9rUd%RK=)H?L(#x!^i:3,q=6u5L16=ys:uC=DIMti!?</f|lbL~4d!$Lo|]09:hBSpJ0u`*AAN/X!$SD"LA(uIAbpQ7XDYX$6HHG%s6U,YTOoz`+$w}cVk91Ww@6Ax*QR8&{Ye@Cy*1*E0}y4~InR9YaX?~fG%~NoqkZ{9&pDvjZNfMa,QRN#WPHWVU$m/Ig]^3PLGOBOak;WiB++xg<0Ec=Bf4BD3rqqY4m!aejdIR1vL<8(.mE4(PPwjC7jlZS^h&uj44$dhI#O_f|:.ThI8n@7%Wyg29,N99r)/_e<mZlEvo8zNzU3THH2cD;Z1+dcnZOz.%Z9qz7!Z9PM7U&N$7A;E^J%dDl@267dd?_a!5/g4O$7_2i*Qd3aeYJKjL5u4L+r~t@M~&z.JE!^.Si(3g{4;Q+hCV87w/no,)_&$@?TFm09*tttWjE#RN=FQqTa){A|Xq+d(p.:>1e<tDZJC*kHD[jAmzeF30NN<mA8hA8>D@?i+On,%66MOfJo&GKM)%,X<KkAi8cowk~QVjA7QWiGPIE!63}@<bi(Hl4IRDy8<0h`C#/WH^pQ<KD^oQ=B|V2.$I>?`.vbE1n2GJwB]C;i)(Cl]14OzO(OzWOayHvY_liO!9vYQ0=7GrQLzj#YgrZbB@:kY`f~`(Sa1f3*F1Apez6snyC"Eh|.cU}B=@Wz2jZ&mq>Q2T<Sfc95qp1>Z^_:HsZ<{3tBXL*F]<244=93;n%h"8rD.pad.e%x&tBJ]`Nw@g99kr/Ln]i==;g6e^V<UfUk(rAkXmz__`BgL$VGb_$[eh[i~`+n&[&)%g,^=S@:z?DwAA*v$?oDC*neii2zsd#q~!9pn6biKc%2:/(%HAW2h|HED/2=9v~pR(frZn{xb54fN=tjCCtzVk~t=!?SqaQ!7Vj3l{dk;q%}xMFw6?<1k1`T5VS?9&4saH}*s!{3e]B=J?:n?D,IY<5=vz@?VjKKH,CRl=IFY@cV&NSJmd(n"lc+ii}$_)umMf$c.*p7>iMl[5k49WI^/.EEf`Tkbv.+K/AEE{O(IfbtJ%DqB9P>ik5,YrEFgXf&{1<]_ac=vzgrmr67$L^$cRWrw[xrm{~@C,*R!dg0E{DqW.9ChqyT!b8%7_nQ9ep>>{fr8os62(Z6FomFw6X:D!:?jjnfApS^`po=9&|%a%Ogf(6=3hOLAc_pGfPRV>s5ir1oidh7dqCf:r~`dk%}"B[+lr!z&!6~Er6{Er<@R]#2I?)K^4~%x*H6a<l_2Q3TG`eN&7*{:OmVgOpgwh(!wq$c<;s2g]Yxkmz939EFAJ{s5X&=rLxtH>qi}C/Ss/29CCiv/l{<Je]k;<ZSmd]@#{{qF^!VhQ~em$gPDr#YPECc(sR%5i3li#glo{_,7t)+Q[aoF#ngBVx%B$g%;<(<?{zho9;!m(,S)XRP2`ZexdoWcF5C`CJUh<yfHdJs6f~8Tsj8r&8/t{y/zm$9cT@Tn#S7sl*6KJXFS%"f6s:XL)=Dt|ML)qfE=qR_9^t99xrqtW3y;;@%|Yu^&)*^o!MQLS4RIXS(95:/G#j:2m2SrJ56[()xS(*^u`!,WS[?;E7zO*6*E2s.t.;b,un%1YQ4(k~9A,w}XY@3:}+sAJIX4R{l"n!;;COO#UAiWyz!J+vK/Kr3,58Wua)jBr@1wFdSuPQyvu.(E;1x.9Sr}nuBj@n@ItRpRtW+<*},0jGh;:b45ipv`iPs]c3{;I@XZ.%jE|np&%(hN!$;JEj5<Zm:M[D5e,|[dwlrX1/0w*65?o(iJw>XaPuyb?`wl=}G<g|OK~*[j>|pX1&JSG([An7P4ChOuU+XX$LQ{%}NB:k:g*:eGydO`@?ma*q$,MLne#5lNRIcB#]tR<+=N^(|?0gv=?e{dk0IlD`:=03CLR.*RA8XL<;6LU0~p0,C{,WuCchf;IZy{_WpNCD2jqpQ<1<e5TdiezGfkRP7zs{**1cd/}WG6a,(e}12PsE^HRaD|94lBjQ8^/qU4<<j8p$nJSziU#2z82SC!3mEbh[HvlybTYM>h(bTlEiO??OzWx<`:I!_0ZTlu#[Zun91]/*,"wZkdsp.,bnQrIHh[ksp(;@<;lj*]/[zH15u~i#Mz$??fgVUX&u1,YLfi!l`bh<2bJ`1i="w^zP9^{Im~^JTn1A[}u|IR]N7MLqXDA^NJ`M%So*xAOp!te3O79i&W:aFho$}tkq)2cU@fxoplua;1W0}84cB+_R^QM~MzLCU.TiS6,+%+_v8vl{SWu[?X3In&*B@{1;JDE39x$BtDAzL"$AR2P[fDzX1tCx,In~@i??J[/85Ma(EyejY[X=$GUkE]#MA{[O!:WJ9#*hX;?i8EY^$PX{nljMQ(pMQKk0e|``^ai]I;C#2=*{XXk=@j!Fr2PSnH+tUy1T;Zk#lLXR%AUke;fY3P#s)i=@O{,ArXcBr,dP1pCac{PR%qCj{".Yg|n1n*:}gd^0z^YvW|GG5V`%/(4Vl5xo=TSqBJnU#W8nQ+~4MJeOW6@]Iw^GsCk?=VrS?]azpBZJZw(/IPUiSn1;UL2XV/e&TiS,LtgUuLB9C17lip:ugC%rif6dFMaBo|)nxApAi0em<cQ2P1ny7Pnp0"BH6IkL^vB%e}oiQqTJXm%KakUC#}iu`6.?x+F/m1f0_QU_PR%X?)*toR:y%al(d#1:vqdnR9O4Jq|uYJj1r*iSlr(j![R!jaNgT>x,y[hSO34h&CmpowjGt$Bakj{"e{Ib8oHmufbp`7#WMuv=w9hyuARO"`E"wZkZgu&ffvx.*jo~gQ:Ar{Zq,`ws;_VGn[@SUbQ{3"lXIrqbQ38Kkt(O1RWMVl}v_<bd>uEzL[fB)j!n`Hdf>9,o`7$Cu*i*@P6=#j`B?q&`F5#*@,+2glZ%7+rtms{yXq:lfJv<Zhb3Y$mu*[z]0|@`nt|6h)6=IJ9zZ_MusX,Zicis,J0^Sx)V`t1v&0]a=w$f&2ycR~!}i{XjNQXA)+eo~Jw>rqJbQ)#FfdM_!lF|ta@OO|_qbPdVEwR0Iquujo&Hg#psp46KrR_>3f_93Zy:yh?Ws=h)2]}f%v=J_*<.)g{.S*q$A7^_Iaelvj.im59%L=I+wMzPuiWNs|d8IFm5p,+R.URk*0+CMUNH9Jg50g[tFS?qu=y.=]NcRZukd+wKiXkRGt?VV*n~V+U.y7x{n<xUpjRp5b[C+_|;,@34={d5?FU"KzLK5/JVw3xmTxoqO(50<LTnYMT*[}.E]y%!w/<LPSM8@S1,%km|@~;i&W[Z5dOkbyn460!2#*I8ODjM~_2#&s$[Tj)bhECfV)|%^|{J+1<YyleTs&U=sc=k:d0^@A^!Vw;>3Jc46XXc^NU(uo#8Vmt;f8%Dh+W]ei(,Lj728td&%[rd/2vH2FJ*b`:+|#iX*UlB:A}ryzyhxPX+*h;FnJ8E>09nPV1=CPu,w<;SZp9MF%55$qRqkk*_Me/!~KBGcG7@%*y;X!?HoDs&mbi^S51>Di0_ers<.?o,wgPG/dd&:QBC,N4q,#BBa:Gy{mh{&6Q:)y?_]W)K0]!z)e}`jogn8c(,1O|wpb(#~81]=?r!`PW9_u.r||I+!/XF4>d{rSoY~wbBkB`at~R(+?R)+Ufm/%f|NMW?!^bYO5)Xw_II>J6|vLif@L@`axbAri&i}n,cz^6VG:Y=L3i;r+rT`Z.;y|9`kvj=:%Vp[E3EtOs&@)O"xqS/iRvL@!P[{Y_nEaX.WT*A"jQqMd]$1gfB:(#u#VmAc20^K&bft+8Ir9EaWnf+IuyTP8ES5`QT!;&}w"Si083q6<AEyn)8KDf6a<dFJX!ty4i`KUBLwPk5F2gtb},M<O<6=w8m7*HxZ9+/IUt?VdZ38">~vNc$AqLN"t*9H3)hM!4~FCA(]jsLP8ueA[93L6yB?R}SNAEtt2qVj]K6yRfq?bL1E]CKt0A_kep&5]CSetM`tCA?Pys?v.WyJ[`7ydZZWkCgI}+riNBCw0:W!S})|Z*kp<Hcg<gSN>Cr#Jnv__6&Pysgw/Yefy7Ctt*9HZG"tfGB*VAp;O/,,wIftIih|Btdp|Xqi$I=tr4FJ95KBcEAuHYRd7H7Bu+O;c&<@<yPGN7i!0:O8c;$(DtuW:C1PkU6yRf2(aJLBkt^`{edZ(Y>G@4;T8yQkN"Nhi$e_w*zFy41kNJaC0AhA~wgPcA|h5R1BGtDA(]Bt"LAR[tP0dZSX;c6xBu#}$dmx8P#j4D_WuMl4biPiX,7_&g$w{aNEXjBOCcM!^NCKxIZMh,E5QXa!yQVfNzqkg<GCXPZJ&ux%D:km86[!CyEd2dfh)ouN${I2Z:ajiVTe%P%qZG5N61.%fr}b}e=bQcP*~M1U2Kh;qfx#ny#~ldWHg1ww}6gTM=7SuK/xv*uOUld2Kk:Y{l2/}/.gb1({qo,nzweI;u9V[I;S(/Z!(:=%g;Ye6FyG8P,nD9n06!m05RrC&{!OL6lm"ac656`[~/QbX3~{VhfwKvbp{_jXGljy;m:9V`d1,MGre~j`]IFv>Rnp?}r%=Nsf"!(.%j`+=!(;J0+*Zs3Cc=u=mq}Zv)*x1t/y}P3F6^$P`:XcYYSzpjF4y])laDNanR&*Pp!<<3swWt{k";(i)*NwZc,)YBt#9EZv(czyxGf3*#Cve!.,Si:|=/;?HX|2j&q5<i:([q5~8}r!tFA3D>tmK{_mWS4`YgiiD@8jD`B?u|Dwk(D2Z>BC<bKJE4mZMng$~?I)i=}GAoF?t7YU]xpCCEByVq<,@W6rar&TRV4oAUWui)kiu|!<TvC,N,*6<B]|"uB+>rBTAKfb,BZWxl^KtCD+#$|?3t$5S(!DI+.,"FD/p~qo@lv}oxs*xptQhn4q#[<3mdPyCsMm[o(@z=s#)/:%B>uG4Z&R+501vo$%oOb|@6[D?63Z457h>dpQ/{V;>KqT_n+dR3o^hd5Lx*{mMq$p~imXo=igmOw9j@ATXdE]f5qj_=CvX4t}Xt_<_sMTrfClQb{}~nX#jR}sT4(&*W99tg0(k>q!<}S>,xA=5t1~2sba>%N9Ypd(H6v#5IW|zgsdnfA`6_}?==YgqiSn6;G4q@I^f!,#Su&JIQ"Tug_l_kP~k>73kKXQUe"]V_83Os9Fq>*^&pg,2h`m^;=Qd(}]0TikbP:TM2kh)oB2D&"7#YB[+t?E~DkS>x%SKj@c2Op7VMP6uoKmAG>tyt(?!m=wjtkx;oB+3>`!O@=$Fng$m`I5t]NK5&!J"nXu|?~N@Wj_t]A%_TA@j3$(>J|"]xE[r!DoAw:(lUj[r3=E+EDbLp83g~)oF@poG@4J/&wdP~*JL4Sxb^Q*B._=M*ds=;_YWkv1ML&XG@`CRG:^%U2}s:QPn:*U+n|xrtF.qFE`^3;,qCJc~_,yWV6b+&~_Gczz(xSY=H]ZRvCS*aAAKUBA[h?Lq*XxtIYVrtILFAKA>HPh8Z[Hi+:ymR~XAAAAAAAA>ClBM<v#G#`iMEB`;c^ZtaAh$VW=jv+Z[?{w_|>|Tdxnw.*_c.ev,ZCW~tr`{.z$(%p^A%M.bY:18m,Smf$]omw(iB;A[;vS8Q|1~P>>g1l9CpU{TWcU(l4wW!;/oe0V~]8t,%Lk<{<[XI|<4i/Iy/H(X3O*2wCAy!sYDktN,}5H6=9vf0/{l[%?i2mx7BBrm_]J{(/#AT~itX;O`dM;,!LNtm+@gEjO!^;9qwRF<#/4+XDZW*dP3Mb{$y`(7eH#Z3|{[?TH/KwwCH"dCFFrTzn1{`@]rX]AVIkmexx&{GU_.B.Z3kv$YyGs]_7yLWPb*yj)Ab1n~6NtCiTTi%Gq5|8.~@4RT:,9W3JO):Htu*i=7}S:Oh;7Eo;2+mF`3y96!dT=/vt$F+({0I<oyvrO`idxp=xg*l=_ER2kf$(/P>TwFvg_@6YC(Ea8*.EfeELxPFzqTl*#=aJssEm.vx/lJ)0hd*{~>*gw<f8Q<uf9N$Y8j7)>~$lacPzEFd9e[plS26ld1H)jJHp_G8DNb{5_6;&,L17e8X6oq+:;Pt10}~#/TfO)83Nj]@4oi6!g%6YHdZq]V#z?MW/)dh$RrjX`&ZTDx6gk]txdt:gPc)qF~5zzSP[y+0DZ8C,mxi_v3$,#I:2;"?"N$AGD#N<F|O)@EeU/G=~ml%}T@&ZNtWn%3nB.OVgxibG"Z}L923+o}JwP)afygMFc8>Zbt!]5~EoUk?W95>*Pn7"15l2[wr7JtijcMq:ll7=a9T5WGk=wuNB#R&k>^m]l9Ykur[hJRVYXMzng7]G6bh=0N_p5)h4hI[>iJsCuE[yu%C,bTvy.EKThDb{aY_kfG)jmu.AI:SR|,Fn`LsDogu0h{kZao)[3+[F=Y%bJlQ=/XpM=823V4.X^u"h@@|35mwSPi}Kcxc?^"NRztva^/MAv={B.7D1RT^qkxI<CP%u.@I$o,)Au8(EV$Tx!EWR7#J05[jOOLX!P$F@Oa/c/Qe]OBSA<*M.B>fi,Nq`80rJQMDchru_?0n4t(>p{ImrXeu*g?=Halb+;C)=4o<JQf]&p8UDkJ^6otJAbFeh>KUUd*H?:aJ2XNBm^ATb69b9QHx^b>SD"=!y/;{_o}Dk6V:o0"T6[lr2;%ELB?l$p9RB~~w|~G;:PHq((BTmxIazT%ZrD#"yKUmlvx+1~9uXKk]%!#1)h+OdKw=]QDKSOlM`M+G&1O1l{RB0>P4THGa!U~r}Qj]e9/T[%v=81D)}mxJ6g7j!u)vjjJal%_*LaPyUk%|Z9A`q[K(MzHk;72Y)ap2PQ[E(QaqO<:zI3!_[qLB}7Mqo`b=iQ<xB,agmw<P?pKBdsKmvXo|n"x)c6[iX8}|>p2^@DDH:+=?)/GY1|;!?/!J?o0w>BGt%.&i%]WpjAA7w)$%03!}QPxrUVR:LrapMNJB:[JCt(u:?v&@"WHt3)u~9%qp)hN%_sHp0JT_:z4<G/hl&S55:x8R_o%j_Ci?G^_jUkoHKFQ:2JEV)qg.R@qNN105t4+ysQbJIUHa=.JuriO[*S#~x@b1isC#wyo}zKuSOvhCcl0ZCqZ|e#8?Ac?PF}/E`&caouZo4ClqTo)&2R[2(Sm9<!4+oX2p<DX<lS=Jy2x:ZsSy?BF4AD%By]6k@DwIaBb@(sc?|skYo8*`YjM&#xQ=axsHvrV#e,0ZA@LiB2X#E<F;i?#:%NzEF.eeX@_N2JEFq<n(0xg?1)2+@VD3,NbFlXeWSJOOE?}T9wv/0+>yjWjZD^aL^QR5PYYNoGgm@}B&|d=daHf2;>CVK}QiXH/#H<!l(,Q2dm%{Sd!vBPs*B2elejS0RI)tb=Iu[n<nxS7.VgPKei&=57(tU9u7hiD}553ts<}>G2w&?W~k"Hf1^B<Ei"9DfZ})`a//O5i%{@zqeYhYdXV6~XqkQQY9^%[?.ebTezsrLQTKG*]ZRw.Db4K67Nz6DIIt6/Ct]H1i@Q0j1wu.hPw;9ex(dcu+LPJBzQ,>2iNOlBu/3FyPFdcGuBDVq;.<]@E5V2s]|FSYJlVFBB[4emuk+U@4=d|4q]tzPrr#/nU*}vN25$L)._BjHt{g%kr`Kgad%4v0d*ge)8U0"d>SZKSHnNRI+3=+ftKp"V0Pg>ekz"o1hkny]#U:cxDGE_*Go!><3Lk9rl4;%+sf00BpEd"yG"=<n|Rhpn]!NjNc;o0$&o_:p$*f?PwV$!x@d$QysV]^CnT8#bVl[1he~e$9]yleb?T9$JA6pU(+`I/q8C:0n^;#M;&}#bir?Fs31:xRlmsECwWFnl[GPg*/qs+b5H{v<6=}mR/EDs5rb?Dx6}>{7!l)11?Xdx]zLZoYd``+]]ctZem6nenraQK*Y4sEYF77?K*s)U#6|J9r,"<&JQ,F!$EK3B98@(%p,?.s*_|DkhU(:#/1j`2b:0_De:q/2}Lj`S=UmWqlSHJQUFi)$|NOiO*}(H!1PgfjuLxjHn,2/2$_&O{B=S@B."wJThOj%k%gd=d_tS"=!SpxN5HOEBi}9Z8(n1~W}3xN}0RX^a3DbgNng/7l#K!~|{~F_47UI@r!1Zh_eshpmpR/zv!cJVnmhG<u|BHk$N@a%h>~c0E&^z*N/x{nvmb|R}X(MtVQ1x*ro5=M|_]p@LK9"|6&mntQ@T{PIkw*r>>{9p<>@W3{S!<^7fKA3ow+]5c]ma.8:ss#G~NLMI.M>Pj/`C?T${3uJ)zN"D%>;kQZ,RZq[:=NPp/nfg8P1z1,SS":Jk@B+tlvWC1D:P>Z`!EX5JJ*3)*Nla#S(I7!)7qS>H/AS2lk+tJ8Q7E9rGa/]0TjavHUpMi/^)#mF3JXN_s*/;!LHJqR!E5#orNqUsa#T&nVOGDm=!zdGQ!Yp/jNqPj5](3SXs<Lt.BDQ"~m&iHxWJZsv9:3bVUg{BSZn6:_+2~wk]#G_^F@|HBXL5SoRmVy~>2l^Dir[n3.`{}r2VQFEA$D6_/gxqs8NT<0|)#863,r7)8(&$g{X(2fK!.$0i/bB~`@=a&*FG28JLHtqg.1:XM$+:P0bQzp.ZXa5glhCPE|}DxNZ_J`,Yd&vwbkVm$az%eY%*)S{(8u.^7vKEu%|Jv3/eHZOCSjWx9Q<IRMk|S~SvufOJqhjm%Qnu"Sf<YBz7stF%>;bQQsM1DvuR~5%5cRx`YK,>CX|mQQ^$Q/RW#p)giMQjXto>bP~<.B6b>dP0m6dJ])d(Sf.4o2E^pmMyE2AkV[/kP<vp_`{mR}c7*#N3c3msE7Vco^Kj`Rr%tbBWa8xj}&r/?Hj!;t(bmPWb&WVpapQC>u7|q)f]188XisV^Fu*gSVX!,OvEJv){Fi`9wV#)ozr154lmy>v[t++(To,S>s&"{aDz]?EuiJlx5LxG{0{rI=|NvN0<iUUXW"o2gI7k.TLwy!ahWC6Ktge_k6B3[3tYoM(YusL&AjNk~wK+1;inB91/g`Ap{8N422:f6jLTHgd<;+ILdZ4EUeR5>#^)F=L|o)c]gCcj}D[b.[8L})xv{mK]W*M&~F?B|w.^09|wQG.2+De~Ul7|,?3a/zVU6jXaHg:ke</v]B&dKe[/KG~9c:`(FLc0Jrh7nV_[Ysk4!3?[&.@^9TF!p1sYNdFGqL5*0n,FY0}C^$+mycL&m*s"hD*q0:j!@>d,:fNZO]lq.#87j7@+DP*x[F;gIvlu:gaZ}U+B0*qrNB!Z!+>j&:}L1|Ke*nV816FuP$^/5bw2;E*IqEW;XBD}Gt01o)gly&.mojE[U054RJ^M:Qcd7QAYP(GOqcMj9cgA;Z{hv,qy*UHoJZxD*P1QtTP7hCYv]_r&s74qO@A2pD/n>8N1&HPz/w;f?s.LQ>nQgmZh)t26Yp"mhhz;@HkV7sNQ{ExSi"zkkLsV<{yc3k{C;ZTp))4_Yl"N<mAobhoWK?!JnzxQ_8x:8qYu<!EXpxQ0zaN3pyJSh{Du"DwC8tQlD70|<Ds1&l4OsI;H7HUY)]QOuXt<|ouEUq^sBSHi`C5W]BZyr6),!.F7i&cuMKwR1&~`L!4+9Et[i8ym||{ogXd=BR*Jy("oxUv+Q1IP&_M=4GTM6@9tFrIy#Y3/HXlHV@GGY|D*m)4MH1]7ov*uU~ei.%il*G^O&bd~"OW{gH:}f%I{}(Lw7&jD7Ill7^7{8E+TPBNfrE}0>JnzSV<c1c^W>$z#yCxrX,M~f5Z68YBFuu70|bl0n;dFB3wtVYlXW4t[=:r=ENJZ(e)325UNk*jsWQSWK>"L7W&nQ6nA);bu~$:mc|7vZzt$ZD#WAo?0U!w]$NrB^f$+eMyJ?p5=|cb&AO4AmN|E/+}jt?1pa|"#)Vec,x;5)[p),kD0VBLCK_P_^s!QD3y^G(VGv!+B}Jz93#,htgtO,7u%P):Y+@EW)i/)wJHui@<u6erfsFI46|qSwiXSbr"v.?gz,MEz`YEBS#U_&%z2&`<}3=1j`h:]12=""]e|i{J6K|Zg{,@`.w1;"p:E@{sR6O$L(zq22O2|@`oQm$!i*@~j}#/a.&o.j8v*/D$aHA}ZI*L|Oha18(wn)k/+v9(8zst|*gOcFy/NUK&k1{^y6W&z_`q*3<n7,qIawTRcY("LC8lM;Uwm#12dW1OTdN>6Gs(,0{MROm*2aC1;`AP/~Fe4y9hiRXZ:&NgK}|Z!y:%VP|5F]TTkE8r]et#0DBP4lbCXJ>(12qm(SH/+(@[L/EUT$+Uw=on?A@ukPTGX*J^;jL7cWjFTLnn=XgN0/uW2_XPwc=qZ<]0L3q4c8o&M_W7Z(MzP!(%)coqnlK>LsX<2BYbrh(P6kGw*h5E{Z(rW.CuKPHg[U8o=XH,@1zTLP,%@L)$.}c$n#*;rS5N5e|LMLKs>H%?CJDle//gzjhwnhWmKYY9l;#*TQfK&zIImZ3jxYVLawE6INwR^wiP9_T%NuL@nrsV}07!&IC:ZM[8:C*DH3sMu[.EpTW@(&]L]M&jHiNgM>x:%?Ep9gqi^<%l_c<Vl(8(D?)PQATpF3:J:GEHz*"4.xQQU//fSP![`J,O!qY;(/ka/<>;"*UAwNNjIL:_F|X$*CR)shG.9Se71B`ieDSCNbImS[.8UG)&<C.U;}QzpPdG1f:5+7ye@<m#Y)V^tH.D71I!gPA%q%N1;n6VaTy[8EtC>8;#n_<yOxr!L&?uF.Y>GVUCAd<j(NogEeSlMfd#iawQU=0eDP*aY1gwG/VW0xSo+|;<ikGDTnX.p>%4,0P(x&O=W3kjZX7FG$bAW8K078zm2]`t7b{nL_J7T]J.+<YB#^7*hIRbNKA7?+,!n)8q/l%V{>?|*}w2<nXw>JZ<*|dy29~h,VQF(dO2[|tozjK?c</HM@uDYQg]?Bdl^8E~</YwfP[<e}Cw>])zUIpuKSeA1GA277>SHw[L$"^LRZRRdJACmTEpx2.h#*Y],N6_|8o&c`JIgs_)(1v&S`=kas+0~x2iPhtn[VMWa^ROo{I"88FIM%^[!20eP20_.zXjeTSe~TcD]LY]:IwAdt0>gf!8?#+)Jg27O9IKbgOK>}kqG_Vub)FQ~e]#q&|l#DRDCNsT!ufdRFdRlJ:x;+_">^$"zY7KP9o}Nk;u@LVAiU=G5,}do/qt73Q=TYO}CRR/a@:o6;4e_.d}8$}<VYQG^m^xb,][P/1<c@SE]FP,uI+G3&/jt0etHHDwv*@}DZ/9DMzjGbO{bgRhm^1mL~Zi7jH#VN$.,7!B]aj:SE2(]N1AXheU5:x+i/EXlr59(:MF,|T=tu|$}i:C&8L>s`wy+VMZ/:w{TEtZ86Do[V0os?f&$wO+Jar:Ipd_<G=P.lHxj?[3oe(BzOYzQS8;|<w`nDc&k<=#%Gc>90#1V5FyWY/l+7!wG=d9m[KA1URW5Dx=vO#&.h9%x&paf6g8FY|d=f_4NKncE3#lXdE{Xv05XcWR=yNs|u08VeJc{`GbFKV9WU.,X[xv5)at:Mhl39GUk1r>guN85u_:,_FW+Tos,DHF+`gu7OApw9upJr6PF$m+:}6?t_ILW0E!Lg%2CeXS18tE~49".<(lu5XBF%AwYRU47}DcqZfAeL:N`Kc5:nik0jEfZA0!s/(]dmYCMAgQbQ]ZP/hdQiKG/?]Z{Y,R@;Ml;oXNib6c2@FJ+S>{0G]=D&hYPGb9Sl^aRX~c6MCu+PTj&]Z}7kr1vHwiu@sXwNp3HQlqY*#(H|/Gf(W^1ch3s4AhcuWM^LCJH+H9S;Q6<9D^o5QOyPjqtwS@/4thYVtq@RyM?Tn[Q|W)&XOHWe^^F5qI3ao}jL#L;gQBJBYJ}cJ[12!zM|$Rd?]Y+z+c3K6|5X:T?RX`4,>fuf.1;jh,+n!Pmv,!R*>9zWpo3r/28k8j.w8wN~`43dL4E6PbSL}b?a~JQ?Yt;}1xD^lf+`37R(KE|Zzb&Sz@ZcFl^<c;Q1XXt:V7Qw}QqvzK.L2FX/!BL>69JE+a/`=}S_S+B$IFFp$Vn~OG7iE]GIi],16Fvd$_K=L!X#Zoiibt8@/.ai%n>oiofgvc8;TY)F)cX*&^i7v^%=Y`B~M?W+dZ+wt|K*;Tp>D1LY#eOrfW5K%)2;f+LBm9S;c7cHL?YlaF!rKxtN|Mn%%`yZBG*h,Vw`bZ.5|!@6ZvN~*Vr4s9jD98i@r=x)[/(uDNZG1z9}h3Hz*O1d;_vM)7Cwp0K5^Glt|O<pRXKTQ7s15ZzL6iP8mmURv|wDI&JET=oT|TnfA~%X4?ul=t1/`w[RTLbpK;l8yFNfo&SJ443bjB,Cv!}dhWHPe|uN@&YsN#b][8g.#bVv@I*Y6Vss%O*J3rhx:EzJcuuS#mNk3r,utNVyeMvdS?!^jZ^C/F^.g"kUSmx}?,z)CQw_j^YU/kb3Z.k7p`0"m_$,A)urrGzL?^rWhFHgR2@`HO=^$0V]]t;vB+uV,D:EPs(X#M02nw+sR.w`?R{`P#XymQ5K2farrPSw"]"]EOl5l5QEx}.:R_^)R=.+[g0;`~DCIG#|a(Vz+G=IOI)sDQg/`:5P=$5;;bMxR64x7";gI_*NqU>:M2RqxHucnY}tcN|7cJp]*SPIv2zFU!HzquVAI=W&U).FrVwXZAs71Ko_@s_ng1RVX(_H)BvV{.7$/;l)8~ewS>S5jJ4sKaLsdAe(irXk2m[FNACm0bU`V:aI${`bC&]?}03qaU&YHHJd/cqc|?%b.,PudFX=RGb|T2gY%8hn=wTj%)tWOD0p(2w`>82ue]$`.ooSI2m{/f8dkliMMix(E@vko<N+*n68i(N$v~n{k/Kx)5r$i!5QlQ(d)RkU>qK*Rm[omgc@V_mh1z$}wpdxy{u]^~[HGwV8iR<5F0Km0iI5#2Gmyh8qCmE0Y8Rmo#FVpTy`[dT#(cq{x}b04wqD&zDpoH:YXrK7suL"5.r^!!$PHxws_Hh~kv*&&%chm7_Yr;:WNEQy=9~,A?fU!M6!/pI$H=5JptsfdCqjl_Um,Rasw^>El_k}I=je)j8Q=Qf`,F?w7S7f0S72l6w{tVjAOV/R?Tg0j=I}G$omzl*.hVp:?/!W?H3y(u("v9v5f8{s/g+Ran4j%!yKp7Y|7H~k8Q/aH$6.do@tYc(0`xH2V|uefyjsnD>qpXZG>zw_R4i((5)0+&$MHr22w*1Qfp+<:Efleqtv?%pAl><@O84bk7upZ1t[n!whKPv!ANGr%&PHF@Q9pc@"skqQ?{Zk;e{81_kKK3rU4*:*_GCv!Xip?Bd?kDDfPozNC6*:m$hZ!736KHS#*5J@p_?Gq{$;Pb4C?;l;Tv8fw|_*wbpYO8SvLy$`&_%;,JN78rO[w{~A!}kz.J:<{"$~_[nW;2G&<^@l~#WfMlj_Ax0E])EMMtYRh<Ny&d`Fl:*[vk6ilhld|*^7IX*~#hX5`yvjKo3S~JL<.R:R2c]bX%n%D<$!e.BwtMqaW"*5i=uBIN;vq0p8i9LCJAfYa$PjZ{"%TS`U7t!oi+Rd98,_|9ijGOzu(4Lb+Nm?];YqnEd?Fp~r~Q0jC:_UQ]mN/K#BuIe:r]Zkw~oNuk|,?ipn`ojG**nCzpD]WtzIc/4<$5@(9n%,Vi?IX%jAZ.gPe=Q][aK!=[Oa;q;.PG35f5"6~:Vk)n;8M<y3())Px7+x~QwyM%B]Lhp<@K`,t^i#Cd5>%Vs}rK3z2PL"$lID&=6MYR1TX6_YD/`yI@U?;>!]_J/%H/I1xDi|S).iRj1Li?!sjhI=c#{Z;P|[DXQ~TYLQ#M1bGA%Z;:K:L@Re^g5Q;`o3n#Yr&2z]Ek,!#6".].=&PtZTmJ1q6}HbfXI1.qq~E{8D):SnZ~[6a@n28uuRY[<skLmW!^}BcC%wXS<.7]d`5|t_L@gl[?u"d&Z|[yIDdyS/gKlws7K|}sUw7/Fh[3sm$C`nV7X!*""kTjA})7GW0@S]F.+dEMyS1HqcgI"qhze}>7[6pe*pF@j_e/AC7IJpSULHL3y7Vfv%ON3Uz}heZ?ve/~7et6=h2r~}(z!h?eN0V)"6PWPyGd]DWb,c_766L[n^o6,kiNnv^;WzK"VGq&n!N*2e3#wLfM^B"_]h1np#eB)oB8s!1@Puv6/gY2F%Ir3F#x`CBYa"f~7b>H26c3|$nb./JvVkWeEGLd9%>XX>,P_nH!Nd|IYNf),Bk(x~bd:8tkSm`OUCdhFXR,bUOa4Y{4p3*d}G)[6oL.jT+{CMrBaEaV2x3>%+S7PmI+E{|I#j`q+(b#~!{z!dk9W2z$h?w:}NDWiTB"vzZXN?I_c0)[.(?0.ojz40^O{MRLNY)prHp!/rkEBerv>Mx@n)|ni+.AwD%Y,ri_8gj2r"oF4]+o=Y[ab=EwL9Z9&H($?%=fyY)!a9Z6}q0>3:N6~~5*?40m5Csvurp%,VW|&Lwu;1gUNu9{h#qR7_Lgz"XNWiM@Xn<v]m48{@Ox~{GS4nLql/C)gu++8>GIGqi3z/F%JKH`7|^5_I$fO]|8`uq^,!fh}h:]J=J17Scsz@l!lT~sD/=zHT/QC+:7.3J{&[m]Z4DWu_{V~OU}Ut.c9,ZBLUYWE/,IdBX?EMd+8en+h1:Gz|GA#ZHeA#QGx~z`W@!{jtvQ[x0sg?DlUJQ.a}(3l@iq~fng5#.>CS$B1Gl=Q<J?uTdw_w*<?#M)h{n!st|a#t_eIBSEXxM8J&`y<<6]ipEUWo^2/C~XIi[L>S#]lWaEshF_x?zA7R}05MRe]HYG^0`oWIqs3A]&0z8/tkDu^`];C3&p,T]?fm(p?]}LqvK&o??/a!HEK2Z?@2qCSIF[Nl+[dih!#z5QKL1+wG`{/=3>`6&D)WdY52<`|[__{b@cTj;W&/b@q,*_?8{QJIaA~+VQsX5;+"fd,|P_KQc(F9?DbLocF?N=*ZG$twzT3&NaXH_lf>RC.;P.ie:[13(mu/i0?/QMm*YuNR*LFuU>6$S{WUi)~EB%+(K#"HxEdE3jL|J9~37Ph!PBS7Fe0URN!5mZJ<0|)H?x0Fn9Ojq0g)7x{W}Lzh+X<w,u0<6:q{zsH9#Omkn0YF7^:z)<]#m{7K)V<W79)1eJ7i}l[xlFr/yeFh!@mXEE?PZ&~6jR;OzMz.):wq):v|6!f9Sc{sB=t#iMw$H!mK&7g|__iCJwsj$>qzaD9d1q@l~tX1lv#kr{>NXjdH`)Wbx9:hJ6fJ6|ZAEk+K*q.5Z~AC1Ot{FFnq}N@y{<9yMjM"IteWH2v:*a!vLUby5ePR,;|g[~z7P;#ffjBpLya{eH+&P|KEM(oVj;P>/FGshe~6LTiRZ?7[aZS@Hi4hmGK]2fjf#{2?a0N^5_IK$37N])+f&{#&c*DP8UkVI_2m)XBKY#oK|d~zN0{%|H:7N^YqL5]+040K*$`m7H3BnIuv1Azbi%T~hsIAno;+u{,kz[)i<J`5v<8RQC9fG>Z{XfJk={VNJL?_L,?XjnTv_hl=r@`RO0_BiZl4FqNPuPsb*OOeJ>,S+=^Oho+T?PC?^1W;%h.pQh<Tb_!2:[x[lz`!eRg"QbQb&kDIi$F+Xsk(#5/!3P/kY[i>8L%Z*KFZn+N_`7e.RH:6O:tqz7hJj|SPHlh:tF*(:oJ[YG7w$^2LI5>kwY:UaOb_(5l;>GuUh@S6f(g*{?uMxBy/r;|!SS]/n8B#_^Y@nOPIVYk]GCnXKjWafKbwO7Ly,uy%5Lb:SYa]mhu`+Pj0j?8Sd!ex>f)>_EN%OuS_]XIa<{#bS5Wl7hh0Bn0jfHXOvhDX+DU?RNh6Q&AXYe>zb6|S/L+E#u:X.Q>xme.8*^jn#}]H]b6].QA3B0i#GQmrb!ZeKADf~N*`FlKo[ZH[l])r&?BX%M3`Z$fFe`vrPh/hE"h_2%C8/r)_xy:ZQfHlD+r9971(D($&@/>cu),q*vc/kkZwXq&GEu4h{p~n86cwIME4^5i>6_bGn0Vp7K52?56R:,|k}3YyF[YMtGSED9vece:yx~JNE2Vnvc$I|g2+aVhQQtqa,/i=?vi*{zx7dT.m+e|8Y%9{XV2`bk&M!jr^"FvC:.d$+Re.|$9PRs:(ql?f76n78v6.J^:uJrMs(#!V>+muB.jgY(dL&<`@8A5uB4@{%3x.(R~~)#V^XJuyUm!<>KTRKBfQ0Q</F)bm#$Iz(6~.eaJhN]`p(ion7Qiq/]DHr]7!Dh~P:y)+dH8enFfJ#FE{iR>!v7vDMbDFSxIU<`IM($Q?4{^Q;`YK_wkB;^;[|8_1;l4eIA!A&omF$"PYc~gZe<}Y~cCB@PRmnwk>B5L.MZFjB*n2M.hFKN(ekwM&P]a~JCcsxxi.!|PUO0wHXbhGy(!5W$}DO6;@YA]C@:$b@wt?0|/.x*M^1+i$YblknfsFvF2?o%[sjCq1%@@<uq7QZF[[*Kw?Py!otm}M>?GC*$#})e=}h3)4}pHOT3gJi3HO]gD1XaD.#a4,sAUWf.Oy@,W]~D#a^<ML3tuGMuiK%>74o0NvP2G{b.D|p6~)>g5(!vFq.(dH!@bw}!&=j1=obMjmm,t{G/d`5`&Ce@Dm=Yzk6;9uM<v=vc1:RA=wHR<sdsV,]_1`!D:qdj.]Yq`&#GrzVuKj^CNmjl"QVXUQKfIMaEh<S=FzhRiYY?Oa9Iik(Sv"%:i8|:g&5]MB}/,h!qSZ^G6s*N1")Y!cnZkSKI]}RqU(ZV<iirc{:@y}*:<Jnh_[FX&$GQd`+Fts,#O$6xI2v_!E2C)17dO#r{7@miYwo$sW2&Ll7H%"!2I%Nj{LRZq>K;obxnunfdNN+U}Z/AYc|@rJNt3,Txbo$6NT"xP(W3i%w~@M_}3]YNa?!6#Zmf(uZ*(E<{~3c^@G(9N7AhgSB=bX<w4,H>mzK=o@v<Fg9?vDI{<7W],E_mKKK8,4{QuVStzt{]Az&4%/FShDl^*xgdxQ4$*eQ8vTzXyeO=yW@7$gyu0CwnT%y{fcZS/x,SJj@$+{;]];%|09l@*|^Iaq)0J6zWzNw7znud~c7GqEB4<L+4UR$:S9RhX7%.^UbHS|A4CC!vg~$j!=<?hH/PMPe:/<+4ZDuaQzIH`mxunJ/tlX{Zv5npA3::*=zNdO}c7,tq:Yl}Fi8J9*dfm~@ium9K[52s5bk]5k7Oqc+8?d7k^CaC%=ntds}8Sj#Z9zL/n3o&E>WCP;W_I>Hd3/u;`g/jh/M(6617:y:4x#",G}X5`{N5J,yitLYg@JB(k^Z>FpAm=1)&i[[b%UlG6_:zVAE$>@+sVssBksu${+hqz_&aNL_ruB+Cw!Eyd,mfj=<eZi+S)gU!V{^)e(yzQde]d$g$!K%wr^XV5.6b$?rZPVReLj1Bt>eG^Z=JPbxjP952IhGx*:u{L3)CZT{?R(6(O/^KC*_|Wa7;]hUZ7cMcnA.CYy_vH+n&N1:1iYYx0?^AWgPrWe:aSMs*^08?.y|.yg~?e"vq3sU=*8T}E]3+;^nv["DhjDP?{cNJW6;Rr&9n6,y+x2dzGPln/a=94RS`Y!;@@*59SL3j|+31e<V"%P*48XzC@AJA;]gpO|_84YToDXn]>:/og88H%i2^hkH#P`I1f1Pp2Hzj/IhAThX[_Z+`PF@7kLdY+NinWH~_k(+zO_Q4SP?,MxEDd`oVD(M}<HNK00k!hDeGjstyYYdxx4oC1_b^3T`(0eQSbTH19:VXKmt^VJ$ei#l.uZnH!OHq0J`1O*<_s!SeZ2;SJgs>jV6.;um!py{UpQxi`LL<HSF%UZ"`GS`[h3X4yCC,<RJ)1wL2u(L60)o^~:6o7$k_oo6^e&n)Ia8zD?RWpSuz5(8]*DlHd*H)aR_5&PV"[KMg?<fk}b1vfhaMey*{tSKm,pD%Q}V4Z$VC&f]%/)wpClM_,Xj8[6=t#L/AcLGDLY~l(U*xbBI}*#_l|P0)t&yH_L8uy/B}@!;UsQ}&f"i|lM*^X=?@V30R_|^XT&WOLt!oEVk1|45,(E;z<JZ"5"oA]SqwryW$I=HbxlyPvXYF&PxXxDf~tiIS;cdBcl1j,>0ubhMLE5*XEcob3:zpW![Qy~Y@d+*M%/O3~ONsG}wO;]l$1vQtZXqy!<o7[<h>qP>hRE$fDr6nn`|D7GUt)"xeYiIwX1n.%/)[lL2^tUx*Uf=P_^]|1$M/MBSFhc#L,WmJl:kX:!<t2#8R}*t>BWQHCOc)Qt*Wt"T[dd]c1ZaV$~O%0Rs5;C4wG7YkuUr0OQ10tNHBzjLeb<+6rfe`V(y>1]ad|5]F7Hs1w+}969fDYdD~=7?]$Oq4x!BzSDWd/tI*d5:Ms,k?Xm?*i!w{#UpPoJn7b?5kKyL>ZE,m|9,!w4&<?TV^FHt|JU,!Gp`:%HO~Q8v=6CL=Z_7yO:eKdyMw[NCN_ER}1x0@OPz5`Ie?S/p~=p[w5nt[J)hDEC.bC9!"riZFnU1e<mEi7P|Mi^Hw(pVv_q>4x|[bG=9P?}erisCxJ;Wh5wd[OD2Wgxk,MQnehvFM]1`"}$TNniCh?7}Y/ybbS5A)@^I]K#{8oX{.1pel^jznTDK<AVvI^}NAg,<s9(>VPq)X/Kx23SmVwcvU)d1:U.Y1053@=U<C9/o/0&.d?$e$(ZV1*()3yOKpm*Br(I;s}+vdtY<pn3_5$@2F1Ed`J?o^N,h!w&I?rwSCZ<nLsLFy~vwHSf$h*w,Z36!r@|~gP~sxxn{&M<iF{SUm"N3wl<mti_rtW=[yb1b=ve1<8G^,";;zp*Ew7/*!+2&2Rl2;/)89od_W@`W`d8/h=i@PfCpoH+Zs0DLNLL]+`)i^|)H8_oH=;J058w8V9vHQz7riB%eb$t?Yar@rP)Uj.(R4YgW1y6&xX8a1M9Q1%98W5Q}WW`EuYXVr;zT0@!rEW<d6Vf*=(97.<bjOKD4.nUaNLhwEA.VxD~1O@rxyEAhs][qaGr8[kB?LVL{][_nxud&nyZe:4h_~rt*6Jd[RDBnr=_878gs_=jr4SfJ(j2P/;`Xv*9Sx#3J#(V?<m,({@&3OTqMT6+g`=}(5YD7kRPy7AE$bBppyO2]Ckx?Wcj6HR;2aQZ4v0SX3t+<z27x<l]?N~Y8TvbpQR43s[lF[$~fG=ef#sJ"3q2VwJ]ZJ`rUmcd"(8,:[wintf+#h"sW8F<7lOc/F({)q;ivE;5SH(fI5cc1T1l=V4]aff$qZp5B5R^kCrZ7N~*^Cou,g~9q.$ooI4OSn8,H%F]NJ^+Y0$f8a7dFp^Is.bu^}&vu8"|0KYB];rb3<euJB.S!x2:pB.%u}dO%I(a.N%]di(?3xcnHZ0A~1/G+3m5MYDV6<U#e8"tyOd7KF+j(OiDyG;xRqe6*Ba+rCw]sQ@+*:Uf1FFrb[popHyTbhq)8j+V)!?%skE@bRyAl{DtDX|5FV+,lB)y<2J(e]1N1E]+ojQib,C0$W}4P<|NG$<3g!#)6e&BLA$^7}{N:nvl]Xj+4)Q`q?nF}k_i/c`(PX5oV_g"Qr{=u2z>E[Wqm7iOE[s2e#~~sr8t{[|:1]I~k99|9.o`mU/&N^]idb<d4<Xl,|XQ*5mbsUAkuvC7+MsP9)9IhVh9HT8SN>!d"hv.qdy,Iz+F6q~?4b@^Jtm{r6`fzbHY_x)nN~PYPj+#5?_C=60%WdFJnN7]a|HddlK)CVfC_[8[$OrN>~x1BL_PcAU`a;<)bxJO$fu&wvsTS75^BtVkR(Wp+Rnc%.*wNa:*$cF5K7;p_!;w8(q9|$iY<TmXU5Ix{D0?_$~3kHKuE+=ei]u4fzdr/UYzjiK21y3x90&4>({%Hj<853&Vp|.,T6)R1SxSb$k2TD?QC7:.A$#{%qJ@)XH}u_AC:&<3"])tbqW$h{qEu1ra</3K@l0(jO8Ea~NI=dI|VsMvp[nM)&4IWgM/H{x)(PbwMob/w)7Bw1A[ywH9$Jy>5LOxn&1k8F7Yc`0x"mD.n|f`N&1G$b5>hS*Liogz:riiDStp9zLtYR%x/3%l_@XHTVxB&0A=2B"`bsI5b]0x>JA9@qj.]]]x2#+k5/Ye3Q3vW,*4FJo;3#/N3:<]?O=qUkiKj2p?5t$Hg_3k~Zby(Kuud?4fpV)HHP^L!c1mg?QCK/<Rkc~z$"Ws#)K"f3D%Q]Rw2)}{]>;fpBh0k(dXD9kT4ylt4_oO)lM_<h7D<^eSh#4&=)xbk,rT!!GL2(NwwDzg"kRcUD,VYCBE$I7V;9$?c^Bf=n,g+cvbpo;,17QN(Tqj5d@M@s0H6/fM`Uw*oNkqX)D(qJc#sgpQ:Y2uGJxrG!aXWg>`3yP&01Gl1kQss2p<u@v35[MfA[j15#GvO{pdLTBa@RF0;3a"Q[#Sk=KK4i|+V|U3k0P]Em<w:,4MgLZw=t[<]rgjMaE!)UkMcI:Ip2*@h4=rtN+9_`~<|Lc32{shPeA(}Lo0R)oq3";)^zvq~;S&{Y!l!MOQ.)#8!ryvoGwhCP53lP"aWUs#^@V.XG1t+0dMh@&>tGd?QU/%&=6E_lzCGk(:&p5tqG&I^P[i00HN?,Ld>2|9TGv_Oujc:<D/?v$9:r<R)fAhlz?/V5dv^u=^rR%L)k9R,RY#MNqp2xf&i@E^b2BY{Y9J*.N}%9CSa>jJrzbwKF,oLx9MS!Pix;<t.+DB61t3cTxWW&dV^JN+GYmMMF98BJ*(*xVPunO&J&0KX@cE_f@J%Z5019DZWK#f@U;nK<ccb"4]xDce2vwufjvPONZ)DQ[&y:pr)UL^+x]WZ5ee2LIxl0Kgy:m"R.l7$O0}N7)iEGQ3g2v6xz%)0/FjP2ZTA9/KC#Wvrw52~w@ZQCcqL]XU>YvAOr#G$8A&=?Xp]xL=c76Q&ppR.x,_}!`vjhgt(6KCkb0VQ]Kp}]NK&!11:9BFB[bP`(yxP!/!l595D6VQ%$94.PC.N@RM%lfl(*uAY)Pt_0qM{fg!~kSJe7tn>h:}kD2$GqA.f3|QWVMY/.gt5PMzSDtiRJ?oiFnUjlsCi8srMj|N?@waq554%FP/,c[JR=Z<5>~5#I0j<n0SPbt&3Mt"pVSg#J0#0`i,quTxyB]XO1`u8*,cKO]v"z:hFJ`.l=T?HPxqU<mLV8d~q6|7G%WeqSwxDxAo%(N.jqJdQ,B@{>pexM/d_dKeS1495"/UuN_Pc|)ciq^kZ*[Cr]C<evN_qjdWWx9_cEXD;T/QDmC9J!qnd;Ydp;z*)dAmMQY>aj*x($wu$hq6lhg6SizR4KUYE4b&_J7!a:05{EB@E+",<zx>=G^P+DSR5(j;h>N1Dvu=O""0":RTsas4fD5x24pt2SUvXih|D@tdx+Olghes:sMmr0vbtcyGN0!aWT8s]@IB/amg}q+_Fu/vI9xg[N,WOQEhzCI%j|(MN;#)M}NTGUcOkN*7)8Tz*]_)nOK#Kc9~/1u(%k}xfxv3}uH%~E5u+REVnH8j;bH5J^I["Q}Y![A~`oi(F38cW0_}Kld79bO_FoB(47_X)L:83liV(:"]BjN}0E[dOeh:XId;UeT(C)_qSTH5`UC@MD42]4Vw{PMaD)f[r^?bBsBE``NO)CZr%5AS]o>zztS`GD~c%2F/g)?XdCUE<C1qnHf&rg*?Td)QT0@6d#qwUtXMeTlV5pQL,F/iHH|lRzgYp5VAiV8"{MG^)"rx&m*:<HDv294&.?.B;;kXzXo}`=Zf{2"8|WmF.H46eQvv?~GR8*}%IWAdd;l~MO>tHN|yTt;tT4K1Qw^~f5DJ(?$6=%/a|/KhC6M?`oEN"Do%co]>jb#y0yGLT%0f`%cG_6+Lw>&#>Qq~947tY;~Lubh+1aCh<c^(Jnjl#z:M(I2WO&58w+nFjy`UG;t#~H.#XF!04vT/hFbhlDq|5QSrSk<]Hm5djmbrN0H=lDpM/I5R<eO4$%~toJxaC)qr"?otxXg^Sr%P60J$eYQe1A~)HAE)az]6u?:RZ&UtB}2WA)]vW15QOp48elq4Cd!Q>hpSOMTfm5kO3=Om:U+m3E0v*deElwo?Beg1!+bBxq"u^xTtrNjxX[L6Cab&#}xiyUlilU{E2$};"?JXxIcbY=MvB=Dv"$L96Q<F[5bPg3Y]B)x`DmX:U%Jumgz98USka}/f:28+Q]IAu3fKRw=CxwsndKfwl~>>*ZxX5hGpBroo?0co[9W~|{,izF?vZ[+rINL}q2+Gsr1HAUx2heahg)9ZaE6d<u_)XL;<"{9|A@jMGAV<X+W{wb2=^j:xT&xRs!K0s5Y{ja5^lt*W;!RNg}+gx;bNEFFOaq.@uXQ@*vIFSo/5J,k1<uQ8KYoRsAHp!Gm1,IJRy,`n>bYXJ)H[NNFP*@yR)9]^aFODqC^NGugX"EY}y#Ymhha5IH]m/OiMF#9/1<Qe0XMzH}[#yDH`fcT4d*T6zo/0jg$:.+|>yP*yQ&U0m<XcVRf_0>$Fn;!*bgzD~2oi+JiE&5ib_jZ8=kqTVbBG:J"B~]f6N!Y10`FZbH)h*3?4z26l/?#i,g~^#_5=(>Hbum7ieU*c~UCuyV*]MK?Js0}G!Q{wjR&zG.Ks5knzt?8PcQY5x+tGUO}nj|d?u/qWzk/gw`Be1f7:Ourjxe1VAK4J_yK:o*b"7<>S42JF).+YPCK.k__+<YXmOqwp)#,keEc2_F7$@.o6k_2!m`J)eC!h%`shOYKAZ[.`ls4qx@iXqN}|<RfK%>IWzfCm~l`.M5]98Hg|3$M8`S/!{4R5Pbdk?{EI)J)UI?_&b1ViS/kTm$]T;s>@7g;f=IsPSv#]~(jHo~.tPMY@f4mq[Gn.@G~i/MmE{=>SKRpLogfl5!a"Fi"(xs<UKPDzP}afqREzf03."a23}4=Fy6xl:gObW>c{k,qxjc>L]aIi9sTw/GiT*_!!aGr4XM8]q<Mf(]_i4;)$hF;K3owJHXYQL5ZPw$EZ8QB:gQ+[<3>D3=)+63g)I]X7Hp2FahL8i?33yYGiN|k6AE"qc.=2GiTXt|(+92U$E^]S7>,{n24NrE39c]VMHhj#v[uSY0v2:x0`+BEsM&qvO[F(.LUUe^0Q)m1s@P7w=(s$fxJGYZL@eS/tD1}P*#RQ8fE]~.{5)i6KXo|?7_}8i/"^;rQD0>,l:w^Byr##{5XAA*x%@gu<R%a56H9L6!0!P)bde,9(O}wq6?%qA0[t@]9L1cKwEk9M~/1<TWf2Zs.zbe6rjuwMy=>%ScUT+)NsA&(3A=vHB/gk+,a497Ipj@:Z|pe#_`e+lvLb"+)v(22=qE>rN3gG>GX^dp+AXs6zm~vq]`?4Bz/@Ak<)Op4@xn,AE_7EpwO=aldyE=SE=2_B[bS8aCDtkf&q_FuQ^a54@L:_i"n8OHS9nF$vr"/i#63z9i1B#KbTxh,$`~<07YCc5YlGLo!_AW}r*6FQRn$Cx}0v8H}NykcZ/DGUlq:KTv[Fz;MR#v=R[JF{teG@"/V6pw4h0e<)6CpU[8;5L~@4,w9[v46*3}mU5c&B@K.wDf_kA0%~0~rN3+j)FCB~,[r.G}6>h|ed#B@?><pUE,<S5lzX"bXMclLuET0B"o10Av[d/[&|Y@%Cp<")QBg>lVjhM|}q.LDt8x<8rh[cNW.Y?O&&![J~izsb8iy%PpU(h%y_<&}4jvJG75A)kyX1BdOkl;t6NYk%8{:,etxkgIKpn0WCz[ZLO/8qd.AQ|[XTST;K2~ACcmG]l:J/dMDGBK9HJ6@ow0@7=wC[ez?;Q1oRpF]cmP.h=b]~2#lmxwcApk)mO`6/1Cuf3X!<vKq>IPP}:K74I.2)YMt![/aP{*YE~ASWpD`3h[_^6BE+@J7d819RcL2,dnG{Sq#XweiEdb30omlNi&q4h`T5>5_RMJ_cvUA=V[LYkJ|s4ZYX:n&$gx]f+&W0v_qD/09@U=J/:S9v_`!Ni/>"^9@~zr;z{LF4XmxaNoM*b_+Z/q;Ud{g<|5lb10Yb~w0C7lz@?}pxg/M=l/I;S$<5Lt|c>e+FU>P#[0sl~vtfMcwphoh<8Z6=!#z2iL6F.82#+lAg<#GWa6IZa]}V9JuX^40q,KG5=q]THf!8*V^wedl,1)@tPmbQOixzsxj_Qy;!"}59G4bwbiI_wB%a2ieU#b;o7!*sI016`y>f_aoh[Uc[Q2,3`W,S1l^B>N1&fXBkxeVTervf31#[PO4_o>sqFJ8f=EHM;+DO7LUFc]~I8IihWPO}~?3.vk!q_5HwN>FbU%t$?&_3pLHjK9l`{FbrnC5x5:C=CtOg!wK=+J[4^reI,?hlb)x]+<e?nM{HU,nKuajm`+PcYSfB,?r##YU*7F88~AnPtG?Wiq6>NAjjSwj3WRYY2ZkiqsV8d&[IM#&zl}cwk&?+:W@@ffr26a.NtErp5GW=m{0a|7HKBtuZO*4l}FJ+#R~gvCexD^JERbA`+(Jw^EiT(&hYUz8IzWoS2j7I`s)D!0"19*.)h;TFDjLVK:$=VM(C2t!J]#:iBkn0n+eEXX^NR6P26Q]i{9@ezB2^OkCiTb;N;d5uGpz]8FU.Hg*#(V&d0rCFjtQs+B>|J,uw(k|2SRkIJESVRc2&jYSMjJTX7J2NI]$WuM%jO|2ss&I;*[]$oa%J"MOnQi%Bo@pF>D:xYwvEKNy[!C~vsV~}g+ua]^}>{UaoPJiXDp@B>KlN%dg"z};ZztPF)VQif+*ctA|0v60"%?R$5^k{cX1BAVujncJpl21x?fF}35D=Bs|;{kuZ[6a$I]v|~vR!.1l`B+O8w`:O=$kgGWTb9ASSZj&4a%RLxkhOi%:Bl;AF"Nx4:$InIF+PO^8!9kiOtDyT8c[?eJam+ZEmRJy[W[bQXcRZbbN^Hrk)M~tijM?Pi11x`*o(}86qmEWv2_HzX/6|@z;DR%;RqAhr]@j]}>_e}xYze``yJ^&B(9}Gj$dDodjX!qJuW>ny9i^$B81NDz+)DK4CI4kxZ&l#oj8d5Q],8QP,HEL_hYk1q<k7.G[*{e@H;~f5^#TLZ0rk_Qi)$X.JD(;d}w4Pu#`)oyp/pBDpgG!z#wPv=t$rJwk5Q&dXyKC%3Fp~q;s3=F%htm:r3SpNJ[=U^BRf]o.%Ua}S>X"|GtNbgOr!V.gfJ"b}J!s3<_#7<O$XH"0>!y|[a;;$<:KnV%DQS|uzagn#*zA,u>]X6O>FFK0G&Hvv|uE!naJuv_>H#I;g0IabvH<Vj$tz)PtyJw"Cye{Q+&~=,cSqhO!GMd;<K8gZDdvp"y{*ro.Bb|83HC^bDr2Y$|pk?}x<DempgXMOg[PFIFYe68wZiE$#0$Zfc1gIG+l{K,,aj*q2w})F2:sU]$>7}<ZR^l)i.|qTND:_[O(1@}JzMgDGea/Y3yIL2<]i}WQwI4r,G>UBKLzOL9|L=7~bJVL&*d/22Z8fyM]U=w0fK/lc&j(Gq80<7kJdcmLQ1E3QFF=[tRr}pbve<bL$+v&I.s7zRJ=|Ue>aNlX;$EjPD@No,H#b!&RYy}HH}h.er+@7GYqTG(e[owo%I9R2y8#O_XQ`SX97[7.n:L^Ih>5~bKk#9>:7LeNY|qcaxHzp)_}j8Zz(usQ/&(]hF3yP$rJX"Rj9=1UAig1e7W)sy5zK?4/Dwd$,1i%qlw$i$}awVeDF(=1rOO}od/^^]rU({}csbnX$.klSw1+QaI4/s*j]at~cXmClq]s^RL5pV"j"<;~p>=)Sg/:HAi[ee_i)KfAk5o&56)o(|2WGt$U<$oyT_f0+fvB2%7~v_pWx:bwYW++Bn2^dq[)o%)65k[,vQ*h&4UT}v)#^%Dp*3nH;_&`=#Ts6H~"c]|!Wsk^91+rpxKz/pPf8LDo*1!fJG<[e/6[Iy3Vpx2Q/Hb[P4@g@!tjaCG^U|2{CXrs@s8uOt|Tx`RiFVC_x20uj9:h/bT<Wbq{+B=@Qob=He/":8Oo1mStbs)+a{~z=ip;ntx;>XPoyA4`69gS|q##L6]43C^~a2!w@TCRmTDhxY>2KBV("}|`C;4{(G5VuI6)55nqQb*T#p$/tX[)7;R0K}17P8JShYj{y8yiz&;5;lP;:+Ul_{Eeb%TKBqIP%y?|wFh:`zdRBM#2hon=BN:tX^i<~"yH_2)CxK7S&GsxUqxOI)n`U$*9k~)aU.9ctP7R+b7wo=x{Y97]jMA!u$h[SQ"]M>:N*h<TFV]X]!TaBafQ9GE?6p+.qSoi1`AUBRa<dLc],?k,F4#ce,`%P]$(BASK%8&8nJ`V(l*76ZXImaa0u%`6?$bUDaU[R.>i}m}1p6wBpq>>aUZT`/=2l;U<GZp4Xu/^+V|0q?L#7ZZb]m%J6uu9WuIa8sOuU#Lm[N%+W,25^wYQ!XJ<v551xc5,"9E.ZuUKFlJP9l*DoAmx{tX@_|<Qb[_lOH]mDw)3]o|"isxNgYF{|~gcnxxLEKu${>dy7OoFXO{^R1XB!pRQ_izy#AwZ|a>5z4zxcc/q0i<L*Y?_P1ba})d8S2`upt||m/o("^L"n:w_76oO{{eboUr2VVbO{X^uYf^SN%:s]S5K.cS#.IgO*Kw4043>wNW}soi+zcL:qunE%acL0"*Knt1%1jnxj#&5(J[v5DYj@AVBD`3J{.@I?"hr7[<I;+(J((*[j"##uZAbXqcT395G#LOpe0kP~*3+xu95Ki<MCHZDLaP4?ONb[|n43~NLv9yt%#vO(6Ze5Ff1FZF?5P,OBOo,hakNKMvZ5F2=3ZZzg~>E@p;*7)9kP};OoRWK7/oKzV2TPi8e*Z7Coxj:2WI;1hRx],meP46lqNk1xTL66!;Go5sneuf+(oN87zAQ,~2s2&>Nk=D$lJAgz?:;M+P89{1k_vMhNFaHv5T}+h<kUBYTv!V~&P#mti!5GTa9eZm;!t#{w,cMt?G&9JQKMh[[]fLBU^<gNv5g[&:"LS:4ROn6s4$NII|f>BL7*4=p!Z{{lw5]Dh1PvCxs|lyh"XYN/~ma+WY){!km7pKSy|eSIl<dABknn@yZn.0(W#gW$QBSI6&G0tO3,#H`$1v|X=y@a*C_^T`S7[hBMtI]vIaTm?oH]#c$_AsXX6dO$pN:BDIVQB*`~x+t=x`I08nB5J2B[$Y+)#RD1oL:@f`i.HWtI@<I77U70.QL8"hpv#)>VKN$8h@Sk=?z@|6"%*yEsZ~I8H|s,&h0&Lq#FV55RyslR=AS5pIYLL>7]W8$8=]T!h=xG&mNqb(Pb,|ZdmphrS({X@F",,cxGsaPCq^FC*J!?A6r]DT>v@{LsGN66oLvz:,^K2s2M81E)#ZoD#9rrp5F//Lx3%=LVc!5H[FIXStFKI(.B.unj;40{"D8Wz+g`?nwq,EccnVtxyf%sV3.`6qGQrT?%@1C|k0.]d|8)99<MzTG~A3WV~4T:QXHa`d"/6X8^O~fGlqkElG+^?0Fm)*NvI3B&Y<~YR<}OD`LxkeN+|+>^N0zJhIe!>FJ7o]^eHsC.a2F=#U~M}ltt0S)xfe}mu8==ce{ZGTSI;x*E00aMaX[q25y.0uVrjZUD:fox1wQnyS_Np00fjRg(a%[96#+XqA{N2DlRs[^49}[t1kKLIAT_|prs{m(4ePYS<gL`0@QpEkeNz_ntcN,ob"J!rUW9Z`cHs@hN#{}uFB}M_8bOlKdyHVjMZ}0}iIUBR80i&7Y0E>e#M{!1Fxx5]5AO5E_E.J[}b2EEi.wfQEhiFO1du"8KT|G3_e$ID+2`_E(|)*an:]+W_4piM:uld[3g}F`^sT<rCH8uO_<YHRJ.0}F<+0kZ%3:W^XbOV_)SL7$K/iPj#{<2sR}}EF/I*%*.zz4nx0lum5PV54jAvTHvCp(jCLhz}DLLx]Gy,BrO!gC"9ann3SnQlvy8v.,U#a$$U0v~z3twHL0ESN5G(J?;5sVz%WY[mgS&d6Ngd/0K,_o?!5VQWx.nk)W(`{.6O{<^aCf[dU|e&Pk#2Sr((O1OcX5rBtt0GLMdou7a!8C.$D,p>|9~5uXThcO*).(q/S0<%Qt>VElkwkZ:CfgOrU[$_@7@/dGcqqphA(1pRAO<l4)koSbisH|9*n{ME~coJS:@b+XrF;av8+mr07;P`i+,>`]m>$A]xtVDr?O|#KOgd=>I6G)cN?%@Ahi]X?Xo)&Y@Ti00h]y<0(6*~K(Oz(LZ($=UMhPofh{XJ;s@cX54x.=(6[Luw}%k9$D*2Y+<%b"8?QU!8mw=t<hU%!SWyKF)y<IY`j{MpD=.ZiqJE*,fYFo2hJ_2`(T!cmi{0dpE:$1pHLBYow~niG=e|PQvNFW*@6(<nu?=GSLl;[0JDDq6XX)G$L@:XU8d@J@!C9?LeB#2:t1usK9WBXS9JC]z#/ATyz@U8HUA!jWW%7BM*cX#DiHcc({`}hzo&etdxRDgHR_|py#m?Z%{}_*:6t2(vnK>]I[u4wJo%0mQ/>S^6%T>G[M}`<sGIt?0^B]B^;5:@S}egs3IA:EW/b_Cu3p~=pCB&D{afP;;MH/<!wvRJdX.)ovkxOH:ex<MfSeQju&.93~Q.%UZ|%r*Iep?,"Cq;I;cfk/iHSs/4_.(`<vjDoGmvd6Z2,^K{TzW/X&,DUQP]`4CfSoL<7>M/6Q@&i(8i,7k:rP_H!`]Ik1ZWb_iK.8t*~b2k=+J~D{%P:R]@c#^4*:zCni9T%+n*OF_C`/)o[%p|yf<Md;?<mOsqsCYtfRaZu92u_/J!FPs(W"M@iB58qdMybPDTv<;Y=]4EB;;#ksy!R#6Xkd~SqN|*%PP8W~i+(q^<$WHsf9:J?BV`^|iogl`B_fXwXs(%SY99!~nS?)|NxFU)TClp%x9t.2bZp1DRHGHJy{|nd!.SjL4a$V;(Ndal;X,XrRhV.|f#Ba4qTm4>L@V{u`HvT{hu;np8ehj?~fT*Z:le4f5fUCe)X<CBv=4y3]{$x(+0=2WSnba9&}>r!n^XSP6XA8$pFH*m`;HKhhNUHQz*O,]s*h!#9{att+SA|K&A&fN=WdG?v[FUY8xIW_lD1[/rOPG.(|!/F]Ccb>eT!0(Ubpgp4FNT1UHSVm{.eZ/ZKGa=Ty(^A_roPn,HD%#:lc&PipHy+5!JgID/)[lYFRcfZG9Dxiq1|D.|v~N]v_%(:Y,0)fDeqphw&]^dwOUkf.$QF&U38tgFR:(g(X(XDMcWA$:g{}gJnQ1q4Y<+?xhWKq6p05J|qO1Aa(n1n=he)ZNa@H5yUkER0K7R4.)3@SS)4P*h|.2D:rcgaO>mA2u2vAEP3SC>&."v,YMhf6@&[[#G+"cCRGoimjVvI4QhMd[hYKBF6QE;lQ4j?1U.%`dG+"W9Q}0RIkIb3XEPTiq7u#ZcY$D1;.H/iZ~GD2kmWy3E0oiwRELM2~zuJbi,%+V;UrptY~iV~{LR@zf)3~zZ@`f.(SJ^;y./+MBC[J7)EAzKCu#5e5,AuTK#MR[CgU$!Imes^e3xnYqlS*#Q*j14W?5cbMS[sz_8(o?%CkYvl:Ua(U9+Kx`Osm@Jr&^>yXS&{ekG~.`c*jb6IN+<a/r@B[j~ie2*`?QAV{O%Zi|~n/!>&Vv!l.SMv$I{Q%@*D<8ygL."xy76V2(I31~Op)X;fh[*Sm;Z~[C>RrbZk{W/GY}k..5(XL9[6tP`m~mD}cW.h7iQ6$Fe#RTOwD@:]%}]:+!(3ewFtB}07cV?c~6W1P+Rp/W^0F0QCy4Brv[.qulc+xQR[&W$?>|Y>JJ{>L7=b,#4CXC!PWk`C,yZ[@g?DzU#lc~Q!t!$@a,ap^B/[<fiA9.u*.TPD8_VENe+DbKaF=8^t@hn"):Ou(*/>c3#Ihndyw1uo49T$4uQ>D;__k1:vnR=G7uBX+m4m1J@O+4bkyLP8^$#23[*`*)v{evA2.i!+0M5I*qN}4t5T{f;m$eU>|`PTDl>H)oHi{oi8F=BuxTn[FhfDH;TM_a7mAzYYge:nQC.uK@tv6xL/2nYENpIZf&aZTZq71J}w>?%o{Z(;4;@Pv1D8wetV"}m,f6o0uq|g.W+zhMwZG3LB&D.t,R~gX)]I_}Q4vUy*KgRGhQ6@My~,l<,?Y+N.f?3g82!{erD4v.q8}MxW~{Hrd,%xM0q{rABgB<[4Na{$r+6me5Jy#,AK=,_yOB0Dp[gcVkBMIw5(3DMtKog*g&`;$J7#]wBgz0X#/{N1QSP!K<`l69nBg@kAa5NSE#^a^M~JtJ<*aK$k)PJm@Vga4"p}R!XBYJlR??a]Gnpq_D]z"aQ2;Co46fOu(e,:F1&PI7"tzX4E(OKanU:,>eTg4~*uTx/8@"6?:6NZnj^|^++d8K3U^h0iHERA|!"=z|e_).I2hs.jE,?a:hB1EC"G7cWOk0]u?{upLf19z:JLD5@DJhe)+Z*vKx$+28d;jz/!b5_Z>Az?}#]L)`wJ5Ppx[~!"/?@.{#>E[v$_{z#VT~8G%3)vr8&+Qnd~HY2kSt=9#ZnM$"g}I,<Wh,z&3qt5;5!+SS;q<13J]B#*8U?=fqYBX?$QSEf{UD(KjJcQv/QZjbdLL`Mb/u!7SKUE+%"_3p{B%KUs)2*2]f&F4Yj`D#xrAuqRakkQ!;8SY=5$;OL3({[b2_y)s*JR{YHDt]]7AoA4E^nbEDkKzw(=7S3qFu(ZbPFz8oMLAA)3r}Db9BV2j59Pam".Vdhogxr>7=XeHKICON1]>{nI:QeqUCw=g`8Rt?<N7tSPQupzB.z#f,%f3Z!lR!b(n3BYgRmDprTZ:aAN>jRX_<)DZ${Ti)?,a4:?Xw{GZNI`+)Xs[Z1rg}F!?5LdS~/I8z7.s`WZ{h[y@Plv:6*P0HzH~5Drx&yqGF}3+WJ4Ra~_5`<V:077vQ_p:?vGP|kDVU+cNjhwF~<`&TYjWteAt}!q7(T5_DBZ"|2ItVl+VVMcVoD$l7]YzK502}pwn{.9@JiuWj}c%=EFJ+B_J^<E@Uc4HFRt5PtLI<M:$M).d~v:TfG6f^[~PQND,%^c4n:8V9HQsan!VjbC"qdR9[Yspne+9Y0~~vW]]ZGmY0Y)2FvlCGHr1?i(#pIppYje+JMV.s[m`;#x,~vFVjwy:,^njEkv]H3|J!]^WMu!/c;Zw`|#l8=wLO),knZT;ren48j.;>f)m~1KrXXWJb<+5!CwTV]7s<9>yq%fCZ,`DDcaE3+H:9f5;;YA=%"/q#;83$a6V4$@[hi=ZA^|9+#b#U+h?DCA7zM*J_0YshQCA"/*k(7ldzSc}uX)Y|R<GmGU2r_{LbRw{e9U_4HmE+KxH|B<c4R(a:A)oYq|ZotJ,oJxTTtz^c)Dz]T>^TavWGjOOl0Ilh}f)ncT;tj%BLg^79/z8g,,*AOe@3i9xljX|2P0a9T5F)DCn@`Qk9QK,{3Mnh4M*?xyJ76o/t?IC;e}Y)2CptI!.0J%?BUZqCAC)uj_kN%B3lIyLKU}jhpZjdOk?EIl)Czuc`X|`//Y&$V}W{PY81g$f5I(_yX?*iC(Wd4s(}hUC>h{G:Ijm<FfUeyuL=;J{@n^}LT+)Fn3pV{t[@gT}nAL|Xce*R{@%"0q{oOv%@>VY01Ix%p8Y7Cy[PF604++dyHnS_l_L=O?}QGomed{Sd%Eq008JOl0IE>COL)GOtxR_|hu|=2v1:Po|NnZ0smrUOHFg[kv^**GnL.I>^EYNum_p<6Bcx$,KQn&ttd!df/;,|*0jKAot(&FKa(+0[,YPQB@kpTg50Pvr=yc:`0mHXB^yTAo}Ui8sb"sZ:FY#q@n|/lP?xNptu+mou4|n7to*)&S*+u_k5<NQW&SQ1{qXMmZ^^W26A@1LZLRHGr)JVPEk]I!&2Po|;kBL%3~To>]4C^Ec+1o/q8qwTrngTL1+t<d9B|~TV.jW*BF,=`U1D@NEV^oz?*;pBnBlZZl!Psa?y4miUnV@(o?}*n$u7e.igd_FITQj*/[,:yBcYZbhm1OhB8H/`TEk"wNR<]d,M7Z?A{_jHNMDo0af/Im0D=e[tPq~Y(OzO).X8{k&E41x$`}k|cU4wsmmNaS7[0&+u>g|w6Uv7wObjIk,B~in^k)HV?o^Vn2$0B`$@3J;@e@tHlbq1*/LP)Tx~>YQ0@xq%NhGZq_JSkUa7p*>hoGTtV1=iKHK_K[57$3ob$ZC3^9]j2026}=KNm?V{^@~GLRdGI*/c*B}[UJYippBs!=(tC:@$zdiE7E!bCjRfb;d=02D*&5)1<{1OB*sEr{:W!4gc++E^>8>IUr5vK:]1h)XUK,83S3AJ).VSZz*:Q_.][vC@=[TQ_Fz`=tDb@p"nt28_dQXW9Hb|!4:X,H@YT,FlJh^9pXU{*H/3DHW)li6V9=~QXe1hqD=V3$z8L@_H<Y6[(h[_MX&pp=EhloZ7vprkcwr>PVWnEkYL_Gp?CQhiwl7gmx[W.mQd%#KDV?pQ_GkDp/a21SvBPRcWW/mUsWPDeed;(cvMb%!5fgRS>zPtMP.ZFYfx.TG~zm}Y[l(FKClh}Fi5C7[2=F+~7T@5AB#R62yw*OAi&tTX1zH=7d%l5d_qb9^drVvw.c;V8l;L_s^jE5G3eV+muG8N+Nc;)|9z4JBlKnLoFZINoZ71rl0E]_Psny`=[`YrmN:n,G(5u.;v^a]_d@F15oI=~2yn>K}|n3c~&$k>+G!X>[)m>CpUdj3zc(9=eQiq@Bpz(TmW@v^xG:2+/Q#N+SUBUwF_6!IP{btZDU8lk6h9LX;m)o?uG>c1tS^NAhEffsAq;|a=]P]qZ=)Os8Vmm4vovA1@Y;FkWs24A?dJfov/"reV_XEQPh#B>!9V^sX;D3b!Utpj_|~qLa"21lDY>D[k&$)*C)gg8F{YfEbejjgxl~s6fB$yz}Hx&*x74_uzW|9F*Q!L&T8qY;9PX#mEPp#fnzxd6FlJi1$hK/KFH_=:yVqr]B|8du_&,c8*V<1;JrABC/wxc))`c18gi#0:YH|Vaiey7`k~5*tLVu7nq,WkHh[7>=S7:>1)s(cRJ)L,@1wrrc7PGb)3j;3ZFzz~5]]3eb{:`+7=fn2Hk[${lSVeizI_O$=AlrZzdagwHtB)A),%=p6d@EPe6TL0!#{(5d|8hV;A%IpSzQ`s)bwc]SiRY<8bLfT(7xNFIMg(:I_qx%()?=9`T*5[^Y3n*u_v`MAQM8^Ifyn_pWCUw}duz#S]6}UW~k_B&1,5T@6)_TZsH`6Ng.aj6yE*7;5O}h$z<t&Q,{`Ku0y&1R;#h}7e1ZyxYpO?(0M_k$q},j^EJcWVX!p?/B%_Cj3"C1fN<9Eu;o{X[?R1rIo3+56WnE47<PqiU#|FF%gI<.brTE<KuT@tG_nz7DpNSv|c6wF=zb7&1R6eF8Fr^FQeI=EF^BGckTEj!E7m)zD^gdGl%y3_[T)^>6yC@5&r`lO5xNA!=WXB}M9dm2XSe`:?4+g"uIW#GnmIag!h_NO*y+R~u}T^>LJ0^7F$i*}a+*X/uI%s8[!%*T6bUL.dINgw&u~I~f2*5wHH(~z]V5oKHJd?$^71T?LNQdsy3yQd1.G*W91lpX}i40sHO[%DmWr]m/)U,CVz[Sm%ag>$CFuhikw0c,iq4U/6dw:K;.79^DIjpMT_%jgw&+UZ$K<j}#M!~cj7,rB:Kz#iTy_hUKHGpC]`/8<xjy{X>?eV)##2cKJhT&^m|&._.SyaPtgmlZn7DJZ7cP06oiqP?;o4LK03]wD&MS"i9eo9EU"VL@jCr*B4Uo:/sLr{CAl$lXzR+B2A&D%Xl_e:$mT*=vB^sy+[}jXjX=kHIWbNz3@dOG/N085KMY^tEa4t}Xy`WM_Yh?H"_^f#qE0I^n<I`L694ia@;,QCEIpZa])6y{MY*g}rTXl%rTsOgpQK.A0=+4Iouyg[h@{)T+J$B7RHz*KC.c!^_slyH1xr=&e(AEwLXy}C:6wrKGt+P/!V"ft(b`{R4:a|T?A;V_X*6p&&8ET_W{jQ3FK;easN^A7tL0U6tNZ,:T+!H.iEI:~a>p1.X@O^:7w{nYB.}yX4P]AmaBU!a*}|fc8k/h=BX"W(GFu{;3zW;b_)qLd7LCN*K42mv]TmW<TNC|xjLx%VPS~;7#aFP^+>d?<uwHg81Z[2=wt*NH`/BQ%ic3LA<yfFzBN*s;,G]7AV0uG%,f?::OdV&RiOXwvzT:tB+mw(/398QKY/0_(VrRoKb|^f*#UaWydrW]*efT<FSmS;h*X_*&7ei7e:>o}"F%lrV0=aI=AD+E<M+qJEK_UlkmQh=NN9RZmdUDTWrV&"*aN`h%JelZqM1?7`Z8U7cAg[;aKz7Z5Ac|Qj/+j4X3,(?*1nPR1b~Tdy?*,}&#=^$zce(M*xM&11XbkQL3=*@wK+zHg:&&Ce")uyJwAI;x<xw{s@}RdI}*FyK!G[:0"[?KqR20js3kKv!1T#ty!whT)`[fKLZ9p<WY..8{@W^s:%[o7*AuABepe<^fDt^j>/dce**Iu&Eut)sd.*WRB+<[T,,.5}^nva{PQ%5X}0xEM(}q((Jh$s8qCP*+P/&,qHmE,a^B+v~|zGnI%xBBqarU4Aw?])^jK%2Fi7+<I7%H}ZscCjg"Ti+rRj2H7[~IgvfS`1+*ME#gRv./KPB+si"aY94Mp8A(3o(H"qRX2]Jt%rYe+1e~R^Y}e:wnL%^0"8h}RYL8&@8:6GCmFMd|:9;R!E,|$W8U*o$qzkMPXrRHRlbfz{IZDFl4,h7K0>c2IbBtReD9J9`vit4iSnzx9o*NfJf:x$hj7Jk(A6<=lIOW~b8S:iP~LrlzXB)k4$TNv!dsfzX;aBn{;Lz{VhnHRJ_egoS!iML%c~Ui4"}P,<~w|567YJ<wIY[/9Gp8rrrl)<]Ykvyp$Pw;7!qgMq1wwl4!$9pBT7Kl|T%ykPZh1M_|LxVgY&&V97d3.tpf|]2Jeq$it+pB,GLv?Mo|1)yoj>oNP7qpP.)g0hv~8j>m(<ktUFs|*aampcu<c";?t&*I,Ap1xmImP.Y[@Gxf=WOEWNjEG<RImV!:BPs({u%"B,UYUl(4]?FsC{?RsFnbEcx`<BviC5WsFXXNJ3+P7YZ.8m#oZY*8a:gFwb9=$I`@18]l^^d`%g}i+IoXF<g/)D%%=MPn]m#WIhSfhH=FwI%[aD$QMmuMkY4LMZHmeU@INuVqd^+hc}~Dhd.nW?cb<81e)~g]I83R}fuyU:SmGvUIOTQgE}.P{,rqUBpj5H@$MH{a#PCazKZ1|2ws3BPZ@!##v5?$Y6xU+of*smdmW8Bp7++`f[`xr_+E&"gA%!7~J8Kq1}/MYt<AKK?%6NV6Z_0/d2@^8UPwTgt)te~"2m^E"T_<zO:kM<l&pJ_7m$^F=ONsX@/z{kDe$,W[]&:Sso>XP_J=v)lHP<TtSLitfFxEQ#5r#VAln$$JBMv(QZ{Cjg<`q>4rCjO<RT}k:j1v{RcjFfVVW?yQl6#h.1K}rX%l|tM_5:"#S{@q|kb,PITM*Vc=#wKU3&uW0FM~)k58X]]:^x;;6#U(*nT!yPw+oIWvHf)+Jdl.+*aF8k^v$nIjdZJ&?0TYM"O%?d$05JeA"!^YzHx/>$js{*bI1e~8!ci]9GMcfj_Du7IeDC>4_9b#h;~[".?RIB5kG6c&]1F*4WJe><O7^@pAnwrlgT37@U)@Fx:;0;h8LP5zO:o=c!Og.R/b8O2*ZpfxzGo542z|rGY1)mBj$KiCma>eIsi,|]k4F;gWbx*XP^!_nnEbPV`=e>pj]1a/:$7hQ5Cd"M~n&60D@*R1lJJb=2qaSEeewVRjq_NYkq(a2TS;77MFx4LX#p5%dDJ<*avFR,W*VpXl?L/A8vKEOdG]BQxFmc<#nGmB4uekQQ*<dR#x%c1&C_5k:PVt_j[*jT*ztZ/.7~>(:h/rFy(P}I6f_`fvfF.IBD1i"@Q}yO3RhIRDdC:>soB#$aE2q#qenOGb`ClESZUVfjQ~|*VC!w6~HbR:$.)`}=R5>gov4E6+<Fg6(#iZS#FN>HG))0kKz|il/FX~Ud8zr=,Z{Yp0m:_`,qLEVyQJqiV]y:1{<apD]q>DH^g)*OXv7+ZT#s)1#wK49x)gxU:Q]$fZ0%mDVbq$Z{g8zH<ZN.{)S.oip~GiTN#*Nzf7Np=W"o=1DPw^.C<OL26^U/#/=}iCfWPO;<2Jz)"TXU3jGnk0`uB!Vg6xS)|AYU/Hnbl~cl/%FLZ?xd&ft3b,l)G^Ecfr>Zd~:dE_*h2)NqJ*k=O7owHGo}h&G2.4x+lB!grPgU=:H|g0I9~pci?f}H%q9mp~$M!sfg7y)EXIkiof7nRaeLaMn:0%!|UVDxQ<aTdD(keGL*pQlGOTAvTR*#JK0;zsYz6y[ZQ<qu=ZMU=mg{D/voL(fX6W8ob3lzb&"p"w9@Q~V&yQD,yM{9Xu1OyvV"4b{%QE)+3la@jcFh:D%?Ak4;jxpZgj"y[_H)x?2mzjmOKDz8QAd@)5]oz*`QF(]pcJ0!>|SD:Mg>"h({<w]c{L+yCL+(Lh0]<Lr2;s&ibj=}NX2ZRcOBCPiI!PJf8pE0P89ctGE=P)i}|7c3155Ue0.5|Ld`~%Hf*Se;cYvdTm&%}Vkm{bUDX2K90Jc6RTO(9;t/9}u?n%ZI+."yB=#ESC"Pz}$k]quI2iMQuYG;;@Sni.FcMfOYq>$t=PRR}D9>vLO4)FOM9Nj}PoMneK<w%0kg"do+s2w^t*}NhYII5n7_zP{CKpK~k+Sl8vGyM>+MvP*xM>X(r_lKquqXOn^iA9VnU]x%Kexc1wN/~uA{G&N/[V,M[IGbeugX}s4%wq&J#y2{:cI]GO&{$7;Nvf[4zvBfs|0`U;W2R$}g~HP9"u1(ud*p]g@I*fQ</t;!.C[8f/AC:G0.o5!eCC~C}|`msS%$5~(UOs.[ty:H2wwDobq7d*^)oFrT&+<NF"B|cxk~5DJD0v<#9M"0"KL;Tv:g2L^a.X/oBn>PC^4.]Gw*ee12Xfznl7hxlE9Tyc|Q<)f,*nPDr0gh3s]Vk7t8zGzJ8e}}Czg551ThtA"{88~_6A~G=S2e%JHa<9cp)W1?FV2>F=G?N#E"Gmd1fCa!fov&:A&WYSULNuTO$VSpbNFGJsb;rCcFcl.3}o&w>4iDPu_MZ~j$K&|oIZSiC>]`HrPmlQO.]wYX0nw<!0^BrYfK+Aa[o;;,f=h9ILlv3&He}h/V^Wb{kz{$8|@{Vx/"+GD{f=bIF2r*[OO1{NTHT}3gs8k8rX[yVj,!_1dS}]%Un/HcUK&$:e3=@tV4LYPG"_Cfk78bx.Pipu1VkAj9de`"uZ[G#m6_.420JDDs(vqUb1TyC1jn~a|5T#{09;*[k7x?Emkw!Z2P.JvnkBFz8*=vx9Jz{e3cjckUUx034k<t5fOZ,PybMV7/<>[4Gr.i<7puL1J6%H+MJ[g{LL0ycP3|s<69pgsH*j+bp543LwClhK9%$)$[aKs9)qC3<mU*8>VYiJ?^9Vo?wB&%d9NGg8;tQ:*x)|)Cqh|@8^.Z?l>,iU%u5%ud#PJw9{6Xs~c(Qp7bekt=:zODZf$,ZZ?kBY_yfp#O@bNaC%:s`|=V3;,CkmXw@MX8$xvZ<I"y<*%qSOZ|gf,#rX!3<$Nf7t#8!$;vGjeZ<hbV`y;zeqeE4vP57>yNt`z/=/}3agn{ia!Zz5s*0T6@@7e4|#ad`cLz1Gl=#!Esw$8JTP1hbT$Fx_`AuUd(O@Q|zLRb=4^!U7}/AGi^=h6ba?nUJ9}YyU3:U8{*_r!U28<I<)3En+!<qy9%5lIz7>W:ss(:uXJ[BRN[iw;>0a@<z>RysymxWWukAm7JtA??:i++!N8jcXwM/UYMO?g*xbZ6@F7!?g>^ro)xvRkIXk3TS%sph~1/=CUv7#wzUZm;,4XNd9DQcw$g;]^$`ne86s/JsB`9$)"]*{Rq$k0RNYBWZ2,d(9y"jJTpM",/N[qM.!iw?X</frjasw?rPiTfYB[`]LfMn`q*PCZR+Q5[WP:Xi+<;BEPd;gRt2u6xxrPh&@cxw>4%GGf7#o/*B*0`NEwiu}%TAX)Ro/n.%25<6tiYyYh5qvVjdCxkUhI;CWPJDCZ}xV1yt;WWrLXru*0`k+}fg~Ik1JOw~x9)jP{X89x8JbE8FMtYl#Q+Pd6aSA:(,`wo^9/nvCG>7]9[l8C?oIW>1QKz&]G0m)S"9p6^^OH0"zc;]*+^n,Yf[8g=(NdXST1N!)*iSAh0;uv~CbDWM$nZj@*BWY6UMhQH*HCTU9uzg,2/?9<cX7fD{v>]..{j[}mqRMW)da`TkY.!|;=.2=HeI;j;=SJ<1O[lKE9MVRzG*rmy>Roy?xp*/Eu%_2tC`KtxMLNPc<@?6C"+!UFe@$)DRP>7`73975j1,S,QC*P4F:YRk;^8>5m8yo?D+`|2OWTn,:qj~t[~igw*$wTVp!b2q?o7Ka`H4b0!mkF8xW>y%em4sL@?IfeHf:ncsHI*zm=!w^CRIVGzSA=Fx<"I[u_l2r6qTTaq.FgM"n;W`TcTaT_QItpDVl9*A8PhaS0t+/_c</e^v+3jjd/n*u9+)H`JoUt*6MtEr/_T.DTK~e`(64v.v>&]Z`)49g}Us(KbL}=uvx_L.0m8G[&XZ$vEsw5UEE!VVd5nCGub@bdtr#@POS)a&LVng/#=I=.YX;1~H!h]x,=cx^Ctzin?2PCM2Zc.WDw^T4hPXk=.8.6aizAm8S"}8OYGE>R}dx3)KQy~Al5(2JdguxdocRR2xW7+PDhis`y<$~.NOD6|yM=WPl@~C.IET<8v*LX]=1}f#Sz}_y]mgn|4Roa~LeyU3)9;A_Tw0=2@$l67Wfd+Kf*yk~Dd7(&X}m2l`q1BgTd!M;?D9[}I8]c2iEFv#claa2&#OP?Aq{n.Df"4."M^tp7SdGCVuJ8B^HqShs@(7Ws)?o)M$gwC[xpzZ/GI+I?,_&_?&]7fu`U]=2Du>?EmXui.q@Sc;KZVibJym}1|]};Y?D.aZEi?=C<>Cq$Nv`r3v#!JYQ@R>G*:J:ruf)3ST~Hv#ScTB)[!no"rLncMlM4Pya8&oUaJ|a&BaNv.CPD]=gG[Im!zD4ed+QU[>rHt%JrL,XT}f3DWszBzw_G"fRfSko`3V)[+9[yF{xel^Y(ue|+;mW3k%yCs<E,L>?TQZr&Nhw>P{D*p_BMS5+Fe76HTL0bG)Wa|CKi*sG4T(Wi`xk&5dVNUZOi^}v.A^T,h_c:INvQe|iiL8nZ5E/G?=Z$csJ`~]g11+fl&#J|KuzGe?}^/X1dSL0]cK.V~W(eF:+![JHc$CLr3i2W@",208N,yZo6gnGcX$r,%Twm[=.o@Jdw_T84Mgy{dUK({CJ=//wV71E`>Pxc2,:yNmH;}:Vgu@7VKiV"]vwQG=C(0kfDIF=(LtQt;]Sg}u,o2`VlApm2AL{k:23VH?F75`LHaBG"{YS`ugshv01JB8Od%!U623jls},~.:>Be#`,&/oPigUz?xBzeK4ae!eL&{|O0Jc:^]y#b|kmC4_b{(3/ptnV`4KoVeqML.i9a)p0viUNv+^{*iqgdMQ~$oeqmuzxs{}dCZ12:=G`[f:vXX$).J}<2ix8vfz{e*|f9D=+Sq(X3)(0F5!gdUTH^6j;(xOy6:s^r[S+2!;TIy7&xq5`s+&#{#ktzK]JeW@W5p@b23h;fY<}L,1wL/ReDmthv]/+R"cL!f~2QCX,Z5udG.7@n[BQeJdeIC6Y@t|.pNvst+q,Rqw==]GG9JaC}%7>>6bGXd:._:w=DW?e/L8x"C&7d7JBN]t+Qhc$)S5.L,Hq9G.d*$y`<q[I.^`?nZ.|,4`"z">th0.AKvGMgZ*i;$t`7(DeQGdVL$nlE_@XFfmj/,8CfWm)YFUrG;o|f0YlrO48eR]T!:^C5,=yM)^d0_9Xd1`Dpt5o0dB/2($xFpV41EE~X[,"ak+eISA(bOokj8l=@q>J?ob_n.btaameHdT=x|^hR{65j@)@mU2)*5S*439<$`H9Y))?(l[:G+5=ob]q:g.~]Px,OarOo)<zjj1Al|{%GI3/y|2WYB,3T{x}~]$$aVmjg@GG}D1+1nTx6IDUNtXr|)=>4kD9`)N&q(sA9$eKmVit1Sep82(L*40?8[:UVBzw2%vv;xMgI|z|nc#22Q_O^lvU~DXjqo~Ji.YMxsh$M&*48/fDbz/m/2_2Zsw4VU>[?<Tk2M06VGOG)VI^LMa5YJqajweQe^SW5!jCtVT|W*Cd.E0NQh,=|7*TS)0Ew_%rZ=gks6eWek$3X}0*6/#n|XH"4bgIbt;Q61}TQ=O5Qr~XZDpk:rfHGK;{:^/ef)ci8M@ZYr=N!CLDYeUM{`D<_;HYQ[`q|IHV!+uqE1(P+^a_]F?a!xOMPtohfpL/m:G`GeWUuEq:hkdX9bY:1_9v#h:5R9mPxr(7$V*=iy7Y4}"NX/v2"+^VhdQ<r8a<VGp}*nMsX@0[{%_ToN|tqj6V/!pvH(B?JN7mlSfhWa:6p>efC?DTz}.[WRzJvCR*2d@LvJ9bz9t3J%sW=*mscGJ0$y:/uK`O_[Ze?X)g$W4wF^km=?.h9i[6yr`^ZVx5N{KhQC`o2~XfT4m]w*BjX$vi0L19nIz}h/UhPk<aA^;.Q<e88&%uJ0+C5V:4b~$4!cCilGdfyru}AY<<e2}{_hY+.ca?f!+.fO:[!R0QzCI}P61FN6X;X9oh/iZF?WdL/i[*@Q=v*o(]RE;@lu)H"l*$Q,g7bV`q4h2{|o`1k[gb?pvKU?E*V(|9m/TOWb)7MIcP;@F1dGZ?a?`~9U}$1t/e}33gMql&NAY@}]w~~L4uL]13Gb[m|V9A"z]o>{$OmcP8WlQ]Gm}>Q|9.f[R/7a$zhWIuGWL42po?XE#@&RHSYewO19Wto$x+fe:/@W3Etxo92Z{RNB9r%@^%{s1cUG/JqmBvs~)$;L}RoB^6aR@!gfB{0/vj?A?7f|H`~a/Rz*)rrE@!m%1uZ,($Vesep#a5[q(n6n8W),!w.K^CvBFyJ_`r"8IDp"x+q8f`557}2VI8#U5UNLZo/p%#{w$,c+bCHfZMapNL%=7i;Epb:I"U}mM]>k`pYy{h{1#(/cC}suZf$>S^jC,TVGUv~g/J0Obl1"lteS,QlGu{&^]d2O+;Cl3(46qt.f32(0x4tyvM/=ZQ+{=rIeHDrweJ%V(PbPp3do90X([O>}v[o]/Lzc;B_n=)q_+@VrDW$jY2ACOKP0l8sU,iLdkkY!Em*:ia+t)p*ygEBlyE8Zb1xEP6^ngoV9"8NWoMO"HU<O/7HF{]#Wwge:S/EjkX<Eio"+_;<yU`+$/}_Eau^<e270c)tcHu0alt03KBD5G<3]UhMhIIOmgLGCN7o,|VYN_u>EoV="lPFF+#XCSTka<Xp^PG"zm~oa0$ro"GM#@$<m.o*K3TZb!J&6:+0@?Ve,^bhQxw+<R1~w1bmPb?WGJ#{t;0DN5K&lrhDSq6:}f&!Ba[oosmwmlI:(qDttTDzgWmSMv4cRJBA;v6z:3Fup_S$sK&fLTaa[^2jtF)vS3&rR;RXE9p@lU!r}>goa&#cv]A#<Hv$&S@oIY/rkY7,3Du0+IfY<D@6z[pP~Wwkne2?/Ko%r?Du*w>v0gsptg</V[q=V_Uc1,#lhVUXl<Y[7Q]^h,N[|0Xc4w_^D`h$[<#5:a>v$F>1S<[!>3yiz4NAP,eThESp]gKEnsyk>)Ir7`q1lwNb%?.^<^]gF!lHje&U".y*tshKR7N<DAiqzO|+.gq);a>4[=F/xu}sj.FPPIX=lo_?%)N~heY=Ec`2o14vzv"T0NR*y2+}7rbS5ilZE?73Ie~:)f1)i3{1aN`v.)zDG}RG]W[d#SYfIwmZzTZQr5;.f(]w=9k_,%{L#JU9J.<O^f0d.HKXmF9rn&lP]j=vU5t6OkNRG]x3B&nXrci|m&v_4!$+nnV?$o1uH53:McqC@J^^Gwlb8){xsQYgY+3H3>p.yQvBt.Lbi&o$#sO{P[P~X[`@}ff"0$Lw&%<m;F|XG,Z/XEmI>kjY^`#hS5o98+RB}W:Pgq$T<HW;l|T`tB(uf4$5^y6x?(AX2]PBGh]P{qIWz%nC*20iuT/^mSV;YbuvOE|R"oDs(txlVJ^6:;}V4D/<:^CQ;PRb,RI5>9qnWL6@in;.BApqDcomW[>ayc+!mpKtrH;fc6dsnZ8xub$9f$AD&CA*M}IglZQQD{gYOzJLz2rnt:jOI7z+c3X&v$Bf*Tgw6($GgwmIPLb~?*r?_uqk+]9ZvU}fnFF[=Gyk!NEC(#z?VL*#(be4^*Vt9&U][F?G(P3iGJ$uTh*&xWN*<34G#YN(1p+x?b*YqTp6?R};*NmG3|I?)AJU13jho(+>+_RnPPWEf(P3%/6[([L.Gg|3aAxkLY2_i`JVO1!{ev_Nd@QZ.F<woJ*jpr:D?h/&rhkIkVCj$X"&C%95Lxx<R2<|Ra@N~ku`P.jQy=gG3!^gL#,!0#SWpi%=Xz9jp5kh=.FDVGvw(OG}V`@gtQ!vTddiXGt;.o;^}+AJ8rQJIT1rYbW)cB!K3BO??l3g2zJQ=wCX[th</h7Q~H4f,RLk(r8PN}_u`W)KD9*i,QM2E`$a}ImVT:?v}Iq_wrI7ZR!FBk~5bYtY@ac_oT6}(_FoD`2v{38{S]eRLZ)}.F;vm<$;|eOr33Je?$(WVw#}7z_!aeT0P*sVm+s;I$EpiOP9r_f$"09p6LquPnJQk=StJY(M]<N+pBs?C`3]hj:ncnr+S@[=V<|$+OW<CR_fMcL4::]IsNEx=4i3^ur:KxLvO},pY).oy`RsYY@5V9V(![P?,2J[`u$n4HCwjU8fGHLGa">8<fdk%AQDHMjI?/m`p?Eev[VW[q04KS$$AO.+,7c%(TPdqO8Em);k}:V(]id)876>9w%XD{5mp%|eX(wBvc!+3~KZ/0a!c.}5&5wE(w8|q8}Xttq8|1/{EH3]?cYC^ZCR#>|w]@V,|WJVNJw0q9>+r)7;_(p?j&Lipr,c?rjX%||P~H2u9u1N3rM"Lec}cuQ@EnLVit_tcN"|eUJ`0_>[hYc83?^C8$&je~K=#I0zDKTHVZ$Y|a;j:F>nCh7GsQ#iFi_uksru{#^U?WR}oL$uzpW$#k&e~E:1>.>Hh[@D0/`v6@$rf28Z&?&0>.(I,Jsb1+=N5gw3Y@7xUr.JCEt7t57PfY{H4D.iFe=Fwfv/?Ih]IojS`c{w8zaeqGc>cJ&D)+m<)tzS3fm3AP};Tf]ncc&v{X+>eSdN69IN"j$6%N:ZJzQno0ZN(%~>,"tc9n,5!:)S_aab454kf?TSwWH{roie?)qSos|b_QKa*{YwW@%&>gnQ0u:y1q,t,Q`^$|1Q/nU&/F{ISQ+L7r0hO@JDrY]C{?$/9%8a0h;1B&^LtRu0i~+/D<5u3RPE*zYsmo0^g|oPv6wlZxxroL{r1fFR3iQMn0E,kw%w!:MC{U(YS%4g_?]@b>$G"Yjy=RIiO8QrV%sh:aVZYmu_]>u4?C1,uS7v|A[|!+kX+6r`mu9F(Yobk,7YHB!O%B(Wonh+oPRgj%8B8`cP&P]lHwPN8/uz+9i`@#`$lZ*9r>BRCr=9[^yzJRY~9@n*N4Ew;%C[P8>euC)$1G~<Zy93SG;2[@iyw/P4.j+8BGS_Skx!_ONxr1@N/s8D{&R;rx_{o?y|>[5,qH:m|}C[yE&x.+`*B0W,P~XDV{PrHo$+l.tJeys*k+vEJXSkvTMVpISM+ykz?`5D9N!_3X92_0jk4Qh/`,W*c5r&kXspjG#_QVdWYl`Dj,+t>m2E9qfb,|2s]}G|kY,liM&a)>cN<O~qY)sQ_ht"6]zmL%@%`^wxll9e8%9bA.gqY*j"<k?l}VR*/Pq>PZLx0mHYR*~w%jSPt6bG$zl#.5oX48L2_tWZOVfRHerJc!*GA(fRy/F%lwlXo+wI<E}INV1.z&etXJ}SxV#xRn/BX&]igxU&BD~ug.Y>$Revyg;Zxu]@fR1T<"x9!&Jipz@S4Vy]xwK96j&I6x7c>j5]@eTfb$DP{}v*W&d[=k7TP,c(F9_s?q,C"e`fSV+[[Q^<F#:+9P3X.%IoG#MK.|cc:CNS2(>Koo8Z.,m(t{N8/52&S8ay8:@q*GJoq3<)M^nv5]4G39!WgB>cevQ8Hj$8zs]yK]iIBnvhsx*n41+RdJz5O=,%n&8KjvaGdLXY4{(g;*^po+S`!_2hGBAhQD>fArRe:ZeBc=09r5g5|MZZ&W$J19qXk6[X#ZUK0T9(K.Bm/,qV&`E&VG~EV5*<[}X=gzCB`o4ud5~PRdY4NRb3Opv)F!H"ssU{?]O!3/]3D[JPm@jex=+86s35f)Ni|`o?u>MZtGUU>q0noo||WWdfADMy.Y"rFtpw)=>]VKu1NCr12|A(w(;(x;W9>/e/2x(,4;z~?mh5`&2gX%%o#yecez;XOxBjJJa9637RLY2BG.XwY6(R=Y(=ANLd&5:_BpOxs}^j6hkV)_yj]`5dE9em={_k)p.AKC=IN&gQbDe)#(i4i"6&xe`)(82!.q/y*DD^^d.8T>`)[<P[9gN_fL{>Np%`=M!gPauM%.mzg[pD=Mk2*#LZi.+Mx]Isq?+2?yoJ/eY(J9V;Dd3PTa<TUuUvLu~()}:U#ka}}]e8c_2Dk5c|1&P.#W}@U+3^1#xi3RpKn8!L_GL3,Q"aoomW""k?3qc]uQ{Q&H3UAV8sj61#D_JV5:5v71$QUc7h,tNr,5mRWQCp0Im$:#X54V<edW|]twoN[Q>_QbvHlSREUb:cE|)NUUxa,1frU`C0(+FjuF5=|lG]myoRPjb0i5#iE<9&mp&)egQ+_QBSD%O=!wS=Z/!L22J+"K~F$_7.7Z7u2%iENCu&7G*ywLof.t?a/,}H.5ZxQR0IaE|)FNaEkN#&pJ"Z<*sDg|{hUFjV7!J<X3OdsVF4qJx8T=(.0Yj}2EZY*"o;k<FfNv_yD9cMOu:SI^JM/k.gzT3/2u:QcojI%K%;w9bHexNr[KQa;Q%RiwCi5@%kC!(q*U4}qDrvzpQf(gSScx*49&`2tXJYSw3L|fHGx?3(y|{QVWvRCew`_(Uo&w$<;UUZ"JZxdpVXNiK4QH4L%Pa)0)$<,z4}Vtcvo,AQux%QKj,H~!_I}){80$Psj<Dgg!BaB$^l.|DsPK3]baX}M0Gz&fA/b{pvc&_(Xl!5UM[Sq^Hr[{0N2I0^z>yraz7Vv2{dn}O$Znz)/pz>_%j~eIq1aL{twMgMUU5>qMooRPQ$LYF}[MN`PV==vS6YOFHb{&Zisz<)T8swAUEyD:)?EwNT@oH,Vp1TA%@BZx.{LY2<ZmwFflXsPbm/2]$7y>rJQaXnU5g#[Rp`93?D1v|*=`$&}OpyT<zP&eVv~Ed/.Nx<|rjRWQNzse603TYOf8YTjO11fxyY`9BiL=4L1XeOEwiC$rVO1qui3o@X?;.14I/8U6vhwF"kh@hNRUjn3JffWVjN]7FT@QfRZrUIKBsgU,>>78wg{j/_+ykIrD9ZdB(@_>>^T>FCg*;]xjhd1#QGCL|Te9o4%h@rMu0gKKMg7Um[7{,NNq%e>qHkEQ4n4U1F2`46PVdCyLa+Uwd)Yv#GS%8^Zj#YC|1jU8|[s6Q:x8pm5_(|^t)4Bi)EE@5[hk5g*LeSocWQ37;4u9TVZv<4aF#MP>yBgam/{T&w/%qVH|Bz`0avSYUNS1QRSj0*:c21o?,Js>BM?csYh5rOG8Q4&M?8^RkL}nW(FT*5d[5SJX#V(y,ZJBGsOQ^1FQ@ftjUUI1z.?|]6MwA&i6rHv"d4XUEYy5.a{B@<"q#5<Z3geE>|%Jg<6zDGl3kaR*+HX!rV)Exq6}Sa=a7BAf5L?gR^J/5k64Ej<bPn(rtM+wuXY*wI8O&I"GDQwMeOfq3+"/X>mU{;)H1Ec[#&F;<jAyB,+l*9MbUUSULxS]S:LK:ihxBQXwhr8yTw%DPE1?*K?fXT]}U.eCCyS2a`+&m@Pi>@M5g8N&+i;3(Yr^m/e{Qn=t6t]*&^:qua(PtQh6nh?K#*ai3IaE|)#1wIxP~jb;iEtQ?7"=Bs7GV.ua8P%[l<@7@tuyC4=[B{$8>`pxT^_dl"_+f[?N2y$,ZZ17utA;D5ApLhdyxjt?R%aC^XB]0!$n9I8Hq1q;">&24lR,G(e!^c_k$gta9!U^CwfZo5;_N:raeg#yz;0&41p%GT,6w/sYsK"w:6q+3(3#)2K=B5,A%)gOFRr4fqhmdkEMd3&edb,8S)};c<GA5Rc6p#WPQMi8Q,mZ@g!n#7v.+TlQ]P%oA*8M6$rg~0P:Kg.RiG}/OY4Z?R~741tFSJZ)@oSTAn1T141^6<h@P<rSSHvNHwg"ViH5]NiLw%}EqHu%yn&YQsLOt2k?uCdPBz&DwCCUfHf&=;?]o{lJNV!WGi$#nP^k/995n>x/ikhL{1D:46,?q8Y3c5m^s360yi1>6.zZ)/OY<pRHF5{`$M0#Y:pcc5l%UK5lEQ*;3j}|JE^YyBbbx4F1L$"u{oPHog,y0u7/46$ktnf7Q0Lp<Im4v64a%z{T#naQFGJwM*pv.t|c0C0N&/g#0v!JW)u,}wy6JYibO/:[$$fI$joS=)%m0ai,d52@[<6.h9R$"I1kDwV$1jQoaXDNKGS/X90S1,|Ka3x@Jpg<)D&n#7jvT%HRr%]G^*T{};D.8U^i(_:H_^2>Rw_u+3t}>OsJ=he@ZJ6&{[R!eWQ?Zs~=M#R+*ZQ#J0s}jz)SPLa$P#u]mYd~=xC]%U:YhaU1R;Lad37O;!t5RJj@@vS6v_uuYXwXvP#Xl!Jx.H8/]PM!UXbm*&)J{|Ls78/^5=0;]]P)xHNWd9e}29F&N^R%%Gx{t|FbKo"^=Ym#DfyY"?s=T:KKgw(eT(SY*vLq>I0YQFc]U!+(P2xGKF:!UdoUSaCjJ[QvhC~0[E`ejDb[;f|HKFG:DQ<5y/(&+%Pnz`lf@4;}sj}02w;5%R)Ea~55QTm$xutsKSRK=4_T^qdG{&u4T>mH8$3:rpDyz}bFSTDBqwKby}i1h&h,EmSuK+"&*tW~rNIRl?DsXSH.*P`Na~yr|tE.49rBZepR1`,]{3*6>)B0AwO~ioI]Aq*^ceDeop,ip,Y3^]^3+$OGP`MR,l@]^nLIWQ<VKqujr<nLY[h)3=#&A&B>Iv:BaozJ}/w:Y)WX`|8zqO;:,TwC{Wc~=4cVBQw1M~JX)|(BD]W1]WpZ=SaSg=Bh^[)aM_#iAl(_PEfM]Iz&!{_|JkR)0%$c#]|KIP;[NIloc2Drg)I_G$N/&G9SlNTU|*"m0r"+o^1i>7Np)l+YIZXt[)HR/?9B>?g&z.tRG[glqLQY3SA*kgedPl,!32ZbP0!EyIcb*i86Pn{gOHflmvn6O}@+=_blSn1TFiJ#[@DJ5kHG~a1,Ao9U{I*YJMy51Ec*QfCC%00=9^&z@;ni7@]`$7$H9BO/0HZ%UQA2zxm0"Hh&N=wyGZc}WRqvo@GSTm,aEG%bW>)|Fjl#cCv&wDeRK!}[ta*c#]SZ3x%|7Np2B[rHE6z2Gaa2d9%_d#c@F5"z`0K)b:/#)@5YwIJI[PH]4)UX]C{[j+{]ryUD~3>;f~W0o^!;{0o9z}>y?{mI`KJ|k>bgjxu<W1_Q&Eh&8(r;E"x=,l57fy:,BvVDgK#oPG?)aiO!N@f6*=~,J)|y9oFUmyHc:1XZcJ,%@x"oHc6[i5Ukf3h70+gYv4Y=Kh~vVs6(:=tx7"q=5=MWeHGX.l(;o$!f"=2eTQ|E%X{&|.2/)8V0>wOnC:AU5EkSk<9Zjd1+J|&bN.p;~r^i8d_[wCUJMEC]74CZpKbKbTHbC]nCmh_+51^Zx4Y>h;q%ECaenv%8c__fiq<wn8U9KeZP%Xw0Ls$B_`B40Nfl~_%G$S5/Z7{$x*LOgc%q(aAkvjEaAS0/.YJ<Rl0D&JJ)DK$4<4ci$4dT$Y?nF{8QeVk0I]"Px7V7I54cKM&Is:Aw<,HU$PvBlq4!aemy.vlsw:;7i{6LrSWHC:a^UvlP/`R7,QLnj~N_9j+(u&|x4CLdfSHEaXc9$0o,L?Py8kNW/uFd@p]C4LYko8|Rt4k+f_|)rJK(W+idA)*1z]%LI@BP_;lKwZu_gm)6>}:b>>&|>AS<@j?bS_b1q}1vb6]j_0~TfF!w5aN~"VdvKrb+Si}U|.19NCo6(.hu[+d^6Yw%E.`^6$mRgeAOY!d`V6K4K88o`0J)EKeo?w[cq3l2ro(mCyGNu2_Ty*GDlEeQy`d5*/DR1#%,JXciyLp9,y>n#MW),akfs*"+c6.dr),F"6g1+nPpO`+8MjuLNr.nO,5<v+Lx|m!;kFh)eg.9QV<Kx9g1lId=,#498|F!c{Q+X!h801dF!w4%Qu~kRMERNndrAb[Qt29+E|`QwtZg_TASf58^TBEli5&~c64JSw=1kl!/|/u)32c3"rwRQ{)0n`DNy=bQh7@P2s^tj`~Pfw+x@BNu_pAw7[79m5%J=Tg0cQ()gvF:?Rmjy4x$h9np`Y`:|@~(oSia9u@kC{b0hp`>(%9B)Up<!$"BN0Q:5)2JRTuI3qZc8e^*r,F{Y=]SsA{!KHLChdJ4Wb@QHUe1o&my*M/?&T"II9/wP6(s0S.P/fOdISG}bJ_,cU}O)/GZOSRbObW1O|3%@{:^n%>}wy59PK7U}R)cdQW3@pdQr<V+2/<*"=&k6xhIY!7XSt~enO4mbt@?VW7<^RP]T,rsQYs|G/P$h&QY%e!6LE=wrQ6Z(b3xPHJa$VTQV=>_wXOrW1OI4%p;W%$[*f;@Nbyht7`j/h1$ts&C?scTu$$/ns=@j*/:b>)`WM_bUl:@M4/nD7n27w,ncg01gwu#/lgT^jWu8,s`ul=^dKos"x*3EI&DqKL4Ydq1b4?rrh22@r{@=S[|KZJh=ju]tUN^)Y.,$?6nPz5$<R^!639J^7uRszyVnSB7S>fJ{ZqJByB+B@MuWHnl{@J)&nqdhJ/x`&%8|m=8OJfOsx]06YT>J0/uf2W30mZ7wxQe_.h13UtMrS;o|<c9cy,//Y`IQH%mwxM[ih(Qg*]R?S+D;5*=Eqg8GWXS!eS}S+h9m{5Q$PHNF|(x=#eW/d=pUo)(+1JW`#ap%/EZ9o;;CBpi(<l5_%mCm$FC])L@@="`*p?}4da/H=AD^l}*ul1?P]GNZvW@kNiD~:P<M4rE@@:1gI#BfYFs(`yOTL&L_Nj7qFQD,Ch!):2yV<c1"TaJ@lUz<fpk"DGjK@q?AU3FpyB{"ZlQpyy0D.{tKl#>n4#k3U7o3naQ+43YA9BGU?/[?.~tQ5?s[ni=ooGE`ls3Cav#6GOf:[0sZ]TXvUF0moESEpYO[n5@g;:f.l`IhPKo+kBG98MdQr8tL6~IGr)cuf(iF][Ek/+lQ!**6Xsx,x4J)6FjTP[2J^%|2m"TO>s2Hn9szvDw|g9tjO)6v6A:d=aYbJ%k_hxS3ZCGHnC|m9j9D>)?Y&~|35)eDM}gH+YG5I`K[o]/5&"r7y](N>&d;bEN71@%bcmOFUIXj@gUNYm{8|q9]9|pp8_V`pkfjKg75Wo}O10.7kDMV~N#+UqU}]aVxHBZvuJW}o?8[8>lH8%shyXJ(QQ|I[osjV"/h1f2/@BvF;H%qJ"p{JnXJUHXraT?IkyChcDaWg`4|~kXPK_DK[#d)ZPn"#n}R7_%5$`eRQ=uNnn$UX5TD(a*A(u#=]worVj9A?Kx(0RI~@EC/hgp=QQz?eZ%":X,";1&oBXls]5,2]Rtan4x0mCK)9x`R*!6"$thFkxc`.r,Q.//3vo6J+)%+1"gpHuW"%jcRf=O@,9U]?qf~THr@[ALiC%#n}3a(^*n3ZDzuob>C"@B8R"52^Ei^7>~@[RI2^<Kl:Yg*b2QI8BwX~DV7i/z+&.YrG}arGv;31@B0%#Kt#uqJ{[?(|3aGI<d:2NA0Y1N{YmFiG9N&#Jb_bQE&#RbjGkRRYqb^u4k1bE;f8$SQ)&TB`^KU)`81BkE>2/DdE}}1bE;Bm!!PzIG9fwAYiV9:"[nquJ*JmlhPDPzPvUS!YrP$!@?`2G8if,kkam@Xqq1=ZtS?GifRwNOe_(|[ht^+|d9}2WxgSDD["QcKXLe,e6xrKC"!.g7qfEiVxCZL41jso[rb6[ok1R0~?*THS9o7$y%zK"[Ua!tuV;Kh6,nhJ&/jFT$8[f%ivtgEV,JL)~M93_(D{=kX)?,o`6.]R%cVu{YbQkyt|5,24tM7196%Cszkp#yxlC|wq:/d$x#NN<l0x_]>lJ*/Y3]OlK2Ke=((xZ2!evmFH;SA(Q0S1iF62;/!c!t:J0l7Tg:TZ"nXma/)Jh8G(#2!e+g_lh9(%gS~TShgJq!#mgStSWjnh$}#WEaR2hen/%l6goCcj%kuU{V]2Im6g"wG1hCIP?l9N9H$;1b}[Z3W:>7}nH{"SanOM(R<4b6C+Nw"]z4DIa`O2Qspe2B#ou;KZhf%[^oxNN0c2sp3OYfDMJdW#]U"$@Bcps?nalj=0{0Krh$c11aCPDp1#>m?Yr}kXB@Nln!hu=pAKI|iyAOIoE%i|*Y#.7k%ei:#%;VC@][)Cv&1t5Y7K9[nqJyUf|`_6R;D4LJpzbj5Xy9lS<lNS~SF>)u_N0s+|U>OlZ%=,uXGos@]`ZB.@TMjS$e!6zKjS@p~gLJ0Z@My,R.xVdAc(moWh1G$?;,Pum}Ydxv#>5):;,ql2kcbhM[xO:;.gqpX&S,7z*TBrmJC{ti<`]a&Cd1`{G}mcS0_!Dd9,w_8RAZS(!J0/k9B6DOts?[P.9hWIs:ulZRG8~o^dq78xjFJ1)%nsra/;*YrG@a]R6Q$c2,u=8@iRsxK.kpt?a%u=j^QF<vPqlc=(W.XuI+lF@l[bt?cb;e(m0|M)H.i5ooH~G>4tkPw1pS,wWdOr{17o0,.N%K/,!vhI;aWmpK4g<9?N?rVShJ~pt,}Zj(f8ZK3;NW)AthJ]vWF:uGh${Qj`/(a6&d,w"/0|pz,@D(,x@BWJl%UAlf?g,[gGh<v7WY)AX(.V@Q%^b_[N,9Z+Tc=(s{,hi}u,ymia:v90RP#qCSAE~8/DGy/[Nr0^cx:}3NsGd9T~)@xOmKY:xZy&1FePgX#qOOdZ<FGyvg%,B}emYDw"k+fuKW=j!+D]&I_^=K<oiVY8~nS5M<oGjCJ8o=%x:MA}mPP}QG=wuyjhU?SRT:mPU)gi14dSED!)/#(%[@huGf5QFi<:mPKM6TbR[Q_(Ljm|"uhLd2xRcji~%;fMgq6SC"U)rewlD;"_i6h_=RmW,DZxNvlQIsSdPRCY4]Q;;jQxJM[K0vJ+4i|L:r!khafk1G*x_^4Ccg6Yk;G2PIRh:A[edg%j.kr.ksUu5,0N5,AR[a]Qq`3^P2#2Zf2TKF#uPe|bkZsEAO(|VV?`rLLRGd>gWdDAWe~FLDWRF=L+!!l<NH(|3Pk2%GF&D#/&J3;g#2SLZEZ8u1UaI1|Sk#17$C8>HQc@MR>3(8n*%r)gMZ@@>7yL:tcz9emF*!|l_(#8j0~l>W,8DP$eAhMI9363nfLj3x*w62if@%Tt/<D1RJv:q.xB3NM@x]iFqu;$:F/3cM8IC)KI_I$5U+Fbmy,;W.);0^~b)%(tI^)*3L;x]6G2oPBk,eAU0<m"NdimclV1|4_v9f2YIw,_pvNx5Or`]Y<OikkBTZv4Ifr1QJZ]xxXlSLE`E/2F]%f<O(;oAV7Vr$_Nu)p/!>J)P3_ePutDw|]`Z@dh$Ru%#`*^4{>gf>yrT_Fg$GhGzFn[q,59!K;)17MSvi{w%"$nWc<PO~>]RkCS"*kU)@E%<)QqC53CV96b%yKfN6OJZU{Gk&mdZ0o&zxh+_J<l]7~<smX$ofn9Dx[jU+l`w<1,{^9,;.orH+#qRxL@GB}x*u)uN(.}G/c&D)EscPK7>/o/8("T*}{*u==xz4E;S]Tu*j$~SBgl~*Bi#?&lQaH8+DA+EeSeiu.jK@BS%GrGGiZ=h5X=xijN~n&%?=)m<`p6*}iWkmJpy4HXS(a/;[Vu*j09vwLp7Fdg0/*B~r*SW}:k{S_cR{{ju=g]Z_LD*},XZmWMp0"I$JAy8NbN}{2Po@^]>rT^gRvSMOV9V|n_E*cW=b#Yf!XY%a%.<aM^"I#7Y6:Lv|J)>:I@"NXJZtX&flvUX)j:*x@*#i040ROjlv#:}}>Z<`|@k#3:69#4Fc2zsE(;6k*S(h@S4X+qvUizw=g/2SEeWCWgyd096/[lPN"G!FY{{jqT/f{fRL)9xInq0d~j8woYJH_OceD%3^9p[@UHgS9kiHP)&%p%]).gFQ+Dvp8t9#QgBl***S&W0RshqtNj#B1oK[wYt{,6g,Llo9+f^>As&%HlGX%clrYRB#F+F@ILyR0RF}X0J+uiMYAUO1p6F;P<[n1EZ0(&acr:y`040R$56LsqTO$z;/b!yD|CRUw!*k`TllPHpxmR2wk$lG2Jfy)!n,0L*OVa&`yivnKlGi{P;,8Yq5p@fD=G.BJe#L1Drwj,&k^2/D`v/ajcPe4?l99gt:Pn;?TmR&d`L4Y*R;nc,UCGVvfV"vn)V|($!y>hacZ]w7ITck2ws`GcyGw`;;dCt.5xG7=8{5T]RuKk?*}?sy0Va/5SC{IX}?e)D{|@*s}cRLST)sJ5emP~_+Ue5QIPC0]@N}}G&k|3atvWg@O]mmYXiXgmhr}qhzu6]((h{6I%[th?>!2YZ$!95):u^&|t,m?M6*tcZQ>.<cB/;!*;]<N^Wy$Y4NpU&G#t_PI+U]iYtp[eQ+K<AD[.Wgfhe%e<i/Tx>F(7i$=3Lk[U~9gv"SW<[g`=N87ju7*|RsMK"ZGm!z9Vi3@^pfSFRj<L)Ex#$d54~|3lP_Pgw/}HR`D:th|7e5gi6{Z~Rs]w@YhC(sZg;nP:FLgR?%gGVy3SdRrNg]$#/aeP:Y2Yn=UI%(l7y[Ob6GUr^tM1{q#7pdqz}g0=$kc!CyD5]UFPLmx$qI@,Hj@k#7Y8my0H_vwq>=)!MKgJ,w`9@VqT/0vX8u)(ZPz9=,DlNPs6_jO0z=@$pg@0({CqL;*1<#UFTZj1]5{>:86m@t0Qn?F[<9dKCng7%VO6oe]9@,z9H<@&nfm=+Pi>DLi>9*ir9C2T*eQPAqvQo|npx##*N32&*9h{;*>@Pf%#!xIPn^N!NYlGQiI*{g$Mm]h[a{AM<)6_BmU37]^]_.E>esAQ+CDe9Fxl<hF#=f;:&??g=vaW!c?,.$:}t*#yM?9%ZX;kY*s[hZA}aM<sW_77W9`>8cK2FU|&J>p`czwI3:pvAxI8jY&Lm`R1B+5KCR7]JzEQwiXTNzb@uY5J*mmvkzlf],MDu{0M),o`pT]@%qB$%@g0fn@E:_<zT="D5QP,&pG^=nc2B`YL7nlB,VL|sK&ruD=h(E,>w9E!ztC{Syj#T8*/T5$?#3l^EbYR<)_`pPd;!W%{v0DgVUbF2wm*[[iYGUmH65A+wPcK!SCGAH7N7dY*PZamw,ve4;fD:v+%Ien7H`k>XYISJP[wypAMQS>E]wmRG4U@dps?SFO9nrV6nrm|0mb$$I1q=GS|BEv+E@`;"=QSI>MqTx}@^l/3%Z^^,5N.57D)kb=er)e_j*XR,qC_h9pm(WG]uHRnaM8RzM#5y/@g0n0pK"Wf#]:gt}ds|Z&oBMUX|]0H*i3IGwHue:zPqmbrK;h>%%**qpu?SF9$o9TImMc>D{c;>|qqF%s8`h$AmF<4*r;fpyEuvS3WalvKN7Y3*4`y7#E@G"9xOfFz4X0:6.R<0H*B)n_h/tM:]F/j;P&LeG,LalH+NO&t9x,[jvQDLFOfoL5XlIXJq4467D4A2(?2)E(i/to2tP{Gm=gT2):LalPaT"HRqunVKFpZ;f9i~)9JzWC!23]yHbVcoEby?yhFM`R|y49QB0E7Eo3P2GkBMVxEH]u#@<46$k/&3!n,RtKdUj<HGi(Uk"1)^8|Jm_gq5!maJa5b9(`DE{Y}AI=}D7I;mt6BVXNX&EB9Y`P1LPwr_LWrENgrEdp/U}UgB7&`:`WgWe:a{O.w6tko,ZN*m?45K>PerFpuz;a{[()8hDE#V1_h8c3~ICF6]/;!aXdiS876~1Sx468zDGx(5<HaeMQk#(x&h_z1fna|*.9o#P.4|yisobR8]LxH3+KNvG2&n.|.m?3M[KBTe_CM7_z8)ki4Xhi@%^&ZU|S)h*6fF0}]$w)4$4,.(tT]a2B9nm7Xa5H9tk$Im1`X~}mWc3B*%[AHM)q"7i{XD(C:[rHt~};14Ie_leHH}|Jc=hAcN`Q!dH}qYv%HU*.[`m_Cw4wwgcRI|"4_L43qV`o@|+Ax3UuZm/<NO]bTRJ4Y3YxO6YTr(MJ5U=MQ2Y7..NT57sDTs8W33s5?>`Kj1lL0RJHVZhElpDYv@4|Yi#jS5.oS?BKM^GkI#[KJgiQY@!%eTj1ru3](`#Nv3kv^}O1/^h!_<`YxN)hqRh|opbTv/,}XJ>9JcEX`$Jiag~|+sSD;f7ir$J6>R:(|zx<;pF2kQIQ|h7:oR$2x8?=?)m`*&1^mS)c$h%lfTMNb@y/;nu>f(4Ls+>qe8d_Hq)nm)(W9z73LD)Fu?<%4^_4Ivn%rBHr?V<KX|ZmtF@*c|^,zMw0GyLS`w://H+]?LZ&Y]ppuO.YvZKqkEZV:El8ptjONc{h~Le,P:X}%6W%lc>CpC8f#XVL>ZKO^8J._y]T`mvMk}^@C?_6&{0yW*Zjs#}faf=DcBtA9oX(_a8O+,D(I|]Yl[(s2Hn$[V20{HimdFxv9@auIBUKhW>YZ#v_DAWg|4]%^bf0yOos4"}#L~SSd6>%>J2tk0u$cmuPV8}h8^/2Y5@hYL~1f|.P_)U<vj&bx[t#[L,|tu#TDj}Xr|$2u(E_qEhW^JM2IpU`i@`C0{wYeqaN(.N9dX#dRg#LDaks*rP/Fq.tdJ[yt$[M^4c_w[3{db/n84u1pK8[9nwVG$ivtDDl"pixJ$}Hc23DCl/q(p&3qeX/.Cu%[B0&6h18fC<c</4xQG0cvJ&%(uH,.Id|q3I~q,wQvP{&z(PSgSTlxjhy$zHE&u:TS;Da~,,|GDW44qTF@"z/4g1+|WyqNcX7Yz6f8P{}Smc0iyMV>49[H&5H|).`jcO}uXVc*"byI~}UOZ)n;oE+`~|7C`WFeM)KjF%baVnq,IB%lZye.6w?g+kC3Or`SjvO`I6wrW|Q*,6OYs2cNIzT<@Y=:o3l.e#5!q!R%QJC^+M^RJ+G3nFl(;ps?_i~U=w`xDa&iFc~!&^/*Plvy@p3<K<z+P_6CI/W/bG>9|)/J`fE^lBD^aperFqdf|SSGW0KeJYTr4bk$6Eo@&^;i#1vin!o*Tf3iuS9%EJY:#.NRzb80C_k!#F7K(t%w|o`s^,@"PhXKFeIiqey]k2#7M|AxQIM+XNl:j5"9w1<QZ&y3uXm:SIxO!c&Lt5>rsDT=#fw$KzM=R+Ea(qlgaaKTV0$aD@MY?t=FoDd]*2Fjb5S?]P@G!Y.l0e)Ihs0A+5hh_(Y9P(Y_y#4)Ts!Uqwb_45Q@vpv?+3gDR?]3_E_Sw!K}#v`R6=mMlTtT9?R*EHK9t<^@git4h#qOSwly1WqnR864kG|fW#NOn*9xJD9>H!Q)>9J^=$4NrhxNy!9>D?:!MhNDL37%Pwc{]oh=KfvB0.#e2y(,T]?[?K%qU,I5sp?(T[?x(,8HKfQWlnHZ8cCPO}#jcWh^hFTu,KjqPjh8K,YTE]C(6ABOND<O4xXnBRMaGW"TdD7VP,9!@Q?bKKqqQLDZz^Q+),!p8|4c.[H(CXr?_%hqazny1#ZiFjVyqJ,IO}yW<s.FW>pU7?M|[w:MYIulOSsdHx"*4IOC|MGYdc#K(<~9pI#G4WEY8F{a%tA/ETWE39A(]R[=wIRhA1ID(CGZl5?m!8>/e/rU}WYG>kXn[T~L/<"|qe$574}`8dS;9YC5?[[I$}C7FB0~=nemO4V3=(Hg^6KauD#!1Kwb@e&OL1Q*%_,nc7g&*9/X<qwuLrjV|{>%,3LdJY&_{dltF{:N*8!!%_`d^(sAj__54w8aOSL9lOe,Hw;fMEi"o8&bED#]Y@1)@gr|hkF*R;>_n8k*HoSn6V82;ey*DP,HE2qDvmVTb%&bq|wWy{/)Q&3[GtVx:pwYs$QN?F!#Nw1*?_EC_R8]_ioXo<;_UrS@aQ)Jv6k=_0jET^j`pkU/?]${&;]U.a?>@C#;`g}n,W2s;W"t95Z<F0XS*if(;%|kgDGlVe3iPio|wM_:6>iYCel&rtGer44?S8=/$e.ARJ/xD^g@xr!ozMF8Nr.XK.DZ;7iReZJ;n928n5Olozjy~Y1V^5}b~QL[X|7Vd9seTv7BxB_9`w&sy(6Y8?4g$v=<%nVj=8)6rRJ.}F!w(w$.)"%_&AafO(dBIh`Z9Cx7qZ3D!X)>Ej&,}e#7D4!:`Knxqt7kJvs`#aAj.S$Ex>Ci|H}CD$&/W.;#NP6jJ44#bEaepJ+%<(*K,6QW=ce)^v+XI.,yQ}cSf.spFMcQ7laxXxW;v+T+dGQ^^_FED~71L3G+v=+Y?BWvB8SwFhsMd5aio)3jS5}=jI9df1<DxzkBN2&Pm$o*mZzH1kG|_Vf|d^}vb(i7)6>)tfET.$d!`V@_7Y2R@r8X2m?n#~TaBa@bg]"O^e^2#~U,Mel1zWya>QjA*kIU]{A9[@I$@SD2j)s/"GlbHJwGf=GM|_FS/ZNlUuU}yrS%_Y2&Heh@"jsQ2Li99gxYc0KXV<IB8of@Qe_HXz2%!EP[~z3C)yC8QX%.8bGi@B)y[fH0*wSIBD[f>f7Y5YJN[r]_7I.!$S.gW(jsQoa5f>azU}EVX93x/CtK+5e(:8Bh?f%h3vo0bxd}?0*ISz^j3Y)B<W~$cF|h~KG5vSH@gzpZr*arb`9|.(g%zpb)r8j*(e+0dO[tnB;GRI($}&[LPeIX?k!7b:mPne0tP:bbg3nO&*&?;vmNBqB&a^<jXs:j3V~;#Sul)YO5O}+uIrKdYqtJ?9>h/HqrZzf%r?|1l:mxC_`:xHl5v}|sX`sZ=bukeloJ`UDyP!OwcivB)Ts,i;4/4/G61P.Oxfynx)KIv)%Br+%pBH37V$_g#E~zW17VX#YHgkCIBERXYGJ^yu<,h16MWneW*3Ir^85Y#sdqK]y$4<]=}gwKk4uQatX&r>LC`?Y?5AUKHV:te+i(?MIt@.qM&..dhsc<Or1FfrpL|mpLNcRtr`}TwgM2[CjsD"nB=1F+mBX_<CpHCS6,mBz$:W*|%|IH{WO2P+:WRU!Kc43=8;zaKsQ2vw[f%AGpZ*9NCi)UiXz$/DP/"21Lq&9NMtqUrt[?,=SpWThWfCCZ#y"d|<9duk|p$XguVd:`Q+MQ"%V)$D91omHSQdG9qZJ(0C4%52"VlxQr5/!g3*jG3*1Q$q0,rgE)Hf#V.B#YL8lKp!!iA;EI5?powaNbT.fO+JhxN^i)Uu7S~pj`6*.yG{Kk:WW%S>9,GBN1BC0^dB6H9Yni6SFQ@}fl7QteLg27zlAR[<P[V$W:T=mm/@}:~<X;mm*Y3ad$LdUd@lFqVw~.p=(Cb$!9`k,%$&AWVK5~V;e6FzEMVIRhr`RHtxte/_`["28oJ8mP}I8b`1z8JfIZTMRdyp.^?ZpD.UZnsBg}Bcj,^LwRF^31?iypo:8c;1uuX+oP>fmq2Jm*.zgNOP26RMZIsgWjAb>f}a=0(LQpn;1>@6oyRN;z}zIbu{VEheIj(h,0S.4*kIazwZoxjL*tqk)X*Z}B|X=RW8`I>q>,3cwhHwn*(mGRQ6?JE])q+6*n3|H<|1eXpNhB5g`jC,C0lw^Iij=t#GjN,,ajjv)E>%/B%Sk`$2^baO!Y+LK%2g_etOTUPxfJ>r:G1Lqf>MH+[Spm~/b`Z%RWq~P.B%Vl^*8e%<D7/whWm+Z{QQGyI!!KRzxF:00Xx`5`_h"cgVeDJ6M1BSmxXR}oEHUj,}bFRrea#ZD0HJ$/;oRZPi+KGX}=v8?}KJ~Z,i!cd7HP%<k]HJEKR0gm50_]!~1K+KpyAO8?4db32xOYEp6.:;00]/s`,<@XRL5Qy~~UWe"xwjPSNvgH+=$yV+Q5RoyWEOL6zB/%$:ah1CsZiA:e]fk~^@Im0WG[W[AiFr[RpgfK%A()4R[&4l#$x(H^C`S4mo=dqb.[k1QK_RAwUeNUp5:DV&S]UkB.E57Vptr`j9>,1iQ:s;MK*9MLb8N>AZ({emX+L@AWo$}kYD(!xy0hc]JX1)(B/lh8i&TA7bnD,>gXK&GOm9r`)K=`H6`+k_,hCJ],Ktg7vA|L/^3BvT(ybkSqnlcQgue6V=xNMcd!xW^<&^s]l(PH!fB]WT7sx{24pi2TgFI<EjPrm{MTH52&;Zi4#vo*C:b1]4&L@[JP9Hn%4!hY9s7B4C]D"vX@+a6MFewEoL)(rt]LhYM=G0<Cp_5W?Wrt{0+e<87f`)%TKO3HocU`bD]OK$<&&$Lo%iV?D)si/+Pm]@P{[(3`_aqX(%NwYyI",YoNp~nYR+3`j*?:>e!R5}b|~N%!gk&`W2eZCP]As]uBT|#;$S@nwi>MA&5S=RKf/@?Kq>QeOr+>W3rLkQh83g33@*,1;:y1n}oXjrIZbE#]6RZmdNbdxE7`m9vcm5gBg3A`R_OeqSYw!2paeihHvySOh!(]n4K~~dQ2zv~9?GF_*4&O|SNnaC.ox<DomcBtr*LXU#p%is!EfyA{en6qZ`cwHVi|:z[r*T%}aF,}PeY[|ex_#^ahjU5XHV[41)BX:EQ[~(F$b%r;KZbb}0=]Fjm|7//n_52PbhR6e=Eb_U||l=u/,50tnrV%_U;7,cCn}?[Yb8$wf90]m0g&)w8Go{;>s+%epf.jNI2go%<oU7&7e!cO<O=pNhp%A<F!JkY<r)O@+aGei=zq9d=pksx8z+mi*9lRs,Ru$tM,f~KConX@_?vg^7h3RuOXohqK$cr)5j%HXN"7J^@ORP_U19f8%H<O#qhH2,mi3HRP#qt4([_Craq!WvNh3XH@qm;E);%gLiq5&Lg>g%]U./xMFnNO@,2JenGDs$@&_,EteCe%qs?lggCP<"B_c"#%3"_#U~gC*Mc2oqs;Qn#:++.$<?cl9ph=37z?/cwc(y3$.;NTUei|p;K)ZyQq^rG9dt~l/3LfTaQpP)L6t<Bw`JXJRGC*n.]UeaQkxrAfcfLgBu;ql)IsMO$|6HMExE]oNh(R/.MS661+w.QEGo?51E?esVg0g|dZ|#%|X5Z%;j%8>x{rPW=da7e/uL|,[>HTSmdR9!nfj/_,*fB#pbq[YO+Jh&VF7a24>Zklb?oKensTzS%SF42xRsC|yWFLIPYJ[O?(b]Nb1J)3#M+[*f^o34$|BVMqY7ZnPQzb~WUbjy/]zVAQ`#<Kuyu1~(CyOlGoPmd=o:/}i]ksvr*V[bz?H_p}vr#?AgXu"Oy_mHTc("ue0&p5t={RK]})qkz,m%vKV=Cp"TV=NXMjRWQ,Hk)[3ez{I41TYlE"5SJ@Q)RWn]]SjO3C:ZmKPfWJI:k3evL+}/G@ySuZC`t$lK@*fsHp.jR{VInnh75{}}4;iy)4FY)tusp;>TOAky:vNHxn)<PNz6:#zu#M?N}?VJZoObx1rQf6;@(YUrVOX+foT]opRXZy,N(:W8|K&gimuYF+=&Z8zi"wOUv~0e"Q|}+rgSku3[#}[&UUA;Hd.Fp~d];}bPIbuu?@D))qE8gywb8I&FcBG?f#W@5:#LN@xSVw}n[Wq?q?8oo[B`i2~$u_8[Hl%[hetwB_CoX+,C`ohyk*`8#l_hAV?$A!`aJ8$#o=cUy?>mC;K7;ReOM|]:cuALE@^;w@^]!>w@%YClg)^64vQVV^2hYmXTu5r5D1[]Uu7Im,+{y^QV9^I=8>js[oVwM(CwOS,@YRxwgTp^A^J"DYY=/4!ba$qpB4E,^Ac6kllv#(t1T.0{KJ|t(~`N0.],M+<G0.],Ly.v<|>Z0y<Xa^k30wh7;AJ2Zs;dc:!&m}`.6m`&R?&{q(nyTNnbtk9^JD9DawVs.EIun`L3Mv(3fH[,,FR>;(y8CioOAEwts4T2!*1n=[?JX9!ufSbE[nmgxoO!RT$EGF_dii^DXi(myy,(XR#Bx#qiCOK,@IVB.(MSoEg5VvmY`C.h[%lRwwoNCC8n=PMKN7F[8k2It?xt)TpZsvXORR+u7YA?m![JU2QIdQ~e+q0X>Atb$Q.u[(Gf:FdO6iclQI*)vnZkaKx*hc"e)HOu=nVcT)8fT,:5{elx>I5!4Q~:!*U0El/7r,JKkwxOK7nDcY1&fHDDDgM0/nUKb{:z:3Ih.I8/xal*kSWRpB#}S+*RDV}q9sO6rP/Bh5SVGR|D6tAw3d5EtuLq,GX"XeX(d+o+bvK6)J[Jo@polCyt^`N;o?fVUD9QGae(L2D)C}T![)2E5w}a"S)M|Q4d3k]=FibS+G1s~}QYo/>`^AyL;(?3/aC%{|XSQ*[*fmX(Hw,yni&pex=0#x+$}}<+jn79Xs*]QJ_{x=E^II;W1(Q!rInbETA?0d<PiyobGFC:o?JH^@W>:E,4+j.EG9<{ZWiiT@pB;jXWooyrv&4X$2aC0=Y/1h2<Cd*UQI(!hZkHbuznD8d#AzCJYY5!0u[X6XIRA:Y")zIr+(40=n(N1Md8P4{6niPg#k),}|oDw|e;`|Qnbf{PZzC}"%KE:mlU*J.GDeWy,kMiVx#t%NBh.b[x[Q`pj/})&a,D)!aEsP5l1U0$93y@Ar6^.&*.FSDXn}I,tSXH4YK,16xx[,y>[]ZU39_`E]{lKf^%=Dz12>[koo<;,eTu)3LyQ;wh?!NO5*C[r=;g~U_{rS0VoAVKmf@ATJq)biU"ku,h0$Os(|+u;f9I|9K&"^v&G!h.4Yaq&%SIVX]C6L{]:iI8o>>p,Qe,c6fx$G$j2QCD6LZrg~Om7{1_pN=OX5c97%*ZQxJf)?%Hi9tj{:)</WK}}@rJ:[7HlLna^GI*%N,JQ&J.l^T>?y$f6x8HZ(^5>q{t=<la[@Rhq3A|s,b{5wtOaMA*0qI/Yk}S~+uH>:nH"V@Hdx0e?+2r;)A_[)eo0Nvb,G]P0Hl*!4V|/FJG=Gg}#G[|yF8FOjf#s4l$7ALd9ZX/zhru2NOmraQjg/{""hi~};V+D8lnW)9G/Z$OU|RX`S;Vq?J7A895j<.l%d9(#wU0XKQ%dDcN.Imw2:oo~t={|N]s*|/X93eKD6?gMVB2Dh4>vw#1g{.hx!E(MsJE6W|{qi|6xWaen?%<VJ_A3B?wi5r[EeA.G{tn@,O2U^%#*kL(+8>nWjKhm6uKu4tnxC*[j;.[<s~B95;4:BfhlGKE!w#}S_TN%!)@V=/@fRQ0#%Kp(0naljh}9*?@T{rQQ/:Fif4X}IJ<|qFvC6w#uf_L9g(A"99:lQX!l%!<>;Ou=BvB0v:$z1H(wFX)OCkDxt9EqAd)G^Ih$vqBpMagjfM]=N,!kK,gxjcr(k4^/X._0_;ku,`3Jh=UhhGmqrnH|yQf]nUXoP/PF4)5>n;k[8GEZ5$/A?K*T/h{ZBGSjv$PMTTPa10{OO,&*kA^zBVsL39$63Cl0Upg[gsLh0c!=A#RiVzNo;2>H42d,`AJU/]@vVMUn"SV>J$Fh)J*RRd:GbCP3ZjnMF9CL"Gz}DAAqG?(J*!6i4%EiA0G.HA.St7ak;I!9e/_D9O2o7X_NuW$1jdRVU4O|dI.8EiAVUll~WxG?<}G_)AAZIVAZKbH@udEjCv+Uq]NJF#R;LS*1EUvPFNt79CzPL^_2:2x!B}WfiBJ7Dy4Q7^HCX$r))Nwh~(DXX>[c]rP&I$_IOr&qu%5^*gGm0{VG"N/mB*,YB?<4GNN1P~1[>#r]yrmQ,:W1C0W{NLI"Ci5=baKjV}+9P=$nnlUq!93f!MI;1bNDLN@2k}GlsA_WIhnxy):AW**y,#z&siTUOT@[N40RVV}K^VhF)k#vX<2f(aw;?QWVKX_"Ho&Xva&4X&[>;;jep:Ic8d5E2R/sae}L[NlIU(=W:#*`TASLxjE$"{gc]pZ"xn8c+f2"kJWz`;CW8wuW?&6*wAMPk;&QI8R[QSEGxFn1]]+77,GS%zYsQ_Swb,5h}TJy+o0V@]2o{s=CG:>0Gm3G`$8PZI/cJKj$JHs@"|T,B/FYCPE5|4>K8A_HqCha1J|2+B[0Mg)A/8p!pz@q`nH7v90+0F[k5rD]t<(#QuIVXHD|!8cU2B.YbJdb?<XtxX)0}(l&Z,?L8+_XuSBh(Ge7~|^Mm,:yQW~M&LMkJ(^5Z/KF99#.;LsRe`U0lQ$b8`:DCK$.F*D@8*;;%TcC8rma_7lK:%yqfJo`ipz`~poML43~VUsK+vIx8Y|XWotp)i#NP`=ZjW(TP+dx7j(EE_OTwiGMn_HfHOI|$Dv(DH6/TQfFM"`:Od4(D+Blv:dooA6V9r1_N{d?F.E[+~Z~KpDzbklo5Ep:8B)QQs,uXrU]`]pfm),I5TUk#MI<qmI.4&QWDOhA:@by?b1v%_V.BPnyM.+ro@#sS@w0Pph9Om@L`#wK%d/euW!rB(/idVhhs~tluDdC}C]_CqUi~dOTL]|_6u&~(4jZ]<F~@yU8Lp:m"}uQzSJuB(/}8g/;@8vtIiZRcl`L[RiB?CWYX_qm0E"_"h?vYag#q9K`T<D+5T=yloaTU*s^tG7%Mk#*zpI1|80;n+g8G*sTSB7BMY(+_&|mH=d~[qf|Se4F%]eXrEf[kM}UQ4MCo>B(l,`iXZl*@$|jIPTuK}cAI.EWt.qqVXemIy,Z0<miVnoS$jXsO8vemKs~Xp,*R])Lb:+6(`8TfN3:w5:chUtTKcZhscY(}3dgD7F5g/c?G^Oqf[Bx:zs&BnO?aCePtSl9Et,D}/)mtH2IX(Qc^Zx`Q_p:9!vooPd$56L@}@@*dLSujA6Ba_V;96v49E*oC)f;/_}bz.:IRT3uZ<#;7:Li4AWAOS/~Z#}D&*|K3>7&xWIrlG#oiw72kM}rB%)+7oiVE"Rc#L&ROeD&~8<FhEasHBdonI}PG#^$}=MkW/2~NRchL((xxw"!Y=cU|m,^XAI9p{GS*rs~5{X`o]u_AP@)DAEc+mHHiUB%@%k%YgFsHkL""I`!@.DQ<}5T5+W/T>VM=Q!tl83^]@!C<poXLq!xiFF}SYiPJ[DAi<HABZ;uF5"kNg*4{OMfOYso@Wid[qe7C4r9X]Ww!y0GVB#+FY4M?%Oj*AW{SXOWM:+3xqb8jBD]7ia?Fk,0+&0DfqY9SxQ+05/j*?(TlL@N6;<#jlS`8pU0VH>YXIfo`lr~eGH`u8E7xOA2wX0=rm)lNcAS)|(*Cc*2b1TpFi)[Z:v=0@O](>u74wB3@YxQWYJ[rO[NTQiaY1K,B?`ReU)<n:[i5hjaTZA.B0[]2oeijW*=heJ63D&^@Ss+CQw_6ORARD6|g`Fv&(u+{j*mX:k#iMIg0}QE0UW=D%SJjHm*hKsi)^P}B)9QPE@GOg,A)BZ~wtvBlDy0Krfiu;JM&MG!Gde+un)B`)!KDS,#HqRJRL=3C7@q`ZRLL8$Pehd$.zGi4"S9C`Sy^m+B%S?h#p*?_4VyTnNCvRkFT(wZq=0@2cy8HUF#X67hd;@k|=64f>,$ol$f7>=nh<EFI3E3)5D.Xbsz0<TXOCd<7jH]O.u3U(w8(p)4jf5u%P0gTm$&;W>I&7XK:TLPL[P5}LS}h)HfHpp)w2nvhM_EFvvFtdu,ychht3t5t3t[<jI}JqK7Aqg8Hh!NP,?hw&4a*k+0CyLFeooljY_&S>OGtwbnn*$Asm1Qfts,w"fg0E!:Vf`iisoCwiHG;=p@U}qwuTn/{JqNU1aNUpaBsWTFl6/0Yh8X*?5Qh)NyRG2G2G2|n[r.)Qwu=V=yaCx~%{SKgW%ybJjrtr`4=^zIg47>/e/1i,1o2n2n2WJvSFQrl;f2jRd"qFFty31^1HYBu9EMy[t1X?Bt,G9D!}`i4?}0$I8sUXZT%=a:,dM]zA:toA}mUK5IlwM$|LnWZ5aB4{N,nu[L_+)(3zB&s!hvhzUr1,@ut{Zu&^ziYBzz%RO~Q5tfh/NuVbbf10cPTVMf3>/W&d1LJH.ZZ{N=1B.JM"5[;NyG{Xh/j?b^cv[SPY{wM*|"KulPT$U<`B/T,i2?bEK^<ro%>ZZ`2_W:(CzaLl"3tm7$m4si&=TZqf+LbeO|h<nE}rr5=Y&xw_0i3!YC[{&dTy%WW~kqFO7jQk$o6yneZ)%~[hz);9^G8*si7"mp#4m#EMy=[.LbI4eN!ag^Tea=]6zj?{vtvF]t.@Cy!%LqMqm>LJ;WtTz6yce2B}oxR)Y^Xv6%NeuH*:`!5Vl`bnks4q{u,5]pR|0<7|rH%I{$m"wt:JBf55Q$J,,!9<euEx:5BeOUMiMHRwQ4SNeK6G<4.PvHr{wpU7I>!>obRM6Erh$viyAflgvvN|9GaJa27;(`WnS*MKw:/?[QF&y[rW@xKr$~e!DKI"feL;1oZ*hN,t#u;k+BY;jiVED#YUr&tv#=,,E>Mb.9&;iS5$?$(}jqG;K<GHm~LEkX(Y^A&<h{rCi)EKCd"!*$IYRr"d`)@VXCS@F_qDoqu/F7*{$/FXZyydch*GHlSo]+lJd;mu+G(e.%GcCK:/6Np,de_t|:HLZ7R#jG[.Vn^b^>k<IH:#Qp6BP]nKGg7T9h!fRT.&g/UrR;.%RK6XgAIj<5=:4$[Xim#IGF,dFeP+$W>!3_mjHy[ScX>@a#;l43x/zEGxrT_:ZO$s5FG?{Nyk}7%(,`$3$z_S/hIa%q!gx#To/#rPD34,:PW58A+SeB6|D}j@m@@FF&M^Q#GWw@mhNQH;i{vYO8?BG:Wq%q1zNS_<pDr+d)@s`|x%v~(k+}R*q[cIY9?d/Fb#*_c1iCWoiVrN$x`n0GwYcMne9`iKa":pv*LUmfmP~dg5{#eDGnyW;>Rx;6Ta8p^^O]a?+W|)d/2Jc%bkyAOx0^^mu=<^@i{ICcCI#r(1>yLkkLz0tW):{~Z|(LY<bZKn{|t7Vwpp5,U{p#GUS~m)5*4cLtM)3~NSxFg)Q}G4NYza(Zff]MmaMxLMD0?$IiIvabg:3QXry(Wh>bVF(%`(`p?{$FLlIqxPwX*78iXb5AOo>)3h1YVJaJj,y!w&SP/I6Z2qaZ:1UQaSSrQ_vqSEl+vaR#x=^Dw,YNs%{+a>|v?S(ql26/EqrA}}<C{hl{<*d)Z^M}#%dc5vZ>@i+ahDY/,z,%E=W5RQ6)J7rUv=w;j8X7/7!sY4)$kHG~$`HlE7/a+T_&J5;[KsZxYN]3W|bcpMrKxY]Jk4)$kbj;DoE>i41/K~"f/tRlO@aPD_yl8X,cs77yo(a`}r1zz5}Sac2|zj65d02RYxj^0Vkp0~,ws{f#k+HH~?N(A3x7iOZc~/8I{J2}uvs@T.!aMr][B2kc1b:2cPTqf~Wz]C8~ctSPi,=StTam_1}|q1YE=B_:frp*&h$@xDP=!2QqES@mk{HHopL`Ju7pLMGRM"f#W2=PxPGZd7$(ASOPH,HA]"k.^`5*w2WtSm#cr~]eu*hshog)~4DIam6SO!:k2{Zc5N5*wYV(56kQ~+,0}X0rQ*v>x~TuMCjWFO>nh:e~VmCq/(QuGK[1ZuB==TYnlY|LiqeI4KFAS&>[,r|7t"9=O@)2]*oJ^n6X(hCsb$^!u)5*XB*~?o44e/F[|:]_Fg]ADj1XKz]a@O.e9Elvotw!!GDU+G]4LvJ`9r*;K74i8,b^Lui4`HrwFeP]n5EmfY{EVN<`[e_~(!4O(Q~]=I?*L#[.96?{9BD_CsrAg?f^8/lb4hZPthZPtIAuei,)qW%hUJIPq<bKCK:iOoP^>i5HXY((Y#L?46#A]6,hS[BE7+aeiHt[q{|%_|QV2A!;>X7`5AR?G?(EHttoO]OmHuJGROfe4kq2d>F0+tUeYRGEAFRoDv(+uhGPOcc@_^X4{sr@A{us)EaJMy.3B.L?ihx6FAAAAAAXLBAY4aZzh:m6alFP5nGJ6K;>=85Yb4epe.ms]$M}igCag*Z]MLr6ydJ/M^:f{H7*j=Zb+nfdul#J*fL{S48Fw(puG:,"1PA+Nd[mum5.hA:o5OP1PlFrxPK*EhYIEiIY9Mu=/xpJ>Y|.CdXVMk.6j1LPa7vT9Z1nfzEAmcs:abJRPQco7,Xb=b$ORg4ji:a_KQX3>SkS+">iPX34;nNlsAidab[E6Vp/{rGuzKkXn+p<%C$7!}`I,PE@WDi(_Sa<lj1]{.bM=nth,ts,S7IXtER5f:Qb0]9ItEjeJ<Mh&`PEyV1|#8Hu^8D=GD&#F[K,0,yUi:c<tI;}bU*+5P,IXpx5[}REK+xO<joD^!VlH~.YvDLR}7u6DWI>3v46EP8Srh9Gb)(%Hy&_T}$SJvF*?WY<8K>X%ah/L=7mKgw/I0c!b0s3@0,aIre}Bam)Qf&uAsWq/Y*jrHU_|dgF2FL=TqDl?rv(mLT[2I/L)}$cQ4|4xyr&`h>dL<6P{.h*UmPF&:C2C;/KaFx0b^]yOx=VVAf?Y;6[kr*v.AwdwaXcK.3rB@B?LUs2|:llD_biFc.8@5?=QO~HH9SLxr^q3,`L5u`dtNy4S7.x}WSp!04np<*Bk/7hB/70J9ZIK}A6xB9.6#xjh%!@{*hBBgg:$x!@m7{4^Zfo2DCrKBV_lina`;@{Cy|J9HGV"[C||h9yr2}kX;f%8!%HW?!p]#anjoi8En/}d=qhYx3=%y!vBuZFrs}8c<XrY,1,%G)DW;4`cvq5}XmOTpo@_i97n`KDBC2>fL(.Bfp_U^5JH}_(WwpOeMc[17~%m{.BQ`?*ZT;wmQ7U!owM6,MWTnZKIU{vRztn_UiWY}=%ea3:D>ScO5Q[#6$q~.@x}$&E@0*wG."^,2[/gYMMDs!CQ6aG+>dZ6P|fT2dJ6EP4X(I3.%k5!SEE*Es5$MK4jH<_I79Hwa@u.@rqgm$<ce1d3Y=GqEP;>,P6[Ff$LsZy50JMLBS|R%4Q*+>z:@I<2yu`f::Q~#*#|#mD]a.4PI^8;;;t;On{[`V(+_+[l"K)/.e[bD/0#E*c#vPx=}XdT`uOJL>~=P1}fJti]A?$F/7:GKO^suF{T@_=]f5458F|"2?>)fW^qx$[O&YH#T`n+=w$j@?Mi7wn^p{Ox*B}?r(#kT#MRSw#WbgVg[7KiMQPb5rgwj2B17qudY6soBRSO*:a|3LW!Wr?vz_{(lCih~mzjXX18a_upS~(fa1e|5M!(/_{{9ATNLIZ/`k61Dj50.HDZ9{D.>M,3kU:|e2NYk3Gut??iCWh]71IxZ12_e9S*nW~V&ccZy="gLHWgjq?`/%$[e#iZeX5tE?O<{dBuop#%)h8n<Rc61T7^Qqd!L]bNo@lKZ32XO3xsy`=}rL(D?Jm0?s:5cU%;iBB}),1(NDADq_3VUy),=K/Wk3NaDW(yqYG[Zl!.4a*h;2?#E6YvBLD{Ozg/U,?23mAKAtV*K*v?D@FUCM=Lr+Mn+8]!78=C#>"u#7%=DK]Q04CS=$RSA@DdPrFn,?^}IaV{BxD/KnHkIDmQ8U+6Y^i>qGkz[mUN~Q4t|Q%o7+/mWg+2LB~JRoynPT2Gh(uFtopj<`s,B0(SP&g}GC~%;FJBWBeVIr9RnoXAU+Iu&z>T*zFEdNE2HQM4y2BOV]O*qu}oVFdI)3Th8iccRNk*5EWRt(wWOEOegTv<??!8+RjW|t~ISJnHx4vz#wIL%v1aC1CZvn0Cd?Zu3S^aa~_xH>N7&K:tElEgRCGt>/xz>q]5EW}yzb(&yZ8e:ZX3{<pOy?ha|YG)*aM6DpQGzMF~Zd%ZYEhGv8*;@ei)F*>*zX{H>M8uRh0e_e[$8uWBS{l|T6blM)uD4`xjsP7+@>8N/2DlkA62/Z+*te(x2E{TQ86K#Nh{h,5H!03avOa<RM~Hj~v/.2mpT<"Mu$mL6c)$?b3`Z2^[HWD)A<>_i.Ag7fB.:6,K4[+D?pr{,zFxK%>Hf#9V&qrbs/roOusq5j+_"L{HElzyK[N(`@Hoguy[Q2ib1s&iCdJav^zbheVjN2*Y/`1CL5bG2{)I.,#6qmzu&9M@mu/e#8>t;i.ok_vo8xy;!8LP]u$fwh3>OFZb=w/B`xfe~):|C3xT$^BbiP}#t^$zk~gC7eruIOgQJIlU]4TJs^llF/K6jD0#TPN@F)DZ;o2]|/[lO(__{}}GLfo$^fk+b3z0L1=JFW0_476V/"1heM<GUrjcd=+^;@DH|`JVKB.EqrI`T]>nnF!a$.OXvmaU][#r^3M:}o,c"<#LFyccH{^dPg8GAKK(uZZXjhcj1[;^StAezt2I&OJWjBE+Ab?ceBqnE[RlCRHk=:f;?538H*"Pl,+a~wfwF6~1;dcsx%AD31Kq<O;JPxPZD]Uq1r`Q|a<bA0k}auLB3@qdzLK[9EOUR+mC~krF/6H+DaW6Xw7*a*W%b>5&#{Nx^ULXQ)Gn%7UH0EM}]l5%u&mjGp=_frv21_75zttfvIbkq^rLPB1e0<%Hs?rL1ji*sEI1*X#Z!)@{(7rT>|v*|r$yKl$p`rexgS?#j`%Qu&7uO`7D$8NE:GUh$Z?r~[{QqZo_h<yJla&shfPzNDUs+Y>UR9Iz&G!5&$/NLL4tTa@{R,_g+/kr%Z)AXK$]FV`[G$[EVj+U?ep..VBa$zO}L,aw+A2k[*D%XK6$ox?gsuSdF$eG2bYf,9w7jo._x~pPKkmw?kTusb,uOHyf]0uF5K*G<`2^h_}2tPtiADxZ`fwJlk82*ixz7+)cbD)/T+7eII9`8kyb,.,WcZM/T(!W5g7tp7A`JPKWlPtHQLL@ayan9@slKdq~>NIan:Li{.9aCg_9<5]FI#,BxBY=4C*&J`PX6qkCz.KI~*Q<x$>?&Dw>W;A7$cu/`u}C4#Y$H1>##}b&}Iv+5Z9quuTdKiIu4;n#T0j07/StSIO`4]b#}#O@}!RGQGaELe<;X(>]h]xP!=NQW89Y3*gLfi5qh>hd1bq*}W|MzUI.vd%ycdLA0GImIb`|4_dmJQ6Y!f4:@x,nF+_G<?<zrnu[?z3U9%xERDLv|zr#LFByeXVkBYk*f&X}ThB%dZIi1#*wMT#DwNfl6#gMbqC5HL7NPy!*yite=)R<KO}mmUt8k+$5fhi[<U>b4RDF,mmAcov7|sK)9Ku|oK~v[9+c]Qis5bW,LfTnl|"S:~+^+@DjicHg[jKl;P|]k1}Z{p]DBmBfVzlUPHIK,2k^f_2oQjnOAXe},9UF3C}HYF,5=7oTYUV*E(@j&x=Sq5YF.m[@?9^>oz#d?Iw}kPbe}cH0r5~C~EL.4.+z07d&1k|`W:uYs!w{nL@HMd]"^zvd`J=m>i=/i9l<CA+05YjeM!MfX9BJWvz.T;dqES3z7Pj@]uC{blo8fG^.K(=vrmu5/y1J/kKY)tW0+)iILk80+ua?sG.`c+VK$uUNT]3YSO=W[#fz"e1_Y@ty].TE89"v=3#XuPKyy#C%MvUctg]DzCyx)5pr<du4w[HlUl]TAEb00+!&TRkR.;wYak?7%McY%~s%NoMQ8e?lNyoYZZ@ftSDP*0XM5^aODIA</Y&cc.n&FK@,RW2x=7!!oY(fGv9o{y#pI"aI+OhK!|p{Zc!3!{?:YVfw&#_09iUb)v#&fBBx3+DnAb+kY2luQ$J%7DDa?GstV5CJc:`3(0&&B5KRB/N|u`m;X7N}tx=gY7cYfL~4`LI.C])3DNUzzAQ`B"MF+7|{VcD.%&]^LM%#)k<}zZAniWcms%=W2#.U)]fS)[6@T]<jt_YB,];{0JW;VARBHm?&]~b7l26S]pyRy6)C$kkQoBB;:tcrMqGi|(#>ya":2gU^".oj5`rvr<}FJZ0kW;BF4795b!4?u2@Oql@sP0$)D4^niTLq4&XgCcZl04!"IFPFRs5f:5pPdqJwbXr3B[NX*>*=sduxK7yX+,_N?!Na.~h=Z`cQ:=i63p=H{{lSU^{sGgTJ#uYAr^v3$ae{|ZiOd>`6wL9P+9`QD?)nV*kg0c}~^8+e{S^!p?1*3L*[4(Z[x,w)47d4:F6@dvhfP~}B9P8b$QHgwQ~"6N"}R&:wbNQHv(jF&/PAbeB_$20!3p]xjB)2t[mXUXh1$f]tb}fuOuKwS#CG#.|qBm28HFlK^k7sCkWTL^%gEMG`Dg9TgWG,^=8*G}*k0_Mp]R|MZ^Pt:7Mf_xS{,_"ZP]Vm<G*EL{>OX3JETu+EsB]NcT`0n"Y7x4ks""=>8qcV*ZX:1xU6zjHplS*[IpTRlcLdwwl[9.1G#y[OQnOh4KPeMwOEJ^|vDwU+!?g+,c0.Cw4j|"#%w4:0wdWQx("bKpFU6xFNpHP:MSh`Mc*,/K*?~c=In{=/:dKrZPCJFV_E1`9r}PYv&<%k9kWNC=87P}"(T%+:,`39RAya]"!y`~2@qmvSQ2G0=[=Mh4JrE+AsobALj,5u&oL{{*C3!Nct"e_r@]aYx@Ny~^^QCu@`;p[t]I{$pa"{!p:e:GZRYk1^IFuIx;:BC`iTAL_DV|;W@soT:[LpchSaDE#i?SD!km$};L/rO@@r%]9bbqA[K??$fm.c<3SXM}6nVv,(E;2j).u^v;v$HT?J0KK%!k^lq!~e%`E;`<MeIGAZOmH8GVyD3m8oqDG.GHPLp5|5sHzc=O4[]cvQ~Hs1gXF_Yf|P#Dr|bb,owBS6l{Z~1X2`1B+,Q;89FHo<n:L&S{$9&?tr#<ef)?{[caS!A#TxxR;Ge4yI>D%EjD$<v^g8.[iJ!EQ;e$N}VR9c&z)k[pf</9J[U`^X8VD9vrmZ@<Jgb#W`,>D4/vh/x<8?6axl4,:k<T1vKeh<)/OjbmG%`Gw8*@r&!J/DkuD|d_Z:i[/`uF=&zR]$a7j?1sr4=zrSjAA2_>C.ZFjuch9Bt;XP#]7xQF,oY{dy0[WgXyWsGkpQ7B4he3@eJpIkL:6J~vvpmJ%oh`A[3&UtC]S;sKpGiMSqgP|{5.cPaQ"246r}iQ|IE2S&LjRP9?=L)O1[V#<df+DSl}lutc)AGt:;*NFBYXT&*c)=E8G2AU(C8n;b_368==Xn^kQEPk3^B]u#zWnTT,@2&5`QE<,;1I]<h*Bw%cDY]xG}G3_!y*o8,[|)8m](Np9pNZ$,44m@xu)nbh}1W3ijT!H6>oZTyn^ZBD)FygeUj:[&YRE]dn(G0jGelTfTE8"4]YR!^"oOTHz"Nv$){q<uGu>n;g[_pe*8w4iaG8Allf%vFeI^.?3vVi@ooyU<dZGNAX0)TVg#%R4Ky~ey6yXrZ%:q~Ic|?;5@1Y_@m^oH"^^V#D`.nwS(ef0)@5Ev!UI=eZ[^U`teyeh2o[$MH6R7nUu}weacax~OQQ8KG#728"Ru!1|PJ(PJKH`?zrtU5}#zY<<[u=2)3arVKuR^MFB&Um|F~]*yy34h=s*Zf7G;G/AF"Ue<K,6>.K*q3Iu2#!e^Zm4C4me#?l"Z^2NR~&T7b)O,~H#[`^=XzsKo%k9k6R)F=Y/J^eS6f6NdID^Kd]y(iY0hDJQ6.@9$e2t[b4VIvhT%+LLD5ap&=E)Xz2WKqR}o$aK511XJ8}<:@PHo./;48q`WoCN<3yby>>#3?iEXCOO+:JQo0U=BVj/<FsuPk!CRT2vL)S+Y!8gN68c3hv+TsHaMP80!Pv5BHwoP1a+JpsW~aY(WHD@O^NGfJ0}hxBDPK[it0+sB(7&(+)CoXCDU9Mm]lwMJ?F_Q6M@!x48i;Lh6p!f$2LH#*pqr0"M`q[O^$%Bq?8^[>f2>3Z;#^SXPHoNT#$KR1[XtS:dB?x[Z@E{:A+oa/wE*tfSE>$x;OWlUBWV#o#<>[H;H".}A_HMlA|.g2pE.hG<h`H*8oY){O%neli}.^_t+IoTf/w^5egJiX{Rb#_dHisv7O2pP.7m$WV9J`+puAMsHnCnUTHI:&HYe+}RUtl8=*VZK%_2Q~NciWc%:PJe0a$D+jEc},xuG,z,=HbfuKt`ghF]$du=$l1~$oT`squM~!es*qFE`QZ|O^]GvEE1@=uHb$BWSOYNoZ1Hlg?[bvoQzNne*^~U:&)DmF]^Cd1_Uk*:;%`nFqLL35enRw+@gM{b#$|WOgW8MP]w1X&_<%8jN]}1%0<N"FE{EOD,FJ%<>5u0^!k._2zO(R{XpUczsXQBd&sv%lU5$G6S?}uip{eW80|x_l2b1VRG~bv_!BMSCE<2n!$)+ZULalSM*0zjL!@ERSN^s4VWPewh%1j8~0%,@sO=/;ey>Br"<yQ5)g4~T!PnIm7R!cFkS~H#Uni~}tFG<#+JRs8`OB?Zw?$mUJb|c<D;zt|D<zWl?*9lOw"[T7PJu?}K;aYexV5A_0FF*sYS7+g=#4{"/m%q.@|}!Py0lWC:*hghwFo~>dH6kOLF!9EjPKLOU!kPsL;/HTW45R`02;6WWi5&$.lXjdv7bhDOjn|9^[%JeT>mkl51,w1ev|F0{XcpJ$7l)2w<Qa!A!&/!R$M4(R,_IA:x.2S4J=RBt3^Em[]:vz#<d51G8e%2BFB7uyQGMRY#^*)a@$f(75,)ACE~ISM(WJS^JlX?d]K#@?W=1lG4B_o0Np;iGy8r*[bnRiq"+S5w:PaXzseG[$5(hp_LKbxh=f5l;5(3+X3w<WL%N<Low!Y.BT+nZZ5/)5kr"KGJ9!ej#g):``;.AP@2m|%gWO+F![2(#!h(5@HE9=J=k5CLOK,<!G_"^*5/E12~d#BG}J~J.X93CW^}}nyPTd4AkIZSm3,.L=,(+ksT;XZw=H}0squ=&*d.Nx(9k#QAm&5.8[Gx=SU6O]fTQ[I(*x~)k}G.jaVta@nA[z:ft{~KuRNHd3_9fN<mvT;|[9bxQ0S!TOvf!sct6Q*4j<")%ht1gyj,8yY`az5..."![M3zpXiHNMDz!woHN:jnw/Mz0$Yh&(L:ha#Z9H1(bX{=B~$<wlPUHP4dJr|!s/UrOtFVtn!0|lPI+qK|.&%8C7]N+|9=3Oe{bHx[v$0ZYp4`=p7BWp]+FM@}*k>fqBRzn2*`(b/9)`LdMnLgNq0D^V`{v3@?m{&MW,[|zjjCOo2])K)#M"#DmT|A_/oD=2JqYlVXb}J5Lr9]!$ZIT;_]F^7oW[x{)x75=$>wmy..O:$doNd{3UQlO0EFw+8=4=ZQf0DHGS&DPUq"_ESMb`6/~.z`tTr9m"08H8Y#:xV)@]wI{d<J3DwBM5i8Z~Y.8Lc0wr!9rSGr_p!zO.|Z:{BeUbF!m?6rn*2OC<;ZX=N@;B$u>a9e@qc"eYE$75DRPBNV;.O#phnmn4M?B5PO|;0XR2cX6lsEWcg#i2;xeN0%Erk<zAxL8>!wpBtyY.*Z?m3St4lpfT{pUlPyPPa|`V|j?`;cydj1f0aEMMXj>k6[c.Wa;x]_.)DyD"d]M@jMuMjoUWoj{*sHo$Yp:i88#5{[;vR(|>4B_#Z~|&~H1!_EEK2A`y.G_d,o,#d{^=BUbkQOB4$;>CK?7w^CiUnIneMXMDNoqvl/}/rf$&Z1>pX?zhZi]:!Mh.(]oEtXEY&[p/Q5FE0^><@wYMWQet!]0+EwM<[8:k!"_{;,Wsv_;InUak`2l!/$"we?x2)[WRJv~!W(8Tv+KM&`>4#<5Bp[2p&GrC|$PuF,`[c2V%r+v`xf,W.Gq&![D]$5J:5]]Ga__D0$MjZcb^C7;B/pG^]|]96za?EP:"Pgi$S%lL%wzZv~_jO/zSX#q:1WwX,Aa~:CdNRU_e]MR&Wq=e!xgZM=GH45,`,361dXU7L1ee{^t[L+MV+?8_?:ET$M3kJYiNs"=AKa@"8xK_v=o%%`1MuTIYECQ%8Nh[MTxOa9kohzgP=I[>p~^QI8e?<iy*KFI<iFzr{FUoDLD]=HL7DdW1{oo1B"2TIMX_K:uG+{"kPh0?!pj"&=Ah<)r$NglF&DC`W[+%~2[kRVJn=I!^wdJPB/r4!!!O63Nl5BqW{f/Ftk1Q8yz5?Pv8#gK`)zIzNQ@sQ|>Bu!Vh*`362#:g)nS7S!iCDh3(/>3g?wV5/D<"@v#Cux)o{T+Mq3h8Fm&,%kBUbT*WM|f|Qu(;Fc0#=JB$];hw1aQy0,8m:>$PIexyVuj._QOI.l{Xxh^(Mny$Y)wXRtT/|O{Nf9[!sN+jE"Vuh:`XiH`QlT0+hcbk;ea}Dg)W[ejC^1%~Hvt$B!AlmnPL3tOk]C(a03)3bV6P(,%wL7?d2i?^V3?~:IaI;tt(x51*=saJFgd*Hg{B"46Vx(d`Wspz_9UbwQsTJ(nrg4^<+3W[w/O?bDkTKgbTky"`1.Z>Ckq$EF?6XDIPS!3[e2hgEi#nf^JOe0rcjaf>@b/g4,d*zi:|:2ypxe9@U.:X8(V1e^]{98U{Ye?;s{FQb&eAo:DucR?WpMg)uh:k#1h0eld"fh;KLtxF^7w:xg*op0cF{RF,qe{uk@j6JXV%|bTw#!yU9b}n@RD6b{&Dut.uz%gE`jEnamnxLQ^UzT=2>eCShgMT20@%|k(?F(q3&:_"CPt!xDss*/Lwdh@VgzL%PUlg]a8in1~`,8i*$9|Py(Q>|jqKP^6=hWdM!jvl:JE4Hk%1"U(c625Y2|i@|6_7[CGh7lHbj)$@<<c;O>K,I?/aNA3K|d?5RWJ;nm/Qepf_<B%{vp1fy7*e0a}ju,bJ1Vr]Znp$R"$~O:LG6H!/:@ZXjM191~[kQEU(bV:A0gbE1NeY8i4,#d<LpFIE_?}H$4>9<RE~]9o^[C?FH;@()[HLQOv`]#?&3<5jY:SUkpedt"t(.g=z@IN5O;>RLlbu}X{H310E0^VawD+pxs]~H>;r{<W=D+AA1vP<n&:.+Ag#&XH>n`gdo/D/]"+44ZK"&:!.X(vl>W2x0m>EFqzp0sOnt=K#,J0UL8H9y[C,0sPk/3.}q.COX}&7iRKn?RK&SP/RI=9m5Y]_l,`zP6bzP99ZB9h_,r4R@M7HRc`DYz!Edk8:nU$0^w#1]7"&uypKZ/0C7[KIOa8SeIs~z7{Cp@.$rNs{C]jZ68liC7b>oPzc_(ND/8nnWxx[Jx~u>~]BlECoVHZ:~FUpz:!J>7jg[,5C?R)E0z|X/O1~c+P1&PyoIi9>vcFdP$LW,&E]lBFWO<a~/X2dp[1Q;)tpe+i25x*[kU#XoAj[PPEt%:]N%guUC}TbOr~8cc<v,bY)Xn$lZMsB%4L3_gcu,pk3<Acx"Q7},YX3;?+8h6?43Lwpn0RmLf7K:QxxCkdK%aC/dS@ov2*Sxjzhwy|Cdv!;yC4I5h*DqA^girVmSFw!cAASk=t7p6:{A1ZLGI@I)odTDn[|:CJBpbz1.~0G}I<82JbhEwfDj[lqV6qJ{YDgd+|@7Wy]cb}H$0#$`{Mi6R7;JIDp:bFY0IG1Hk]W^zAzv&p}R}:rTs.#7py%>iIMwM(g!LWdJrltxU@LkSJ$]_vQ^8,?<vtfLW/h7tE?eLEBy~Zb]"$Sz?)1pc`U4(Fn33]%]/h/Q.t"aF+P+to7fBBR.j:q!Tny{(,N/Iz1lO6~q:q1!>]bPOI&xch}G)0i3{iY2=9@J%cM1WE?eMTGt:U>>vcI1lMZVaYh{b9w;B%>tEhPN}{Jax,=BYT9V?ouv!:ut|K_9o!,ot1d6{)/Kkao&"CU0=yYF6x.pSz2^J7Vgqvn<V(V`gH!K~XUku^tXf,}Lohe_T)O/;YO?eH`o|KroI6)gHS!djh(6;*2,B|L2*J.4?M05+_$R3EsO?umt2NUij{I1mOoi)n[w7VaVFjYQIIwI8wgwMB3qU0.JpBXEuhC[SaMB&S#6S5V|4qgj?:2!7v*Y_]u"vZia(lU)q[DIKdW_y4&`N&n:P)/9|b_.XNX)TDM5=<D}TU`niJ@ToDY]Bytapb{i_8.D_>xT)(ej_D,lyHjB@wyyyNJ3p7@rD[Nk_^efZGUv|"T+ve_PMcF"|2Df%GR<Gx<$O*+g&TC9+Wv&#s8aD=D1VzYkR<.?J7AQ|<6>%=uTMh7m80k?;]DFapdyGc=$V4|VJ*=_D:4+V_Q)7)n`Amj[Jl,n$_m38%a:Av<}8y9JbXb7LILwI[Q=ax5VZ?Lj(mNiW(qt*7GYDqA^]`}Rrf)[]2Dp/><)s*9^`RN5fNTrV6MS{kvnDUYyP#TZT17p7/!)ep9oU)zt6sjCq}7?.))e>*UfqvL:TLUDoH{Cx%iX%5NuYFfjCf!bF$8oW{M[_OQ@3>IPS&S/NKWtA"YdXAmn`Dp~R,"P&&CWckqf.!$23qo@$<bd`XZ1g4(*G>@uuQZwP!Os!(;y5j]0jNthXGE9^N40]m"2SFy(ZKRSTV5WRTDN]1w%|Jw;IPboUMeUZ[?)o$P2^X^h9Xv]pdaf!M>D.*Ox+|H0L$o0o4G6*6Ue.;%ci7JyCB8cSM)HMBb&;W0iR|[][/zW5*fCTe^FaB|3$`nhL4,n:2CcKd%O"]<QnXxXeGO9"*c+W8fj,"I]e@E3;,6TFbO!R]zm^)p!k@a?hN3;_oHmj.mAS60"+}e`i.#V#=&4ATx):OBWd>s]?U~{R]O/MoH3nd)j&j=wA_}c?q69./YdA%!BmAWf>pPL=fL<;rY@g]+.0;Sru5No0&:XOD@Oz6Ladqd^{6%!2CBl(noz8kid5S<+p1|ZEg2(CYbC,J9lfW]>EGI1GDrI)hxWQg#_&3.W=uqTJj2BRZK~adSZxb=WUxnt:Sptstx2Gs`tPx04*Y;?H{Fw?c+/(:F,[f@q06zA*KRFa8DoWsC+@D"ps=40bD4XY7[ma],W2A<iSLz~3{L)Z~%;M~K|cjpb54]6^`:x_87B#D9_*{RC<rj.BY%~2o<`4Z@_G0.BkpvlB*pTgBY7Z76IP2[FT2Z0mG/>O7ck@4|R@LDmRwX07qrXB^/k?D8OlSo#a&G{_=+_co=4X_{}.0~)jO&>0pd+X`=fS7snHbPd<%WUtY4_[J8R{xRTV#ER@(>*uL9F_Byhbuvnz!aCpw?oy_LESmKCK!`w8J)G*}Na+87jz*e,Fk|nWsk(&S!)~b7=BnpluXHDW,O:}t:IE.%]:waI}h1x=Xr__`Et9B_F6F+:o]Uzl**2T{]cfAk,g7WQPHidg*mYw7A4;SbFDb@<I)0lL)d5.Xn*|m%*k}V].uW=.V[1)dK]q>f&EwIbMmRi]htn_[2;N6*/$<8E}7H_oA0DoOK@|B;DPsDG0;cUlHoHYVm/JFAg[KfUK`:|J_V6H!v{/.<M9FG{Ow@a~;RgKd[v7N`9@|]Fh.YG*tf@uy(wNTcv:{hL0i2>$3%Hu5}T$dB(3OT:~y6bJ#Fi,)VEL*tNp5wI83KU#LcY)DFe])HO!l@=tA.u~QjqyN%rRI_]jHy7Jp><V9|=94&#D1^m>j>2)V6^i&`Z;vy6M^xUa9]V<ajN19|BoOpd1E41qM!b+Fit^x{7^{alX4VL[CX+dZLJaUxjU(hr4*pr,|_$%8pg[X}C.KrO#F$_<(?"6[BQ::Qxc$43vs6E_Gs33BM)q:VKMiXQ85;QN~#rZ=`a){,ky?EQQ!s_,5N_i`l25}=U=4ZE0ucM3vQAnkB9,%ITy)b.Cwgnn9~2>i`){P"">g)iDBU:z>^M3)ywK6BC|,$D`GL!Ex4wcPReEfZmb92|w]To=:dOz_p3LXJAkj!bABqnJ2;I~Oun3QMf;M@/%2IQD}E+>Q^qfVU%>t4m`z+vBZ)]LCWR1Ke}Iv:N?exxI"DXl*$dFRW(RiCAlvxb71C*vE),6lQ.Gmq,nc#9)K#w.KShg^$E;t!+CPk7v9(ruoUd4A)*"<t,X`CEES"~.f?&x87#sh$umYgkTrIwiJ~}JLItln~r6$}[WfeL?H~D#wHLc/@!d`b#iJ"@mOcaG6Ob+01h.Byy99;sEcw4=ir)wy.)LYNO`a%g^0?y)CM1/fl?i&+rc^N9gmru?#v]{1ShUMv~"[F9<g3Nn)|jF9]m92{WU*9tYF*Qc>F1j)k6bq>#/DOf}Abz%Dr}!tCm6?V[_{qrvN*[6m>Gz(/j{m6D3/j]$"rcG3*wV3?QC3%gh%m/@Q6kK^y=WxSSo{E>(=/wW}o&F.J];{V,&d+D}.$nn@)W[r&2lyfue4:@EH+PD*BCA8r532L(5)xtY~*M>Ea#mUJ,ehCSPF7}faQ6ehpRVt)xu;8$;V2sXhPPOr}([.zRvx4sn*gTgj7B"2ZvLq^ojHWlHo;=.5Ar)5^{M%v7gz8wv/|6HBeJ[]ySJpY^/|nn>1gpk{Mz6I"&Bda%)[alvQ5(r_>|fv8o[6&@c<?.fl=Xpy[[pfaz~5OMH(__eK5k0r>|ki&<#oq?V/_AyG|pH2yN({NL?a:d:y:d{I*q3wf%8:}Xd;G!G#"C;K(|:*n09IAry4n@Waukvl(rh8NG^Tm8^os:2CSmae5:6[MrB#Q6(VB[B%bA17]$@3qhm!^Z=pvJsV"|P!ks!%Kwe)d)]5q]c+?zzhN~08prQkn/j,)f"SjVtqFP?D|;f5g<GO_bvG&rD:CnD<$4E<@q<}vP3rE8?RtOriR_,<lxz5/p&b_[S@Mp_5$skzSi|1tT7ww(^;agQ~c,Gia[ct`D6QE_2%lz7~C|d/@)gf#5z[f$|/D66>&RL?;AY~VsMF,6p5T5=Py4L]_x<8?dU%XRGJ|q}$]?6]Z#%.XbXtUv*PoI6Y&@%)!m_XeK#+0>J3)a0Bv{40hT/TVW~M2oDyGE24;br<Q=%LyCuUP<TN2APQco&kZvIYHywFbX,/t78Fu!lGGDd(@UlBK*bB^sTo*|rf.:>^nwFP&}i%+h,G5NB1yfQ;qOH%Lf(@ngWZGTl,40([9hvS0VNdYP,E`N=^XSFFy~1FJqyWbx@>j1AhbH8a[c8L^5&jzn>35N!DkmP<%00a=;W>(we*N9Lg?Q&EMh4oTKMtHYWD&&.~m(ioao/)gRfLl9Zle%hNN[$VFshh)c"1LqUl!VT2SjkaehZxg,_I2oYtPD}#_e:|LWxac/_CV8V,N.z>(+mrpg,eHx9l(FJqfSmYF)LXyA^e{`@K.)&ZlKqTaT8sxZ}=#lwv|496=OKI#ir3e^NUv}Btjp:ZNr;?#ZB(f}[^wB@A>.($^$6IbKxh:pFSZ)zKilhB^1/yMm}p"b+L%z!>6OtLyg@LokAkWOVYo7qQ`z856CR8djG](EYT|g_N9`tg_gOg@L8S>=a#s<lggcy8H%~KET$B%h59SCr)DU!}{Kh)<C<(^G#=|4=qY[f8bJ!{#L3W2jbD*_f(*`o$MwZB}C"(CVF~vuJfJyZ&`Yzh|{mmEF5DrF~^8:Q$<.fCDg{<c/SyYiC>heF2m@!qcU/hhkG.JTvRBha$(k|$cT+7:iTR6}u6rEA8f|d;0N%q6L%I*nMm8D[>U_kQYcI8k;{4Ej9TPYL^H_XRu)21"V>_0lpS$5hap0m/8Wz&}MuA]>M$SRfpi/gNH1)BEE`Nh%;?F?I{c{/T(;EN"|DeBV$N^]aJMPUpM^3j:{(n(9V^)G44kH[a*|q%hV~DJbj:ZKu)61Z|g*:qt%|w^/u~$E|7Ozd,lXg)_e8VVtE)q.VLqtr?I=N]E2&_4ibz/{_0Tnw$M:S[]0QsCP~}gNbqtw/L1H0ndf%#2fVKoB|OEIWl+0q}}1KG2}WqfCRCD:_QD+J:nHPqYCHj1|S*Ko>^iEmK7!`Zr61eTA"EElFA]ugK+.?kUR;(zO^|/JHwpDAuW&|X:PG&th_?Gg%T8,s/Oh}[B`pp_C|B.r_AUE`ZSX$mcUQxrpO]1K}Lx$jKJ=`s!$ZQUEh7"K@^wV$9ieD:0(A7R:)DaOz4`%i)[@yLK_amDK0a;raQF)YUbff?/;a?Gk%~ld1gx)@^1G4lI{_~dT:kYJW{izP]}u<=~>/Y8vjTyorgW2*^2EVsWaZu~kuZs<UdwDFz(K5BFwNRXo/8rAvmuD^TwFV"~{<)R.$Js08~!fjo(p6mm3hF|hlTg6U2{x@U=RHk+Ibq%H?Xxj23tiEx/+WMvGc4JY}GYw{H/Yg3Z9iP2wsxx9j+ujPy`b[6W92JUk)jhSseNCH#W$WOJ!9qrT+D*:C$diJ_p7U>tUu,|rC53Zq]y*3cjWTK@,^86?ELPn^[.TVz*:D^4pgvG0uPxXzlq~&n,|kbz],Xd;1Kx+fp,zyxD+J8!9.JX("$GW]h#QaGNqaG3;zkKStlbvj=_Ep<4*1*G)lFAI}=*"5Dvui|`y=LJsE79t5>Y;TmoLV@m&wI9O`+>u?$2S7nTTO~>x51d?P5P&_1Eqk~|3E.@.7Vs/q!EvRV4K*|Lva%DNXPje/yr.XXamUO.3zjcrRN.,e%~2BsOLu3jmngwUNF"$>ojgTQBR#u)B}BT(v+oX!^b+$#%;YIK)zLfgHpGV=RE{/ROV^vjp30VW5MGpAv>9X$vykt?!`6kInV;fQ$c$*!}|hIi>fxSHzpc(&=dih5<P$wzsQKBygG{08~?Hsox^ej_;"FJA$>D&fn{{H+v{I_{q`{r_qB0r,K>zD,;fhOFRFNN;O.b4K3<C$m#g:h*x"n^Kq9KZs[16.Fgg)q|M=6/SHCzWB$sXb)gQZ{;R$prMzO"{0#o8hb,l]70_+k"_9|OlctNZ,~{FYnhv+4V[8fdOv,;Ybv2%Y)QhY29aE`BFRIU;c6SxxT|,Cj?rD2^HTd~BB%}NS4y:SRw1[3VV|~o_i*>@cJjnw1?)<EDGF~P}bKGUU8y&/EP7baVb+s+S)WET;VEh!{hMF6(@*)enl~_|9,UU})94D|/~`:"`TTETg;(U$vxm/BEo[#pT"YF5?zcoPZpB6<kP%Rdx00k5`r!/Hw>D5rOx`"t[D8!!BajG!>"s"Fk*^K.CLKBV7L5jVO`LTUEMvwF^oDiLtC9`6G,x"bQ4x@$z1}vG6U`,0o),*z<faCg2raZd;t3O.Ua&?!bvu}M=/p<HeEULx>%P1d12i#Tusla6fU53BuN43xrsKdb/k:iN2R?Ksd%nR__EM?u$B46aH9o70E22Mie|^S2._nDS?tK/LAddJQ=fV^$M+C%2p>>lW"vTR[(#Z3C$wK!!z|uRL~Nq|XKr"ztf]ES5?U)2_W@BQ!i_%J>!A1m5/0e1BjaD;)}mM6qYr*SIOigbK!9idn<Tpkb*3t102fy.z6?BB0EBuimd*RZ~>pn^Gp>hZv&Lr8a$_KJ<2W|z2pPv7KoDnSn.PtZ)r^6@"VA[;yEGT1_UEQ2l7iAWCNv6ST_T)LiWx<lYteOv#.Fp/o%G7f>1UYsi8o|@3a"`q^"/DzZQOqGU$y.qlQc0R?OS|8i4WfxDa2~9@fPgE:s",O2ptB{CeFb$3gKsZ~}>G&#W$?*IZ}Z_0j(V~L87Dk@vcG&i7B/C;I!#h1[bEXj<1K]mrZC3Iy7@+5I4+7V2HmtWC^[,uCPJn]Bp!u)nh|]3$?Dft!N,(aH[I9w!Yk3kF^xK(X?Po(v>$<~pB]P{q;9[XG9BW1_A|62t7`"i+D.]+hAww.0jz]Gw"e0mpdhdl8Yotbh;wC})MNM0"Iisp!J%CPq=/[m3(U~iX`+K,huB.bGtj]D!JZOy+6$SvNcgwectv5Vl}M$.Y0U0`053xPtas!GSY<ZeL2sX&}:jxbh`NpsmkO?.}9m)PRh_i%v5AQ]C&>v7R3IIg_yzp>zN3or7<&&j`}!^Ze~%`<fk"kMV|G2qoIaf].iO#BuF/A!dVM8gX(7F1h!?pM6u7Y4(7FY!FV(CyJJ|@QNJylQ^yV0pSS,o+ae^]x=wy}A9n1BJ7(HE}Ip&94%Y5|8O5#O=&N+qH&$CQ[>{oJH#Azjv*:oJn=A9saezr!G}YPCix``!B&K:C6m;a8aV|caW,i^,~kAnmMu]"Qw3S0j(ghk{B?q2v$=Q_a`UNVcsJB#Ufl4Zzy%&IPC60m31_)T8elz}N7WU>V(l_Zg]n}U_bB$7S%"20mW8K6JJ(Cu<|>K#N!caMqT9h${:7{mQjT0*Z}H@tYX*n4@[vX^b:rp~4Lz^l|/SW4A2w}4yl*I6kM`n`g03`]MV$+lEsnQkvb)MbJ$*q]G&)XpI6.8oI0OddY8de>IY>@NQgNMG(/,<O{4,pGX,uNF[<M:d`&^41Wb##sg1"*K6+a[;VH49,Sgb$_5Gahr^O1uWbaw=dVf?l(sd&Crkfr_K8REQ^2_!A)aFUPF8`4O}|8J&!x&r;TL&=PiXzVZC?Da!MBT3c%_[Qtq?o0*sk]OYJpq$6SrXM>L`;gUjOJ&]2J5E1`6NrYU3%P4vdV?~G4KDl3[0m;P"S5@m#O>g;p{QdYSL9.DD.BkY&7EGz]6SVN#JYpM[TU3RXx)OHiC@r!?"C}f9^Q[N:p*nf[58)9`MNQ#_t}Z=6hUfc&Ma$RH{xt|=st~_@JWnpzpnub2u!qQvG7BtAHqf5@HNBdHoWWaXSn@:"/fcEs#lNYRJJl(9LdOvP!QX*{:v`{r+bazo=ym{D,^K#dQYXAa_xr:U1J$(@7.X#"x9Umw[A@MbjJ^~0*ego!tRDVbbwgZwpPTX[^#2P&4y,9+#%S?u1mqE*"u9:)|~SGw*W^n6,6*,mhs:y6x1.VTC5>J<Now7|Y;@f8ua}IH=K[I)+bdRai$S/6S8bav$E:%d7TJ!2b?iK;Hc/p2De(qLvcJq!1!7FdI&dD;Xqm{0?5k;#.b^AXH5dFo042}B?qP8TX6VS8]w%<8jPTBSl9[$Z2M=WYWc73o;V+/CN&UKq}FTv4*ewK>q3m~w>L_<bDZlHK%::ALY~MUR#,QEHYw>tR@90Nv05)%a!GYa?=svF](iX9A|OYHam,9L%_w{MsYJqI1pS7K1@y$qEO_BVP)~X%dv@MgX7#6*}*9lxH=>}`WfYcR2c:L2pO.H|f_o+EC)FwEo9Z)zLN"lEg,g28I!4(cClI9J[Oi6Ei&}3wV3gy0Gg^bKCzzMQ.DN`x4ef_T!T]27yxqutOC^SJeBy>9Z"9:trd>0v)ozWlS5(?,344yS:7Aee@EM_E{ux=!Zi}UE|di6V90I)v~=*yK:GYCGiP#aD^byNs[xWDa0}(rW>)BWv}nOoE2CEZxG|cUaT:;P1_uQ$w5h<>PEetkuB"%$n>}9%=T@s5J@q&N/QS/m,7|t;^&Zi>L?m^vZoRtni`R/gZ}bBqWT&IH>9eR5TkA)gI7mnof}>12gf+rP.[]mv%E7H;_W|VIUQSbG5)ja:j8c5:yVzBUWc,I)=mQyNSSMHY]$Dn?ZWbQAOkp[k`W0uu|vZvH@9?0`!X70`^u{!J}&!FqqNnIlOgPxIE<P[OYkF+ClgYq*hB=Jt.Zb0==cJRuPT;_k+QftM)nOa6tHqSlKNI/80ZNM/)~jk%U/.G^V!m:aiU0y<Ro<VD>uifL2&zC+[AR!//;H6{vt1;_]]G(RRH{u:4|W)OKC:9jYzUjT%&Z>G`.zv+p??6_jO#yV6uTKsb)!_tddMTJOIu@F]bguJ@vZO2t/vbvQyrFcZa+[6!HDc`}5(DLw,2>qOT`;_c0~__whcENDe`>a%b!<Xg8aN1`0.aiuK3).^7HBAl7r9t1oEE&Aq_mr!P/Yh@S/*DzWbq0[x)~l/M(]A=%~mf1&IqH&eY^w?.J$e}b$YUuSsmNJlj}s0leQEf?XfZlB(#l61~Q1!&u!LQrIBFpm9hXXxM=i`?(H.tm!_J9x7BjfaB&gu1A4w!/faIBBFEw*GtLTBDaqc.X0aYAJ8s+G{&X3Lv^vkHNUFhDHSN"g}#Ww&foVZp3FUa0HQw0RIgq8f,_+vX+Oy;.?V.)J?5~sD:6`W:v(eRI`lvXm#;DdBAt9:574hDX/mvgqw+d%o~}l+C;<s1rR7T(Hp%2)%Y|kCf,rd8tvHrQJp@pBO%avv>xaGW^yL71p[j*U[rqC;n<l"f{mJoNX2xS(OZCNVGBu:{WD;^$UI*8VsnLL=n/lGc!IJvp~b*E1K$qDoH$YaM|bl@0qcycp(NOe!*F5~ABFglT4OTa58nG^R)eQoMWcFbuHaK@H^HwH$@0B)HBM"iEpe9XDt5mT;(R(33;WTdC?=I4SgADaJ5o=[#:G@oPUbJfNx>ooA^Y2#1MRYAX~Ud!?6~`Wg2##2c0^I)!#1`19r$Fv*>Co=Jzf6aef~`:[FXL0bg(O{OBb#y,&U.?r~Bl}/S:ZdI5Y`(O2{iPrXB=,!xpX[S&}gdCDFYs=d"KzB^Z&3Qy!hzS)zuyg7qd3>i;fnxHk0^^/`t@IeW#c3]dkg)Mw[T?Mm*QhFtha!9BFGUu)ohdvS*0>&v`{:/tKB]MON)J!xGrJ^{qwXnqlyP,@VF=R_"E[JkH<8U4i&F!{},P=WFEqg8X3`9F>zHP,$KuPRIz3PWf6sk*>4K5?>#~h8HoA$g0=JBQ){^0]r>]nEOeArs<{}kf8Y{yx=+iEJ,1DX%{H"|yR`LpuCUl[KtUrZlz)%*}t(keB7W3M{":iC~Z]+k>LMJGO59k?rWE+3uvF}wcaes[6J_dw|701~XylPuf[Be,u9?=g7Slb*gG8XqN4>@P+J_08W_C5m(Y]@Ly|qL4bZJB(TdL_F,=U3<L/bhw59Hwi#UPf8+C1Y5Jj3qg,g,K{V7z23Fs?TZtffTQz@P|8WSQwlqge?Jc$2,w[mz!WnKy&b?/M=kH0[u,+{xtY{xA7sMb#Y<zuTun9C>6Pep)ZRo.Ln7B]"hEvuY/]bSmTx,*Iv03&7qpAT5TO)e<k/+@7*(T<Nfve@O]wpUulI2)M>+rSxj,n.HL=R2X*s&hK]wq$+UQ2{0DgAZS;hWm8tvGHvKy3$QBz<{KkgNbMfhU1nFb4!Dc,_npt74k$mRAh6?%`j<3HgVVpLCWUt?[l_OAZ.KKZN[!K4tH!*S,@V7v>}_fojXPx2vB!3@,R5tpf1;z|x8h})4zztKJZz]&Ni8O{liX6g<6:uZl(%jLMGLSiQgEW$ZK^InQWW_%=9:>WzR5{D?"3l7!??I*&yO(`~I*|1&T]p+4Y(]|hNru#aC$)Ntf!>bzz}Mpb:_lA$Q1RgKN?/4Ry?Hui&4~$J]~/,L8SBL^WZl6<QV%e<4XNxu]t{E_Is3C|2vAHlAq,8b[~FCUjv)Bp$4OMtD"ibImK!hq4?L([j[T}&/vAg]f0.E42Jt3Q;[vt&$;,%T_JD7)tWk5`:4M+MRZN2GS=Z}T=B_7{})VWrn&R$"cVP<PL|`1Z&u3#mNr:BQeWEaTKW&l~GCr!4VpP<9>6mt593[o1rP5Y47AxT_<>Mw_pA:,+0ovBxXP82:MwoW&@Y8EF}N8yV[+{HDLJe+t]s75c"{vz7Rd7`MC(Z(rE?5jtft4#(_pk$wG$786=BWB#^*&4yoXEKdzpOoslq7*Q+[M*pGJzT/#c9Y|]4J>XrS:UGL7z$n*;i)]V(H,f9=O>4857E#aSbW6sMlI*DLrCO7yJO4lvdHe1MB@DtlEk.=0_|b`eKwNP?YZU:5.h0+Oa*IW{NCF4ou[FX)t<{)acjIGE`=*KvEk8{>|xDG%)XGbgcN1g"{9~xvmd%w||S1i6d*0k@],@@_A9BChNH+92w~:Dv6(dWyTq)DJHd9{U,_`7U4t7qw$p`r.et]JkZ*ToF#)oQQ[,jjsVVR&5vAj)~"xVv1(FW!>^d@nu*MwQ;Dr]&29b/T.!)HL7uH#7Yn%|g5h!]DZgsEDX<5A)^e+yYcO!`{xkw{AbBmj(/SXKFDc.x~ffX5:*UJ;?h0{}^*:y"jIW%`r8s}!I3(rQ53p}q4S*49SzVj{NR%J)wPNRb!V#ts/wc*}Ocp|i3VhvTPG"vOKM3%YIH>Xz^:oPQ?HQ+9vT%&B.77KP.XWmt"EP)P~hv%Rjntye[sPfFU6Qm:yrPU!3:glo;3xt6}L80q~V;C3!<XvCuko77w8YcYBQaOgaxv2cSSJiA$Bhy*M,)eRCT.IlM.jcBBpvgHB2phAE9_0{[48OoAm~5#V!Sy).Tx"7#Ir7Y2d4&AzF{|<S$<lG%/qnW%#shG@qLoC8+U4GtxiyvBC8zVd7~l8nCLkG7(,9@r"Z=6DJ>4JU].r8/D#5o)Ao0?>BO;:B+a=h!B0l6&1S>UBG;GT$Lo$HlO7O0)ivzqowW6Pl!dc9/T`Bh%!c:^`_pFY=og]XSGVG:8OAO3|"Bv>=fLOuCLP|[~>mfRX#HzRc*NEj%=rAbG%rx|w&)*gxY(5GvmlMMf+]=$[u0gYW~s`<^aJIt{ni/o;#tln(/F6&"+qToMb{L16SP3i%D2.hU$7^^;DvY$)0FTfcatPQ~0f&Wg8>hd.+3f;n9=jWpFW!iQ$(bB&kZO^n,H4:8LNx`TyJ5VK"g)"$!hn_}6k{H/kl};knRq%t:}i*pagXXS3e;39$oB&M,2@qeGf_w_6jf}SJaL.T,4xjb/Um%Bn{ZEL)YHs%sIp[[ktS;u[4vMCq:qr$:OX/"Ig7Md+c@.}cAGuID&@Y$I;pMTdVMCb.,fa+L^Gf^or%`f55GYw8fE#}D/><PT[*TGz]CYpaAP~hX5KRzZ7mVQXX{;gbxrmT*`6Ni:HbEOq%N%]DQzz;7Yi`F/7]k.:;XwR|.O#1e%~F3x#%7UM}iVOLqeD<_e60nx|*DkPz/3r80yGZW([~<8puQ%S9FJp!&=k,*jPS/&%A8P{B&r)HGyt2$mlnhZexO@HDmK5PPT>XK$]pNiHN||m]33@`y:DFl[^$i`"rp*&YqN|(KYHKh~{@rwB3K{S:&|wX;05M>+$f2f<R?r,4:<nAps:o{li/Z8*b:Sm}BkyK$Y<)aCdh23o6FXH=O+VVOO/C4!+3Z*A<Cp%#JPxeBG1SMIQrnU>rSo}hcrJfD/P%^R&12Hs6JZ&>gy}RlseB?4*DDn![Xi?I0wg9]j%^X~!]YW&sA8X".eMzC{5^3D/:E`M8>QUA{G+o(zrim13YXds};btvE?&I!+[4qf!(A>djqFwXH6fSE1.[v#77HdZVT&W9t1i>dikaQ;LhRMVBn>0<"D_=h+S@1Q~?~R7`hBRuc)54:k+kmSYPfw.XN3r#xDK1380._D}uRgP9ZJ>wKY5kzto7>jb7W~p3aE3^$ESJ?d}+YwJM/,xbA<c?DlQ^,6J+bDMl"=/pawA1eU]nBPROpe0jFlUZF)5iEb4;j6i&bh|l}IYluCiGcB=!"V)}?bVW3t34,/pHPq24^T~B4[,SLQ&i$?P~8RSB*Sbhd4{Inu=G.I[k=<hJ44AI:2d$wZ09*91kFiQ?[w%QCo2GIsyvy~y974;EkHwk_IkTP=iVUi{$F>{?V!bNH%)mlbM`2"w;0gLY,7gfRf}|_RJqwcPNo3bSoviU]HiJ1,$%Y=mX@#O4Rwb4|dwPKqu8peFt:3j8juM};ydR<zh$vg!~rz1HAUp|,{{a%?D_;ly,2Pfka)X&hCEj/6<6!z=bnZ`@1E0FJRH%.$evPem,AwA$vkW=faSh**,W5pd~&M@9f%6?|en*}n/sp_X}Tv"A6%/i5/4V5Fe%e[X9vrqP;m8Z[nyV$xTK$#j=Za]7JCd#R+Ph5eE0e3^<~Fz/67sX$7;MVvmld6Vcw4Wo<OK.?]$C4?NZT0+uujj<(qnqX3dm`0%6L["WgAZD5~EaLZ1_*7(rj|YfK=liyWL|y]9iaNg;860%QZ$@TqV{^kV<~z_NRN7X>{lj;?F/;?OFP,_T7(zF$5.mRH}5nO(n,v9>gP~]:w.G4G56T/3M6h#T:2AgCT>TI<t]~>>Oc*78E$MLEkVx>{5:xnDx"x+$$273();|H3n.?vx=3[:ch4&VqE6F7oPwOhooi~PypR=H}DBMfxg@|Hz}l<J8MQaa`OIJ5b@Y<D<B,gUP|"W2UZmxH`j|Gb{Ny?S!E%r=.@eMAIKD1<As+],4x4LTaGr/*UsGYb2;DKZ*,3"c|._M,x],ByOcib(q_JH7]3CeLx7HENi^]X?JA4YY1LeND3gy@u&Qhe:Xwowqb]6[_CBi|f+fokYW3jy]#Qi^2eDTnk2QGx6L{,9jec55=RJqg/(=g~3!k.R^5zU2;J}D/%dL#AEfpuiH8Nw`lK?coa+a`aQcY+_fL7kC(?mYNyo*?3H#`T!j46fy=919?46wV|D{VIfbeq(tIk.{^OJ?YB+8v&^p<sePhxfvi~&V+>`KA<$P0%bjM3a@Zhq,*^wZ!J)+R3b`S?L@b+3EOljab0s/y>7&X/<HHFqUar_+IO[<J8Jx#4}hGkL+Ou.L"W4E#BxBpOGW~+,l/kH~4fdB^2&{TmOnoTfX+L{uK.n*NA@&&%?I+I"YXj@l<Z5*M0.PqV_z^">e$YgK[aFNe0#hGvfCj5KC2BK+&5M067&TI^dd6&5=Rx5W:..9ncUQhfv"xfkGo@Z&{qA|_$jiSk$v5uQ*8]6.VWlpN52O4s]b[Mg3K`NDE!:vVj^zc!+},^SKIZ4d}G{mYC"2#C;|K;!~)5nvgUo2dtI".|#smM"3L%Zk8]3GwpO|.7=PRk/$aUe}r6PX9jt{|,;o$6a?nP5eYp,lQ"edP|kKYdd.58D_l0]CzJX<Qzd|>qD[qe7y/Y4AGl"|E1|L0?k%Ljp)Cq*<5$Ob%t6uWrk#k.Z{ify+mG^7Dom!VQdt=Jc9ko`F`.Ns<$Z.qD&a<JkMSo0R0vF+8UR[&`;qOs`$cbPcLP"Y&=)6ca=}0e;>h%R(x,rEbdh`OjaG&of;vdn!<yEQb21k;"`Z)*N)v4&46{NL2prHLvWB.E[7d4a{FH./&`V).JeXkXIKh>R8#:,MOqQPz^~7||Sx{s1uzz;u"dd;OLqh@@I_XP2$u^9=4CP1z$JN/i=s=54s+J!LmHJ2r5w8=XmTzz@Fl>W8(*h6RYwO(HA>]9<N}#V|L5i5+{(&RN[ide9mMqc=)).vZ+Eh+P(]rDYL6UUC;e@FTD/u>%#<M6hB]kHx1Y6sCq(%+<#`o5r+Asx^S=<gq(}NdF]bIVaLGRD]"&RETCN.SjqlicQp:/s{w!evmOr*&o[8UA8bJR$yubt<*/V%R9^d~~&W)4.eHcJL>lL8Nso?#fb4C_tWde|6{Oi:WnjDcXprh|/#79[UP#}T5{O%YzdbREZ}9paLnp1oWJ3g0l)!d+hcSg}6Wx8S7ja5",pv~+l%C8A`10f>Ul6=d<d0V{0k<m&=9Q<<xBt<1Ss7iYzEpCj$m>,k7nPI]mPy#]:?nVyvi1<22k#Z<KqWV@O,~[5mFLZ:mp~0klP3*u<dM.kc)HJ0u#XHQZ{r:H;il;*K03uMI3#JD"/*=LI]{){+jjC6yGU%YD^QF6JNGr`!)D6h23DEtTOq2*owdy=Uh)2C!dgV=Irg>+lJ[>?E0c+pSX`Vl7Z&a+IU;EG56g5C]k7fWtLPK,].GF;!)v@%*:tR~Trv7k9~c6Mf3p%_+vw3,ggRr=Q?jy"?jEKbqHs&$dIt4~.%=c&?m[Y/3oP"6z&vL1OMrHd40zD?;zPNhFukc_TYlnW%/T9/|cuUA/u,$_FEk(h]cg^,qd.kv,:56Dq+LT(#hmiY(all(1%U1bTyuiFUT)[t}wVs@Y$6~@Fh~8sRZ@[O92lYL|q<3c:/+_TsalcO(dj!cScE6OkB*RqZ:)y%uA8ed0wKFD@P!f(BXXwyQJ;%w#gO"($ax~,$W[fIH_i]8:=fi%IVK_77]w8d=b++/P`CA;HInKEo5;zlG/R?_X+P45mE:gJp=n[WUUEdwqloYt^SSM1MS54F(KPKDNt=U6^mtpqy)/SMu@"4h$|L?!BWJqQv`t<8QR|eM~a(CKYGy{bR`qj091X!gd~I{$_tK!0cB$"h4@HGX;Z,+t])ShxHbN=7#VzOws"85^LhmcpNZ1Y}L;3aBci"JWWJ&+,OxzZkHW<Nu1[Wc@k>{d?L20H$4II+"rkN3`Ek3EOoMgc*ij0viFbp/IO*E|76Wv&mhk"3n+]R@S*(oXD50>=w[K.8t$4tmZUYn7(jvu_bds4H&|w}IP9d(k8mD5!"kdp0DT+{7}p!Wk%3g;j&"/8Y(^6~houJu>^J37L23qn{knP}r/["|)v5_]?W|4cNixRFm)=m+qIi(l@z5E$Y(ShBNBusJFNfM3dVhl%`CahG6TIcB6mk|[#|heH>B&Yg2Q*H*Bd0FAN={upFoz[2G{@oMewG,:oh$1NO=UZ~RwW!?KHt{8bEQ.%7d!]NVHsVsFWVG%wI~e.w@d4RNHowvDZ<B*Y<QmRdkUWk`0]y7f^E/Ly`/yh`,*R`@`^pM`Mp1?G.AbviU>bX|irutX/`:RBf+.n{?7Lx7L7Eq6<55O"COOqJt;Qv!"e)kBm~bx#E=N$WqW<8?se&!m0dj|HpviNz]G{oZ!jFu/r%cn(X!nO%jvVIB[}K+@73Y8eC:u>K#TQ7AH~lI.uOkGPU)QKRClE&}LyjaxQ~$UmiYm7;b%[?>Uuir_)=Ba"k!tQU~7H@&`D&,ji:3%PC*[yiyfdDvy:VfT^u?][t!u#a"oE6P{k|5Be9OT*.3T{$XV;z_*p~Z<x]Ga(Gk5$7f&z)u8ow6"Qg{oVu?el#uCx]3wUNo{F(Y}L8A]YSV]]pmJA,mk0L@7qx^gWMOiCxQe0Cdw+xD;PSS7PzF?@K&t{U{9km}IS,7X4$t%g_zrA=8:C#K&IZlfV|klIv"*m]e*ArGA?OtD*c414Hsjh[;[`j?|:#YqZ]V]|<oLCTE;N0+!~iA@~Q2YErL%wkaev5,gNnkUT4m=8?d<QpkBl!Ea/%@|a^|^vLM~${l}|[Cv3lDP_;H_a)APn|f4jPP@1|>&I9;0lrD+yro,J~8d>^x";%3Mx$Ui?zlJ!Qa;a;ElkQ`^E|gT.:T:R1fxrNVkC;/,["?4vH|]z$)#ajHAm8X}W>kLJw,Ot*>={ovNd$$.&`j~qBmp8#XT)VVcpk#u*m:ONAMvVsHuPZ^#TIIf4<9*%TZe|r]ZJ8Oxr#S:^1sMWa^N[hk99Cm0TG.z~7X3A`<6JxwSQ2{_)IKOS^%03yE?ywtwIzo,iDaLTPc1Of?zzK`reGBb1r~<LthmH/9La!LCOD~WC3+R;YkksZ3Y"rm^|9IzM^zRM&`;L_hC>VpbMmu!t+{C~U1=svi91~E0CiN7|`1FaStapHX6?,K0jMXH{t|C{p!jIKcAu,q;5uZe.dKePBz+[|OSgyYar[?ATkYV4T}V68w$}hg.Zx>9?|lg6{DeNv&TV+41|rDG{=+LZtLl2jnBua?k:i59ixvQb+oO5XTg1mBCWHMzYugrMn[>$Dch:KzD/UYRf=n|jtKhHgWj:gsLXMgjiq^D;j`+r+<zOo:k)S|t?U,r/vAn|L2GMEEg_N*JsX~S]U`uv(^NbrDJt5?]yo%EsqKPUWX!sl7(bZ[8yBtR[c<Jj2jMi4>98XK]FMB43_bzG4d3Xy;tS^nvzN={m<Wu[Q|G[?{Kg,DbgJ|d{/7,(LP^NA;<!5=i&s`=P+,;t%JmQ2EcJ7[<qO#P&p/5UcSL_x|a#z1"%y]e{o!d,m1[iQD:V{J0[}T=Zd/!^/yeMYFa!.26Xuc9x"qZqa"u,48x)kKyVy!Kr,,BB0f~(,]gIL:gcoY&W/KteG@F61"R*f]/y*z/U?oIm#bhy}nHl2vXH#V@vXCPVGsHiQ|dOpUb,^:H0,Xhy?`~nHp("Q0I$n?W8&B%Hle]n|9=+BB4xu!.O[g#x$>,@g$dwRxD:=e8~#_v$qm#u2xGz[c4k*x+Fcfs#$PVE:()J[,BCbxZK;an=6^v:rCrkUgtT3,KED%5LY}%+5(P_eFy]E7Q%KV)_K~6^wm!g3z&6uYg/gnLh3LngiPMrtFNP&2]z`?37#@itS?kb1G!k[7~YncGy.fD8p":6xe*?]eJlRUMJMzNE]F(]U6#DeA#l728`[+b,U7Cg6.e/ePuMYgN&DCjaBNLL`$4pM9{x&/#t4M)M*iPgt"b;sqMSH+/zJ!Jzj.znxN7^=6lR^u4zs~LQ#qRMp~i%ryv6N#3>W!1bKntvSqpdNdjS.Da5mm#J9VjM<195QH">8ihHF|@1$8[z~RT5Ik(TpQ;=cql3?Eu&4F)3k8M$g&;S~~t1[_/zW{kXPM+k1%l_cv+zfIlJ!8lbDkUZiff].p(;FqTero}|oU`!*;m8%Uze.&0,>8Rrb;%CaSMa_27H&W.!WdZ,G$g30+z,<rU~rh7/XaD*BYFv`VWkYJxN{L^Zf"F&N=JIOOit@t4iOO<<$1@FP2&JE+b/$"ACV~0C0!x^!I{xLS#mciXl$tbzHaO:NNao7{mJIkq$Lvv?rN*FBu!CX]j^xM51zvu]l01TJj|7PF?MRdy?HnMw3B/df1wRHDI9VFTuQ=Nkrq+D=X>uQ1ax7&p`Ola$?Vici]3w)esShPeDYQFJZWly7*?TmDb(M]9Q"F}I|0qv>Kf;2T?EzyW.Q%9*~GQc$*_.`1k}^6K^n.&FMIE]pTB%bubWtF$2aNrRx=LQ_D[=x%I]~n1x&;jH|Fy1Q"xE4?EB[U#i7r)/2%?VzV:7xO$K>X|iHB];X#zn/`o|C,mC)f0#y&]%]F:X+;g>d4nRXH`|PxOehhXC!FX0jX7(S4a%i#2>*J9VThJ*c|(gH*LA"LSFb|1;e/80MsgQQ9ht4,jQ2]Cg@%l5gW}^jQBN{]<MNnI<NI4=p%Jl#&V5^uO3Alip>`$Lj4SVM+SHl~sgYPyq]29)4z7d+W<>B*ks1:o$6Y:yV>G2k!HQ^MP/q_n|qVHq1rxGSpH25c{07]=0X$2ulY<|Zrtyz=<1[]6rXLbflbk$qd#HP.yei*qk6@~.~6LFkxlv0],#7f#L%f1><ndAT`zm&?!=v<QmQ#Hu8|Uw~!d60`XTT$3SjJlbOr+RuD;7T|#ydGXj=bNc>JsiD~RxF>st*+S!T<i@YjWI_>(8Ye2,@yxT]X1<Cn0w(i$Z1YNx,E[+sCMGx7PDV|:AY%b$Yl!=qu9?n@Gn9vn!ZbCXIThoi#B90|^}cd`R~.yzgP`.iYSzCuB+A?vL[hCi|uvL@YyIz2R|GDl5moTU809q%,IZ$@ozMsZ.%AaDB+)CJc>Xc)ic`j5JHZY}9]<Q6nmF_3tf5Yz*4v%r)<s&^odP3i?gVu)M!jv+.zTbZ5*P*C;2wI7C%sRSz|6Z}8D<aXq#*l_*6yq#s1$4_!,/XRq=Lb!_Ntd:N=VgXv]ge!{A"*S^rX?f3c`N,dZqxJUE+D=!V9cX_3K#i~85aNuo}O&*u|y;Gmqx$WP0Xs&7l)Lrh[06]H*!nt~~ybC.Id2n5SKHstMm{j6S1UGL!v)U(Vc|,=cdA!x=e:_t?$czg*wo0G!D?BU(R[>4aRGz8P7x:9~~y|vA;&Nmt?)~Pu:,k{;({y6u"/uJvTqX8E2heiCDGLd}m#smw%DxUV%BUyJ`]a3iIv<>tVh7.%0"zAjL1r#ilQP5s7fmn]/**X]H[+Exn.)#k31czFA7}9]KVd#8^vw^~}e{Hu@;gHRXTZQ03m/e5~/O%uZ^@0+z10ETm[d>y>(1/`15LoNnn5X](;~F"t#(UR`]EZ~Ocmc<uEOvic7T0y/S?!_Y3"6l+r)vJ+A3hwI7m6mZA<$x}1TrbvQ6J/zJ;bL4l<]+T}R*^3{$IE/OGa;~]Ly`zWNk+DE(f9cBKQH@jmMST5)<wx449MyTUHT~J!{+^Ey4h"rixZ6U3fg4ivvyY9:0g>x4}1*&gQ.^upq;te%][k^ydQ&/j)3j,vWdvTqgWnATtC4dbdNAmkx$Hf^FhpsXQ)Hs/|D~CsYht`dIl%UnMkrD<gFmT"m@7BFt.3_{~N"q4.c|9N8kEnN5pK2rjbiJ(+ypY2vd)hD=bJ{vE0UND1,pm:Tb>ke&e72"<<%{OveEzkTy7*a(5[l.!W/,Dl=S(f:oRyz:1S;e#~[~0_Vh"^%Hn+z$%luccwi}v9U$iX%&pv=l[_e_V?,ElNI$(tVJ22*mw*r%HKhswAWX6gum67#}qxHkeY,<O0wo|u)Wy4&WqYzc%rTFGcAV[C%BO`]&RQIpJWNJP8Kkb=7XXa)H10:"gwcz3!8Ky/3lOIx<Ij@|!ZPTu8ow;MH`>&Ky`[WuyjY71=U@GkoftxUX3L>E8dexhit3M/<zGV~~k7vN+Kbw&OO1KtCLO[41F9+V:6V/&W5U?zrr*sibXlK6HrPaj@@mAJ,;FN?9g9Kf[@8X#f>aXy].2aIb}vKbxNlDG#l.JHGnfOAZy<tg]68tr{7.z|3teEtb,u86Sms1qmDA]QxKydyR#ecvk4n*=#QQJe!$,G<31*=6~o0.uKPSF4<vN(_C?6)G5H%KV(Lao7LD``NQ8#V1z7@}&0%^wB?UO.N3gw|S`r`SM,DiN8UPi8]D7CAM#3I&:IGOK;W1Qme9m/$>y>?4>VCbXp+E1v]y8?,w_tf:QANstOrC.a@h3`@IQ(YM"daE>"InHci((=?q@<D^/,(ik$vH4V","?3:4msY$pk&afavx00(/F0cov;bp!^KOlXE@AFstC>G]RphJ&@>[.cMG*A>=ho%5^o3lxav5JU{+ubMo3E_>oXNgrl?Q.8D~5GOeA|%UwCkQ%D@:Jj<RC=M(#q8yFG%xC$2rJRXa?Z?OQq/"&]:B_a[W1{Jh5&]{b}*!cyxD5$<B1d&#.}oXX4q8q]fsL!n=#Dpa89`$|rqxJN8rz04q`):_?X^mGEshb_)W"rl28kxagHGB~kG4kvBmo/339irl.,)/+GwJNym_[y0{KR1}I0Tn:+FUQ^qB|mKinRds}S?3IaE"+YtD>T1&N0Q{7W7UzU~Wl2+{~Pm%B|R<afPDLRH"ntDKF&#pYVef3Gp+$b*];#;!}bf;$BU;I_)zl!H?VZ#t@jUB^9Q7|nkdr%Zy+pLMdSVu[qA4a6IMY.J]46FmZ<#}>I4k](#DYR}JVVqVbdHv_*!1Q@<R/|aBqYgA{ZqW#4o+;q{h|HAqUSWwMmCNyVRV?=+x16LO8dSzJ3^EC5(9^GF6uIDN<pg?Mj6CqaggNL,<jgUvp9Hp[bDGS1.$]5HIsO&Oc{oS*o+zoejc$`YN"_+AZRlo``kWJFw#ORe3UMB;V$$xp+Ip;z4?=1r=!~_P!!q&iBAy#OLDO{q&tC|Uq]|!P4uvf_K_uPF1*a0]=5c@J{RGM.zd.^3)?sxqq_uj/$;*SXhM~()]BR`Z@etfw<Joax.k>"*R!Peka4,=ePP#{X{#G9rp&DXuQOKWD<?(QdbRb/z@5siayXuaZ61XkyCYs[G4mnY~pe4ww[#zy^QlkzWWKDRKt;p+B]nel[Ro3uerUszmwkdN7g@3rz<8u("hwk&SK;Y,*H19,ZdDyE]Q>y)*xC@!{Stha{sAG&[8I;+`>~.~l!Arb{TMcJpMW$A|@wKJ}=l57c#H?h9FOw<3{_;4!JlU|z*=jEzIkG3cgr@pABAo`7;c~;F/VhrrgSCUA*LMtb)nr=RW+nQ,u/f3R8_i}iIO!!8aBN*{`R5m"sl2*$Yf@Oi%;fQrz66/*6|>X`]?N^~{L!b=`0EI/Fiv*B(0}j4i2FB*_am"P=oQhLVB()qX7M?><}lc|?$~p]NEX"p22.g$)dx:RIUo((r0Lx~qo/S~4UfK2XYh:|@Eb*R*nH%A"ri[oIxGPmOQG5lhyg(6m]Mvpjt{>@],T]?M<0eZ7q=J(Y<TS9%TWDr$47)(988des$!V]!auZGQ6"VRG:6I*3pZAzdniw<Ek9$<V22&[{^FI)g3Thc0`B!sa%7R*mTej4ELkbR9Ayn6p"kK:[18m3$:"S2a5hD}U~dX./<joCo|_i&;lwaT`YbJemuGWD_X"nM7X>UXxA~W8o[NVbjRrrbr1[8:x)DD/xvA9L!WY(q}^k[arUMnf+}iz]Am*TFvcTUcwz?lc`Wt.2Ef*Xuc6/dr{XV9]+q0egQ){D=JdjAzVKN*/0{]a0x:ws/jK*z1w)?AK,Wq}X$sb$Lu%k?(]GipU^36UK<;.o,iBn12,T[&B#&_1==/O<Mg|)[9Z7#E2S}FYU/qdJ39&;Rbt=tXQ,)W,>vi<w*0/(X*fzw[^H.fiW,0}GI}t6jF^O{p$R,h}4/w!|Faw78,lsNc8WOdG#|mfKVhPOj:RQC+hxAl^kX*;f*hotwEX#z03OmFL5dSEo3^;mF1:+[p>:7s^T]yk="W`oIB$CR;;7WpZjU=!N/Kk,K:VX+R(7TU5/.;N}#~pHdL~lj|cDQVAXyx]"m$6R^Rs,F;Jb3Dui7tOFQ6$%?eph]RQ5=WlpeI!jOq{Ss9bk:qw+}[kfM#O5qmHbQ.Ao0Vbgp{c&Gk.fdR?6@;U*8"EYD.W<WNvynk3$@8(J#"33H1&GbKLZa`9~E:GlWwQ7+}%.#o#,[aXG>I:gL%b3!:.q+L_Zw8QG=~Sr>x2WaRF|=xTz^;GBv.1Sb5C*EjEL.B^=Wc<vC*X%p!c!su*^>o^!gQegE?2e>TOlcm.:2Wy8bhl%2$_A`_a9Y_$SD8?W&OfQcRBv7b``k]^9odz&|;"KEo))pelGLW+<d1HHdq1riW(?6p}}3b|Ul8]ujY}EUn2kr,Rb{Rm!,&/sfrGu$?7`)dtR,Fn7*!tZi~Ao91[u[sxes3K30jwNxcr?G=o$O=)Pi.S`MQRJH~~mG|d$uIIjLTBzPh^d/`/c4w6WlFF[#SAL$]=,X^0jgm^`(^os7iYNmij>]RTjLs2,4tUiFiG7{do>tq?v~*!GhSJpx3`$tBI5TE[tf|RYm?k",V=vR$ci?,,b_r/7f_CYI:vi7F,HL5phnJ^=6Y]T)i^8x<@IknA(`alQ0Gez(!5LXaSsWrhyN:_WVypRjvu9;#I7YU4yAsoN4|>"y:A|BqaOL={Gm3nGKmB%L=$7t`4AmwM^%fJtk=GB]UesgIo>R8#)R3v;Uu|aKvk$&5hXG{r]ddJfOCUwD<KTj_?C]ArO%:AkwS+_PyO/MG1ZRi3F=NOgDS0[d*^r,g.ht]Vr~DGm1K><{S1.*%+wGpW~G|x/UtM4"YRjv~4x.C6T6/a8]#iG$gk|y!I?_A"xf?,ZNJjCE3.B7$VN~1A>7PAuSm;e<Np>@xnfPUglz}J_tTau|I,^m&r(/OnFT`cwA)s50YuTb7zXRNudLE<C=cB.m{X$:z%W5?j;nzG17YL*]{b8m9N&&>`h{j2Y5haL@j|$@gn_{!*YR~!%eb=}M!6o+Li1{K$e+dayX;Xn83ftgzOmX_e4)0|b@*gj_uV27&%FaPm{^8%Rf%F=ZMc(;Sm{H|F<+#ZduRNra{+sM3~7]>vu)p]~_J{zGv.g*212~F]*?8n$Cv!1;$ir?82H&l|";p}:,!y8YrF|r^JE>`{re`8dbFFi$^<K@=1::3)JH[:Be[,<e2V>pO0;}SEvjh_]b9#F"d$5KEhi,N=#pr@#W8It,O0~P^^Q6o^J/&)T.<mDXJvguXC_*5xS|Zc4gZJ!$V/8GfiDcGj3ggreW;yH$o&^}XfHG8c/y301^[@.+r[^Kf5oh*+Xl$w*m%v5K~A.nQ@x.NA|7KzW#@.SfhZ7A9CS=EFRG$VSH&CtXJrg8]zG}A1e]OR"=D+|y]yg4grK1^HaaT~}^g}>$rmW$#hbs+9ta;rTPm+SI||:V0YwZM#FI{zIWq8T0Svc/GJcy&(RJI>Y1II/@^U2L=IC5y^yY+nTokf0IrNYWY0Gk5zY1BzY[V,nQa]#@@{)ze.J,X4oOlic.F"Q`[T,t+dEtf7(jdkWwMHebxlulH)<U>wIZMyPD){gkhxs8kC:;7S>K9_pDSc(N7{w4x#DlV`/A15X9e?8H!$uZcKv/LS&UC&f9K.HX}{zd~nsh$cJKB)zduyBxiOMz`suDc#P`X[|?uabB",py,?T_#7~dMAKNC{DY@!a<wvu#ccD,w_B~|U=%JX1C&{AyTW!e]8"Z?fPKm2C+8!YM.%=nM3^/bD!tQ,ixuf+TQKwGmH!AtR(%y&}t/3I7~U<z+Y2VoiS@Tk&[9^=b36G}DBo._q<i5c$Cu45j0BRp%BiJ+B75x+O!^BhrZF,3kv]9RQ@Tu3*:B1`DNG>X[Qra`"3;uHMkm!$lqc!Lw1P{0ZB||j"zFNL.J@P3wps%4y5/`Yd!7knHuJpw#3CyI>~BMNqTyiS3z%8{BmB+fahuEZY8IKw}+4PHY)N]`71shXp,=gpPSAmRAK./;Zp)|>(Zjx?MC}]ISSO/>]63P=M~/PI%7fHgP4,mt@6VHoJ|,H>bXsdYQC#u="#h(88AmU)PTuS#3B(dBzy^Fe4bruZrQD6lv8S9SpPr_A|$dC!u4mS$e^:)d{%{1;=8FANA&I[;8.)dXFsgCCz_?%KB8RXbWmLhj4!wGvhO)I(?i$:kWV2tL,nqyUA|zkGOcg|m8NzN0MxyQfIHg_^*;aug+&@[qE1loD9~Wcfw#opZz^muF=+Oeo<RL:<=c(6dN7&3?oB;M/dWw9AcZ&`jT1DvrpH)|hk;=})#EQvzzVWma+jO^m_1eA~[}%@~%NQbE`Gx#9~:,U0zPcLo)9Gt|9e@e/1cQz@:vxvK3uSc6hj1DHaOni8A]:Rd/KRye);FM}:7RCK"A+yd(MYx7UZ~GC)RroP^mB<V6}oP]*@@CD3I5Oj@*;qXc@K"s/B/>5rO*~]?!cZD[lt!EJeJ>Blyl&_;IJ"<H+Y#~bQVL2bBg|_}gFio`O}l3iT|mOt6F07&z92wqpJuRNtRb^=+H9im}cy&fDwhyPiJn#j<Y9bVhSeg_w3P;y/:dC3L&{.?0xjetd5Ii1vx]f;z1;|ce8.^JG!H166:]oao[DFu3HiAD$/7LV7?K](^a"RC>t?NERS=v/_ik(Fh):Fh(5^E4%a!SKO{j6PaT`Fw4k}.)f^`2AZJnsQPQ2w7{J`GXH>z.))=Tk*^#,vdy0d+;QH2w"[<"ZO<rwP{|ic24@Xq(q]u<]q2Z`G8nrg~>*c+;j"nShg<V!t9yEZMO2=6:bh"M2#cEku`YiOPCW]n|M|KgdGC|S8%rfzXY>KX@=Fv#w8lA#=ZqdLK4Rqp_5N]oF%y[Ak0u?l+!O9fVeos)p2iO0s0gwGu,d3Rf@4M[71^|zdiQlg`PT|l<&<jRD)YG$_=^!f5EIhqfPiRYzvq{0b13U$gn/FSZgGJsoBQT,q>hc*9VLi9k!{Qhl=i?EnWlI$j*bourVf[%GGwf.9!>%Q8+x^*1PDgogKFJk{cva<VnfL|=Y&EnEBRgCJ#e}l6gWHG{E"1SO"Y{|rIRsNp%tm,BV`Z}pNR+T6@*=12Z5&3q3po@xONV~"@Uvs^]_ds2#i$.A|s,83Q[>&Q2I.DZ+Dl(0RwBK)HHi:n*Ei~?;]on>t/CsdC];#Q}NeMF^!@?lHD6p~m:6#2afV^2nyHWqo8JB3d:}=##P>vD>u|>88WcHqo~CBu!RW{;gImr=c13&=O}NX^{Y}l]EJ%sQ#e&MIE=NuZc^$@({vI:Q`"b_8NLmBVv{Qz+~IYX;n!^o%05@@GWD[s/6&w`Rj/(uHJl`JmIqzEI/@oUS,qF6/R+i{W9q^ELpU(h7V9$)0{mR`A]q2{2IWg90w:ELTYJuXAuN5E5w4A*6`]C{OZqpI5/i"nVT?|:<EXc=N^k,GPzc{]w4?%}1Z~8"|n,bdQb`K!6i)2*J/fd5hUd@}:S=vx#:D0+f|,>br*7$siz9u3KOtC%C<|$U(o{h)FNLwsW4VtN,4,PoYbaDmiigw`XpWJTul37Ow/7Z(AB|+[4j:l:tukANs<ZbqW6mXAF=&$(&zM+x$Alq++%"/1#Vv%<8EGR+>lLc@O5cp<[mrA,Nzl[{+#?W8nxeB6@|b1]dPa"hOI^1lOG[{Q)aaAb*ot:Lv%T_G%123M:.:[p!F2YQ0rg^MAMhG>L|w}BJSgQSwO!fgmYq|]gKQ7)g}u`<8Yg}BdN=ni1pTI3lmNq<I9!A6MB7cFmacL=<,8*(S=SP,(`cY8dF4#!)<E.[p8.,PK^;pDjCKL+ls4|>=}+Fuz*BeI$4CWmtQ,Z[I^(b5VQh!71!|u]LWy(F@,SR8<NhI;/|y]r}X2R:D]k>h+q);rfE,?7($I:NOiG53rUAQL1Mo7bS}ODm1M7MkWH0F+DxseutKJ/e0%E,TDnK4[YU2.>diyt7qDaXbLN."FFL3tXmO[Fe14CL;3wy*xq>Bv?C;T:@hp]4n^Xoj*9RjNXmDxf5kkdm6)wYNdI]EG,[0PjptD^QH.yLeO3}>$hnb[O",U}KrZ?GC0g:,~i:&H*TUOFyG;5?guvZzQwtk:.M@Wgjc#.{k2"6<{Kx<@B;{RgEX=H(ic/|~AU$}rO*yWB"bVca#jz=CvKnos|r6%iz?e6i%qe7X+4>d{5z?^>jsu}gPL"br&M$KibGuQnrkgdahq~>|<Tf?"DScJ%zcHp#Xet*N1,&ySYUjlL?3T+H}lOxf1]OXiNX]cqS:k5pl/`{b97(OH{1C0P$G|OHw[M]#_ti|njoqV3Gt0Rs!!O?zBS.6g^e)8Zb?=!~RZGA.Mj|24?/tQE|wRhN6bw;l4]r4GE+j(5fFu},Zq_UTl.:NaQ4cklpkL<qV690ygv%f[s$69lnC<mrfD`y>DU]}p>`e6/0~e>QEm<!*T/vuGu]5u32S,k4~)SA/}`f}m_Ogy=)7pJ0(q(G)GTP.W_ol.&.Lq+WT4+]voZf(lGaEp?FtEK~ALcFPbV:IiQT+te;J.=THZl0BAZwyXR7d8GLtqFc.}i9[qu}gm9EWO,}z@;pt3slmSSVeHvZ&E?*ME9svfYJD0;%[H]?0sNm:ySI*R%(V>{VZV=8UFCXC0J{ev<F^=Y$:2**fY!Jf>kRa;j]SM8>gL=l)3/.%s%UHWRJNG?oD`GfH_Ll3J,|?vW>Bl|,{=G5Xt;xIlf#S$gT@3>L0joUk=U~1aOxP+i=~O#p+m]74RY)evV;7ycMh7|^YvF.dBML3{SKYN{$bfnjuKN?HJIR}cu7jaFLee9Y|zg1Af6i"XdBThe[{>f{=4wm2W#0mcwlup6f&pw?]U0Vx/&Jjg&}r`#dN72xzyWG?@jE$~%#pH5)v]oPTgOAWv[SP2=f3[EJh8y#;&wjdH}uU>M8{K7EqJ)KaxGWh%M$B#IU347"{<CKWVz8tYDCYGO(e^N0zRp)Wh^VC./S%YeXoR{}=1Zt@+I31A8[k#0PT[N!cH,kn+MVIFQAO+(M[dQ=/cwDPwOEZ5D:u8r36VFI)={,/*DUX?c=xJO+g]q`^N#if)Fjx%Zv<b`cYJ8~*W8NiPX<rjr9d0t6&1olIg$qi?%|,;vk<)4A{|>:x6GE)UCa@NHA_O/)zl+U0!/x)#+7(256z2G$/?d@[nBCU@zfZA75%YZ7!qCHA_@5!JC&Iv9H7O(?bhf6)&q7_tmd2]1fAeEBr9Rbt"gGN[Qjpx<BOEdeZ?LKnql#fa?@/;V]j<j:78M~zxPeOrCS#8f)6X+<Ujm|4h;MhzPqNBdC8@=2zQ0b?w8V|`v,Q&dHzFd9#3o."=$8GrJA#]klG^+lNSxm@QM|Rb#"~y^&E*C`vVCfqF3M}2<(KKH.640MLs|`3ABi?n9fR>Mds_}Z7^W:!R(^sktHt"4r=8h?,Y#fBqqn&MO>uS<cj6"H`T2`k9YMJ|q7c8rmcI7PQT&M{2.}afTcVCVu+6_<~3n]c<Da1+^948j(Tps:Q*E!GF(Nn+"GIVhSr>3+4(rWB~(JvgZ5nc~H`ktOE:TU,t)zJ=x#N><y|>>v/H.~x,Vyz"8@nHH)Haz=7Kqbr>.{jhH^VH5Nczq%Fc4D#m_zy@BAyF&)YwgR/W2;>3t[Pj8QnTvs(/lM<3goFvFHcWa^"tONPZGKA^Z8n1M;8Q$y&I/.B@p7Q^?y,Q]An6xGnFXPHX47K_Z34Pg`$q}@wa`a`0vNc:h4Q>QOe?e1(iQ::dv|bM5&0_933pLEY2kGY{7&YhD.vId8gJGfo7>:<7aXG[x,`%7;tKg,+07QE+&$;U*7Za+vANg>JNokhDGawItE^HfFrSq(;mxBQ,aM{)R~dL,a0DU(/QCj8C{VC.^q!&EcKW%o|IFLT,*q}|yC]R,S!85@9RGEw[S6(1+I1N~|52D^e:=Q!}qc,aCQE#6vILSoRYM^_cYy(fykgp071=m}bj(|]3N0pQ:BC8iPM^pLQ6[8pmlA<EdbJ9]mkd|95ZNm;lL_~FTx84%x|K^7rO5UElpZFvL7Q6[}M[W`B7U(MIk<RTz^gl^9eRkn{S#pSPu,^j7u<j&p8dA8O"V1JXTx@cr1&~W&458^o$L<pZ4JjaCY1qMG}1VK/;[<;XaB#bnVg"5Uu}<rR5EIxjPEF=#!vSO#N8v5+!iC>dEX;jX>ua36olPzbcY8KzRpX=n|y`%/u&v0aTD[Wh:Xcpg$qno>^w>S[(M(ThLhw,>wsH$"b&T=TZb&K$40I/*mu*Q4]Iir<UZ!2|VypLGE,rPaTf`qy5bB~hDK[cD5$`I{]^0I!D[s*C$Q20`~/F<!YqbBW6x1)mf^R(Gp}T&KJ2iS.!mAs+Zk63<Yq#*}i+z!yeRA4*AEo3njiv/ac#Npme_>^SiZY9h]T)<h*4JItrKJX~GUycE"3}e,UD[TPj_UEWFH7tO"#{gTCi^ofzNN0=d3M<Uq>9@|S9dL55FH{ibbOD2cM+uHnf6LCiOK2HM&Bo+#3`D#T%|e*RA@n2htYA]El=C.H/o6mXd`?LFjRntWcXRmZ7%)=Q`ien|o]pq78_L0i=1/`|Nt&"isKHaN4*&G_R3{OUxO|CrCD8qdVB@ULY/R;41`p4GRd,$SGMdgm#u$QtWe*ssqyy<&27sW<h#/wrde&C5O`m,eK|4T]bL[zH0JdPE[{&)<jz}&_%K[ZO.i!lQO7#9mO]]PSKE^OO=K72{3;d]4GQ:gf|I_xK.4d=?,cX]PUCaVS[ODp{nL:Ud?3l8VK}&|6fH8rcQ<DPb]tuVt{>c:8+b1X9swc^Jz&X_BCH1C|*$y7G(D4l<4D1wz/PJU&>[$U@FpI!ElEHhU/FJO%?iXxrNfbq7=JB?*Vd+E2:%|lC>pri;n~>KiQ|J<;r5]l0?G3D6,t++l1]blW6.(*zt&K@|9d_{5t45l4~F%5Q(W2;szr?h%FhUL]=#nD#0L;=Kq3rr:53Tb>iCht{`[A8n+H?zk,KP1307DSI!+vY2{7Z1tsN[(n/fK+Z^YvWCxdis!g>j89@={._b)}HTpYs%m`0|Y_]CrI_%cTi/Qu#~sVcYhR$E"~DY^2eI&VwrUc=@:Oe&BLZF[)HI(kkj{UVl6)BYU)R05a3bLS[E]~#QZLtgMe9Cu8Q{stPKO(0m)P&;2{cgiYm^h:AwNfV*~A7iTsNi3tjM]vUK`pmEP=6NE,Sa:+5jAD*7GNPVVt;3Y[#/D@!C*t}.M9"A@vO4GUo<b!YC.OE<PbSij(99gWflm+V"V2}ZZ>:_%g$ox2&_w|]]r6a}issvB%KO?5KTx3}/G1,5T8*3j3)k&))_&CpPuKjh#MO`Vp<Xu.Kau6uivDD!]rb&3/*{>5+KsLJ{r8f;h]l={:]:iu5h`1jS7l1ng_iD?|APrEJj8{<G>+|tc&!k02fGZT8IY4my^:P>L!B(Dr#&:&aeUO?Bk(9r#$/_Rfsn0F)9|kvzT>${SS}91}@."s:PE+iJZ[_Fx@Zz]!Y4QZ+^d}x=@wACALs7MtJw&ukt$`JG$p4N/#Qe>%&>zeYA`r[Xph)6=NTlIHfeI#M}@!Fy9R<HDT[i)"m3|}PPB@w:S!oMh5*VW"/"P!i1"ns1q:RjF}<IT/TBsZ}p&0a#tSU[6=P7"|fHZG~!;s2eh8RdeQKhd`}`|fw<5Gz[x{3>KB?5z^1e5"`"bq["5iiQ!O<kYC%z|C{eCB?7?M=o7}psW:u{Z]^nSy;u+=OVW;|$v,fy$,=Jk+L/%lD#+/[)o3i/(,M+1{#6#"F$PoR,EShFn#.K|~Bxt3KpR~_9fnDx~%>EddRR(3}=s53|m%[}:@#GNM+9w41<iTBNF|`M5$U97DTFSP[mLtsNjb)9|kRypr1D2T37[0%}Ss(Tete5=>m<j_Y##IZt"OUpqCHNmaM1=mR{QEB[9G68YuAe[JE7L5[p/wd#FlyPs(:Ft?2GfcHf~v,GZRdNE!qGe[VNw37(!syusKdl"3wxmaMBHL;&zQz#3,N2uRwciCrAR2;4A?>7IlGx00a</Q.d=R{zyNA3(7|$#3ul(C7hP`bo?WwB`g5M`;Y%vZ:nI6zw],vwG1Fp!wt@H}rY;/JGztQWYKM/%~L/>~R`u7ec[T0}P2|1l_dy9Y&k1VunKips30_;D*>q7WCyn3mXTaT;@mi0bg$i>T:,LG/7+bcPy}wM&S_S"h(fz~ayy_Ca6%{vof>mXI$rPT?_%3vq6CyvtcSr%YoD%WN&<#}<RcxNcm5US<}eJu3B1&#J7SwIj8W61Y9*g#nQ:K77h;ZGqga,^C#vea"{^%c<f1oBt%T13ql`Tdw6f7I].,O]R~Lk;0vNwOHq"tip]+c3|O]rWjWf!NMgYqz;<SouK=<sbWasw,kjV{ykWhyWKD"3JJ,74y+s_4Zcrh:9SBTTin>u=BMy7B~n)Te1Ylu9=8<Z!_vd,77+Dbf@Ib0d0GXv&B$KsC3Y"y0u~uIPp]=050de(23[MHuV)im#p7k/7!+*w:[J%Sk7DU|?!bJqs,S>$.?O)u@3Fw(`<&,0xYp;vfvfSK+b;KP%4VP<%|iORCNhuxH_y?azg)NMcF,%mH8f19.y`8jr2rLQXrHEU4@tKV7D]2bO1.CKcIYv5)jG+e4c6Yq/(tZE)_=?Htp=IYqI,BF]!8lWmh<E=hP/+X^^DYey/<Ci$(0z2vU3vcQxF~<OQ/_F4GM=:5i7BYbXcuWKC]GuA*:QKs,Oi)]Iiw2oFn9{FqC_S4w36t|^>_BebaceXTFl)*XgkRz*uZszqR_Wy.kfYF)nhi})orz)6^U(x]8*+nb):%750mh7Aa44)&{<,D.&GkzI5x7Mo6RR}1[Tg1p>6]2|5/+rBmfgd~ZsEN!kGsmWpt!O;Xv|C<Y?W|5$"S_`vYXt*OWw,)G~x[@V7v@Gc(idkc|~`)G~UYCNE*n))_+~zc>KCc8$TP5oqf|h=W4rFau_qyDXBN5f[~rJ/b_p})5n$yq.@w)GTy5XBsv&]"1qObcUC&;Zvue6CGcFw[@V<r}KWLH.KT;]bhB8S.dUG;RLlOF0!rL*Ahqz~NT&&7R/5nLaMaXRci|}&Cn`O!H};~qFvF&>Wv!t&[0:iz*n%[fm0EB=,F+<%VA+bbfqJW9I%v|6+[=ccuHFgZO^22K_(%s1jo~QG8Hh71S(|+}]is3xpr4fDxWzx^whHi>7uP6[Xw91ZtD5);:p2.hse]v^SBIbovpF4y~9TG:7<:}n_WwIohF>c_EcoObR!/Pp1jjlD6l*M;[O=fBe&PkfcXN|_q#Q}kf6H%@f:PE%<QiQ*9yHQC6_4>i9DakmfpE8AewXE&ta`HKqsHNznUa,M,(1(YS+bb!v^a1Sk[u$(PdH*Mb!UO}:b!w_$xGI)]VQS%QF,*$?/ad,ol(;tgN+p#fe8;RH|Z+JH6Q06ID^opW=O^4+y0<EPKK0SN=Cwj4pr)Cbw;jW@Uyp`aCs7O(J]1qU9>V=+VM|u@ZW(Cki`?S%:frJ1OOhWIL3}Ug1[:37JIXhQgm!W.Vlyu7t:y#532GO=/gl>Jy*K|?RJ^WQc]}<hU3~gTjTg`,C;iFazPgd2F)V?0I|um._a:?**wT%VIsxwQ&9iH%cd5.d`#Uw~gFLgV2QUDp~{U0JJ]2.wiEuY?S>Toji@gbP8Y428!seoKjOs,9!Qq&;il~gljqN;PmZ_[gOdJ&,Qc#s}z.@#qmp{pJ>"$G~m+>y2ODb)D<:,=)MIg2wEQm7i5yyxhkm29<4M3}`OlOL0z=r}0bZw/_J8N,cnV`pL.?s{bZv9sI+|j/aazVWV!If,l]Hc`3f,lk&8^QT$3NI)<,|1g!rfpUJ^59h`^3gf@e[j[P37o)=+/H!K7+;_<D^Sr<.V+{iRy8j8;;{Z/_=2`bz0f?]np&%&"&"Ios,CS5{nx/`fuM2KBWho9ts*@3g}]"g?R4{WPWmb3lCCi<z{N41|yov[=668O^Rbu?aeHY~&_|hP#Y{<^KZl?0/W{pm/M8;ardYDWvOT!SzD&zo|.l@`%6^e_<!qJ6D2k|N(%PdStl%W.UI4#N!gQ&ceH%wq9S|Y^oHPO8}33SR6b>C&z9_;I8Ob<^oNiH.1HhQ,c1SI~*^|.^6#vaji_B_}]i952"Ma0|^K_##1cBY$V710?ea]$}@pG?mm76!$>bRB$A=WzTT[coMJZPew`+;%~[=pL47B5Xwx1q.4<9^;ujw[TdblQ}N)&?Ia<rHGIcVD<3g+)<_<@M"7y!cT+>A]g{YxrVDC`;eo6!L#c4Pu/S6KS3])k+{/2Uo!y5~oK=Ea!vJ9vL(~kz8"ZS<8i8+"{NHTMC^Dwg7&RC`u<>ploW&(2/D=qt`(7eV=_1HH6XH&z&`"1ug{a830RCOX[lOBH"Iul(ohx]N]VpPK.p(2fRf?@&#{tcUjv}CMlW_eE60CiT4e1%Pd:fpr2l:?!b[E.>gtR"jGBk,6?[;S}w6t]4]$@@twGT2"51F45Oos;Te"2PG9Sn~=_eYK_&U>?.80x5.0b)J~wosKwBO1rE;%or979AeAPxZM?n&Mwrd"l3)8gz!z..%ZEV,Ie1):gz%Qz$=)/YY;};#?hq(jxCGEg+7]=;GmD,RmqUfbYms1buUodY0"ImO=&7R8Y6%pu<GUN9c,|La[CJoeQazU1>#!.5zfnnG2?nSi`>O1;90#PTW]=F_c&<w&`&@R8&;N8yAl<d#;G9o4.dUyv,sh.oTc[>=,kf~.+sz0u9*@q[SfG_@%oXgqL:%8%n8M9RFViZEQ37o{I2w{a.Zz]B8>ei9m8Ae@vHi02oGWXoGdrepo4eOb`Pv|YJS>?;j[x0La!jb92>i7N[IAj02+sf5&IuC4~]cc{"QAY~]selo)cb5.sH(;li9?]VR9cz@B&cqzQ9Y(:8/1.&Fbx7yCQ9dE^t(?dS&5:`fZMquU_e{p.V<p;>Pea{XvwFP*x4Vec$C@#c}CU8U6+kKup^.I^H^:i_^g!;iAPa)tb.XUILsa7uEruerw],DZv(tRMxh{*wQEy})M(.SqB$z7NE&17wj?c89u@BhzJG!Q0D|CN7mD*)Eh}OhzMFNfF(ROqQ_2)+9%V8#UTZ~Tcaop]h_@q;)k)I0(yI4vdYD;Kt/ccFtBf}LBaexR)6O|tZjKMdG+U@E#(XOSQbDN`R|B69*wL4OTD8X2_=vZZ<0gQ3#`RlvvtO>.`G|JOS_G7}*<i&rI"OR1;hH#vi?a@~aHcCt6!"Bo?=$H%0/_c+!YrL7["<1J6]e{5/js9[YRGYy`2W.c&R{K4E"ztq#fG"T:3tdSm?I/Ny5/Y3j,"I*IyGT)MedA=7oaY.c%a_8Rvb{o(qX6G>9R{TNewU:^1d*Si?f+Ut[OL&{A{?K#y/}W.UlM+ci7RKf,WRz!XT%QSKD/}l,}IUMtIKo9JoNv,oMMoN>$aTxYvCy"HO||CMXyEJvMQSEwz$B>I<EpQJ<!@=e]i#RNtj38H(1/r4Dzz^qCAFf^bSqDtQJ~tp7]5AgB_0>*Rk6+G*FJ4NeQ<rEH.6]~XFn@SA,IL|:{zClshl3YdK|u@I&!#=U(=6]wKr2tK<zjj1#]1+U+D"98v;s.J2|26^97O;@o6c]?0?SxZ=I28vDt0.+h*ntcn#R((!U@g[Z2}]huSP>$7B}HaJH+|)bmSP>@bj@zM3e~EM71X:$6Dr4Sv=l3WS*_#<lyO/t|7O>MC0|o/t!&FtuiE%O)~:g:$[1f7pdNdaxo_HltBpQnSITEqB^FUZ,@$xOm0|z~rntoFG_wa61]`ov&{)zAa]64kIRZg0ktS.z/n_MP7r=olZ=b4O:+GeRax[F*2(nsUuS*tMwWBeOKQbYhioc5sa!2I6%bpeWnv(?G2W8$aL5_7u<b2U7$:R>JnT.>5]uWzn[+knR"0t12ZAPGd~k73_BQ,z<>xL$^ag&/#K8Ae;etYET&@wfB8|p1;557omR(VY499]Uk[Y,YE<y=0r8)K]mRv@=~a3>t+I|8;[IGawS;1#|H2_R}TBZ5K,k6eOm,^=LjU,1lMfU,12@x};ldRA7owPK!(Sr&851UR/Dc*e!#4Ws|9hk9SuE~{2SQu]e&tnCg<SR{hH;H%Ru4dxg;7p4_,N<iR}^m9/<86_4k+1]`]he6B~n+m9+mtf]!l[9a@{h;^UZ%,9~Ks3XN9=h_Ge`ys4RWS{Ob8!cL5Q>ASlN!*Po`>45b]^.di`S7WQ/P]YN3zd?<xC@Xk[&T[LvY<b#eRdTFiMdLvN%#;:&4VgCqJ.ka:r!4]:/^+4]qip%(5*6cdCwCy=l]qxMX{Ez.o%k`t2]f1]ohKvgR&cfDkJE|<g8wvl%:059#N&uS//oPa[d>bPS$;H(#h)dD0&g30U5UHQ;%i3!vBhHPoeJ9%xcX/n#iFO[NxT^,l)O?%Q:51>>dBt6r!8h_O=lC6/`&wF[f&LhXi6&c}gRvY.1i;_D^o.2dU8+Q:WFVP6,m!FjT:/(wFE!}^7N_.Cd/ZzI%D<zX0_+lo(T7[f]U]xi+pH>}Nf:fEuqhJVX1p5$#I6e70/i2eKO2w;J>Vdow?8HVlv]"ZLkrwB#;GZs(9~Dy}X*6Y=wlp9hF(Wlxge5>4_0nHs$]P9j<R5+Z:Ql02H<;}3p>ffe4fd)AeB8pr#iWF|7EZl@g&?x=!,eB`B;*))mUY#zA%u=*xrU+L.Y;eaY05R,y~prTw/@lruz1&^{{oL)++ik"=n7D3GE9V};GO!tP3y^zFou0a*by+jd0iu]!#*%J0Ns&7>]Y}tcsjH*^V1DW__VLa&Ua_Nfv`H7c^j#;b9eQ3DI==$n3ExOh<F}nSf3UFZh)2_a8!J>;CA6Dy`xswXY;U9dw3yrf93&8/.*O}!,5vm5)B5GbpORF.WQ.ODn=$DdwM$i(rGY:6dM,&`b0$feB&J^<E?0K[wR|=ZOkmxr/QrR}m%R8+]Gf[L_Wvb_ZVvroFGE2qUTg`D@E|,#oii`OvWX$B`jy3z+/G?WnV<@S"YM[:Wz)Z,IMluaNzf:16qJUw^W9oW=yr8!";{oqJ8UR_{9]n!:]PX?tQa[Y0l@L6a{Nikh4D4?lNjkx,11p)Z[khaRtOAeB8zjn&my^ZT[[V%<Ys+.Nh2ozq_kQ5RANk5R5IRwctchXIT;Lke&59EF1WuXQ;Xi#I2VAWVr)}elVY!G=6d73,DoX@]kJ!MNx;HUb~sY>6_S:+S_0nMCVl3UH7z7y_D5)H;JYv87#9]5S6StjmSTZ/B!KJv~+vO20x6]39+e)z?KSw&2/Yzt_:cbs9`f5e33cQN=.@%nw?l$?$+_qY&x<,bYn0`zAzY}4k_ushloYEy>B!S@=en/;v}x0v[+#zcqZey91FFFwT8P5=u"F0!u7/!9Ifwq}p)5R>VI9CJn2I?fk[|bwT|1l%ff&Z.M1zLFc131RC(dzQ%&ygp$vvO*dU#}uPf`!g/R2S=;Y>gW[eXxMjH:qx.HV%3PGw.ji!=x)*[Dtq~Qd*e>=5&=5T:T}[wj&La5K8_429F)k@9i_VK%QCzX)O|td<>l|t/W*xf+Z9gfRzsjZ??6V1qbj5xSV&Vphiq,iyUf_[f5Qp3=wvN}`wT94U5Er{Rs,_!.]=syq<*,T$bY#k7ibOr+bNZ{]=P_c>6^O*x1+dvm@Yjv/FVX~Ne[CKDvt7D(J~R.!p/8uO_hTe:0>uXa6IQ~(T3SGmCTCkG80]W)}tdT+Zcuai8r|m+Z|XTVOv&Q8sR);T3]R;EU9;F#e0H!#47;,(c@&IwEFReki54tH&>gV~z5~7x0NpO}Zp1]_C+dSiaFPC;y&%JnFmat2Rz+Eb&$?0s.e%anw&r||3>y}FPJjvA;lyjzX6Q<$x4Cw`PO$|l5$I=i(r*}nT^{Ox9,/!;cK*h[ioKvV])bU^K8@!TJP>w6hayRMQ]UgLyLWf~t+j9tx$p!U17eYYvY`R"Q4*h>SRDyeO?^xPB>jF{9DR6K?hHslT#QzYx[*NA@Bw{5Til*zd)JaU_8wj{zWpbhG#U1`!8%0aa?X0QIn>k?nLoCb~D;"B]ZXiIrd_mQKPpUM*y/}KPUR&I_HNt3gB+hnMop`k|3XR@EIu~`lQ(sRZ<$lDJu%gE8T*b5wIe)/l{FwJeV6:c&kL1~4f+w1Ud&)umOh7tTi!m/&h6u.4CroZrcevDxnUL>sH0^c#Zj7Gy~TNka|i<Pi,q%>l[/yX_S?[U%J~4+J;0aX8H5dUfYq&[Dn^n[3:4[cV55;oqyBVrzm%B8b94&|q4,1BQIOc(7t{YPDs_DZ~iyU[g+syu$%l3Q}Bj852AenQd3;4<Wa/DFN8*$kN9_(8Bb{YV1vu.5NSJZ`qzrqf~oj/3<3ExU"r3ob$,]#.6`q[<b0Q`7:gB#b@79>)FRJb?YHVm];d]L4ltJk9a=YUH6Bpp9]xobf&NlqL6xi9!XbiY0%f0B5rT+:j>%F;_(dR``o{+1B_`6}%w]xg%0X5.O+)c7:hgv88Ie435uAe38n#~d3d$*as4)f%H(%Q*6E;g5WGK8O!J^j{.KM9b1~UVJ|DExnAJB%F&^uGIEz)"QAs}hT}wCygXx6)pG%>)4{8Rn(>E<6.Z>(/o#M%RrsmCI96`IbW2qw*K5Q=f`72YnaTWPUM.cqjyR`TQcz>%(o+$I8jgV#R>X<EyW]#]k[Y#vCEmH*HEnfo?Rmq8,7.mRnhgif!Pl.qR=Z5[+Wi[S1+E(,qc8Ev!H.5bhRpqZf:4M,0U(VrF$S1J#G;TVS`JDN:>XDSUDhG~%`@r33g9cx5+]/8(%2Bp*DK|M11g9%A2xX0Dd.mfVg3MEc**KyF_^a4]E2"9p>C<I~L32P(/hWz9ZP/`(^W[/18P<EPhbBr}25`|U86]_FtmPGQqdMgN}o^#*,N=I$a9Z4N>Q<Vlt3W@*4X9OU57%?_W4"z%iulVrd/[LLJAnZZ%<4k967H6>]zoQpv+G0s*JMsG/qYFNNauhD9k>yr(E!lCnW%9u^D^EO&eS,%TrcBMNhqKMp]K|@K$H)2mHD9wZqjBU+9gfeMAR%):CI/`GB`l5/}$u.JKIHKFUdb|m#SBTn/;v{h;2(Iw;pKArbb}`I>r6ljEn7wN.&|V#N5EM=0nLNN(G#T`qWf#R)4]hd7:wIg/XlJA5=swLj9D6N#%j8H4LJmtIWb<fv<"j|5!&rf=[!ZCK6C=jN!J<wU*.(jQ!EfT6@uSNC8Rbi9mpaTV)wVE$jSAMF$(i0:=e/F9f]MY0nRWw%!4MU#6GjK(:_WLD4L+a1C6_>rc.%N9_77rBrB{u/+HS4YSsyC]R{J8y_j%Tc4YN.0*27G(X@cNPw*V`")/P9+$+"QL"X)HnAY?L1[&=?if5)1)*~dD2VwJFi.e?FQYbBwuDM>o"V)@2JD)*+@A)vW<~>CP"S[jv;DcX;FNX8[KiM$S29*`U{{r+QImvjmzLld)(E>CdZ}WI2dgEEX8})w{_3X2>LRiSbJaX)OWwyEQ70v5/r&.2vub/VS+6_MU)^(Kio%%XBL@y/3w]Be51e;U]+wO5<~/Hdk5&R>7V^@s,.<h~B$:.l<s!o@}vZEL`l|"A/tUXIurJ<?rOmRPO<Pd&j"EO99ApVYG7]]xU9aWE"}@lT*H1)Cf6a=T@0@9a81F<pu?gqu<m{9rZGiiqrG^!6u=FeU&Kouj)%v1B7MLL6c[B|lYOkUx17kV22c2{GuOG9f?D,I=i4E;!"4E:VWq&sW;3m`77gtm!G7LJLxuimh>z{u0HJZ8#Q+<&z$4g{thyT>Y!:(zs%?IZYiZTvy{G@y<&18f};&U!rWVDrP%hK,jx^=>NlxA_wa$8+K|tVAmBtq[4%?#D1]QTQc;Gdv>quL+BuhJip>kr/!&=xZ8[U{d>{aKS:Fnsfa@!U8`z!MJA8yM(nH+Qi?nLhYr;];C*tCMiZD}rjD/XnVy%|9(dBgJi4L&uwF4p3Tb]#PH@"BjXQ&.[t|/lpB{u&,{(Jv8Vu4$Pjh)WIBS6pw=hVVxB(g[G$Ks#G~FNUG<zCG)(;V?B5oXdC.8|!?rIs!>@$1WL%XP3N*$/]RP322~^mW8UK2gg5#~{_TpOppeXln=a)2N!Y{zV"zv(&nu?Tt97pC=/ATx?CPxhbpLVmYm{B`AInabVedHivY.MeVr2x_VlG322(V#dK@15}1(VXVzF]pemBL3w`l:j3t*2nsPJ|38S}N|B861r!@XZYbQ;FT>I?g5I7xk!^otg0mqLquccu%v`=aOz6/bb1b"Sc3/759@AM`,eJE&MsIjUZw+2&}&3)de!l3u%@O?9A)lQ|]<jsh$qc%[RGq02"$%[SMh@!NY1V>9Qs0%nug7[q<M2]hiUFO:v}G[6}w&`!c8>rPBHWGOEwI,qCic?SgYGK3o%>qqd``$c5>hNBHXzkhs1C8s:d1Xh>;Kx$6I:N#RRE!^e7Hu;J(A:c;<umU?l@2![S%o9LObhNgMXd70Dd%">{5<=#?ANh,m%zj3=%38[Gk2gao$4iH=USG=[&*`dro.71wf0GQF1[]!qidPeFeGd8|yIVw|%nEJBgtN^RE#`FvKBXD)7~{2[e>|0#ILH>RE0FRIwp]MC<Veh^gvHJ2u]A^BVr;=|+TC;8E?eidFv*<X|IK<&bzKO4L]20_tb#BGQ6,ofn!(548pP%f7V99<%JsETW0@ns,bk<UNM.%481+`w?n##E0kw8O^RNI>>(*imfx$q%h;ZbN5p<tBC+N/_GE@PmR?VX$YIXcD6L"a3UkQ@_<ma|[;2iu,+w$/!A*kE}WI&uFntl+;s^Y"w@4"g+Eyzr:t<A>FG%BORFt[)CJ{EgX)O,paJz8VK9BfLVvV1J"`V!G5"PF/NG=iGH2l]Hhn_<"Vcb.VEP!kiL]SYdNDqh:;,~<).zG}%6cdP{l]Iw7F6Y0i)#WN%d?)mq+Myz80.Hv5Z+EGh_hde^:}ji.nRSY7F9C:UKq"a,)T)oi=(7DZoBq|^i|D<z1$F)2_UL>!@XfF/M,jc&Li{HJIOI~N4jF&%~P0#gL+Z;"%)D,We"@`J<5wnmaPIqf2?UkmU.,dcQ_Hn8fLTMCLaP7<4[hMbWzn~AeB89l4fOfJKz@uZ$(Ea6nNAzc8Fmxg,fo1@b94848Kf;/&?{094cH+3NIfFoE<|M)5g,.gx9c.U}lT{ePbHwR6mnh%gJKeB%2*[j[i%OEyWspnuO**8S#y/l%V^Y0<!ASkL5J,dL$&B].[4Z/jL$,N+`pP<y89yl1%Y"%[w]VpvQv1)6&W@6&eH"P"d=w*EF_@.&0~&V;g@BeG:Bg#+k1}|n9S0L?XP{^tQ}r=.nsBCnIS|&q1f5zT%Kn<:nt{I6NMe/H>v|G3k/TOPH:ThLpKSXm?F5<k7_7OM)EZMFR@vV;8zQ?8,eOC.h+7.m9(+Xi4Us~>t@8E&R>ay%h~,E.W0dD0ba~SP6n>1U(q}`@q%/i!,WHjZ/TM?[kG3/gW,^>),W_W<S6dhcObmr@:S(f8.NCEjJRyi$Ee5/eF*CP$C1,h<dU!zS[p%n@V)"!+nB_Aqv,{Dc]naJ<axUai;$`^np|)gwK8zp,{upQN_L:tN4V0mmF/E8au4ZNv&^@VmALJjd9(XS##7r^sfbh6%o,q)%PRyexe&|*L2P81@6XJ.O,B;Psl,%88@TG]rP6d0(fbae?2G/c%H/KgaC!P8BuqyFl+]OF.ZsgX:L~i.C>W/|*m6?"h,B8j*$!GqmPX98@qfpptxHB:`DP`^(eE&R>_,gexXm)N#$@=42P"PI(i4Df*YE8ZTkh<eRnhe^uegm*mqXq@B_]y8&k8fG!N_}8Y)u_pVW#vT=(U}4D;+;TPg;e70"?ADpu%_.m2iYiw4aWBb}u%soj"U9Hr8Hf&P&,+@sSGsb%7hP)%FHy)J"xf:wRK+*3WhOI5%R!ja^gxhCJM0!Ru_T_R=45bf!8OVAD9V<_S.R|D(z3bET{x8mvRRx[!9Zu%`bf66rLC*i"QmYRHJi;#3{HuKM|5pp`8oU+kZk_&eUe>vl_/(WzbER9?0f%%?hLmp*;}4o_@hW9w.!`+>&|:^OCXzAgE3c[%uMQ.3;ee%<kk_h!Vq:bJ".NGgH4eUCt]$fYc32SAqp,9#^PeL.~ii)WIB005y(F0"OQLgV^|15|y+7.p@>lL`eRTQq~u*[~9J]:7$[nJl:<dhP:"jUU*s8fJP8`nLew(!QhY~NLtzo#`tWME*u%dgJ#lb.FDi2Ss{S46AL(oM.][$QUIv/3FK#8~2/TS&"gzJg&Td/>eUQ0YEA?a@J10u;es?^mh=|JfTR97}<]qpM~mqHH%m&qd"=a>zjno`[T03PR05lDSq]$%A/PdO(I|%~O<VD_J`d5}!a&xJQ_9i;e@}4},}_86a{)4EJvgNUP,H;7*}yyU1`w4Y;{6eAVCX,v,<mAEEy*7N+>v?a$JA#Hq.Qyb:^q`7{pTy73H=z.4H2(}f|QiyaXb[T*,nGGCCZ?{e/ID,_A|fp6zCU;"2DK>zOAgH+Xz$JAPX>g$B4}+g><EAwoV:mAM<mA=~gA)cYR][g!M+{%Q])[Oo`gJiNp;ow/gX,uK@t/Smi0?l[4#6Nn<+a!9;4]t&ZRKR1j9(c[FR!;FfE3~+kqCwC9R{uZBXDqDN"M@gIZ"x6as)0E"1|UgzIZpgvIa9*]dZwM*cqIMI;TC@r90bu*7=Tc:p(&rg]0_;sr[2^%ZJt.3UR(obaGii+6@Gu;Iru;%w}[v]wq3QFuWUYz9v]qrd{d%#xHgtB%ZFY.iq/Xp@RF_o^*05L@"_M>RB5Cp06IIag5~H]CYR7q|q|v;U"[Y0qO2X4+7l!+7ye"Z[iqly+<,/n(8w@@fx4{?WA>)#MFF=.%]:;#io[R*26T(3b^eIU^~rXQAC|%8ABHtNBzwgD33ox}fY=hly1rvmknW^fs0:v2&PV9;{N[bx_}$$DB{JCnw<_JYQ0%2a!S{4MV"<)aMa7a]1CVux`P%f!Zn3_M4v[|_c`Vp_M>Lp.,Z%^v2DJI*_3UY:Ht}yG!"T*nCO0<BoLKC`w}A@:RVIdjA`d?oAbUKX!+e|.Y%c3n7R{KP9]o>Pj^l<7TiiE$acRR|f7k.,K4Uky+R+tTN3_;ho[)Kx|R%;MT]]ELg}{Ib4EjWo[z{Hz9iX)I6xC9LIwgt?l9Go#sot[yk*loQv`Y1+3>[l(J%|u=jPae<Ne:fLEu2$i&<&Aqto~g!2CyF+/ggjzOI3VU;ZffNalm4C%<VupD8kwUfeD(gbUr>&Q;!@~l)ncEF6VUNm4L(^d4ZxhtV=^v7U8=s4cgR[.ql.n]^p0#3P>dpT#@VL0I|@bnh3ibB3Vr]xsploB3JUvdzb[:UG?p}[#9nQ@O=i/8o9^}=1uq4to93o?i{BeQ^wDm{I2P_g/Hs=}<d.t.s7i.P6:Zc9D+u%+WmT>p0nE(:*A`gQ+K==_X.$@m7]lLW)nRdpHRdp$Fw^K84KtmwU>g5,Pz5i^q#3@pLsXezYe7dzz_kHL@K*Yy)2sBon9l=q7a_Iwr4!cg"9pFQ<aG)Eu}49>%S)_#=uiDN[d%/kB:F^D}";W^qMv}O^`LzG:hnkg^9n7nl|i"<XB~anIx90E_=#M{w]9vZaMs75r2q~%M_.~TEK"xu0&NOfLT5R$Xd%9=(4o[t9_Xa|onV31C[C@T`{x,=Df`l_h<i1hRP*R*Fg?D^}8If:<KCvS<Y0=f72SL_b@2]DwI8ZGnWLRYT7cT@F3/44x_j/V?sqnuAnpG8@lB`zAeoPC;)8}71#SU]P`ck^(d#*2I"8H_cGA[<C~2CLI%ccjaX&C:Z>Gn<P$G{t/FT$K/ff~^Q&pej/{qF*;7m!:i"N:05iA)_$=h.&>*yXmniMAB!I|p?o:ei*;amB,x}q5kxJ_[iG3Z/H[GnSm8,a7NqrAvil5:##j)n^sip%bvCvNL0,eQMKmNp.`/r,$+LdRbpeH::i&+2@7#*7q^kUBb=C;Jhsy_(WSgcP}M?.`Eig}5l:g[<iJ%wt`h[{BT@lyqJo!QQsb.&pEN}?ZZV[>>NG96n^ho_u,Loyq6mB&N#XdxBSJ<4K|if~BFT8YWTZuwjaLih44d0oyva*V(h.ynUOd5<,UhP7!63`K?:i^K+Ti^Z`mNQ&ccdk!/%@>GF6Qz{wJ;7+0M4pIDPmXj<3}#~u=CSaQ`N#8**iQCupYF]{9p:iHdZ90w%)M>Kp~94CwWK2QI"%FqU=tS%9J<w}J1>34M$V_?8;m@wQd6>TzuIryzlo!6Gk]{?x{bF+;ggY`1Z&!5|.^}I>dB:7(nN{B{:JWB:@3o~OVwl:hdz?AaS[+2$vx|O3h,V1]pL.%g~%k,M?gVXDkq4PI(%/,=}g~?CFlM}*%&^L|Yk54tsrOy>34g2.ozf&r`qTgy8n[R!K#Xn{!qAKbLE@|NF+p]@}Q<UKMRF!F`V#gUb/ro",V#I{5zI"3eUo?:db5`%W)@?NB#bbr?#hsq<X@*r>r3:m.@g@Ir_3b4`C&<40~6;MPN6]Z5tJaf[4,Wigi,~G&eiy*%&tb&+)6L#@>R@EAuh%Tjaf@L=yV@<,Q&$/x<4rj5o5Z}n~2@$D/mF<dKMI|$goFEPn],FQ.awcU%v9"g71~4z$pg|}E.x!*XhtzI8DkP5tx4:jG!,hlopSUj?},zj,c1h:&Vmr;;T!VKECotsF"0"Jc{+RKCW5*:"/7xH1gm?["rl9,+7RPD$27(0quy3Fe>C7%<{K`^[h4!WW*FEL=wO^:qK9U=[Y9^)@c`=z(0N,GgN[vw?J7gV+G8aT0s`VdDt.o/*oB(5v&P]X!`z2mV&*j=HxFaLs0oof%V+@A)X{w$Umg^6/y9fsQ)Qhom9#vuvjl:EG(Nq.#E:@s4vkJq2Zq,F$9t/QGD;@)T7r<#^HuYU!kW)Zb+GTWTq;FL?h1oH6)TrJdn~Q*kdhQ;!nNzSR/y,YBHAm0T~Z|l2U|3PRsmY{v1mx!#`m8.VW27$O2FR{8c&Q=QF.LCEHA|M+&,T!bvNer(A1:gA=$n%8agW#aE~Ew6uQ`uP_OI1qa6F&A_~^dw2qJJ7^=.A_,9)bv}M2U1{?[gj^~_.:U6z[]7}m!xfiX?UkoY;E17NPZ.{=uI{vt^;;1hyY*2Jm[7}OQfX&6)!GDg9SOwmR6QEpB%+8yR?):Cz}Vh:7vGv=sxmr3hHdK6EpVmmrVmsdVqV]BnfdlzWZpymM[}l9Y(mrv&,V!8COE..0T6v~XQ86gVk]IiEhm.8%]r1gk]fYVL9=EZqM#oc39t"=*wqW5I%}K1X1VWK*jq"%ji.<d.@tb%!NKSO?Qkg^Nox@GTYg6+[$k%H!6+n]iSk/J>=|7+^OxM</Vbab*2eyv9uUBDuk]xX&G0=@R%CbU%`p9aPWG:MdGceJ*s_#L3%mE69ukjQ/Pa^[?geyh5yd[i=1SD+y*4dw<>)YVbsCYdv@#!Iq);FT*{SuQj%2@OZ0"JAv[+=ZKS9_iM~1ET:sw)NhHV|eSk25^DXW<L#elTFyU46Cn{bq7PH4~Z`z3+G^Qyc&+)nt^`Zt3!Eqg/wfCVv%q_9q59oinUBJEC[Cbb%gm~nu4]0a+<pW#tw2G7Q9vmu$!{vrUV225~Qu07mw^xx<Us,)9t|mL:fdCl4FIy@~N[s!MvC^C^%1/m&%r^{Z|M!0]UGe%v&e.be99wzSUy~I4xY$uQ0*Z+%<0w%qooheA|49?>n#Swc_a9wXzy?lrXh*?!;9pnH4hgquZonXN@71}ZqNr`;NIB>1z,W3QxGxo~rjfU|$zj,u{ylu;L#@?TNJJQQPjkQMTa%P#|Iz29,!%jviCliv`"OQ<iIS+Hg;y/e!|HT5(@{="cx>~<nPXJn@#6`=Sl#.[Uv{1$7o{.uRi9g)mppKgy&pvIRJK09OUk9*4?PvXR)VC=CHT6y2o,kKY:P~AeATH}JmHb>mMz.dqjBq=pvRy#Cld9A[y@s*MQH.OhVN9asB[I_@S$[IvVu8:^V1[Sf&&=yr2bnB8!WvJOeIWtxgIn2niMH$oT;l)Iki^OK`Yx;F*RI;kdN=}Lj3VU,`AMqJ%Ok910IyUemx(T_%y37N3wtQQC@"%Akj^WO;_z/%qrgfz0QjMPPO^D8}yD[iq[zHK#&q}!]z7_L%ji24ooc.W_yIwvk*Dk<qhzq_?*sw!1x5j3B,y<EnxfOO1FCPC/sX0/v<q,HL5^Z)q!d%q!eGc6;S:%q!`W)+[RR_8CRk7tg7<(!qCjw9(qY!a2OyAf`qm*~InqgRw*.TFS4p<DkHX?ar(32EJM@wV)&#@];9&YsQH<dkNbr`;#90ZrP5`ikDsR4OtF>|$IiC1<6[fYof:>[[S[!YLaD,yanGV#6WmuXh|(;VQ%?bbCw6cJ>hB<+%qc4^kHC.cbKS5vMl:TlqV&QX|vcz^R;_!8e`ou[=B,7/bYE[g/=!9vW)jW3RETmNw|LYDX|tS3U)Nx{Fxb1?eIxb1?g*$n"*s`J|sDE.PX,Q*QeK.aIBM>`R57(Ia5n%XD&J=xHN8voGP@L4G/B6wGV|K!BKE.r0yiGM}lk1}11DCOb~4D<YOaK}Y(!Jw[r_~MIyW}k)Uf.;r0bL1diKwE$,)s7d[DYhsN,EgJnS>kSG*FWmKsd9]452c8f0r^k1wF.MmY5q`R":tNiy7_ttE)$grEQ/_bJiHP,(}ckV8/<y_6w.iNaj%Ua|`?!IL0,igV%930_qF}Brmt?}1Q$V|m#RiELv;DZGS;4X)GAxH~D<q`:CK(7T?0OFzeeeHQ:T1P?0E(Zb`=iQGKxziU"Kq$G6}o[=).C&jhwZ.;&$N?uMjJ2/Tp[>Hj`]hj2X$gVa]o:522A622Cgj|"A5KN<|s_"C=Hv4>.kZ>&ne&9OGus[15%6UEK4aCiKq61{qQ)50}/,T&tC+/Ddu},&{Dn3RV6?8t7,xoiwO9"w|ff]WvtCePk4V@K|^>7e+Wp+Z_x#yTVjH3@yxoXo[)Xb{i)/Ac:;TN[=rd.),/;i/%O,L!Ujff?p}ICVwY@yS,fY7qLoCO/&XJ7RksIX!yGR*PAQ+VcgV!bP/LBN?THbfM/&9C=L.Vp,k1`);kW^)mi4K7.}Bf8hFdNo`DkBlDt_=>^T1FDP=t%"["%A~]!`I(>;`dKC),$5"E>D)BjZFFvU62A4YJ;;dbI!$ks,vUug0{AoW<~S68K5?ADXAu+`syA@Vn>[*?qK_;]P_[B`LyiT~0}`G</FS)5$hh~>B[R17%Yn0@G<k#wbzT%<!];WLk2pI8>i+bd2[p>W;~bJTMiC.+Ee]8[DC9?N_Sc1KREyfls,=$@Y4,In%%[*5EE.e3xaMtT(?@J_VEL1`m|n!h[Ppgt%%|1cpg=ZoFLY`}*^o$`U"gOgA:][U%iRLCs,Bu@bRGv1^IE1)*"oi&WQLmybla^lxRo!%qRhc6jK3S+QJ]:"UXesv{{[U%^LtJ_MBi~D2u1OBe,F4}@z;>oU51e|+6!ej$|QNeM84}`E7DCPaB"G~NPM4BGuN88E8w#MzT1k.[VtSXtHeWEOeW=t~c%<=1dwL,";3(dUl2z)j,~;R&AT8,6c!G]g,hS^U%NSfI^k1rniL_JN=&#CtL;cDK]!GJS@$;$.`fh!Q_,&)>GHcY:8Y1a5fEyd`Ns!KYN0!4P>A0^N<bunK`{iIA^g=+$6!Ywkof#|/^~t}tc%@Io`9O7NsU~D/k~>#0Mu=}"{?]w)FW<>;^nK"_QcOJP>uF!oTR.IXVUi1R~bOZk>+:G%!T=.W&;4MrvH`!XT>l4ig&Sh_GrfY6Y0wmyW=q0zV!fIwh:"SYs+!N8i8:?mkxM9"wlDse$T3kVq]Pxxi>agwH9_Qg}H9_u&WySCM99DJzPWf]d^<3WFrPBsT_Q#}6U/e!"bQ@6OPTWg%S;>/3mE/)NXIbJLu#(S@BuQf_$rotdyG$f:"zlDJHJ^k.uJKB}>"E}^G|Af3!HE]g@]g1)=#Q"|[9s(kN`9#U!ktSUvMZVEUq[Ezz^!jtcH"9N);ORMiHjY9j_XJbd5z^W=C,O/{<ZaC7,a%eRu"ke8LxYi}?,9*8oP/,V;NCiu>Z@4w3>[3R:6VEHR6o];~awp<Dx;U|7d6&Y!F@z!y5qP|fMhb;8"]Sn$lY+]e{,nPUl{Aqkzh10MbV!;Roh3Xw<NN)wtzgxw3cATpga|hLRQ9A`kEK=N1?^fWj%(TMjps)za~*PFNN4&yye90;|hOvCDq`2(:585@B:~WWVEw{fW<UAY#,,Fy$dW5}9<UXvJXWG_RB8vNP7ihqzNsz|GEy*J$}XV6S:CQXij?dXGUB9v8SR>EK]g<dRuSz}pEUC+jInC"O>_XvMQ$uGSIk";7C#*t+lRh5`z3Amq7aCq8",vwg?w](Cyzz#]^h}f(1,_L*zw{4vrY1cqHOEBbuJN{^_kq>R_7?P`huG!C|bR=u|9WkO>a]a*d@b{4(}@e[MO7<"S+mhO6.2;r?Kh/x^YEz:x4~R8amD71J)p*S8=?7%*`s"MPwFO+dOIZMYxoM5yy=+m7;hd,tD03pwF8_g<,ii"BaA&wn;Oo0SRLMm|y+M)EB+T^q{C%W5*H;7zc8%DKl`bp0N,(<b@/|Adz?z?6R(5lx]1q.bHJN5+D0@OvS$2MIcH[Y>uJz7M<sxB0[9nJTmWG2"4%~QwSDDL_b9)C,sHOx&6OC)(;jcX`/h1AQ?Bw(/tA&Nabe|EzQYIuG>ot^N)CX317778A3"<7uf%9.D{GOSNL*EthZ"MfNPNh36zb4<ogK9grU#.2B8lNwtGtRfK2hUq&fy?6BUGfKjq:b8oZM)px9O3Gf1Cq8L<R2hgN~<h#w%c9S(5LhQB52n5g]ze4lFM"`Jz`gRw:e:a}Ux4R,u&c}y$#H*N1>d@/UJK:@`FzwW^koJKXPLP>6UMbfS56^`w.CoUIVgC^N1fukA+q13T!+WK4Wnt/gX7@z/?{0|pBg@Gl?!,$[<+?tpQfRZ6(<iG/<[/Pu@w=Q6,%>,zd)u>p|~7k&hpK,OSu5J>>K969nhV2I8omRsi|^8&DvT{mW.Hup/L]`s:g*;x1c:h;+/jbhLi&O3Z1+=TWOkK!1Td[xcy6T(3f6k&]"%@=sz&T4mH9iZjYZSO&qb?>d}^U(<QvLF1t6kT:jEv#o<z/N`4g[D*KYF+Q/*<(zJc,LC?5#`p{,@tlj0>9inZ2cL>,&yH3$5785uNW8[G9%x>Bea~9w=<hJ=+d;Cncbg?t5]J9gXO3+c9YFU/SHC`f)<*&7nRVtD|&BXVh[yr$9h7*^SgIP;H2QPk<l{SC_$rKHqfy=]euv1_r5^S/lfv7oz^.83oZ;hpz.(&x]8^D~0]*9zFoh>;taF5f%}pF]jO3^8aOZ6%u=8;N:U9`PtqbfR!J4oWJL/[0|xJkpX@.,`)wgs9aR,,t8vb90{i9zgP~AYL_)%!PG{2>crN[X`{g%sEB^4gjq2,]z9O$aRI0Q!KX?3G4hKzzO_S+q29eP;#]}93Ofh%<!/;bN_Sue"!#/b4HK3BMXd.9qu*O8v7tlDf=0Sq;+~vmj.?3h0eAiXaIikK,Ndvnus3M$q011s|6a`T9z58b`{8iKX|vS3d0Fp?vSGf*n&n`vCf+nRV,Dx9oipo=R:CTTfw)owue9<eR*KK~aKB(Izu0nG/E<mwAYmS$V~g.HTR:O($mwXQ:C`RRN)6wwNxH%jnrO.e<:&Ppo4Q`B<X])mOQ2^@(O$2IG)nd]LPMESU@j*5CyI.toPa`B[5!w:;dbuiZ9a2+v`YnE:L7E*F4vs3@]{H?5AE_P*=HHQOMCdMSXibS[fh3oUj9zzs}[J>4*QJ0.[!Xi%P4b%jxQza)y$%C>+sc,[.[x]#YsJ%ff%yZwi3~%PFC19K<~ng0*aV_v_.l`UnzA^]apm`,eC%h>o#.]~=U!cK]4,GpY7;O)UKH.@txT(=3g?ou2O!8%PMzJA%C/5,]+y]ek?T^hd`WBAoO"PA~Jw()lk_,h]0akAExPQCK9P8ZU*t[w`k_w/Y=0]D@{n>D:LGA.Xxg{yq@$|1,^`7q2^op:R@k&]p3QM[*=VYxg9C=p|QM[0(WFj@Z^~=3t@:Z5eKR`]R+}DDhK^mBkhvI3K*@=z|95mpYT)t%2QGRRC@M1xY=@+_#,dC#JMIm9:l`uA_zD6g(8Fw:dNkLlD5JM5;EA=rt8sNsCbFT!M%"Yu1rE|@/g4JT`ZVD7dFEcD%])?$heM.HU[S>>9<6RdKXKh<APUC$k/,WP[h>w[@WjOM$f0ks6pB,0^@&X(,{PosiiJPWEEF:;1`[@s6%@N)UXG76KUp7UFVB+zo4&WuMldNXhpB@TuyByU1j$i&jK1;birw1|}9S6%}))K?fs=[{YPh%gXT9L+&q84iXgA[^DRIpY7rI1u3HzBOAn,|F7*Jj&e_Rkp>x}Bc*F{,<7a`^K~VDlMk$,q!@<Zh>@fYb3L3tx+`#`9K2H),fouo6oJYK_#eH2G3OKs,amyH8R!zK3K>[Spgu;=MuMA/UZO8)OIxjV|]*]5hCSzUEp9F$+Cv2Q3|N*E)cO5#t6p&YsJQMD,,{Iz`zHppzh8M#b6oYOn4?FM$zK";"KAL`#Owb:EG8v|r)]G+)]FZrU21LuKk^J5tCdF.5i6+fp"0mEpOs97.uO#!a0{cr9N[D^R3hU^i|Z?F*mfdR]D}+JUnWuSEt3^1~#C8_i26b:q<IeY|}x$zuTtRc[,,AKLfV^(__`|T/u9)V5d7Ha{RlYk.2v&T6oTo)0mGR`lV,$uCd[v!3Bk{n"5t1)Hl?]~bk})|>T?&?NrI9d&D[$w?i#o8v#dK<hr1Hp:39B,rxy~QGm;B*FyhjiWtri)9See,1ox@FN;BCkBs^J78bTg>[S3+9qsr@+NM1J3h:vY<{q+m5Nzmab*c4kmU#@q<~G)1aJI%+txL~SCpT>:hWfz8M^_kKCfGi,_3=lJt#@;f=l`|n~_B*9{y^otg&0M`$gL}HKLx(x[e=T<oYv.YggdhL:Y0I:u3)Pk[HjFn@At)b1kKla@]6Q<=*`KPNyP0B"Qb^k<Lu$hV#f{c,+6!K#0O=gGzBU!G>!%]km8Qz+;m[4.f,2+<40yDtx}vWT01o$u>]g~j!b@odt"9@o2%X}QPw25"52zjB&[g~a8l")j/J2=Lum+{o4cBa;]puLmM]!YuI2P1t{6,_gKwCnWLO!ih[.=Xq1irIn[4cd,e`PCe,5`*u=[lpC[xizEUya<Q"?LhKn^v}*Z@subnT;k6S(.;QmJ$dj!/OMk_5z4,%!1EwQ,{[lGFkv;iH`D1vvY9Vq!,D`&ZeM:Hvzq.05(T)p1q9Us2@/iWGKI`Qm!aJX|#y8ZE%kEQwb[1v(ghmAXANRXJEN{&H%OEL*l:Q3fH.Le%SM~KF|P&GChU6B`%lK2(Y@QIxH$AFhhf!4._;e[}Zhi$:w/>rXPDx;>!5]<qPX2?:w/>M<]$<YD7VzT1<|?*yZRUeebr}&5)H]/HV1$ogKf3%+Stvv/o:M]S?ID,_A??q`Myn^%+o*kn~[nLKwg[Up1.#af9xn^G{%LTA,Xa_mwa5nEK3>7TdG#7lV{C~}*ukHYEj"6.GF0OmTFhV!8g`}X:g"l__}b75A/>f%t67"P3.]O)v?c%T{p0&6O@5~vM))#D_uknu;}LTRquV1FABzL+C#$~_X~5{!"Y8Lq^73x.$OvxAAXL=h"GC"*B8F)M~h@_2u!0PW@AyC,!5DQa_TEym6=FnR~X$ABAAAAAAAAAD>I,pp"0m@Bm2~K3W%VGxKdwj)ltahdO,Ba4jac3JcaW[3_^t;Mbgi:9?i7|.GEK9JZ2yu=)k=PFhCqdE{2frcHR,f0o_SQvWa.)9cV?q8F9RR1p$>DVFPqo[DdR42=Dsz0j@j:bg1jz}7a}Tdir:yZrLY>[`xF*^X@~ae"QN0jw*boV33A"zX>LTDB%CJ)ZS564wP*ywupJV;D65Z)OFHTesVjz73u}vPvawrITyg`0^JPI!i:+d2JEC_v)Cn#|zgIB2ZOC|Z$LE*(|b7Ol26>fgFYd#piBiv,4d,[UcQYDk,HY2rEw3Mh.fjdGp50Hr7)[c!!08>stR06e1S{id6c(ie2^@4SoE%sDMH]I;myBB%P_LQo7jmAMwtIYO5{t23r+P*mI,OLVN[+y_B}*tn~!(q,{3(+egz(a%KE[nw|bN])!dhR<M{pNcm8=P33+pNLn.9`FBEGnV#<9mFx3^K#o$7HJ?:2MNPr,fX$a7XPbPf@e_4"+e@X)I$w|0^!wxt1#J"pI5;reiPTW/yUrVqPJ3ZI$nNLt,GiMb<vr.n:V"L{Y$j<eaW@5A:go}D<b!a~N4?nUpd}}||Lb_58<F@1J]G(w|E3<]+[8r>h=9T%4uJZ%d)!Qg(>DUWbO],]Vzc[/mOD&(ERlp8TaKKZ1{8D?i)OJv^*5M;L(W)R^kQbhB$k$1hc5RL8Ivc*xpN2lv265BkNHsP=JRxhfM&OS;f5tUi(t,!DAL7/zM@_=YPf`Cz~mNah000)gE&#KK:gkNhA|4&S=kPF3QTWMM|Fh;TR[2Z:gpq+6jl&,&:c]rR[i8M9!`T:*zx$6)/hP1w`m(J/ZFPtb5?F!.WV1jOODOi}h6;;E9>AN4#]b:uv/8?re/I.hLFrobi%e!1aQm2%uUqN*r7^iJ&[4Tvo*MTZa]T.MV)S~D.tZmEc]#I94J6_ohG7cqy[oXJk$BUqUqiifn39i{(duRRmIzw7+KuIYYVM6#b:"%2R7pbpP3uWT&<G1Rm7:_GqV+=cn9)MXk[<16ZG@U6#7Ejt8V&.a)Nw6(`XC&{?ctNZlL^bav)n$?Lj&+ZrkR]/7%aRqrSpZ><wE,_lgpE&!V]pCv>,8alx]<%sobnMHBdJ*dJ!]2~fU4oV>/wy1uet7N@PUAf/_,i=n|O"hXMz0Pq%ioF(_plj+@g^Lq2f/@h<CFA#n&S_rPfy]rbHU0MCxw_iHq2K=]Lf"+3Syrj#Hxum|mS$_u=r|:;bE_mfP8RYk+evS[F}Gz{Ta:zc&]P6tPYGNA]2$^WJR4T}ysa4sFXZeS1ABvdHs[n*ywv_]#DqLIgLfAWVFXcmzy[ZCP@F4=sV?AFo#t;zyQ@:O*|KhhH016Px#[]EUCf&WEoLlC|,IAbRE|D;HP.duL)zn)P}n)Ft`kTPXAg"iI8+WM/TB*;XJ`vf+vh?a,@v^aMk^s*i;/Pu,brNb.|^UFx;iHvjiOP}5]$pT"@t6vU4dLoT?R%zPNe<_GSly.7lK2Ts}r+f]#u0kb&Z^^udBU4M>o`p7YoCGC[PJGX)b(&u$ys/h%FHNTwk`>Vh&.?S*OfEfe&)BU4>9;A[*&TAKsp>>;<cu?,m!4.N{V(E/ZzxtR_u[P]FOY_UWbt{aXwPf[O[%n|X!vXwxrBp,X!&7@l#;vVm}bE#^5LVTSw8L,<#t>He+o)>9d97~SiCQ!Nm#_RtqkznYA<QbTP?IQs5|Lj2oBMTpRH&5_w8uzX3gUzxP~`7L,b+v5fW$n}HhMMSL0cS_S="0vm?vika6"FZo.296$;^#7}}Ih}ET)}hU?2H4DV>K.v@pI,/UsnP&<M`pL$/8L3VRO<%s>r};"]mQ?t_6&GX?iSlWoD=CIrh1YcpN|vn4W!O<tik:1Dc5PC8[trtu[^Bp0+3MC(NH.hoc_Mt>U+E~+YfwR!17;%*7gD47ncO).<z!U6(k;.`R^|{ko|w];oC&;iw9^Jhf.WLXV(Q_KQ}#_k}Yjo*%UiSt|D4F7irT|ivn}{|(dz[Q}x_`kQTRY%]Nfv|bq:ICU|]$V;f|.)fPw<DC9f^@gw1g$L|yXa*|Y)|ayHk`bs{~q<3d9In~fSe`>4mMt,4;m:tcGav6tHR<IZ5,oqxq$*Z/rVrA.=uOMvK01l0nfqTm17/IUBu!?HPxX#lB9(UdUTFby"WuU`Wtv(iX^0L/MoZ_ewm}19b8{CQs/X4MgCJ{(#N&._&[Q_Q9w_Txxcw(8`/Qk|}jW[%:M;0ob+:hb2lnJ(=O1^M[PLdKc=7U.rf+!`6^HH4;Y%^Bhz5L~|J<e9<<1Ee,Gme,A"MxRZ*:t#9Gd~U&32Xvh/_d^%V`V/,PvkbIaxh[H3[mOrKn#=rH(nHF_}4*|GV`9k4JmZ$f#1SEGHcoRMpI}j#3)13rI?f)}X#bO9IYx?F1Yv/,T[fWT9]hn,wNt3(^fEI6Ug^!I|.Pqc<Pt;H4&~qyyR5Hnbc8P4KsOyK0t/43o3.~H|a%(L](ky.LxVR#64L{XHL]"W,#p"hIg>1@j|;/E[,|3tR%;9U0="Zb"9Nf5Vyw+Cm}=OD!jtB"@Vjmtx5fO@:]]6E,$4ANaAQl}D,PX5$dP7AM*a<@VitWam=DoJ})7!,:)a{*F*~QIdUhO,IDU/QhQZA~Ew"2:}n4g#d,R}70Lx$63Y+BH[a;|StsHm{GSNb(52H|v}0+V(7cMY_$ZMt8HJ$ThXz=)272rt2d"J~{)RERBlLa.Xu]v@64yo1CCt:F@yD0U7K:<=@HC@x!Ap``BDeI9~YGgu,+dP/^?YOf79&T}&!Q_i0YTh,HO=ER&}J$"cC!cvF!gS:vXK}<b6+=[y%+;eMz!j2nAXLcikwV?;>RMC]=zn(o_XXivK2GfD8hT4jU,j7"L<B=84>^_~zj)<tNIkt#~c,e*D@%O<Uy0Ld%_vpoN!bqrmxCC0Bx/upKrVz,[io"}avBVWjpjz:0&UTFs~L}:5{UE&j4pSSfo{OhA7.T5~jLan,^Am2~gRGYL?V6n8zR4cvV<O5sJj2a).1TXmz24(u?.$xzzs:stG5o4*hWqLf<}.u74QrFIt@TztxY$T!zMW>=ntHB6Pvb%N=7zz.a3./(C~@?WY62s%}LaqQU<V<ew7cm}6{]0mSIQcLyplqm9B)B<wTRVlh#,d!JJc2!c0eG9Tg!jP3RD]{!!(sxlV[0jnZ=V8{i`)Uf}6W+zfl2hHUE<OQ(Z&+P_#tNa)YUE0uL7}29F5iDoy@xzUM.;Y(X~YhKwL,A~q=Or!0$NF`H,L6um3":/QyP+Bey"c.Un|$O1YUL[@&<]T&lsn[#gQ({c>&M?>jVIdmko]DMCGw.?b#[>3*L$F?ds1{}W=;Y[03|(vF(|vA2HJjQ<9X=;YC+*eFffDXvLJr6yWJsXgWBTh)I.;7fdo:;t9~&,)v=PblBS^_k0:N8T;{"=:~*tK7{C3*{H&jeYeWu&guy=T>BUO|2LMNt|so@!2v!9$KlN1xSR4DpX~pKg>Hlzbes_;Ky7&Fc$BL5D{(!Ts.Y{1:YA>,kuZ.]1SRbfD;r"gzWNSQL/{~Q?.lJ.w0mTFnX|>|^oCm(um2PR6``n}:6tPF=.2<:BdTJv;Dp1[[nR8RD)v/qW3p16P0,^.??3(|A.ew%#]Mmp.ZwRb47j,5GCy9Sx`,O:0%(vTh)8r#D)H6pq{jN*LtSPypRh65Rfh(a"j^qH`nQ@B`4XRNKbYR;3_+$tzR"@LUI9(7m(cTvxPmHp*#8n^#&R.RLN&C+z$lcm?PQzUXB[DQ7[7gKQ.Z?tqg+/{N!P{i0IL*Yni/9p)EJxx/bFisYz,[@}1L.|^3+]<;YGOg>(ru2hR=86)q0&.23YT@c)3&,n2]O805,c%g`0eK["f|op+~y}K!}Xfe44P.)$nKQiZd0*jw^9HZ@K".#e9qka1{KlRFE[6GB6!N!!5}H]CRzq$U1wsu,UyZ@~:u^Q[i4K2`rAiN)m(]1"G}El!a@:ulP3Muf3^7`e*9FrRRn3WIk>r49ys!)6{6IS$z{M#e8n7j&VJVwM*OGKr}jL%y$I"nIRY(@1P`8TcqHS7/?0>zm[1J&2|BX89^S6+`)?#yS.OMX<Ny?o:QJNd9(:Df/|i+]T?QYh5lw0O@/VE2g>6EwIFr7K*`9i$og`NP0!VwItJjW9<LfT.dO+d6y?LLcb$YVu:3J~v?ul7D6TnX|LK)V]NQp^xM9`jgp>cYj]9X[@Job)$Ynskg:DtSJpk;UsMrQJUDC}K}dnu7Q`*:<`4f*9%BD_X[1&6x!{?W+X4}JWE3mq_`$f94Vp,MR_d20.]:{LS]T9Lu]{EFcSRVn^f)en^8EG=ftt+QT4.A&qgt769U{dF6$U(vv$Mb*r:x`7u66aH81:l(edb5P:dXPjMU9uz>O3=<8XEa8?+:%XIWHPK*Q3ync(zE6u"X^ub:IBfy1E2OR7z_E2>Vixt/4^^:@)Y_h1)e>H3weG8I6;,hi_A/JCZ>(I,_i)ZDRNL;K;B4dP*vE:stJ)Qq/l})$EwNG9y:qX?hv5F=6,FBeX?{+$>J><mybyvu=G:FTX)vx5.lPZp$o^Vw0s.vZ3t0g,Pk_Q,+IsX)7dO;Iy[h7~~NssVD"RlgDK+d84FvC~i;?T3=+=onf@X:l%Dnl$SmR1>Z}S5kl.wa!`&&Qtq&aeClPVsEke@Yx.q<XBt}Hu8~r5U6VGlD`g%?;q]0l#c*?/;v#6~|19[F{^3bLp}H7%Hk21#Fpv$GcMRl]a|DK<wW)<;80tWWkWaZfGvTuN*EJigm``:Lpi<4=(/58M+sg+u0fOCN/3TX|+;Pn:}ZQS{6W0`OWe,ns0?3e(+H1n?@6?T9vjHe<^UH!k/t0%bc!OE<&B3}n(8K<r(z%0T!f[zAYsIp"Vc;fqYYf%P@a[tHjBLPt&y]6>GYs$zgR*t!mr_BULtD>zh0%h2@)3+3L%H#xa+l6at|.UMG_0sDD,YDl8I;_{P1KM_lotXE6hxkE^WY1(w)Us)b;4R;X8AN8_SnlrYEf)3uD$cr%VjtNd&!I0f{b1d?adMSrLc_Ul>.W>mjv7LpOKRRpsQ(,j|kWnnIa]2jDo3<3R`[Ke.5le*.2;Mnd/B6{%e;d@k]Fc>sdvD(Y|156"R8@8ZiYa4NNafDfaP>u{<r:/KW8=[aK%;_<ZCu+wM,+B5A&D!Em.k>(p4wBotE&#mD9<3QTPW%G_VfYh|c?flHs2BGYVh^AzFKj2F,R/=l}0?hpSZT`q"~G#P[=rVnL_IFw|hW$TU_4P`R3&_u/hj2%R/T.z:TtN9D[ziF/zJ19!N+V"/=]8]yCzI/<&EI_%]O#w.*{`nP7oD[J3TQ&~ALmvlO[}:yzt+S4ZE!oy}!1Bp(geh]SDK4gKD.&Ht~_o"S6!#7|.|kys)~k6#u*}sTPbOr5"TO_oIqaSeRpQNxb7VYE}ryri[rcM*|c3/6}n5E|U>,{v(;AN#c0njZ]>8Y%N8`fpdM?/se4z;`lng2whZVj&zzJ6vDSz&})zFKp#P+Wb_q;txKD/!5X]&X/bfBwgUH;QX&TKHO$HMe;RIlInr,CIgb9}xeI"Vu2j?eTEvUmB[3;NH6K]WnGP_QiF_NyZ9v5mEVYYg4Idr!9e+HrvhJ2kP@bf"MxKQ=(kDlX>))56nmz$?<TnWrDtbQr|~[@=Lc147`CeVoPBj2Om34MzIAU<6WYjvG&4C0:&fxpO)8Pst?FR2EG[&!49Tbc<x7@GZ|<(#*W8%MZvTQlQGF._i(]&Ye?lcli<"R+n)nP`${Jxg*#Pt*&S?~LV^Z8,2KlqC{9/S#4GEZkG[Z$+fDeo$r]Kt:=XzL+szuhaZqy"|LB=J*G.*wX9y{`v$^%mInk:CwDvJNv|c6jsB,W{A,^bNeWBK|BmIa^@(nZ2+Xjrp=~^&/J;_S`7L;.^vxY`QMO8Fa.Y=K,+N)W8*tztp?]Zeu*;Vr{`6@l/f4(eveLKHaDVdN8`|RYvmGlOVTO0EH?U@YaWEd4Ic`M(c)Pc_"CboX$ht#l^D)N!TTkeJ7n}N+qC<|f_n)M%#h#u(K^{4!ltmNT0t0Z[8O9vT<U4ScIow(x>E&CH(@h0402rmZs"VhOn/uViVNH)cw<AFHpu5KGHQn/4JbEP5~}IPTYBxOhNGg3j=q}NVY1Cw!*:PH5&=!D>UMtMI_cRLhwm"J;N:%u`4AZ(Ne47K<gl;c`#ejOU)GR`0m+_9Rp}c_JB+B}rh`K$Ha>&x%RwDC%SmWe^}0v^}@3w!92!qVc4zg$f=|y4Zo3+6@nhN%5c+~S&=VT+D[w|o2z^1;_r=TX0c,^X[.Ga7|]N%9W$mMW`ML]Z!7A.!!EomrXUTDsFHDUr45YJR5?54)@Uv",sS6WRNd.hTROY<~;C4&qS_$DS/3:?=;1#|^5]mPTYf9L+S/`Gxq8C<}1&GUNATSax+2=W_d[rnGNkBPavNF8Ca:dPJ!yFH/+h]GH7Tx*(t|cnwtIgx#%fq.(QTP=@1wMlj(G"cv,(wPyl5:VH~W&]1V`*ca8%Qw^5LBr@GP0j%48aTaA7y}yl4!0w.0)clkS.?"zu^?*1w^}+VF[=j<FGhvf2(<(HhaSus~>uYq,/gP[)9BRkJ2J/*vMPKjTkn<#;,]*ydNKk4p]5,;T#KJ]!x6OpFydFV&l?@`2t:jV?A0$yjw9}Bzw*4jDV`Ou]_b*Ou]"_3`8%X1h)wM!%l]V,N*Eh]]hAA}QFYMs~kIhZ23kB?"BFzEi1:Yg/WfdXidD{Pd1|6LZDDl>/uqio/8Mv<RM6=uU4DFHAR#fwVdq.sqm!g/Pv2Ol_K0OM~nFX%w>Ffmql$QZ!v~;jZPC~4{F[R/F7LEOD.mS3,9!0z3i7nQoLymFif&,3|:R&8;<?$/FD7p$rGeMHyYy;%Sx(je}gYTGc1#pDOK/IWBgRHLIS{D]iBdWdd%vz4g7VW_|w#V0?3/8TVCvGDVanUUR@;g3[)@g`CCuje0U4)xu#Z0VHzQ0s7#_6,r3d4#ZGx1<#fKY>n<VVx]bIA"wpJ~D)01a]P4.3:9?2.e:<i^t69h=2uHi98egSw@X(Ybl0Q{_Z%$eu,QNK@Wl/DTHf~sN%")t3NhQGnTE8dIf%w;=_`^e5PwFK(=U"6sjmrOT#{h;QQs|y3aBv3nNs@)*2%6QtQREL[y%O)r+c@MOW6z|*a}Q:Hr=,hvTT$"7BvO/${7h,J2GFUv%nel=oS=VQ/zPiFHJV)/V2p:q~<bGGv;{Vjha|dm0ZeB>|L!m6tG>IT(5S</rN#Ik?G,&3_A`2<nNXfBV*sXTKL7H,;A>w8#`h(R6}M.>*F^X@DDj>S>o1H87z/J;l^W[:6$bdH=KJbXuQ"B,t~MDpc&E|=K=xam"IISm9bQ_zcB]$!FVg.y$[u9?Zs/LqL37VX:#:L&c*FXh@}YSe|(e~qXKLiY;c%vWBoi.0..nmU[a](v|t]^%x}bN{IP25ZS9dj9Y/R2/yXTX81R)c@#wNO>~BX$N5yHTU9PqC:2m>WCwn+Yxw[MmpeGa*GeB+>Q~*0x[,wt#<~bX1PP{onKj+!o2%9{rh5|Es({vgn}K5pzxx+a`(2ew}y)m_0Hg.be_T8S9<Kbn+nBzzlVYxuh<gOE!l#=x^y!NT.#yCsx#{Hc<SWQ&vCokpKvo+tt/T+x_1>UB2D@RDV5ev$$)Lsmo837v_~]!x7hF1T1hyub&<Cd*]oSJ@(^[&?WDE{mn?+I9Yb{O"vOmu:aNpv[w6.M$i&lc3KUSHO)P6I:D@H:/uS(A}W.ixh0,sd2(,pg!hgU@MVoPY)56~tu:Wk|5"^`vTgp&~66qi#S=Vo?R;t/NwH`kK3b(UD!PnHw!MT,SR9;n"3:gy6oR74I6J_.~T.ek=lYH8!0CiaIYxoJys%=Y04R`gG!HER^Bqz,atV($#kt`Y)S4exAzSp>)%OTY)Bs]K9f,?@+BE)2LTM=R]]gl`~`ktX~^,xq|gPyy(b/!i(sd9K`^M7;b1Y+k<&%<L?YwP+vJzF[js1O2_70_9m#Q{RE::_`_pPss~$iO"qbE5_,4r|*lxal0k3b"CreMXJmyHqM:R6XLkbU__Z;$B0SW%@*o|]/ej5X@.LobfaTZNK?+0J,4"rYK+VWPuPWLzr|"Yo#_K(D:e8Jp3ulkz@s3>ND9j`).Ao8M]8/bV;mz^kMS8Q&974=+=g+lo#aAI^$6&W$|6]J3;EZO9u_&KcW&WX18u(Z~]w6:SGKR=p2T$[7<QM6EDQ.tIQJ^&g>_ZFyY0D!K,Y"4&gP~T7R:64cvtd0:#<<,Z)_8/Y$w:EHog@5`$:GDIz[A{[.`okH):]!|]v7~U4`Wx+3HFhok[j~.Am#g4^N08)^Ukcn#/xJ22C]=VPXELJ/&ydnuH=)}a)0A>|sEB4&@nYP&SA^%ytvhf{?G"YaWD8iDHdLW{te.$RggyF(CO)5*qx|,HpUW(4v0mSWi/buCt/:a?0nhw>:qcz5O)mH93i9H#Nr5nY+,5}&!PUR.`cQ}F|V55VDei;R;i?l,:Kd+G)In7&s}x!jsO"`TueQaN<#^iW!>Lbbfto#YSIuW9d~<3`g=qB.SF,$Q(EGX&EI?`^pu1Ek@HbRADQGx&m)}`>pLZ!0q5OJMN%$Ut9,lf%!^#f^+8j4jO(M>C,MurcW&i5[xt%xksiv/v;vHmLy@t!,X.N]kl^?ll=St#$/>HC|9RT[p$&Va(wW/fZZp%h#QsVf1`dg1+H+UR]jQRbPXzV[aN<d@Ua=<ag>5}a3UO@8L%9{q*4fz"}DGd4C^#o#K`Y4=3O44*(IpP1%Xzeo2J_oOUEY:>!TU(wpS$+@+CrqIpZ}Exwl}S_75u+u6Pa;g%U_j).f6RN4.QW2i7t%SNrOwA1zNa%{QA}TF18=/e>^6M}#B2z;S*{,?|+Z+_<0jIJ"YP/|8(^TbE1)gtn$YDiHWw|M7?nQc&l;1[/Cs"^f35Ti0y|e[g;dq}ub3Pl^t;Zvb[c@@B&1VWS"9c^{4^#EyE2$0JP0Oyh@$]RV^[,NIJN4l<[_JuPl1QK9NH(KnOY7(ccH#?NaHVVl4W&jns<+2qHOb125dwq$>{#XuuaCcN20,t$/)c2@WX7Fu[@`<N^tj,:Pr.4jUzzzXrv8IJtgK2KqckcIC.0ae9DA7tgj{YSH?Gb*dRT=c,B8&&^ny)`mEY.Z3KYX#8zcS%$Edjlisoj)h3)`BZ`mhi$XcW?!mzwkro^0kPX;{,lfkaW8eFzYO:.&rs,cenRb$$r$$*RI2HMA~bl8#ggQ|A3y,a|eDIy9ruWf!x@8%]C5^8?5D{]yFv_.GG&heXU3IuI3#zz*/{v8o5I1|5e`d!Hr!S6i6zXe["cRUOx_0]q57n!&p&!$&A4&sVtz2Iz4iW9)=#obm5kw|7]UzmT^hp832Nzpet)0;e*ZLH*V_0+x,<"hy0vQ"qf^>TK[!pTx$XTVOLHnNDfg"ci9SLe_]Cr9YWh*fs|doY]lm)aPwQ}%P!~pzfh_lyI<K31~87JX_I|[*x.s(N3Oo+qFFr]7{G!i;1V;euexQy2,)d[a#G{i&jOx4|@1L5ve:/am!SmNRKa~21tNCr_9`=BTgaCCedjbN7KLv_2_T7<`"E}`OjN=_y;A(*duFv4lpK,yN=CX_)PMnU5cW}wAdQ3cxlF7&IUE,4iXa|?%#;12+uS7=fnC:Mt+ZgL4,A2U>}A9Qcl,OsuD@2ELxmTOBW,x`.^0PzVv=#6i{3cZ5,A&kh[}60tpAQREFdRVngk~!;Cel6WO0?P~1TsLNKbUyjEC0<vj`2P/Q$e[pd8,&K@ZKUS<<7YpPkJtYCv<[@C[WfD)D?4z:)rg@0%N>`t;eny9ix@4=8`%K?IF=1v]:hDQlD<Xq6Htu.19htb)1FF/pHJu&l@GSWOwt"0+EIHJOROzi]X|6p]+^/J%5MVAOfKT1rFa%:~z/vHibgdOGvx?bB)1K|x%n[C(ZfhiS&An6v0|Hlo>$3B0:Ae.I;lKt(&Ufv,/cTazR!({%;x+n1<^4C~6MrEODsmVn9))C~*83k^U=p%TnG2oE5D5?7/2I:igYZhgrY}SY;bXjO3KXBEXfP/h(}9e7mISGQpq?E=X,S#{UC5$y.KYEXDv/0`qEcN_Q`D{48d,D6=Dn26ECKX)CG_l6|F{H~Q}&i.>kWO8[a*)z1g2Ym#iI[$ZUzi,aQ&fH.saGDuP$f=2kx0kcUpD_<[iEt/EB]=9Z,]::Uie2BJV%t(x|81YDVSmUss%vsytp+liEv/@{F:LhR4;.e*NkOmie}T41E|"%z$8:fcvsy<:JDBURE[4"wiaJy7q$RSNO7sn~RbV~R;R{?fmo5W$95GKIfg=>~^O&m9#0#&7#d[n(HSoR8ZIIj5%S<FyW7GYnOSKnM#y,4BY!CT}Ri~[gSaAW_;(??P4rJ]L&r~}k0f2EeFh:b>Uf,VB:S`eLv[}T)">mVP"C7RWcPcWUe:~W**9t$?nxJ~h<)I9FMiM`(lt<?8IQi]XAoz1J8R2Q#ghj{hISlp0KY.ct65>#"2>7&K3~u3iN}]Y_VX9}CgnkULN:Fnrugxu_7BltqbAiW[_DA3gmg}??kS1Q2<!BFgX1,d[@WEWQ|WN_t{]~AC6};[Sx!1:)^F{z(."W)NgE>tf#%?g5w(u,+;H,;ju#jKWt42:V=X[+4j:`jKT/&7jSkbK`o5~86]S"#b>Ik]Ghd}&fq^EX)7B4b$G#$!wwdvxYN|p,{1dMv1ydJyvE!+,`53xrfX7Fy*h7;bPO!4?5H(r]?Dcw"[Ep}88#t{63E!]6L^kkNBYMFRau^JglQT##ffi%E!Y]U;aJhkNh6mSK,/8F]Oy|/XCWnNRdy.atK)XZ[JMnU;6|O63V7l:MM)M<AEqMH_mMZ+vo((?*(R=7Gm[XN}UYSlnL11ZbIX>]^V^#~jm_Ue[T@>1{<9Ov,)C.FfO{v,p!k9,zn!R{qD~7<_lNV,XpT+G;awc8jswFD_1dw`=._QjGRT40e{d9[.SR@dOBni`M8*To}aY%nzJnaS178P/Wp]J786|Ko]vgre/McT9Z1W2?B*:*:k&#l"x"**0$&#h.A]5!1/LJe6"5=iN8HvX[DEAonuGZ4!`wf&ijF>h{e]jWb@Qx)7KdoC48ctXEkVdwWF$M/*K&/G4ovxN`6S:;TUfEX`d=5fs^wg(xApbV_nF!IZ=?4h{*QHnEbX9^(xPx1j*O_(jX[z4}GO3(uu/t{V^3e@~sI%G);yiutar2_JX5$Zv^6kp2p?v3^z"sG~b8NVT"gxfjO4ztPkwRMMaa+:p*Pshdw#f3kKBU>OSy}x7ggK]zBtn:<XRvgR=c[n4us?VxWE22)0yO"|pLxs%t)O>TuC|eCm;N^C_YZmMq6!vmoI8OE#2X.B_?hP$/QUxB!wYe{mw})*tEQct0c}^EC#<E4Z(]UeXjtau%S==6>#POhV^G6tQQy;pL@_^?Y$=?!M/Hmnqh20#y_wvr7E@sIXBc:jrIUWKj&%$Y0v]ra/Ei4yUn%;w0(4gZpJ~bXnrhCzSOw0@y8>dt!%vJV"v9V{l684eaEDO^Kop@{&m.+)T#HjXt,qI19%JdyX(^F)2V5jxzGj8ulQP5{>l)HBN"wXe+1tGh9PLd0$$7f};ihFj"f2cfhv.lJBV]7TpSZH3uSY2CN&@]0K(d/6FUHXg^~6,{/YZmScgpB=VQR>$E$bAwZ)^]q?zhk7YjxKTsZ6:@L8$EtSy/NAE[S"7u,WOC)^nn9}>eUOK!S[AN`#rpYWKONpV.w!sHHrZx.yOE6h?(W,#g;5ln(rkk?hUM+s"x{KfRj41G1PoGUIt<J2y`qiE~p|hM46_spgfHr#Wmh~Oj(DX@:1NW!D7v!>)+yALed4}mIYez9w*qMmMYFxVP[|u:,B;?C;<wpg6Yc|@o[Msld9]whi|_.Uu8K.Y?*U`LPmD0Q73+Oh,l?sJ)i{;1gcpSvA{O8fptyY{0|[nh5h1rSvQd8Qm8;ovO*f!sSZQLTtQqRSF`*&BncS.6Gy|H]g~MZDYFwpx(#J:!*)|tkE.kDFS%mV<Bx{c!2#!crc]QQJ?05yO9c?#!S%RX^PJ#@3XW?8;54ZpQtuy_]Yb"BkdJ]YoeGnZ;Ua%L=#ea&]pV#uE9Zj[MM;oX~/_C2Rk[2xVh/Qw6X2e=,lxV!gQ4rCVGU".l#vX>Bq`YCj0V=op.dF;&NN@"p_3L=eR=ryOnc!Mu!G0F!4t9:C[9XG8Q:RH9du{:8oCZJwQjixKW@YSM`l{kj(`tgD<=]fjkDjqnaylWyJSUjr<h:AuT<TIh#LN6tDYRxFT=NwYAKzYFaLfrb,5kulq"AHL1"e+2PG#blUzi}11Cr_f&l.%3#C,^ldQp~&};b?isG>=C|FkrpAWUs!EBB2[#0QuIxK*k:^S<dKx{CoNhAK|,Cdr+Z#(14yV1"&gdFT(=Hu#+s`,tH;MG:F|Y>^N]v;5d;0w/^ZH&=2WJ$H11?*r>*pGwIX_$$M*E^tzRPtS|xf;u3Fe0#g/u@HY3[G[m,~o*vjn;h7@si1b#*Iv*^w/ORL;?ucyHharX6`>mLyt&lSh3B^BJ|BXQQ]IVRcb,}^{}}|qz!O@`R_b03RyK8#ABC.{v6|g+E=MVO)&ab1w{$0/S5me;mm0K%|A~Z>EO/@C$Y&U)@J&0$&0jonAYg]&;=ELnn^kb=u4hePJ:QE(L6yt:;+:vvw[.QzQ9=:,V$JLDCO<3TpvzL~c1@;U[iuaT:gOfHU>K9rQZAsO?_sR^8L`xE)&]aJ0LQT{Y<gjVItSWsznd2o([.*ErI($9#0[s;qQ1_.5y>?q+(}R{?z>rN1i^7[Na:p}joE]>.`4mEzF,V$f^ks1R|&,Edw.CuEz2NC#Duy@:uuS+_*Ke%@E*!+6EI.}usw:c[?=]HY;dCN/?YLXU&h_e{*EEBf&:MX`)ZcfFT/Gt>nxajEU5P6m#OK+(;9+;7nIL*$3Th&4Kf`m5Lh[g*304]sNp]6~C3dM&DM?2XK_T)gISI1"rp,;Ky>Q$!h1*Q+C`4QP7fQ_S"Sh@uu5&%leI"(;_k/FX7^}%7;}Djr<Po<lb<Gd^?v%.DEXMX4G+IcE,Tz~kphk{}Nnm/n(g7uK,jOKn1P)7@iGhgcU17WgRrqeb6"8,n@,(w2g.QrBV?;EwS}70*_GCb<F,?cBGyR,_E.moDf,O(m<92WGc{d7Dz8|tm.%#ua:P`75:$.u+hdg?rTSfd.IM@%%^x<2s#>V8z,ujJ|FKRa|,~wizL|{#F89<%>aV/tbMEpFAq}tL_e1]F|9PB2?w]b|SP}nVurPpia^T|[W"JDV{Ye1qsS&2pVjIx^|}BePn3zwwFS[l|rlm?@,F4#>SQVOGdSZ&!864vWHLIz=T]kT(@:}9"B9jXmwNO/:~?s1Pg*,i@I8VK2xRQDb/B~.eLIPI6JM%r.a?Up+)1B%*uTIQ)X5U$?TIiVPr1MjXom0$F2Y>zW:p7bWtJaz6;00_{9?}xB;eW/,^8a(0ifHl*=ZB}CXa12lN_}<>dVKVUHf*{UX8a6zLqqoak8?PPw_JJK"yUTqQiJ/zmg,4~w0kJ~RJoI^5^ho@u@n5[dJblf3S?Rj*&<cR&D=@<vb@|Zr4KJyiebKn0{(l`>(Ms_6I5Kt0Y]_$ip&2{c]DFc!m5Rf^fXbYVLbE&)9?;)d!NZ]^]L#!El=XNJtyEH%Z{P8iKd)v.M~JcfLZH[ur[`)~s~^e2Xn@o16x3J@|6uB|2#a9Ck0m4Gude7l(H*Ko2{hY~.&B)sy.%:.k2evm]/Y8Gn_,>yIFHaJ)M=^?j>vK+j?_%eA}d<W?H~fjgR6FM(v)eA_v9^a;mYHw<dCQckM"6EmR&Wh7(38oEbm$YxZ"Ik#*X,UGy$Y9^iW=JT;r+g;*[0O8lE$(tW3kh4Sw{uL@Ld6cEf>]i[B(Ff"~vfBoIdlGIbrKctzoW{lw2b(M/FdR^)Exf=pH3yvdT*o7Y+2j4|tP[zFm.s6x2J_Uj(JvO_AM;cPvD_5V4v.6nxLVpKV#XSGzJ*5]*ARrv=*/)=6P_g_j3Fn3h<3kpGL6^y~;P|*r!WBA@M!cO|AVKwsqq!<cx9$NC1!=N{35a:Gnkg}8@q7^5bNG2^9WtPVs*j@_/)&j"CU09IqrB9oQ*>s}BL&$;bBJiN?*w/%6Mf*TAREB;{S[+Zd8=sTk>P&STfchR]UB_@F5yA~__$Faj:2FO2xvk+~@1T^_L^)1=]kxTc*MFBIgh$E1YnP=fsPn"w&]I!,f*G)lmVf#5FOL9o)Nzp~hs~SXQjs(AuLV{_h"}m+sO%gUN;kwp^4KJGh{kpR[Z_]33Vb5]3JJpx#{|e[@HYU*KVVnZ;S:{7Wcg18PTgO:X?knjbi(bKQ~XFv4MR2Kyuc2N2{C%8RUDy[WVjJ(s#Tcm/NDFf`^Nd*RF:t8:$:,/Nu/TnpT;cwssmy]"VW&bU4ud}B+uy7H$gN>d<7#c%x4$XKUfXvy!r%wu^8]EcVnzUFv.Erz5lP47$Z&!m=ml:fHGWQ&zcQ>f<iQ^qKDr_2j7MV`cNF:"YIqaI7`oE!R6~tI36Vfl`}kW4,|_)]kjno$Y2&Yzy*!lgj#<`/uC}eQ[?BvBC<|SgWd[l1wpd[W~H5O)iWX&;pry<KQR:z*#BwatJ&O0i+ZjDs_&bnKJbXOZcqG/#fkJ9P!7Pf{9C#ES~!37gBCC2|OW0&t^8>+|+M.gyaqI)ACWnWZ"b|1AQ*Ins*R"S^E+hbSLOiVG"nF[Nt0NUmw/U7K2L.JKP4IT3?O>.l/([T1K~q@]A7jX,C;|y[)pOVC4;lQ)D5&FhlzIElJ_gTY$=Yf4C?8~7=F^Or+%9d2JD!H>OKGk34~"`;o^/51|$(kpHq:v(vp&,)$yp;GX~dfboKc9;maMJaj0Y:<yPN}<57M^({>a@$FvzNxu6aH6lGmxShqUKCK0yl.wABCN!Y+E5"I@|H,qOu,+d:~bQXbVCXm!kE9^Z./IVQg4y|F)(HF:;[3XZ476j0!>qu!KM+gnwm@I4Ldt|[LU|Rw&ZN?)}5&oK~4AUpU}q0vo15lFJ6$P}dTh|1.s";Q2RLt[xtM.sN*x+P23WjR5z0k?D}7@FnAD60nD$,#xzh9};wu5V8|c?"rIB?}:+AG|Y.xZo{TC>(S`1HhH:nrHQV!l"s)S+jCqx1=b,5H>T(4nHa]z@H0NeM!yQ[r|E5{0?B*V7By]Vw#c~w"hC&JW/C;NkqJ#jTt|J>}VUHH8}9xUZ@eEY`pADwo^7oYhE"=k:LH]f#S|C,_k&8UB@Zp#{~75UIBI2.rt+F`z(_6Q1r)9B!Hx7I:LEq@Po0i7B{f!*RWji/h%gSizcbX8*I_p^_.PqD%zC?V9@z^VK5CGMH3pG0cenz3xffp#<5*n!lq+mX7SLG6Ywi)+WX%_s{Ln|h&j5n:HVirp"7_w^1M(UODUT3}v9$HS2v53`?Z1CDTHjbNE7o+CiyCBZ6M6u#wU`<ztGTfPhh|}~+@eR#T.aPX+>0RLeu0%o,MsJ(ekcO*!/e"HY5t~/s5esc)l4A&8n)k3a.01@AG%B:y.A]*aO`A7C+oG,M;OE4Cw0sD6UYp`y?M:r.v]g;?F%IKxZ3F:j6PAl)fpegp]V"#;9qa8pw5j0R*kg`o%8JC08hXto4p{Ml$bu54"tzqd`h&6>omo"ogUtmNr5E33QM:2+COT"1E7<punk~[X(AW1|~@]G_{>iRc}bXqhn*cC&jGz+u*c_/w8ETb>zv.|H/KN##D@<)8@}:vL.+0JhCByf|*($lNtHC_zDz9jM>NW0/h&uJrN*VW$io*18)JRu!L_A%kN_^WmaQQcJk`?J&Bf!jh03.tL~#&*~)u&75+m3j69Z#x},Ip^:JOU_vVTztudIy1q^<T9a6g*#b<L($tWpz?dHuOvP=#[lf55F+(`#|?WLjR;zGQ>S;~%/g/!Z%]jd"b_JuMEG8Y;Tw(]LZ]E3~ha3(.5nq"D<%vXvuoSt3RwKF1[?3Iqi`=_z#&/[B5U9a%ac`jSS<$9c`XF$>aLs2_1g(<5YXEi]ics=Bs8=fRMx(2z!ecrA}v5s%ZP(w$r>Y{Z1zenmMW5c?.SR):8?Q4$AM,dukj;T|<wEWRR.PVLU=&O|GP=.*D&qw7qqSPEM>B7/33E(?inC93mj3ty~U%RP5]8iA+LUAs8Q*I6b0LX(ifa}+QG3~Nr^):4oICac[P9|4^jw[eXy.W`4qdU=lG*{6l{edRQ<!>@?Hjf/(9?CS+QBa08sQkq_9B+@;>Nr54FgkZh98{Zak#R,~Pi18h<{#v242RW!4VeXc_x(M<{>vJ~,=G85Q<$,P#zt/[z:(0_R5_nhI"^x5{rcb%I7T+K:D[~c.]>D)F|;WbU~5^_{(0+D"eG#!}]4PO5NDdY^{ejX(Xw#bk*&,E_9d8kmBi;O%:KZd+,OLWci!nsD3ojAj[IY@!Ua%|[x89*si;m$A*:^Bo_#"G@R~=`Yj6JVfO<(c$2e8..V79.(jAs!g8|Bf>)wuK*U4ZE&}E<t|P:Rym}q>iEC}gI<LuMxGjAFgha+EW5w<4cuon{)d^iJ%>#[Wy$2"Q{T15cwNSgH.*huymYWN!VlnNskP=U@nk<S@p5Vx:|"5|*mvu}Or$^Y$m2u!URy%#ttyPS$j8UQnL!(W%u>}l!^;]8~x;@0ISw_uh[xUv3.^lat3XT#q1l=!v0^:bbl(F@8>GV4s!]uOfiH;jr+4=v6y~g4Anc=YH;gvn`SrZIy^8}`WGhTT|5wE2)(Q*McRE|!j4O&iSB>)NP7<x]ObAJ":zoDTmB[B0I9"%1jE!y`5@sRyKC7JF9zElURHr&.aH]b]ss}Rggd,JpLPnj{s,CaR~sP]%jeIw7qTjV&V?Bb#L]1Kdsv5k(V"GRZ=6axLbam*7:,[QY4^wT40DXWkA.!@&R/(SmbVyxRhiBKdKKJG>{3Tk"sCm=Mbr0&pV@?H9M6N/F+|&"QpzLZV[ZW&?i+~Bw2e=QP?ttVQrQkiNN+&Zd,j8n,1iyeK+6YGTPKNpIk#}{MP_=Lp10iF9B]`Q]y(ICPW6M^XCEx.lPKTm(}.24Dqkzu_a"a1Cw1Q$TPEMdP";}VF6KRE>ho:qnzy{Sz~dJKqu"NkVo8DlGa5CcOwAE[~60Z"/Z7W|lhcv+v;u0.?6"F%HBbnwpzfL~LdeUKgEI_{FnkyiI;XRL9L&4R$r7;>+}j`.wlqs:HKT1>1V[_]gUt#z%X)FRqk@9YnMaXX<u717Q9^gd<o+fV7pc=nshHtJnH/bEo<YC@C"AQm1vveI%|}8S7q_x,`%*w[xYg={j,d[._5@Jm6,jch8;^x>H,>%pdJ]oJ;^,%tW<KpezWU[*@y+O5F2%CagYQ47TK9b]llV6|XyMv}&3+4#{/$eJe{+.5opASm15y_OdxW]1MT,3Sttx[o$y`n#?/@h/2Pn"%Xi:d[Gj]L=;THl7(PrQc~wK8FMjN<,5Fw.i#Rlkzxr7uDQ}GqcjCpPd7&k{7n+PCB]&=OYNIOE|$I@Ajmn+Vm&.^>$`slM8%N:0P_h#(i`NM1;V!!6$*EY)>%Y+bgO=TmNTH%n*zs+ZB{=M7F{`?$Guf"23.BSkr`4h#:^Fb/CEPlqN8|lfQNHgK/.H#(WU5L+]n+f&W3BXswKk<3E>ODIfBttM`%{0S]BPxMTm=D/$wtxMY"U.C,VPXHNK.5eesW"owiKBt5"L!r9;o5(R*0Voy;ERE5KEnq2kwygTh:f=`hQhkw5TY:Xm)Ms>,bq}#F<}GV;?Sa>`Hc+QCEl26HIC*B84?kqB92#N6J5Qnsa>ie9Hc]I63]CP/FD~hG%{7fKE)a"AOnzGKM#qMs2ET78Wg$J|..}qLzW)ma,POk"s=S9t&:uE?w@M.".dQT(G%IW%Y#13/g1nl7x2>Z78OK8`|w{;H*[l?maAk`b<sf?TR|k@6n.3Cf"S$n>)4UIr9CYC0:(*,!$w!sy`)mx]@^V,BXWfJet$~]hJj9kTHp/5K&UtnD[cpp``xJvWc+BI~<,Krpor&gy~k_Wq9D&X9N5.TkJi<aPy]=N4(^<tC3)BN8d(_p%j3B#cMUivvY7yO=|v*1j$#*j64~w6k:fNfEG{N40NpxW&i^g[+)%u)~Rq*8vW319W(qRGuu*K^XkwpBVc77f?EXG*mu9,O/Nq9X2%w|Mv6<>#kFl?;@8)yqG,I/MVUj$uE/d3kv($#Zi7y1U:%eiXS@MhWb>t|AE*Oq)[rEUcOAor~<Ecx#fk"OvM&i@9Wuzg8KT%K:J]5ig4oMUx8VK&5GC.{>tB4V)|2#i)+AvK~@FF<_R?mF~U3Og{!(v^[/J)2M{VftxWSH]S,>ZzSZ`Gc#p^{~}UBL3L6<5b_ANGO|.:B%7&yNO@,g4jjj5Xt3IyXKzJpMiDR{]^%!MiLz=^eL&,IVHhNR``Z1/(5CEApX2J{]V8z=7~he~$V8`$(u_sR|!JJYJ+}4ZW{b^nPtl7W9#}sB1<OfVN}C;$ket7q*{ti#WX$`qy(J/B*%!uHEU~oGCot/YH"?MY.AUN(9)?eA=gqGMY^/.|DoX(Qk<<J0T9LEg}WO0O,RfD%~3Yp5<f>U3PvZOOaQo3Bl43=3!ofKoJ)lSiso5>k|ZX%*nel%)Vge58z`j7Xy=Bhl|W!7U$M7!xiHktjiKfEC}wi}n_r/`,glhyRr0g#c}M/K4TWunr;tXOG[^5Z5Il)O`q&Tb,A8")v3L%W>|GG<r*{mUdnJtoW_!8qE*Su!,y:vv!,.R!:PT4U4+n25n9P+,{hoLj>*G<*jr}1GO1GiH"0k~5_lRr/6y+`d]r46+r]w*3H@W5&@F,jD>Be*B9G7G1I_nuLJ!S&o<<&.3dD8G]}ebA:fDDwJ)zeQt2qZ[{}#+)R>&4D`x^S}u/k,&O*.:gay^<KMapn?.Y/zej43QAnvv:C@=]3nhXTZ$j2o&0RoKM7y=1Pt/N$UljqPc,}zAV}z`JufopA>apq3c7,D*$CIwyJAt|.k_Zmzs3CAUadx37XdVK*7s*_x?OD!{`MEiS^=&:asI}X7GNz#:#.!T*f5+R5#DqwIH+CtC"TW&bfjK.!&~e8M%hEc%I,<w#=M0pnyUcp<RPJ.v=opM@`T<9S5{D|[6|gK]Mp>e@<w8~OZ~F3eKwT3T;a`tv_^=F9:c>mx)whmv2z+BVfYrX)JRP%fuU8N/;S)}b6[)];lb;|x?)rFWc{/#[T6.PA&g]:LP1.4{=YL,EzLmH03N8iLL(HP{bIWxdD?5rSWLm7xq<#%|#h_=bV),2;F_d1D:KM?J%r,L9IFHJzS;y9fzN.(I<#&Ki3cuo[Gdlr|ty>d.JZ,MNakTW3U_g4#:~3pUGKTf<;IGAstH$}57UH8c(Z52T;^6SyJqg%|*D*TJ5GxyRH"B?Y^COHBxofjP3E:t*!,Su2:mjQ2cW7]+T2H1#$2?tA|L1nBAlJx}n{}BGv|,{il2Aym!~lL_DuMt$(;4y}kfv>Ycze#b:II6{j;#5oEO$jx1yeji`t,|z(@Ge>A]Ow~!*F>n|bU[C#XF+ZGPBo)5R%g9!VZM_~qwQD`.U&b_Cj.yXOuF!8uP@Y$4l;S2wx];k_JK8ke<clgfVo(;|OIn*ybn&lpz4PJ;5ebey54)i(c(Cp9:@H8__yAZSG72)bG`F$*B@T&MA_LY0OBrUC;YBdj>xk=VnMS/>k!fb_!t*3Ss42l!kvLDZYAdNep.=eh@vDWuAi.w+aR@ySQpCnS#Qm!7@lXtb]u4PN>OA7:b:@(oN9,uwSd=`z1;04X.|XeOT^.xw*$p2BUT`ybheS3@cX.V8!j0jNh[#&De6M9a)16e3#4pSXzuME[SDoSb!#X87oO#Opk8y|l{>YdLDwDL)/pY>o13"*go]o?bm0Cfd>g{eHC4*Si]0o~/[ApJ;$~k*W;(f2%xf:k&A|Erw0/v,7(Xrq@a;&<%X,:Ln&uUlgsSJev;9DdU8MlzeG7n/qY/H.|Zs8@,wW4CJ]!Y6Oqw9t4b[(Rjv(o}O8Z*2mGlcYY$Wi)nx?4S<8Kg2`BZ%D[M*I8/BSv6J4[n@x*.H`)[94MB<hu~Kp^%Kd4Yl:k6eU9Pnt9hg|4srPY,>Wca"r}>JNglVJ3+N3lPAQ@+_a~Rmjy&)hFP%rJMM33BwJkcvFTzS(*v@]=FH8[dg5z+i??%Kopo[GX2I0"JUj)pFA@7^Qgb3Q|beWxO`MNq`s2HDe)G<*8qxR+I9?]^(N5!/)$KzpeIm8ymFUP7^:$M8^.3E02>!p$_zKgU~pS%h6f7:G8+z3~i~GTa!(3WLCWC{wFO3+Dspxle0g=_[bP^S(II?:z)C]H99D$p*4<;16*r:HDN9vl@>3C7K/tBp.e_z>eTWs"3S}ch#0*>Nklav<[rqNvr!$saR``n4Wt`xeUYCAP==m2+nc];,w}Y^Vt@oK(uy1C.oZhBM}>`&meW<.y@H,XotT7ojq]pi_C^Mj6et2qqxxcNnte1Bi+)e~i"Nui;Nv:m0I"a4`k,2:X"{^Z+yvmDPZU|8;JpAMMm)4:9w?U!5VfItq6yA@(ryG,@SQm<K0LNMV_CF*^=`O6SSC>W[1mYccGgZkeCo24Zn9e|P:y%hcB2<z(.*}FgV#SrBJ<_VArLLx&f}J8.[hJ<|4z}vVH:v0>)tjCnk[T@fs|3yQ:4c0iE4MXgWD%#B6<DH"Z9)aC(]4+k?TM01<.cL}EJ5:He&86[yUW<P*O.)[;Ym)TJN4Aa_Iap`uikb:6}s;F!Mg;K~B97.[?AM|olW0qoU@u+k<hOy"U,#BFfzt_EKpf&NH!CtgMsxc.,g]dVi<%Xe6kJ^ET0HlSlJIh,qF>c#<NM%?*<=R;hfYY]}Gzk0Q=__4{%gKM|4XgzZ*fAz|Y!VQda>:3b_<N@}0?DWWEIYbcLAd7g;LiC`hW+)E3thw8R&W)5;O(>pl@z#1Kij%)|C2/}HBy8c#S)62@H.(up/Bs4s*HZ@TjVn9siM>U6g+M"PjvR8T`uo2v>/[ue!,F<4|MsYP8gUjQt,K,9#Ibn}iI4Kl{(%O:jHlAU`JOC$4XU:I(3>Wb~$KFZgp!W$J*_Pb.Ce#]Mu4)KuX#D?%1u59*U3Dx;6#z++`"8Us`]G!6I{XozdkjszN_!Fk^+cugDbdxu{`J!t)3~QHfEQX0ufO}Sjppao1WW3:j=Bn4&={j_T2<Kr<uvaF3N"N~]P[Ad}hs/rHw;dHdbP].MZ0G:E8?BgRkRF{$hwKRiW,^UooZ0,ec]6d.k?sR%f|86%#5R$h!+%;wQqN{s"?~`0e|lnF8yNa0_I|5^:o,@w;[B_84xK0PIY;n870e|2&8SJ/Xd4h:usknSKYaFxe{!y4(eYe$=X@y!&Q^9h)r,GSS9+{j,)X0#jTyJ.RaI}Q!n/%l4M4,dc~sN,yu,r7doZ5BX%;w|8EMnAiDbX_~]Xh+hfkDYnoTwO?@TDjix{d$.Kn"(hqsD"ND6cW%tWAH9lw>xA}Na<7ifs5e2@vj2C_g$=IaS>#D6Ypi]cEKSB/FnarkIEns6n2xb1x_6_tpKg`?n$L:uQ4_r<wxqQPl*$l"D%vNdMz`I+>m)lDV#PLBO!K{nYbiL!w>^]D;wQE0,lB|v$OlR>h^9+i7da6USb5ARn!bHHb})7Bo;t_Ho`1oEG:xm3>`<3rD]uE:j[<cW#{x~%O;KfW9y;)wv{SC8*>Ro2DuIn#}cQzJe{hNRd/3[t[w#.C~B6j$6)#t7LBGYrx|Y5>@Btnx{3BawrhdH$rm1YKw([vrwzb$1_MB~MXl)|{>)0YR3i[X7,$}g(|h$Sf8qq=A:w%|?lH6hp48_OzL5_Gd$og&?SfRsMFpPbOYIO%hqGe@fSw>t$2sTdy*D@PV<1wrSDUKF|#xTgTp|YQ#]SVqq3E8123CY3r]bnZ{chK(qNJ)t<B{tOD`w8}M[n#~m0C`v+cKsPWr1@_L#?0vmn;6x06((OBsh|xf5IJmw)[5n)E}vqrA=h.#zpBcJuN5}U7{SFyB7TUeCc7D]ABiUib.!3y0r91e(u808YX0>:6QH&;TJa32)F#0RF}NVDJn3lKM"E6:j`ZK_!0Py3[3<2S95v]b&L)OAtvt;,ha*<H;y7_#rV5QfA1<6)zB:3qJbwCsZn!`s[HWw6HiQ{2z<yKVJ,k,(<i.gc4y?W5{6fL.>/Ki_WlNGPxLp8:ELBi!W=fd0o):24N[CIK8P(h}0g_WMj3Ux0IWyxF0SujaZwfJ}og.R[3Cn76E^4f&O!_rXCWPk5#a]rIxPFWI}&e}kK}jvo)6l?P?$TY[=opl3um(C:V,<9h`Dg0{"}r#t0w_ls42)b?uU&nMbA41z=9{`DDn|p#1?&ab#CDSNV?|Oad{4P6huwmO=BjR)B.Xjv1|Yk0`eCmT<L+e@Bt@fT`UG}r;8u#Fk"yj1>kS)>FGKNL,~PNf]X`k80zG`(DSPc%YKx3JM]DB`PWxZFZgV9zL0lSpw^d#ub"9)TA,`|`d|Cr<*?<(j;^dVy"~L3QXO:7.;4e!W_)bJ^YZ_@W?FWLk0fY&,&ngE<WOtPSe8LGEH.vdcSHG`D!OD1$PJiZkGoVK!Da(k^I4GN^!7:}syq(R7HolGdB5nMP@;Vh1`).MiN_xNJmSe7fbyV5Pi2HN/Ah1Sc7.E02n`!Kg0ResTG2K0wsRDi4V@^G.:M*=u%2fZTqyl(^prDb;4W,322zuEy[Gm:8Oo2rd0lhgxlw{z!C:^^<Y%a&GFI?A+v(~RPa$rP{9~3fXw0*1M(rpYUUu6lrf(M/ibd~Uzce1IIXU[jg=Rcc+S}VHwY4&}<Iqm+Pt7aV5([H)|<*aXh$BgXB/(x:<$*y92Bg?J%}enZgJ*__wz~1G|N`v|)Yr[*v[mP`dKcT<rhE)K"$}SVb2ym}bGMCU!.@1.G":`Ywh`,~vU}:{iAr:+6[@UxJ+v;m>RlpIX&^ildBL`PjC|DovbjT`6LES>+BHy@D~(<9@t,K%$Ma:j9`]omOX+zJ;(@~Ij7+FEYZchq]w+^L[DEWt{=[A|g("do!GCygQ_M7n%XrLiP[;;#]q<fTg|ZHB/Bi1C@9{RpeF,Y9*`"10[R58HT3k?[iplQac_pI"c`[7F7pAJi=5|mQcujctlbhs;Z7r6=2!@md^XQ8YY|aNjR+KID?^D{f7!zwm=J."l#>@o11|{}HE6rKXMv{5svHe+^ZRtA&QR$b(QRrr`WUgR(sw}Rz^aBs;1sPL=OWNb{JliC}oVD!W2iIJP~#;Q>jNf?pt`I4I;[##`[Kh=quji=n7G"V1,Ba@:/O8D,&c*v70<F!rv14z?af(ko(1_|>?jea0}9Z(smfbEB6AlyMC:*uEo!MXZu!6?fkc0{HB}^=wy~4t/a)hVA)$~N<>6X:g]I]w8ZlF4Z/jClz}oKtnaE`y?"QtjDiwY3(CbiH1;jw2}*T<S6{<Otc2JkQ"vA2Yr#ywdHd:C,pt%bfw27*mVO5[ZIt$)>.?G$m535KymE]AkC&(A+/w{6fnDBw.^J9#TzlOMKB}t{eJN;{2zZD[(+Z=B0KCV/{w+t,VOBPf~P*LVP|N^WN?k+^KZ#C[#>PO72oW$:v}+7S{Z/Ew|w96R|cjvT$VOn|6b+O^s2M{x1:#z_|M6f#%EGZaP69bsrm.Ukoo#^T,|PMDPuCFEq18LK8>74Xo?V?NBhjtq8{9&W{dDZCc#q/zkUivm`EI@$K]a3L8}!r<~f(zegj,Z_?kNpDMfk>[_TQQ+mRvj=pDn]x=7O=P%ftRw<""}e/SjGSzOnn<a`NIHM0uoF*c@ntuWG5??+{"6O[&T3g5iEeZH07Hftp=[V>8%mOB9p,S$H&5LVF`HSQu;!_+2|v.6iIkX0BP;q%~VdMNaldF45xC[%*;5SF?ZDt/n8:w$TL"}P`>v#B/snGUkFtx0ogL7p.prgqec%Q|IacTUk0_9aHdFvj.H{CcG8K2QXx/d6O`yjYlU.j))g<j06NUH4l*=wbyd=dfxm%xcROzq:4S5^.0H?$bm|bSkrvUg<%Hpfs#1R=Wo~}3k5(RTC5jhMi6N]I@Y%gGtnLgi%gz&4O:P]kRvr+7Q57(57I[Cn!*:fx[6u=4wEDNJZ^&`(]l^leX2"vFAnfbID40;}Itj>z_FgK6Y/)L,lVt}YTKX3sVP}JH#@KVtlOS(5<Zxd@f0(czDcvK=Uf|"PjM+G&&$N880MXwzr!k.LM[9;hYBysElt#^^o#4z4Z5[KC@`I290Y44OG}(D21.tl)qJ~5mbEc`s;:&GsdvW|sENKg8LmD4A*[{?1Ivzy$6PE:GrwrQsN"ESe~VDh/e6O]e5^Et8>hG#D|AqG"@1iBXe<Vl<S6h8>YOZL0mu^|oX|Dc.~S^_AiV#Y;(S"DvhG!tPo3CR95,2MzH%akhgBaVB55OTzxRKHXHR1rM%~tdGH.@/b]!D(Io=Dn{+j6,<$G3TB0Xrg]vnARI/TXQ$/Te>R+3j)YvR/o*^<PK2UZyJA1[^BbRCE(c)ofQh!57s5/5L+1CCaH~5iClvDH4>G*l]gS<%"51.e6Kzj5huk#4fNxHIalaX]xx[PeN_QrXM;q<n{;Zvzd1w?J6gIz23w`Y@hf&+&OC$tDM*uRUPo8!$wJNV8%zXO>n/I*r6<%{Z+f$S5[zl8V01_ACLx;vmT(DM5notF%@.r`nFqk!)@sTWtXe}M8;3}vo|Z8*Z{YDu.GjJotd=fEX]sEpGF!"~u90)&)D<&&LB@O1%mNmB[Kv6&&!RQ9)qtFz5Y^K{J),?x4&}p#4h2z+$V5*7?=_mV.%cf/&?oyiwXj@Hwz9m^B^Jy?^W[nNKf&G9#(7~fb[$x}FQP>;iI6VU?:{GTS6/~F#R^Y3(uI1L`%Aht%"3Ot+a?n$F?i"hZiix]K78t&6y(2Tucc|ja&eGL*iWlIYEtu?/[4@w(jT(#f}utIZXCM=_/wlo;3S5]|=Dnxg6Ha(TJ?~h!7z=qEj*dlHxcRUXX]_i_RK(Ue=2|LmKK0A4p_y|.I!a4d<]yck&;I4v*<!.DN6]0!dJ"O[o(j)9U(eZM)m~THyzG*tI6LdMps_K7/Pk"XGhP6fxc&hPQRU;@"ufgjzQMBWWRA!05j&?|jHN_A~O.~DiwNz*!Q>]~AaRDMSEIr@"dLsu}l)0lm0OD`Cu*xd"?60UtOJl^aDd`qnW@s/,%%1iaHg:G&reNWa&4HXWiW}*S_4+hj|s~r@fR&0_VXE]By|(<iaKQs9=4(!Q3qwfSMD!9|?$k1HCWHT}*(xx&n$?J*C9,^y?QU1R)f(MmY9oj04gJd$gM9d_%)4xP!ldZj,PWr>H%R|%~lylNdH_#_1p2|wDOQf)Fn^@QfBIja1~]Y+I(xe^f~G;:,rSBmrhy1elzeP]*qN!|*v_)5JT]}7<if]Nmem6Gcu:ZqDT#ph8%TS@)8"i?o.qGf#W3)r=>WHsW1puxPKw#kqybooJ1=L#/oc]]^yK~Lrv.rH)(+40!MP{5lfn*G0<i/VZ@0QrpRQ]?cw)$9:LLhv1E/;]ZOV]KF,hDJS5@_t<~GTU]s%_2HLqGTse#N:*!}1/8_G&_TB!T2PRO!)DW%b/R;5}A};J2"$jN0=z_e^tbMm)b7E<]G4ER3Kg2)03"YrSErXCqX*(~Ehz]B/gO/KI9Hd1/n^hp^x_yU,Yh:eAzooDRv*#G[0x#*!)Te7LL(1_XOo1x:|F$!;#!1Vc$Qb4T6Kh(#9^a8g9c^+!:7DkKqkZ^lBxy_t`ToMMdE)kFno,4<4+TRc^nmp[>WD){)rFWG.j5#~il8akxeVzBkSJaT*}^tSvUncw:5z3#GW,N!jtJmJD+5M^fia":o9K5EgZ|Riq)xrMW]/XJvYrR:xkukKW`1iH)|~oA$Z|=@{RQ=Q/j[sZ/ycox_)NX[Zf@RwW.3c+iK.D67Yf:tC$7+mT5$WF.__xnf/K|{8*n*;RG!j"{Cp1FKwJ&un^TE6;Z]sMOc[TF}~@F8o_6[E}4F2:)Sm8Dc2eQUDJ9`l4Q{@Uhw[A&)CGn.y8D$O/pqEv2<zSJ],/6aTYW#}&A^AZF!x](Gw:0`]AiX*`l+Ze=b]BpnT;sB{nw*H!p>,}>WvV3+L+LN"=mW$[Xemi(qVt8R+qO?(Dp5~lrg|bXE,o~WQg$^j4LCoUm9bj.mOsqDXAh5khKg.iEC<82;o3f2ZOP?xou~S$fC8HYBzAd;i;&U:R1oHI5FW#`#:wWG#f,j#/[+"2?[Ye{]_7gmQ@2vKq4yLj>#*N)gZ0_j*Ln0ldfJt,%w>hM^{#8>d,#X/l_@Jp]^"UX;GeC|<>hQrUx#ZO[@5}M!aIa"(v(ekCDte}LjhXPHJ2;6n1_?nx#y2YYolMUw~1l|?iD$K5gJ(7Wwv9YAJVme&)0xE{1TOM7WK3j72*f6%%n1Zv:N7YZ`9sg"FCrMhdL6ETkh%eIDCw]Pg9/LkQ].mk#7T)Ng"Apa6/.)8$H~vg5>@<|@*E8SBxsnO{WJ/F:ACLnR3aUD2:A9fv%Oqlu1,#Mtwd7%&["^(v+2g=LKCqsU9iaO7D$Ml<TW.}vJF((Q&04L*NEK}TjOSkAAxJyGwc`s1AG:HrpddH>;.GApbHbn)T0MzI*%`/6TA&KrlODfVXOKdK}|U[g:")S`lN^!!])5opNa%SOo?9(4ug6{E(zwRNopW;[IB]]jF"DM55v~rn>.g0BY<c.lF$;c0hZzDRo9*#cl=bIIMokP)~l.%M`H":^q~).pTv8l1]5{cA9N!"[vg#gVm{CE}KsFB6[[i!XrNVd):SW|E|<h}*Lw(shx+6;@_h3#?6%DXBy/sHU9ioGB|aA|{B)tpl/^UM48{H;7Vi^+m>=v%.jz7yyT4k{Hm2G@7cZEtl6bpQ*"C=6%BW>6R@BM5tjJ2_#~{>7S=rofT;x%F[^GlpbF,#XIf(wqDgg4jST&3t*pu>$5f7K6+k#G{*_v$RfT,V*s3hR4<5wGB!:3r2q>]yt}@,WbDVE+nOZmm`LVqh[/@w9B*|Yf:(QrkT!B:]>eR><Z"N;fk%5e32,}N0DTdDRc9RAz%FND/wK@!:>Y;!d/PL{b@NGz0%^sE/>2fHsTENX/TJijdYL%=Qglr~+%.+94(Mm@`=gbNYXGeB:?aZ4!{5zmE^r6"^F+yGq)>8qmjcZ/3tUyv%A^)[,EF"RFNQwW4|nZuC<H&g{i^NX`BL]BFfie&mmD!baRz&}p_7CtI,heX)TsCEi0rrshD&`;E|CpDL`9YA!`&E"MMUZ^CDm2WYZu}?Ojh{_.|={g3[]qlHqZH7`}h+G0q#x5`g}pO~@f63eq0qt<12gEEUqE0n!A,:+*LYhIqOw|kB0BwV6morjHyOQyOO]/oV6(9($?k.5D%FleSi^sWg8WJ)rRPs(&N"G2w!M782@aa^lfr53NpZO3yb+YUHS~DvM@a5f!h!<gVL>${9`apGY:Zb*mz]H0RA~<4bUfVO>OHNY|)%Y#pjb6xMA)nmq`4JP:nx6P7.8S0sh&1(KI]DY`Tk@I`hbwfCe.A9Yx;zOotS!L:XpQ~16YSjPy3j(QW)HNtL[oJ^w?E?@BA4fVa>iIZ<,F.}yay?;AwJ#xT%Jv8k`;8a>JmhFw(0&QT:q2~h"l%Ee^CDh6njkTI7l}=bs~ryUJDEu.C_#^i;P+l>cIZni7u&f[<)8HM`:T3tUd$!DlP)pUn7;mel9|d^<:dZYo+gNju4($N]@cUV=R]p|vzSccN}=g]NS5V)Glqp4LVrrp_f#O=|%GwK>gqFU}Wq%={FVyBfZt{@^Ch}d})T4j!/yO}fj+"_q.XG30L*Mx<Hld2U`bV3J}]RQ4;PV5:[_IP6titfy6a(RI+)t%+Ra*"pw)D[VNGNB~9;{El:3LO<]u{[jNy0Pfy`dYy),^$#~ZZ4;jwD`q}|T?b$~24R[yI71Bu?$5~mn7{`s)^zWzJ:#q?kS/c]*,V6Q<l$L}%}+cCm&>*sMa+aR.erFrt!c8R+=(,Ha8[9fGU#C>H|E+l*A<d~RwOBv[tjUsF[0jsGp$]tO2Lc=SMuzYvy^oQ67}yV:$A%j,7Y:K`,ZuXdIp!cf}Id%N^?c<no.adK:/|&|DuxC*D?2<9UXr?e||h~Zt@.e/b";gfF=|o0n%}}@9)FSdjAsNBTO)=8O5a@mASi7l{OLxVAM?GX9xh{4!FLa=|B~%N&]S6qf4@gE5u(N~M7(yHoJl$?JRgr:~H8=?q+M7`XE/Z}N8WfPYDj^pRbm,z}GwXqw_Xt)FT?*lP;(q2j&J_:*H_@mzIPVO)iXWrg5^]E{J}.DOwDNVCt[3af,uCQ{p*>W[m#G=}RBO23_*[#]b>c5*]Ha;(bjLJZvs5p*P&(e#8PazN9U+z1S/i.QKHc.`kmr1PV!RtD^2|Z%!H(,:]Uq#,F]rUz#rsc%)3aM`U*lV[S"RE/[=C8BT2)>&FXQ5g_fDzoo7!bm7i8nO_j1[2*pjKm6{yJW~X*AV:FiWYVkjE=Q4E`F3{q8DY[vU65i};v/==rS,fC$>LvVB];=r,}ow<,pQ*%9&ll`Mj{AI+k@$x6vpLUCvD;/LUHfZebb!)__Y4auaZaEk6J[$/gEioWjOCXM|nk?u4_n$]FzlAhR8`d7c2)fZ`_8ti2`7jn0(`J.b{Jprm~a+5ad]^oezjh.ztxhF#d$,@O/$fcJhlR<,/?Uc0p>G9]]6=eg2ngSEX$Z:cOPDIY;e[q_QK5Y2EX&GfJ0vd$IZHZ]cEeDH=w<~el0;!EUOvkw?A&45W~yd=o=cJ#f!C/g`5%cB2eU$;/j)ErhuSkPV<<u5Wgm:d"^$nwc("p18!mPtNt(426dqnl;[><*PcGX]yHkJ+D:&u01Nq#MM#X`OSp?zPUxD+QaGcLyf|?KUrwt1ceo;T3<m>[~7bKO]b0eT,RG#/mXT7>^b!k]*CdE5IXi&wW*~4,[~lKMG%<Iolpt|{Ze$:rl7|40hmX+NEPlb#$`(U^d!N_][Ro:oK&?FoHvMc`rBakK%,qC=;3u`9>[fPiDBvEi>M3%`,a}k4#A)"{i=O$=o9X"Qt5$$ZctX9L|B>)xk1[nS2a:HiYNY=J|`Br_lF!,)uftyWZ&i^4hx+*:90]vvn^w_gSj<F6$f(^y(vxe[z{i@~eujthW@/N~o?8pR<lEA#ny><W"Y[ebIVodRIQLMM{jETPKFecrul?VQj?XQ/1<+#Vws0a,prE)k#?ly:5=7EM338Qk*]g^xZi*(<ZiX,;%TGCj3q4>~U&ipK+NyGE2?)a6u;5Spoq@Z>:+%zg%p";Y2rKb<yQqm[g6g^W%}/bfKGl.d&"zrJP9hNn.,|k#WEP7H{{;!a(#a&^o}/;X>FP~F:&$]2T6|wUu,762`J<!T3[H_ERwl:R0)338XZgyO39kotG8PO4d>HsvdulsZS|[GD#4iLfjh~V9h$wI4ZZimsCNd.6@>X)kt<le[H)=ypE;a?+>xxYE0[:Uf:p524";qS<V(Cq8ZrJ^2Fd&D+{c`[<9$|4+("+!Fu5[FKtmz]TIn#S,3h"<M##19*3pifdAQY^QscVo>yr*+aA>v55UY8S`TWP3}(<fbgBtpjU3JjG%m5dG@P3//ogDR5o%v"t=[y:18dJ4Y,kNEklj?t"aa,UVK9mk|oRw}v/e/iCz.^SMZ4t"yt/|FE2cFl9K~&Jt::JRu#I_P=W04(1JN/zcSL[,8tx*;=C>x}{q[tnt.;/;_O>0j4{H<Lr?5"WRcSFa];c6m!G7:;^wXZ=&L{SbSycAX@f/QJ7G}6l]y,D*pu~GWC~N2Y2(Yajb]UE#m&V!"8pUYbO~/lB2]z6tF4[i)8vj<)3alim??udv:;0HWY/K$P{{58kQ6/sbR&$7Sj9gxemN]GZ35{Ok&~cAl$8St6=&3&F2Vd[_O6blZAu^&H<|]I>?53%3$QeT(NT!DOWOZF7/qP+k<KY%Cf)S?p>{&mx"f~^q{V75*dZmd(;*Pe5SXp_:RStvO$u;vJY0t$J|+dGq_~]=mmfNXhgYLJ8VYQpS^R4bg22POAUB,bV.VaFK9UV*$]814X!D[OeR/42`$2.hQP.4X.uKy&XXfPGF0Yp7a+8?C1z#L<g#?<1ALi6NytL~nsl*Jrno/5<$$]oWAe;)*];o0&):GvJ1QWrJUCKT/+]Bl)dVd&L,%B09)_#"vS`@z2z)Gsh7I_HbEsW<{pGC]up<h#&mytz_xV[~e!sE2H*|,!@LP*[%7oiR*yOn=uJD]qF[cD;Tb.4rrhnE@&&$QVt9tmX:a#xG.1a~4wi87modWJ77%nr:*uCQ7?f}[exT2o_LB@"`,[ktT~0Zi.839!PUtZM!e8xbrElCO:?:>:3O|%ir;KTkForb??@L3a}r`D0b3Y=KA>?#qWXARsV8m#coD:CVCB:ae=EtPOe*Sp0]1uiQln.^!aUU(lvf0(6_yU0KQNfxaJ%mDi1%rMx+:utVg(d)8m{pl((ActCmM(C0LLdM{eHgtqobIya|Iu$"TsP,PBFtBcZ;^&LGH%o5mkPtXhgLF6(x|!{.sRyozPKg*cI,k14VkL6uo:[~}i<>MKo?3r*qGBbM#fp5]]N*&nX+>jxG:l@&[{J(?LK>t?[zhN5mD9p$jx,>!LaKI/?~X2Rt*,OJG3krq`M^CaS!a?7hb&^1Fn(;m`O~KW[QiQ)`".&bit/>V{xteDlkQDQA4f6mOJ48q16ViuJ$jsw`5:{OQjg@3i4;Al^7qJ3Flt"zioN7GNJu`Anj`.$n<V0DZln~z;tZ5[|/AS=DD]?N?Y?y(sG^0?=w<W|i)IaU,Cx_O8I)h42Vle/)ymZ"C8ntRxPkqG!`G77uxj&g(JFrClp#0mJ8N|s}Eir[mTQPSl);o])!k_TNXQ&Q?$zNC}n{y,>clY]a4_d/i~8@koI<WXrSZ`!EO:TM:bAXh3dVb/PkrP<wY=q6ZrN!hulbm+J{fp7fzA1:gEznmjDMaiFM08:ltR;L%D?s8gl~&a?p(8CpUc,We`tr*H>VhIoENvP#.:C5C|{B:R|4O6H/WTFvi:)xC:(/]>6YXx*JlYNBPm|vVwT0kX%#D>uWT$5}ZOvH*W`2^4%5Dnl#V2RO+!LiO.2pm]=d6u3eAr0Kc?.x76r~&6CCk!Z|r~;Mr7UI]"Rok(des6;)`<5ELt9Q0?m4G:re5?h+Zc/GERr*!4CrpiGMY<epSXz|i7]t)S|Z`cKieYmmR.#4Rufb<V{{Zp}D;3bIQ&w,K!A6{?wMx%;G(kV%8+}KJwyG"&1rrKM^lGi%`uLtiYG{.qL6@}^PjW{Y#">l~Cl9+TR8ipXl."AA&QjFfsI<(b8J^vm`[.Wrf?W85]hbkK{OeI3K`yyrB^ymv.DUV5F95uy3Y1t{iP9Hhuu@z2&St^GQ5EP~6~249)kkJ3b<1I={AG,{})u0f0L4&|_qQRoO>xH]z[)0C5V&|~%bxkxM,3Cw+!2eq?,81hna;Z8Cwgxi58yz6&wB9(x<V7Qw#1/!?T+YXaucp@rP)%dD69RFaN.UZ=RJzcV+v6.+s,.)uk@MR3_~*{4Keo06h"_,dHB7`"Zb_&^_!VeQmvWy@sc*8L6vMb|if{ml#tG7W&Y?""%D2v~;_2O~t[wDOPO)qg9s}mg+5=PU*O%iJ6yswG^/.]&{R?PamjjIvYGc9:=*P?VYVxVya@R,YRKLVchzj,3:*0Zk%*K7L27weV6}^v}}Ue>y(zdz?,1hk,c>hPnmr!34br_2HGm?G"lnX@v5[QzAnk:I24Q(XBQn}5v(fhqfz+eyygy48v*mg7q{.7izFob~t`X^j]0.pS&FGs]MM64B`w]tLB=fqAz0SIc8BUM6+FzG1d[c:x6/!@O8<9Wf6l,16,m]#{n24=u$kVvi(h%g*UHWo(QmkvkX!Ttw<"g,Q&=blt{Dbd?:g&FDtep&t,1$K^|xdG"$zNIUb}#..}:>FONQFtg^pZW(Sfufj"jc)Otn3iu>A(Y.Dn%HKe:dHu]Kn7NM"Toq4/V+DnlOd,*An*IQc9oKX70:F@zC#k|j<J1BKC7)6w2v071`&DBF5{Z`1*A41lYdj:gNs>57y?FDILXKKU/2u,o,`q#;ri*DGW@GFn,lrY,#}OCui$E[#a6F[RPmQv&],:R;TyUV_{/nlAWM)$*oly.rpOK~abdJ>;Pc5YG%!#/B`&"C(9=unN!)d767q;~.v1Sx`:?H92t0di<+$;4s8EIEWo;jV1Y/ez#8E2`R%@F/0^:g0QQelY+v)@wf)_3AAjjl/,G@Fl`^b7>6(J}xm*)p|=#`59%`%XVuZ$`bK{;|FBV(i!Z.RnVIe.zpu}9~c:ydFS5Up;c!s++^747W*?TmG2t,E)*[]!cjnVepjb6/!;^8C)Gg6&B,cmVqT)}lgm3NL,6B3d#7]xJGJ@@M9eqWf9x&X72r`A7u@^hM7IlVd{D=|vRRvgUBZ`;,JqEzLcmkcgT~Cuy!~O/t^97)Sv&?NJ^:h8fYBm}8?Oc8@hchBs<D]E(Hw,BsLB%uos=",o/YkFQ%{~&f<=$8=L:c%4nlCvJdLzvbR,IF;CryaXp[y(=bvIoyksVh<vq7HXhQJ#"Ylu:`x*m`*dseHm3GjN`Juf.arsB9e,_i9lJ~Dq%kQ%C7y^Iy/~w!~r+eHK_/Ly~4uBQGRia#uD[:2y^m6apc#f{w?9r%0>9(o6GME(?Z=^%z2>sQ!aP6B>{j;TkB&dF)Ht9kJG:iOkd"iKR;"|h`KM#H?0QXLkIrLz=ug&5::oOOw!0s&G1@(eg)(pJ<)1KZFW,sTeEz42lgx|%0;3cOf2U/phu8BBBsRrB"p8lu:y$Sj,PVkP&polbgkDhls;F#1!7(xVGA$ewRExaip*r3UyW,B3E`MY[&g%e8R]5|/B4uE]zz|"^+9*[X(]>jz2h6HBjd;B1eUPLAj;09h%uPj3QwT(qpZ&Bgxn:`38k7z{^%?28cqAOBD}(oUFI<$Z#Rj5O8*wJqUn&.wb`/s8{L2V]=b;|oa<Ch6Yo2OA^0F&^>HW#tUyaRVe9uCm4]*F&r!S>%[9`x[@NqApy)d~*Q%H<Ic6FM7R%bC#v;G3uBFu@|1;$YfpuB)8P{U%Ig.tEh(M_g^aF&}=QkX+KWTyF=N<cMFTO0_2{!{7RFaLxw7){g[lf!yAl6"^`Vrc"Ihwu5/8kM!`q{>:q$w89qt*|?5~v<gZy`6x@[(8U3?Qz>Nxyu>2DJLw$n.4"APuJl.V}&J7wP4g87/k*?aNc/f%Yc?D)P7R%,Q,&dugZQr:gqE?^gn37j%$$K4&>pI[({jn:pAktp0{"%F8T`n<g~L=7Y$A)g!IE026|u~8S4M/90JPzU&$Go_EDN!Ycc8?rbyp_&EAJ,`BE#ia=)"^>OLLp7C%qKjiEF/|T[Jy=a}2P{2.X+"se9+X2ax;n&;B7m0zu$vp;6u^i;(0PEJ[A;0@?Q@8H}`[0g&@[i|l1Vw3D!WG_FkxNUqEW]Z6C@a_nY4U[??7.[QGgn;^KPiV@X%1#3SCszBtVGaeuLeqQAMoI2DALEoZ9}Or+[#$zhTv/3Szw[0}tb)4`ft<q(H=E~4^8XwO!bC}iV<P!Pu=?[7sEq9omg$;p]1+(Mn,@,vgz8WB9y:rQgL1W]?ZYq2_Sa=;s5[N`c,#I/wJBB>+_[/bxUF.!A|#W`QTl?(g9/D]~"HO;PZbi(qX;(=<rp:|hl?Fm9fMP,0+,dShxq[_y4{Oh=<<`t[NGV+ZXN?PpODd}U4V?NO>fwCm<Z%#WxNOQsW@thl$KlzUSF%a5XVLq_Q`j")rL3Z000eQKJDT~D.Hv2:CzG%,7i!?Paleb"a>/z(C%3U^k;H7{^a&)*gev@*L/.QV.T5sL4.u!,_z8$Bk5)yI<G"cM{OcK]Zwgpl0kaB|(sr(1},<V:]e*.Nl%eKy{Uu~tRN*PGlnK?Q"Oi}#Va`3VnhN55?Dn{&_{@_.$=(L{P;P.mIv~uMvFA%l}qBV3uugvXq?`=Prbg:|$MoL>O<U#pyYOpvXaRw=_,qXCo`]tz2iC:E;XZ4ukHK_K3Pz^aNY(5TF3nfu)*YGUx)Z5H/6%OM6.>Jki#0fn<r/[qKLi"s|/U>j|d_dmCfp9hYaNo%,r*1U|?0Kf^_*zuG+U{h1)ySw9#KZ"TDun%fnP`)(P0wLMTVChqW!2(;&GX&Iw|1~kx$nLct8fsa,E3fF^69pO2Cr>d8Gm)vd0!de!BXi(U]H1=BI<x..L]81b,M(C:nDZZ$Ft;L3"5lNFX,Wv#b6w,p>TWC+[QON1HpQo7.XH^*G:gaFot3]Vfs&i}jlXCLvBZm3(Cjjc_>c;;9:d7bv>q2=T98Ip@/Yv/S<S]mMt<dD]Zgg,1mD_]7?M!M20[1a?HErWih=W4gP<!CgOaE`4xnbr<$fY@^PV<Zi&"ESoa2>5D@@dEwxlmo68t*5p>=,yMtFI3@G>C$zIpBD4"NC[Ai*I40b|KY)?D:jmBo6A,saE|h%ajj<hK<0gPfcl&*oHbY3IfQK]%h!d:cNgqJ,,CY*M3RmCrIuWVXQ,v0KDlT}#r2lQK.M~3xu#XT{.N^4[a&"::S*py|BGwoo2c*3p#y45/e2=ss|=~tIOATTL<er+mBk&7F30#9z=6RMr_qO5}{k7Fvc2KYT>cp5v2bM;v6isUMBi3ZHrysr<y(xcE0;Bg]&4_.DJ;2,Iz2$(?&YMX$0w`*Wl1bBFaTZ#<HUI11ED);Sy[Ee8)X#V_qTqAM]?Uo*Sp02J?7.NaJHJ=>!qf3]LVQ?:l?p0mF1xINm@b3TTWF^ACBbB6^nzPqEg)OtP!Bh[alc)+p0g"h5bt?r6IOByRc/.`eh!I>r;HHY8Vgl$X4X?c!`9zWsEjb{2I*(yu4fjgRTfF2i#f<L9]D101rM?U({L88|oJ)7}%p[,D*kc_N2#AKA1Sf):QNzU:W6x{d@f"HE2M0jPjY^qHC.oJ|LU0C+hpVDU=Ul2`8C.Vv4w~l*AfC%mc?IID,UKhXGwtsm|<syshO.+jljmI1FNno^{mmdX//]pE$XGS#8Gi}Y7IQ]7tW_}&?I*g:0#][q.G+v|q+wNbhj<a8#b/PGfZKD,TqWU;=4>cxxYiARW#l<~do9GfW}SW8[)>ClZ^CO!O=PZK$e[Hfs,@x,A?v@k"wq<o*Rxf<*YZG.&)&c.b6|]AmH6oxY(@)"0UD7DCY`P{9pbC_Up3.XYIz{|nmfC5~DQ!nff*uj|HQS2b?1|d9C?<P~wke{TIUlI>V*#vxz20dkKr3Y&{J"*/tOU`hY{5!3]aIeJXG8M"0aq_n}+Lfh.3UZ4yw9xzh=l[qI}!y^1h^P{yy[Qx9ISbVLl7L1F.Y2X*cE2.!dD~HA;"l;ev!".]DZ.5D5K1;KN,|5[yD%wrbzoftWi|/kEIMw4"A7"FlVHC<tCrH:t@?)_oqo,3?S6i/[z#<*ioLg$2tmiyfih>RL]bc&?cd{Bh8Ew$q9=tZl1aqlMG=F_(0/oqN8**AH?USEzKX.x4e_SB1ZYyPBcJV7n~0a2}}0YE$g6"z)|RzLny!(pjn~]s44F+a8lBSN,J5uc*=NY>nv)3U<Y/xnCFg@n0rD<1fQA~~CRFg5%Kwc@`N)fXx.6:HH0"gQD{hRQbod,>E"/<U9}t)8]N9`?}Hz~*N^I>O9&Sh/oo#qOLRPBB2tw#lh3!zB_;#+H^W_Gh}5/jt4n2!Q_n@i|:JtV|1x!H=JO8N]|h:`<z4)<pZJ.]$7*>d~4_J5LND=jeH|EV>edc=MwYh@:IqaY#Pw_!!jn@t0[M%zyz7na>J{Pz)"IT3Sl]RH_}VFW2+kWW1:B6P|cx`Xa@=>6{xM<Iv*qBdw^wcMGpL?03R&!9kx|K%~>K&KZdc0y];"EU*(yv5OK]fcq%E9IuJAR9:i3MY|qu`xP[>w~<n@@V?O9+r7w,18Z7hx3fH@,bB,?U9k)!cC1[R#=w`l@}(NXLL23zn3USsC$1SU.IMy!wXypSc,ZvR0cey>(lZ2vaz`~~olMipD,p[V}!fVSznpY{fm1j(JD=MvS"#5[qvbu$[2$Iu_$;etXHaB..D<#L%8MLrD}%s3bDBEf3yq^o4uc2hID?d+aPbWOIm]e/&3}Ob3Yh|NjW>Tr}F{G#R)!!]o+*[PcL7W?1%S]}ZXG{j&yM(w0d$F;|)gke:?UnDuB`J&Ejt.[xaLL<!twxu9G35kDSZokiI%/4[eu2nRxhG<U?vU~PT5c}h~}5VUO|Y%)xB_7=23xJ}D..kHuK/2>s~fdCbi]Cr{E}}DA|")7thqSGO~b71qs4LsG9+~LSV?2~xb_sv~xD%tg?g5~B@)xvIy~LEYujii?uosE})oRi#;<~]GZ]7X7GWy8WS}=_hjC;]RImG0mdMI2Z`2?#XJJ%$g.@T4[Vq25!jc_YdCO`U/l"p|EM<tSd2><}q9.DG"ZciQPq:"4NH!wS<QZ<0rt~$yAQSYu3e{m^LWkuo<1&^<UCmnc=6PxZuh!d7:6cGCxE:213L67]`6yyY#qn@/<&ZwF/u.W~<]``;N?c3/Fr_ZIO:XHPt;|YN`7"N$k2o,f]&GL}V3G>E]>FN}y341~nt,Ei9/>gOdnAh]qMcO|T7kS[`Q,v]"IiWG>a"9LRKduyy|Q]1(Vb?dUwrKQX"EG8ntaiCHD&uD<MUYMSF)I8sWoL</NdmYL(u`Q^:ttT#>w(Vy8l(jBN2i|W6%`r1ir_=FN3<AM#4UZlFxT8y5HL*dFaPo8`[xXBi8K0>|mkX/*:{}Q2M(LQ[z7iiveWKbmP?6@>a(__;n!9!KGk/O&%2N^dOt._q"eq;oxl?XzHhK;l(C:0DWCiS(%/|5Qn_8b^lrCVSi@ex@ju%nK,GdT:e06X{yv^72_~9]XKyC%cFra)pRh~9Cm"{_gFP;/p75*BFHJqh*I/;rC)Sb5E^E[T^&9;/E}F2C`Y/XT~WT9@^Db@iaEk5n,ov7ubWy,N35R*8n[=J8f?~RY:kI2(@aO2>Q}ea5zwuUUcs51lAf`}YsF8)Y|j}p}"Uu(.Rz56|2bfV,QOs1%A@6I(b_!A_OCkvz#kVEgn@HkqW|Q#L^U"f%EIO_lm)yKzTCPkY&Cot[yvjh"lSnDk)cG)Y$=$agmwF6~Hc=8{Zrgy8BQ3g}e8nrok.0y&qwaFUHWJ#yCM?m~>B"g>.g=RR=;0XNq/9W^~/ZZ2|&TK$)OSG4fC.@lnaq`%`ALS)~`G2W&6S{cnZ$cg8CT9k>=0rroBZ5)D&fWY2UG15%3D<`MyF>%a6vhG)(0I&.Ku%^Ua|IlIfW,S5xGz7Nj&.M#yr&.g2:Vs.LeR5$=/$<Cg5}%[[[Y+)n9MiH#C"O^{7$9r(22q[^f!TF9Ff2iClP6(Bn2v,t`d)#v;!+M|K%MbAXNKK/#j2@,3OF`7zty/MH8<bHa&.:)y~o9Ir<<*Y_|,GTo(n8{jLC2s13IO>W:>]|m^2j|CPxW@X$@f%4#`hy~Lv:9F7pw;9)T/7{[|Rez>L*ZFZ"0g97jZM7b)~lQIlp0]e!bgg.!wM/L$/dD`%9IK3k+DbuudzdaSjgy3|34P;|E$drNB1G{TXCt("X<PX@NQXTQTRVXENY^B<(Na<wY~dxR/_5@BzMQsL&@Qnt",[Lx0@<8(j*:bfrIv@Oy#c!5pitZ>t==nw>YTq;j&Z`z]#N1cm{]JJ}Dr<2[PpJ)O.zB1[b?5y|${vMJMXN~YV}GdF4]nWoC!;wvMLazI`)@:M^>vw;w8v,(C8DhlQ(c5!@wG!>ve/UC5SuCZC6Wl~.;n|`w<;/=avk44mG5#Wh="IL@6*wAS|_.${i40*_Sb.&K9E]$cSGC+se~c(Qj%$xrL>ckD1BReh2>9ceI])2#ruYJ%pkORO$Q)N{yoN03RU<|jqVfF(DOq,m+(%/Ej".[#TAVF55M)Lsd<71ZG[~Cd$o%q9SR6_fvJX.Dm7UosT1aTV)Nb{aba12I~;E1j/zNNY1#h;jrDQBiD9t88QjVWh_s@=J;`f;WWZr=0I4_O~zxSRVtEz[XL1H_EHA2oCXn!~>$b*6Eana7cGo<SG2o)G$16CM8x,]6m<}Cv+=l3/=]7Ddd~AJZVIQ#Rc]f"/iG(+3>.+N!AWI}%dgB*jd+9:d&6[bTEGG7B?QWXB:B[0L)4kImLRG9ZxM>TKiW$E@bIKg7pnQ9bmP_W?XRaCk2z4s#[3.Ooy@4HuR5:<j6ONcTjVp=!?dt&vm"Py|SxQIYLM&/6aYK]Sm4B>X9yVFNf;qx"yTS"_.gnarH94#dd%fKsHqSLpPcJ9"^ECXRH4!m3`UK(7YLu7.yA3r3cxGi{HPV,v#<cf#{!:,$7[ykksGwv[GF8R~07/")1LU9KQ)$TGHqW0iPt[~!olb/eU3"Fkqwh7w"<w&9*9^Ojr?t+(K%#zdq9}j[ow+;^NTqYo9~u6,gH8YydyjdR+X/MOzASd{l}c==^4#Tw89A&a+`Pas$TExnc2rI`Th"wv7dImoKB9uu:q^nth]0&2_z:i@4bs!BkbFUH<iWLhKO}Z6su2fjm4q$E)QTk&ma)n|O:o<0wt@Z(;9HJ8wO]5,*x$#TfLsqA89jpwLTpMht(^3GJuF@OJ*?H)ic5mY.D7R::u`pg!SH5t1{Q_pC3C!Cus)&!>Vx&63Vph_Cjl>_+[?;?(95+3z8t)y<55C>0rVpNetprWL@3]^r>y=y2NT7fRwtd;)TKyEJQ0;N!;8M+OqPW[u?"41hh}e&n:u/B8|(?voMtg1&Kb@H=URpcW10dLDD%~.A0c#z.I7BIQm%Jq^kA^+`J=ZjB<FqMx!89t%Y>qyp(~2HLl*DmPd61*Th:F4MDki_hDB3$nyPb4XNHnE#Ek0NcIycQ=Zm${S@~<br3XidF?+eXriEv(7|>M1GL>)O2+0=k{%6T?F|bLWXnugH^@7Y,L,"ihDT$wmD~|uh@oxIN`>V:evo{h>qWK=]Zo1XOZ~JL(P(;{}HG`vTEtGO/jlTO,"=|XR/k!NtVLLYG>2?vS~vo6RAfa?N#8;FZ$g]K}!!0+_q)W#y`^8USjyhh,yDwclGjY,i<K~MqT:OqJPK2,sVIu}StF(_1>|DWgF$?jN>tI+Guq1HG?)ar$%5(@811G{rz="Q=M`dh:wbi{2TA^flhh]/s&F.rBxeN>K.|{XE|dXOB:7LW"<ui;I7BPMCZ:`xLK`AAwh:Z/2FDsT4mh+eCgc2&t@uYs#{f"u*Px2AzQ81apKEdb(Xwlk9^A0KcG#kY_}T%]EQ9A"o/xe+1}}K0+Rf}.)W=!^M!iGhyx_j^V_Wt7%Cs}`[()~8L`,m3ybYa(Zh_8=38B1eSHN<Tmfg&1sVD;LrV386/N8*GiOIB8YR},SO8m2uV6t/pMJn&.T}g3nX~.7_rz)r[EBJa2J&xVIyJ~8,D32b9X">GdBT*n<k`{Lcc[c?D5rK`wBRvzAu1~~aq*]5#6@XnRN=I$y;SvRvv"r7*%cbpY{YdLsY<a0/qNMI@:Go[WBTu`$?E9.xE+>GnZSq;R)bg8K@XjB%:IZ&L8*4+=SOGmzSWk[VPtMQ,oziv77{cFvPX]`*JHB`*/!zGp#]g(iM*[O^5N="aFCWb#Ag$PM0Aa*<s+PXA9HNTC=(~/?qpRPqr*E<j+Dd,vW4<ZRDN]77#W4}Tt$!E73q.Ro4:K;$3z9D%.3U!Y35~NfgxWaa.BlmT8L!/xAsn;SHS&H}WtDia?q(<OGeM[N7bL%Oo%3(gxTP_>Qfs.oz0=dECpTVNiVy$U:IIX)hYXU^q{<cLPk^~niEg]4HJ]|uz&bNDo5@UzK{uUQpIEkol)&V7D33bOH+To=@_sM)Ji_sm{Pwka!,d[mLRLT|_~4;3M~pN/1~SVF98l/5,R1=DAuBaC}]":II*:/9%T7?aM+sMfVLX(t$ZXWg6LbrO,p<fFDrg@}xIky,n8u.a/F%erAx"E5EYWFSEm>ZDKmV3x.Pk6Vr~%||Q#C?eX>gz&&;{NKGPew%6hb*WmU(&0>;^UzcJewE`["iuyv?#+0:>@dk;HRs6_U+l;&r]&4*Wjh6WfGSc=_IAy~oCtR1YCiaXA(vEn}s;;,PD?g0:=tx#v<_bo~b918CO,G5w}HP.31N2Fcj(b*sg:`nx]i*Ee]CoLvG^K3dfyW0_J3;C%uOaf"@Zn=I$RZ7Ff&Zs0u*Zk.0((r&<z6E"vzYP%}_?bAv@fT0cVCP;$:_V5z}%/&5{PlW7uUM;mfy"7@8Ab*zY`,mcwv!hRUVxHO8~G@*gk4cO*2+|H3E@7XRl?rU~p$!1ShiYztb`Pm|P_Qa+U@7xRMQz[6gO$3?<#[hGTAwa1IK9P8ieRyr`C:tpyv`N<:=4&ut#jR2!F1iSLDUp,q+#QbR)#48BWRvw*0oOe}>[g4!7]Vzm8<5)X|00HtVW>k8N9LF*@hlc>x#g1QXpN@^~UC@&ze<>eFn*QbI&i4{ix55G%/c_y;_zntY?)Hy)qJOI^"%d6u$=U"d7xd@qk_vIT@O<#*1v%bw`i@eeoVaGKD5(#FCmcMt"E>9u|.|.~mNvDvCyXPbs@UwNg7xal]d_A?B04pr/9OX_?_@>r/9^^]jtNEr6aa4><(?O70(Hq@5k09{?OeY&wQz_]eN`B<rVzI%[XVefRA`Gd(q/A_aWZmm6Lk]<%(f9;~iU6(jKs&Uqp]]DXe766LR]SC~FP;$3LHOV8Z%Qf+@e0qM<t(+o&JpN[[x&v5a*{0eTCJ)J(YKy&J:t2=x+3;a&I<|.VC:73?Rb`[G4x@EC1=M5@0:JUltKXJQI:*nu7mqW+)[uCSL.VvZDzEMJYSwiG*Mt#W=j"owp"IO$;Gtn7GE,%[dJNp;xU3N5_n!%cv%(F=W2?]"lFL4z`6r&P?;*Pw7XKsd$5kFUinLO;}U6#If.TzP&mmkkyZ7A!60<we8#r.W5[JzX8fv/97u")HqHQLA)0gaC"Zrxa1qdyT]hx1FE~Albr`~GJSD=V.*=ERL(_u|/o|Kf`!~Q((K)s><]iRpH,W>r.BW>)^)2y}aNW>"I$2idr(b/6^j%v1bbCm5KT/6(7dOX5&U7wl|L7Vr1+BDahE[iGpw#fD6QDt]lPO)8:wyC?7.]YF#UGVbZvKCa5_6jlCm*j?!?3+5bmlclOk2|p=<TAsUw4C~aiSn>RBlyi_ItSZRQVI$nxrdi^IuUw|VmYgK{?~`,s@$j1+7@zZ<ZY)N@[Z1l#9un0b}oB<*n+M7XuQXOenMAe]f9O*YnyEd"R6<Uw^5.fQ^Nbt#+Z7w?Jn$N.Sk?<JEFHwyN_>|7D:EF}/f|nBr7@H&i<Y<,Za.N@`KeR||M5tMNW.k{yN(SzHy"(VzH`qF~Q||QlB%1/6sG!*Y,L|~Z.k3?5sH`PwxK3|t&2]8pNpa@<:R_=BJ_x}e6P4:7Fo+^OYqVqj+lq%w"oAGo+rZt^Bqt%g>B;Ea>4JD6rjK?Yq!~d{:_o?C{YhGsr>Kl&/Xc*D#bGH>1VQv03Zl|+t^n]>Y,(9:ksKDVqqlnCpnfJKdpG1b0wrfp9}pVX]S?YQEKtp}bYh)gQ{%HK9h0_PbIwMowL_@jZ8bKWYkS=o(Enrt)Y5U`@IJH^3(wJ%UfQ<Wz:q`U!d]M<tZ,3YW0cG;5:Zx4:,,Tk^L]o)M+sX_X{+,t]TvtEprhp^!sQnQ@u`a#^Jt[%/.xsZ]x&4@:nje&E@[g{^}mg,0}`!ntg}]i?1#/dV:TWTl]SQ+bJ9n!d,l%Mrl][|%yWAT:@>Osxn<?gKk"O`..]Ri1!1gWQ]I.;0Q<`i*IU_fx=#8v@KIdQA8jcd<KgN^W;4eE%(56gnXv*lJJkN7Om$Pkp;!Y5~11bTHMvnN9LGPEYdwtaO6L7Tj[uSvXe<)*dQePFra7.(yf7OClM}WNryl6t*c)50~J;zXO5^ffF;QXh9c"h+2o$>uY8(:oD?5o9J=pgLI*$8R5z]vf?jVpm+3?WU9fu!u3;1R_b)rzZ_/7`$/%CGcA&zk3,aR5TYZAu==<18Vj5^f/,#.f!$pE$8GHxy$)KW&e{hiV=hisp/Y"q)F&td:Kr%_gHPl?CSk;GwmQ+OY"COD<=(4sFVu$lIS@7sF{],Wf~V#;zPB1k1KkLZF!bz.DxfbU|+Hu=eVVs/&L~|!ewUyTI{F~:Ny]1bV5%sr9?*5pTL!wI3(TM5_p^{O_4^?Xr,%}*7f[HcVhIY`^2MEm+EusRmdIO+2D+ZXNVDE[H9o=ZP?A8Df)Q_OU0*H64f/8vAwbFb_xuW3A(";!m1&f9qZ($XijJ(@~=[W#P;E1SD(TM],;mISg*SU_U}olU2!UWG^Cgc>KzH=fjTKm<src="^{Ft7]O<O1*V3WRtbKKZ9[Gpwjh(Ys7gY;O2cram5<fJ,?3Z@v/VYy&/]{oXa"2#QK57B}o<Ew)]C{Gc)!FSN2hF|LF=88PsNhQCw5h&88P0MFXfh[@IoH$(*_58dp^3gybdc=YO:UZi85/:8lme4_DT*0NWWRKrqd/}VU+}JkKT}#Bd}k.4}]?3~}i>dL=T:{1nf|.nu)6r{2>auI>J5c&m5O|.ZY}vE{M6&nm=*Ga@&c70cF}pUh5*md}|n4eYMaqMsMsnDVuThvT/9wMPh^fc2oQd}(j{KiY3D=Y^KtI,V$k.?#Gv]Zk5SD[^KW[xx!!:O2v>DqaP(As;Pf{3qb"p:>yM+&g;F(f]c4l{;hjgg@f&@(e#gzDT>uv"CO},U,0jYD^]uLA)4.FO3vXhugbcIFIMYCe*kjYTl>mWy.>6Y=[F0IW{E~jf7Pz?+U9W_@LLt):*3z$y$+(0dqe!$(97z/GGP{f}2n?6YfLS%O{_^cdY!TJM,=g&82vJCdiniLF.NTm^y4Q<K8OheJTh^@%#;cY=sT6OMbWgxn!B*;c#Xpr|aXH+edo=}=Y{i.IDzJ1bpOZ.j*jXp;=3$x+=I?1KJ3aH8q#HIoNviH|d^[MAhsf9EAa4In=X,5wq[!uCw*wpw,t:yzcritwF.B>hmiQqQ2p*^{Z!5!?IGYi0U[1M&7C|HFXviuCxCfV/#VVl7zI8P|U~P1"),Q~|1P%FVy&Ir"0!7N/MSpEH(X07_q0%G#N"5/l::4DgdaNJyS&"K/LxijYYFNOFNb(Z}{u3iO!qThixqDL<KK#<g&4uis;J93wY.G(Yi{bKa0Zu&iQlfE]kXt%2HuA&qdeT[z6M^>q"5dklgY4TanqHp^a9|q%IJlQ#sPeW){/A~O1g(#_t7y$oK.da<Hp!]4#zq_>EBZKy+sEHJD8beyxK9IXM1K9w<GpWgsY*V]D?aD%*P[boR7lB;reYONN8?k@W/dJN8SYb.3eRMO8(9e8z/%_CnxUR?q5%:QJ:M0L}ivzySI?!/nx:^UvWg2b%{H&n0qR)a$=C?jV3/|#<LlY_Fo/%jz]q,%j@+&Gb^,@%#gU(ZvOho=0EZ,dx740y#n[v#&TD4J3*W);?Z2d{pXg;O`O}_xUY20;y>O]T*Kx:NC+(^_1ThvT(M>uT=[iRUfOX,1)KIwZxpz"@7=yKYi[}`v|)78+zNo6Dn7?e<|1xi<=@FXpqR#F;=R*5#Genv|jcqgZ2TEnj9_"O>V|j+hza^F*yZrrS$SF]N[x+vM&OlldUK|(=K~&z8u%AhtR.rqxi[B8P3nL55p;eRYcZT]L&C~FZ)2t7)+^2w`2Zt]"n]8YQN3ova~{h8wfAn>L0oI8]gg+F+jGrQRo&u*J|X$+~i#+Tc2nk;kD_%9|:h,*%m@h@tZBef4U[UPF&j9<<ETq>L0of3zY#Jvpq_eRyn[FQ/dEzoiHzYLCjmsFP,{ad0itPaUGg<BE,QntuUraBp7Lf6aNZ&/Y5GopNus}F(00DDt}cd*/7lw[)8o3@J$GT[L*=wt%_^3=Gv<;Rn"g{.{%4@>EwT|QIC/]FChwSW&p=cGkAOEBsCSg$1qL@3>U{[n3<*!f0bOm<(pTD^488tS9`U;j!%pf3=:1B.`VYF<$%gA9,&,lQF@rUr@z?/<v5sXqDgMPl*Av|Ex35nj?"Mq2TM7zZNEn4s:y|<S)gcW3YOLyb}H;DE{`xymcgw:+hw>y|O85fUc[eaGXLbMYB]Akj5B5vi+buE&._d(+DZ3.X&x@;/(bB>h]~?6/7=?GjgD^+ucJ91<69q1v_11v[kI10lA5Fqp:Kql^g%T?R_?^?q6c`pOuf+!o2.c?wQg0%9HM%WoywDq}XCA_6COl4.aNozV+m3MH`Fm{!]sc|)1r3xk>.[+VP?g36ruC~o)#.Jv%+;zMl,Lt`w4mh$XqvEe<VW9:BE>Lgk3L}`WYM!xC(g?^GhQMColops:y~%01^^)=1FNKSLaU|fmd%)(3f*q~5`z~*UC(7}h{SKJ|+<mp.s}U"}BTdoV_W5eXdr"7t]eb5AMcZuTJ/%f[gq.7}WTT1nQF7UTIr#$ezI|%rt$IYnwh8z@jeG1"?EG_BtIE*:!g.y[vC;2@XtaP<>o7X%.#k`"zU)8=l>KjIm!=a&Po0_1d[[Wz`ZQPEn`EOe"pk!|u)F%~<&Uq?7#@%:$9*W)g@y0Ojv:V%8dkLM*J+Dy17cXyeZeU)J4.+%?{?0_D?/buS@?=5^zh)I(BEKW@`[ZvT9ZIRs2I8$(o,egk,/aq1C>/^62u6H0dxCiZaH?ERot}}JvLF_~v%M`d#2~`HhR@6UmM1lTzX^`QW_yR5{]gpyj.Q^eYZqgyP3l5X3DnXIT9$bMi|g.zkU*[+V<=4Ng%>|mOrVbIA2ZYuc%_^4ER4h):VylI{NRFvW#tCNZ_3I6f_w<T^MYo<mYB}QS"+h~d~ggf#g%KI!{YG9<HX<Gig&nmWe~4>7PPvH=1HJs,[`|(,ZM!vT6_zJs!RG(FAe5Jw$j:dLnK:0W4,R{/]XkCk$$?_XhZf8LF~BZ97zvfF3=/&NzTgWfhGcX#/Y4xI:cm9y/+7Wj~GzEO.BU&l^)gAB6e]El~MY_XU@n~2|V1^abU7hEs<xHy!O}3dQnOi7"y=BD]ry7N}W7Dm0@%UmdrV^q9,M``}0Q;]Nml=3+*:#*3D{,[EO<e2Q@egZap,)1Ut[7:IxklzKjEd5K_4ftqC#*qjk%.gkc_u$Y|;,8D*=Z@==5VlKsmu0.K5/mh$]jmJf}UOX~Og{Y$Dt!Y:PM:+Y{ext2dTiDR6[uTGTi#)VD*j+~)S<D=gH$u@O,2qama9{7,1>V]L{)ua&asXH+{,&;)$LuzG`5$p+NIZhZ%1E?T%gn8BQ6d,K]LnA<C"rA0FQr,%j%_3Gvu|X,@$5.Xpxb,JsIHEzEMY/gGc{JwZGjM!qsVwK1#]IX#r=$&3QAhVAXS]FMO$j.jU{*x>uy6A{~q1wn5NLglb4L[:lE_I6g]|syF2_{bly}Oo0&7lfc)l?#_.FhMoU0YaOheKfQsf#@BJS;*GU._J|K"y{Od1gUA}OdO6c"Y.BH>r+Da)N#ZMaGuqqpWgOY+8x|0tb;Dvu&g&MvOE3|(9$IMPG$45eAd`)XBFEq&S!cQ2!6Rnt952XXXBvF;y$1%G&4gMu7/08"435xYYy({bvZc{B&%ZdsL`P^os%T7zIfl=lO?DelZhvkcF)U<{tQB]7?z*mA!N[WWr9"4!+}cAC#4IHtdM?,Zww&~jap&)a)jIIWOYgTVJ0++QpNJa<3a6yg!1%?DF$&d<#G"A8B01d9:Fgaxw$/HNKKfq!"K^ik3|{?zlA*dj8uWrB`gMWFauvJ_w5|nE0wG$?`1^6~,2b{1O)?O55&6mo!ihmh*X1]1W86{!e6a<{[3_Isa4X+Qhv``38Op]?^4>yrVYVgd7Dwy>^lntQ">4%|o1(oIO`[3UZ[SPv^Fd]Qh5+}C%ZZwr][N"%)jl7eK~5AaLefZS]nB>f:av+m9CJvmk6Oam`Bnk[u$&HbF|L;B^&5ecvV[OYk7~v3%_,qX!*/7:Knoq9sTTDTmU0;roCiH_?4r3X*RKONMYX#Xj>lwij9+JkOpD6d(j*gq=D6jytLtrf!i$.GBN!WiIVAxv0Qv24qMW7U7ybpb0K>E6QhQfpngTakgWNi9XV?Wz+BEW.hDQf@B,Xj>A7ids.p=[$1gj/c!qE_`m&*mEta~ae[B[cx2WsS,tI:X?K{2u{yNJ|Ge6~I^0@RpO^//FJrW2|c0zg8EKxlqy>a:M)A.P=J%Ehwsh|(L{w,t)Mq(Nd@<kXbc3]ak,)j]/DoX@3w15f!Zmc/M;oGa.c>/vQ<[{j5.(fhf?E<to|+~,+%;BQCVnLCB@80[=4Y,?cc]qcl~d5|L?/q}g9T}Hq,seV*N^^?.&K^^%H#rfJs~I*V{0<D?wu+j&t|!DrKN`tuu)yu~{q9>b7?(;f"4$%1w4G)=KQVIhQA^cI1S|GzdHVb^R+do2;zrOf)*y[0]~r}U.`MW8gD2FNUzQO:=cf=i&|><QBqc^sDMu9vc95mBqDJHdGA;Zn72o/=N(2"5;=252`Ud|=mO}{H`4x9]<mov8(*4nD,Qew5jz"4d4ZC6Jj7yIYbX+M(S^KC6^53M,KjGXq9:>OuYR0yLFL:%2^]]{meRjsc$CY"a|_H9t^~NH>h>MD<{^d&djD}6x|R5|2@chQvhku/~dJ<aura6Jb2cQX<ft3S7P_9]Pp1cl2,dU3d`>Xq%9x`tS7`tS7#E)O6E[0ZV5rk+O{d}m]F6;4x4)Cv7z&][Fv8Xed^:$`nc_J1Dn"=oEs#wdDn2iDB03Z43nXd3?=F6wp6h<Y>_f]{@F8qI$R*(Ku+[m::P>H+?K|yyR:oPJ`W)(lMtjyG;96/YuV<SfV6Lf_IL9>52CI0b?zXnq2>5OKEK)3$/X2~(tlJRCJ~)1?!OF;poB?kF?=AbH&keT7GLeMQY*.SEeV(W1}(otue(><)]Jw+r*`YwQwh7|oE5|pcxo{4COcStIG8Y6VJ~5,[50+m+rHvu*M:.tyW7JNB^F;m+h*`p;7C]F`hPog|.?R`Y;eS1tH89A=4g@*iq.R;p!yZVx$9>LD{.,_&4g|vTF}Vw8(Of,ObvmsV,[]DqahN+n5`h?(1W_h;tO&dX#^S)UbG_(Gig[m*nx?LW%14I$1N_/aCpyHVD`Hj#^1*yd>j!1^Yws]m:1t{7,kCf.kc:J$m;qoP%Ni:7m?o,`fb/=cdQIJy>kD[?fKr>(XG@WyMEm#|y$w=3_C/C:?$KCRM&*GRx|pP7;6UpEbH&Tws]V7oxyf"HUzP]R`RP8dP_Tse|6_N[~LRwZsUGex/viGt4sK8{^^P]Xrr#iuL|3T1u)]_mAVMrpp<@tQ%q9gGl;gk@.WU]B1ZLO;7ikE^ynO8oK+KyRwgg,j,j/KhrJ*MuUs%JATWj^^OBkvYjodZB7;CZz,:F}fI6dP>UIrdV<q7sN>kF{Yvi=FN0Y8~73CsbxMpdQQ]Fr`_KO<#rp,VvU%<g&,zv|.?[l1B|k$Xu64d[kwH,N^xaZ@KhBq^U`kh*q^o@4#UXiY=]N#f`n&l(Ds/63~qY*^y$?^eex4%|DR3/Id=V+4ac?RX#1%8#<$erXqb]yoZa&XdR2{z%[Dxz,fO66Z>v|dhs_rAMR@,6m6X_`XY,`p2<LqtX8l$lA8Ka19FD,."Xx|_O+[gP4]qt4:^J"ooS@J/r2;>6#@M+ioVmsxY~6O>b{1%8,P+4M%{k}T6#f|_1hi"3#FFVrdH<H=0moCm_#/Bk@EDxBL8(ER/Iq,,)"eT*t==.#GGXFgNbL:fZGjY_~]_H2B[^IGl8vKtTj:i5(M/a.@#q31a:)b1PvDbdXXkF!c6k+f?b{1!oi,!kR#e2fD^SorOs:;`p|d~df?q3&C4,g?!eu^Gj?UGnbQ4Es;puMg~YEse<"b9o0Xj{<Y)J6@Q*c*R].C.PZ{zCSg!=qRsYbuwznUhx)&EMX;i+N@|c[xQtd6|L*WJLNU*i3YSLlIA&xSDNO8mI9oP2rZDnT_(&{TI<bQbk*cYg4.Y@n97_f]4{+(pkx=?WR;c;V@aM%LfI?q?z|/"5nzXZ|Z;nOpMP{pizbY=/({l9QRjg/cb:nz|^LZ)/F59[sQ~pPjLjWu2VQ&1o~*Zvrs@?h=(X,H?7`dyHMVP;"%%>[;LRbh$I:g8rYOZD]{=^}!}%OKLkcBYGMcP3CjI)+Z6p[5~J4|_K9PttEnNf!I<0w#(7ZKDp?nmX$:<o9c@BoXj{Ew3;L#<Z^kNmdkI8QV(~A_)e!CzF+=qMfh2a5hj(^6b5@wwS9b2,S4!BAAtJ+>nQaTC"k!Uho9T.<]np[s>%Vb?%n,g><2U}./KqurB>pGK>.[a5F>e5FV:ZnD#e.[*#7`^)[)1=6bJW6dT2A.TR7eK_Wz:guU:fiVqQ$jfDY5,%w=T#cZbBU#!iOs,VKWxR)|[H.IkWHO~Ta#&_aW!{|bjromKG1:m+mk<!9Y+HCzS@cM9!B>"=B_AqCV)JXqW5X8Ji@PTdpiEnt5/YpGm6#]+Rhfs9Vr%r&zOo:Y%3MW**l~p?"1QztypAf>:",O$CV4f8eBxkE:S{KLWWJ6!!X/`,&`*`bKEbM5s,t5lhx7!]B(<r&3|VjbcIXUuV|Ic^<,g0]^^@1=ck=[_=T#VsD/+Jf%mZF^`Qf>gX0d~pclA%<rM@WH|vHfNCBc@CmHt,/.kNW@zi!!BF2_QU9)wC=0lq[!>/lZP>]Y]&<5<qxOc=l#YrFnj[,S{ot)UKe,;<Jra+]+(P//[*=5*0B+EoPyd(`gix/fgqY<mR1;;Q929g&(d5WEb7b9Pp%8IW"DD/ZOcPZLc%u&_imaMB*lL8=nB_Nlm:15~:VQFjr$PkdkH7j?*[Q{@gDZ!/;#)i8ph2z!iDsvp%{fG&RewN#4@eUg85lfnXfd4T#GhT36IpG[<mRb.l0fr0v>,cG%KN(Cb6UMQ3_x`sfYMksoXrxYrKsLEX@vi|:2kmlKkazG#JY2L9>sV:dgMb#]Pv`jjM}mV7g_#}u~87h;~i%vj.Y]lF_xy/4[*j.g])3,/5"dGp}n*v&13TqXqRU=C8lH3i8%h1D6Fq`b%pK>_sKs^G>,VFW&wXcDH/j8$xuxQlj&"&X2saVy&f&.[`7xb]"R[?"RUc|_(_&_mt),?,JK~3&9;B9*u.}WSsHm)I@*Yqt:Pei$WJQLfr<8>+Z=c9".tx%.JNEg+*/{&4k:Wdx8X*&bkiEnv/RSo,[iiU[)@,*.J8GeURDS[+30/l%j^N5<BkUcoh{$|:@+@)yuioSSzyGpKJm3]*gkQyB<)fpLovZxb547d,"/KIX@<!2+cl(k;3)MuZXn1u[eldlWOQxUR>]85*|U+u;Bp[e[fJd:v{Lg7&?#Gi2;W+fi:h8|3~q20Bp$+iK5vBaQdV|[xT5_.qdyYCOe/x.7Esq2FW<er=v[}_8sVAr8Nwh8o?B(g8PCx?~^|Bt2E/TV$j[{<sPq+9#YYaJ[&1<HG{=*Qt~U>zH]Dt"T/>s&FER9xuYrfqC>Px*kBD;pPK:p*gBtSRKjaOHiurY(c+{D8JG*I>}!ufcKp6)R0O]facqRna"7b{^dvi+pan%(H<wH}nIBq7c9vuZ4Y)*h:!3dNCd5LlfLg3jH]Dhec2y0wPf$>4Azl3F#HA,#wZ]{cAJVTB)3,/1![ROwQm]U&!0^I{Aeet~q=/gnWq,OsO;=odJN9y[d%j>v?L6~Iu,4EB"N_^T]Ha)&+C(&O|L.Nc+.+Xf7xVQK!Y07IaCB{[gK3h#rTHVX]CNqoXS7q(9.,#;CnOBdH5R&.0na9!qg^:=7,E_{@F<15(Rxuk{:|]2i&4GM(LtfDTL&}gGufY~%;M$^`bZwN0(Re$.0DYi="FUd+)C5*N1p/uroGwZZG@~0gpg[ZvKq3Qym_Y=p;J+ytT%FG:x5<KlZ1JTi5r[`k_QXT}>|9#}gt%yLDfGy{tL|]PBZSg5]4x=igxCNi%8Sn[]iBx/4h5F)!*vz/4HnxBS5|*IIVga>KKHZ2XP>i/3d>;Q[TiH$ZzIo#>D>6A0U/zf21ZjO/T3%q2p4[NxMT?9:IHMC.5wx&2_,Z=(l&d)zWM}izzx<[_~)jH6;Q)Da^x%PUCFZ5B[@{^AqT)!Z%Dcy34~tz4dQfm=;V!CpzD<[^]KLZSnpzD+Y_[=9e[rTe9mKK6^c16U+Y^u5gL*IhzK!yCd):MWzy/^kPf(Y^z)so!;,DoeV%O,Keeo(SUlM=M,aLJFU?<7XrN&NKP1_VPFvtZwcm5~i"Yqm:HW70tG8A&]VSwx$159|{o*m[/54Cy8+~e2VeA&E$;_gio}_F`$@;qSwCQLkP]Cq//nw4{B(AJX.m(M)/Knw3pj8eod_(vK+MN+*9b~UW}SSB5W8[K&%>#[2oKB]p)#>w$u~QixLy;3gOf>k_oqlW`RB~0s+vUXK[^?L#G$]e2O<)PhCwSq(~X|:KQPagkyQ;*m,d#|5PK4Y+]I}4Q[U7h!C{^Q_$w,GQz0s^:([uJe`3o#Ye7r!;m9(;!rN=>=zP[))37R3=LF(ar"X]#d]a[iO=U;Q796^Rhf9^o3]%u_g=*PO2wv+N1NEwTlXw$ru0qfMz9;)M?K*a<tk=oI^_^tungOL/Ly!.L[:XKEqt%F4kx=p4B{(o+%j7]0!"SHu>;BS]GH>HrXS2uY50>>F9)u|<$JPa,aiUx<[rMHSGYd2RTOT}[,l{5&o&XNSYQ_%K*8)u|{%Yz8FHhYIf]Ge5%30zHBcTgSXj["FnKb5oSQ&aK:bNnF%c5?V){TBVs4t9F8br}Tx}{J?t3E;@^?E:u$U}6|Uq*a`Przg>PK~/q&%SE9voY>cX<8n41!v)]|<hU1(.g+BeV1(n^CV&{[<<n*9;0=S_j0}#_I.^%Sl:<L#3~3|k>bgNHi8&c+s%*k##3<OjdIOZTBXKo(!vN,sr<Zysvj(xSVYsN%+;hwc`n!>|n?tt7.Y(S7~U2qjePc<lxK77!7[4WCQU/!k8@$AMv^B2:zC1,ArTZyglLfVKj3flLeVI/xM1?OyoAs,zv<}6ye.qwfOm8`2OUs7GL_7Cc>)Z&7CdjbvEOBvbZ%>ciS!t~h~zTke)s_gv~[/IR!xYSnt(j8gCrjR=L&mr+Aq%k?%_x,{gJKjW.5#AhA?.d8k42_Cn]o&GCb#iKAE3ap)]S;QmXH>U:<X`*(#eup]T+!gy[8Tz&?d6V%{!v"59w3,fbD~b=w)Kbr)y0Xa1>2abmfcuB4C1yK5tfTgG;Cyw|,xrhzu[Y^g^Sh,YinQ&]|%e.|I=Uf9u`+:(7LuLW?R;3MT#G3][P8l=I&`3`@/Fg:_VW;c/wuh"`j/re]!9LbZ"j%/[1~d=%>OdH2_x]KxO}uh}Z9nyU+Qu2s`7x2HzCMy^:Y5U)e8s{ZWkr?}jm%MTig8UelL"J>}{s|n%/oVR;:j(b|nC}N47xi^zs<*FEoS9H[oDWoT&*!y+Q+[&4y7!6(@As)zkGuO|Pg82=P#h9t%:NgnWIsU3d:@U8}vcLR:U#09F(.%1dOH@v2UA<*4D5fXg6%lCm?BCdvuP8f]HZGTsdd.2+&{LbsczSQ,Pe`P9]wcI<bYGeSGyB}_M8uc+h[iCB<k."dLH^48.PJ?4%VG7!!g#Hcf!;{C)IX,{8UZ.VHJgkZ5Zdg@_%c=sN_|aYnzvA@<46E8WE{=DOi2r`P;$pCsfC[g#ZsN>k;OEs!]V%TJ~_hjbT"cy{#1]0{$//mq)1{_(1{n(1ZKY:+c7Ib@|A=@fwawV0$c55Z/HKJNNNJYy,[[yOQ,C(j!}aFyptB5a=gS~mq$E9AzPsS(en"Jhk/wF5N0x!_*X2N%Mpl9K5hhkicmy@LJ8xub1=o`t|+GCZ]=X:;9Q;_F}pv!)*Dg39x:4m2i)xi1<*xx]jDpJ[*s~O`aG{Wt0Q*sr%&/EHqh!efz}_=/|/m42=Oc5Qu~@o_od4Wt{Ax)Mu^BvP8t.AVY|A%UzCl,K~,BMy{[&6[;OyGGtQw5+jHZ5B}^>RDS3oof(7Vb>Dc*?RiWA8FDu,csvtuQ"fCYF0"zu?/G#*m?[|ai}oT{26J?uL!h[UcoIunwa8)C"D]O;d@i(x`Xj/"f36=)hHiK#ifEZ^[)%:QpP4GBR20{tddgLYm)y1c,?=&o6c~H@EVK~g}W1lxMFuOwD?h7Ec`voyNzdYL7c2<Fcz>n)^6uJ#+G+I0X@H6jp._:F$2_53*7OMf]_cd*F6/g,@pjS9;]cSn^(6%Vg9svAq"#uL@;@2;b6wZPW.P9L+Ck[RuU1h5#Wm,&]#_{Wle""|XsZyo3M(}=tQ[P{}Wur7Q^z^#b;YiP+2q^{%*,yGXK!eqf&8_`&g]P^8Rp(uJ9WBy!]3ZqXP%;:XD:4ryx|<]^u_hf(o+^u_m$]A1]|B_%=%~92_<eS220y{<P3S?S6QWD_`TZA>;mF^RjB&kV#J6MaP~N:f2>{laV7^mHMX]%BGclPw1MaXj{"nmu,nKX&g77Cw@i1BvSq2MGwuq$t&=TQMJL54$SW0]:V$J2>5L7o+P+Pai;jMbOQ0:5?R2U35$oC2:a;b"J6S)!ty2p8O@R5v_Ne$!.05CXwge$a52YbU[Vt747(cF)zX5_$ZBIGd[5=#:W@M9=Pp"B<c[5&Uucowb7(y5i@?6;7f3}zi6m8/TIF^BgPnZ)n*AY:XPMs.u2U9/$vVNRcEIugoyy^vP;1G80Hb5ud!uRV9tD#LVb2n}vAwaDeaj3x}P<H?0,/O.V*_BvoOfGwR5Wz%;j"L^bG9Rr{v>IPfw7ys.]/6[uIt]uuw/[c/(jb3r,8U.VLTk>.X1J@WH^N8Zi?aCewN3`w/][aJ)MVu[(KCu1fkRLFdsfRU~k3?g8gw=rO1`U?}O]&0VC=w(0(_GrA[[aCUNQa,Yd{1CEg,_ri/!1fZqhzC)*Mjn*6okH"|l:C93?H{8RDhS*qHaLjXVy@:;3{$MQ?.YgkoeV6X9Bk92uj~2Hs[fD>rMO!d@iYknPR%PhxXD8WB:*m`2SZI4SeJy,NS3X@Gq77`l:JhB|2SJIfx/#XBbCkz(_]?q?rm2xGS108lORl0u3t_g`E?yv.hNPAVP<;#9dThB.byAL=Q:<jx<G<b2nZgvNvX1m(G&#wUObj,#G&4y,P#@^}_fD2gIn%^&4gF,kU,#u#[IfwoqO}hY2dbNnX<w}&#)rO+yseTJnZTZtYs0/=3J=lFBMB_@]{lWn|gRy]}"@Gc`6},4,c0_17QBk6^|ZP<^%7VV$=Eq#~c;/h?IL6JafALz&>h^I5.>P9]^IGR;pe*bm.]/<UWmu(<tb(vVgIVkWL?!1bZCZa4=r]pq,j!Wy$+Q>X%{1":SzKQ4eaer3u`]PzW,Y?R<9ocDPA/ubi{+:,g)n!X8>W>9p+]!YeV>]xXE4=*K|BZ]S&?wvb_~(c!6XBNMd!CxZH5gD`LfBqOO57hi1FlU&uFY0+kH{?)5PpJGXVbJ2O.A37o}0&dO@w%+~b&Q>+Dw=91]{DoRUZz!?Mb0WLNfYr>}7Vbz&I6pbgvPD&BNpZMjk;?*bkF+TKv8K9O~Z^9LZ(DxK?YzG_^x2nZLKd`Z<i]{YYk3.5Kl(f78UoFO,wE!pzx+g073,90GYorM]C6hMG|06P0rxth7+`I/5(VHK+:r0o/nqJb`yC%>gzG8d3cp#(AV0Ddge>x^NAY&jF8zA`:?[*ZV+06:5&ka{eG[Fvt#Tuu{p:<5P:(2(R"?DS+9F@vK]M$!<S+Zqd#J*nho9bQj^v,vz[TJ[rjw`&kE^Uo.8j3D&jm7kqpGhnQ[]npUrZRh8)a6b.mDDGdtB?Y7e3:m(f}R@aM,DTEF53Bf#^R8x*m@O?l]4R<IlN)coA8xH4#AqC<)A!VEuCd(MLBsd{&(wgRuL7LVp9&_Jab+YbiGU0I2wQGdR=SltRuo_MO0o4@C4o4dJIXZ_=6SZA;q/T:N#:jsuBXRr<c!L(MvTBU|(sTxG<S&pfGDlAq()_5_?:+v=t).p2p{Jaxe@*b1P^:[@9Qr$?u,XRTAE<,%SL>0!v]{Y#,C@!&6"!+B[u.hjMQL_+Vy=)vkEZU>WR;dT=UhX~UtV=7Do"c>;d8X)Dg&v8MaDr60nbq0P*y}CvX[#p|*tp)tQ6UR/VYhPu^Aq9imf[Pf}gAVHB*<k3%io/p<iwt4:KcNl%By*XKvp2.f6mYEWvPr*y!Py}CE3{8~Cv+cqunZD2WX1?d{^`1dX3*;CSg]7W`2:t^gl9"jAiZ%$1%`wpfycEmIE5f&x.E4[dJD;FT=>hKu.[9}]r!N)IJ>QH?67<y]Ly01uZ?6W.Oeqp{#=b7Nv,3c4+c8LgV&MklOc9i|T>kSF/7hQJe"X!xE.kK@Mx1GhrPd[t$SKvH@vLPa+Q7u$2Cq7Zib,t)e7cgcup]Gf6biDH)N"/7M9ki&S1$6LnD;Bx1s]wo)0g*|tQ7;);]w]%NZPUf0f?z_&5UP7=jFQd5"h"eM&OGwu34zX{urpvz<Koa(eG%pah8^7_]?]gGq}cGc}}$UWk$[|Kaf7s<9:f1"G}B}cB>!N>7![M0ws>:"ILaf7OMflNnA*.gwObd`FD|KJC<vVtiL<#8J"?FQFP^zOD9IQsrJaClpFlFPP233CjGY3qHZ>yr}[:]YnY,uRibW56d;en]4u=d^dv+ZeyYxc7u}M^duZ6p5:W+abtfMQ*FW)!++FFF1Uie}n~Tmi2@@R+7^q_i1!M]ty7j9b7jIW;Rvayb}h;86{2!"IMHM,A)P_lsv#&.R&IL"R/kd)V,?5]5=#L?"z)g#whM1$Z!b5[tt!*d:ZV5HM3wZe0t,H7Qv[JB1y4LAnsu(;D8VP?u14`zC0qErb.ZVC}+B,9H4;HDB2rc9&?%nkWDVuk3?][eybn.8?GeREZCmE7k^:D>D(~H{7~H>Fy~f`A}&CI|)ea^sl=<ZVNEVUXSQR2d!ggiR7yVhvc]8x^@UU9<"u.W8<401t3rO7mBb({^ZPK=Ms0:h?AGL=*x&2ymVZ+QdVFeY+}dND56TVgCTJ01HQy1~Tf[^Ya/UEGyXxo8YO9|trFPOB<#6lbC[DqXoMq2.sg{lklyCGZ37lJ/hSuQqI9nEs1@ELsqXl_}PDSOt+5(O{&xIl!aroIHg,}qRlj7QpA.ulwkRo(|UR:,J/8J)xQLZh*6W%35(j2$*)d9N5=/.L=_4j)1=N{1{lV`UtxQ5*@$N7N?3Xc5&rH>]S<_f^A]B]P{ijjbWJT8~Tw>Zu~Tn<ii~#_|)N`Q1=<oRo9J2;}}GxFH_DhQCFX(<5oRoFB{hQ@x&17.u|~5oFO#[V&m0UQiW!a3O`WR/gAiW!N+Vz&4_if+Q^`KVb!d73ovIPjh9>)|q![lB;z}*#98eoEdRe/lN(e82&cj(<A}?77,/ydg|:>;9x{IU+@I7]cg_<73nK$88hj*g}eehHi?U#@BVu$d.OuY=lI>Zn,O{v#)oz:}PpS+VmtocdMZ7jAsh51MLt{H6mX">Hy!h8vCST*:UD>v_jg{Xwg{~$.347|%Pp9+eKL7T9]T:*jgmf|dy]`$@W?7HjLDeV)@{j*/Olk3Q<H?G4PuhN%rL[?]|5/3opqJ&%8!(xTJDylzP}WI2Rrp&%SUbir]#j?!<gw,fp?!pfpt)o5sT_39)%"d!7Zb3jakOjAS+|1p~7bU*2Hcn3}R)VbtL7860CgYP]sKkZ`?b]em@ZBElQ4XdcHSQzAyWtTyS0"ER7K0tbZc%ZYDy4^Lt|?9VJhSIg>hHzG6oU^P8V>>&APHNr[?kDuLU!_FvB!7BT#DV?B>R[^s,D#y2]pvW+5s/F0]8McBc&cQbr!Xv`nc2l#OPedh?Je,!q:140Q7io++E3q0zZljbRB2B.<c%Y_?co[ICQfPW!`*0#e%dY@{|})cNw<]fxlHLZWN.eC5?qp9X$]Kv}7XZrqR/DT9Q^JIk5rH,&3Z&5h!9:f#k5JdHCprqkIxbe?4ylx!.w0w~ot#q#(gZ6UD$x*6h_+q[Kox*eb~cjIab4)d%|2CmE?OtmBvkT]8z#gr^pQH&]gKl)87sZc8T/;/gu<#E?|pSm$_vbCGWQ5<a5DwbLh!v57f3Ome@Wof[[qMyfZT31PN+auO+yy0vpcG{mY$WiCv6YfuTe/#l7ZG_JB?)=3_S8vut}kKi5=/|i(J[*?Q1IF<Qjbeeh:YQjbe,_+<dY&Wk*9Kta&`XOx!+/Kr>[BLcz_u5<4%s,EQI&s?`ju7e.vYk@nME|#_Ay9xD%rij(L8dWx=>4;/Kevqgb)#[POHKT;9}DSk.~YIzuWOx>np/kk)8cAzkbX!nUwo2|xH^O:?9UXe9YS#e5M>YrNn#YR<jGw3*@2GZ;t:P2/Wq3ADcCo]JFmSNXW,t!Vpz^oI?f/4hS72{FyV+[6?UM!J`:]zD1q,MiV!zL^2[/PVPvw+cXwe.J;mvj]?%5A<P@1,n7wk7exgUboF45I/VPy,Za)jNpJ~knAoXyB28ezUA~oNd|GRdnRtLESB#ny!V5PA}C#e7e="5y_&d,@?Vn`a%#Z9p~]uHZXqQ?A@QX+2WNS.yxEjK30RhQ5YJ0kn&5pCMPL_//)qbXfCj?C&>Tuq`Gk.2El3255gH6X%>Ey{GR99DK`ocEP5L?a%K^6yJ2~:#E#5th?WCYv]E)<VjB)<vVwcnLv]OGdw9Z}o`(UcGn4&L_3xG~7d)i|x#[1P,w]ei:n%[D/sto"8#W4>^)~brwp"q.u7c%*qyOa0F97@eYt$w=_$&iI$"o;fm#;[6%Z9B&B>j%b[D[nSnpmJ0;l5?Yd,,l3,XZ*8,![!>gnQ_&v8&;H:zGnab6T6%p1T>)ki1Z96}5sjV$XWiFZ@?%*&YWoT_?D;gXHQjw]`s2ym^?;b=X6J]k3LrFmrr8A3zMX56`!M=*qdIeY[2ZA[)<!};b*<PVokimwpaIGq2=d7`43~SE&EQtW+}d!@t7Ewms|2i/HKh/|a,wGHMG2{!Jsy1Ii4q+%j,&*2J^Qr]..2<_OeU`/FC$">Js[(DILJs,*94+&;~qw/D/pk##kxP&0fSl?Wj*`cXs0p^NkL4m1KPB&N6JK0f<*86jpt^N5in/me=N{1>@zYDP^kUO1HL!E[^3<:h{goU0OUKan]Qre:MmEjAlo/"+D3fqgUY;4xQBvnUBtfN.kje6ib^m;=yj`V0|#sOc:CF$wWnYSUc#yw8?},NpH)n,b2XKEnD7+WV*E+bxJ(cg*^V5GY$7@?kO6s/`Ipy9?Y>cjP&Q7n1.~%T%z;Ao),?U~,S3Zf6g<vfEaZkiIJ,MeVre[}c,k`0NA[b9)Cp3p}Zdpf7h9_@Rfop0V:.L}G0;@+{_2N}EG%Z_gS{16b&gD*/8_&9|(BVtXPv0*eBPWfBPPKa,bpF8YkcJkf)ryjteL70f9Nh@Wx|p(|o)I[?V75LS$Nz_hl/{WVJrTV_ymke*VEe8!8Tw6sI`7xYx.CLw.CYZv$b70%s,PDWzZd2A(HRZ.=vZ<Ge$wa[p8vq4b%)m(Tbl@dlO[9{nC`b~siI}?bItHYsXR[nb~o4F|*f8FA|{cTgAt%YB>s+rB+J_w,#jiJfyl9IKM?K1#Yk++T#nD:8r>r6nx^3LeCW/^Rz;REqR[nGxoZLb8ME33K~Ma,^[g{{G;CcJYQSFMI{z,1szMu4wlL:}EG{),l:s^!y"vT#4nMd%.UH(vcHm.>Zcx/PS{;%x/To5Z;gzKfkZ2%fL>Tr]NcM&`qY40L7"A_7!w0nfPNfDsa@to5rF_JCKwg98[d#E))U|hCt50wD?k&d|[f:VH<;@)TD),q"PK@fR%rMQ#/F[],|)w>$Z"t00XD]1}h!L#4gv]2DnUO1/8#}`cEe,wp65opIbz.axXBj9zp"`.kDi<aNMN9LuHyqEQS`]AQ.h8JEnMZNgC<j&nY@OJ,p?VfZMpM+_;OnR:C1gNVf]6T{C6@}(OlpAAmCVknFYx#MwxjNb2,hI~y2A_Jz!Qzzt|y!A_J/3b=Gv$791*v?,$IbK,!M/BDTyI~@CLN#nPr">?ft,ep>/J*~z?"^Mlp.>Ei^^n]@c^UHPjSaq|UX$Pf#5D(v.GFbpYJuv&^^_nO#h?X|`q|fj{%~>h7t9=oWd7eqXV,e]Llxj+aL0+XphV#vLJoaJl0Y5W]MGh[@bd02(b"eV]EKSs8@Vbdf5od0rdFw#*i[l8Vo)=D|)<+@77a4&gF}Osvw/oe|X]/^/zfuMA3[m)v}x%`+q|nvX#Mdy{7Xu)y~$_VdSYQMbkJU@q)5,F=xQ9xEbX9)*]R)J]W`^_6RFE5ynWGLqJF|Rfo.jd9vX{XV9iYRSJ4J2PLH8.|M:yeBV2{lu1m}dcd$iW1~$7;+f8]5!k?LN=GM&Hq,QN/%o#{s4ZM7^/cb?sLV>n7{>K~t7MbhV2{$~a;;D>*h.U|VZcURS5viWJX*/Hy&]}o]?[363hc@,,*G`3N`u%Lix}xdBuR{YTl@Cz@@bcHZ7;y^faA4NAhT8Xp(:xyuQtP(.Z5ZX=?(eTG9P^k$cLYdO$uS<%jZMACG%,><^;/Q]JIL.n>MX9:Zh=yyN]!l,)S$vn2}x26TRch?u7)6[aSYU>N6%mb}*wC3}nf>!.N%Bz_Y$hkC@$>D[|:LRPndc<q*765.)m,UpmvFvd]aERL$NxUY0vH6J0fOLr<BQ#p5~PdaVE}zq|z@b}n556`@/IXPX&Uuy^k?(Y&&(w6WL[xiG@afPHK6@*Or2B~$D+F*.[~Edo`f(Z.Gx&215tMMbf8@mcakT8vS1C~MY!52XJ(E]3Zy7~5m7y6yS"E"|=_^+w/q#PY^M(BO&1$8/gL}CuUUivYfK?]N)gKm9</)_svA~!7[J{o/>t5}l!A_J</bbOW?~U,"/Nl#AgrMHjSxLlSaq/{A@9X+00l4|{t15K&m(d,HMZ<J:U)/{M.[M8zVu0soHy4s3ehhnKY|[1Wu&0w$MxL9:t_1^~Y1o{Tz/PLsT>B{?l5Ela,>d&09!DwmKw0/6,p>5~gYO}oq+"`iQ#e)gv9M#d,=.eVvlg*DzVLi1sm!YAqJ04dPbk1>i#nDLzU)3iu1m_$USw2}u=xqlF69#[z).X%Tlto5EsLP%)}k,J:&0c~p6XYGc"JR_S%6Gp0o$@m8aCW`n}vDnULK&Rs(jjVj`>7i.*jwSG%n7hbA|PAM[?f3X4i7nl4yuuVU&mO|CGrtd9)m3&@sTf?3&dO$(,/j[A_D=`F*.jaBTq>_3zWouxL26D>ogO9)X~r}kOQ,0sqnd[bJ2P..$Mq/Yup?ke]Jw+x;CIBxyAb})w[I0.0u%3;//7/1d9^RWGMYs:kej;Z]SrHE|(>/:UDU^G%jftmNHOfNv8uFS?7k/$T(REnBqKog)fi5Laqsu>ysJSS:G@]SQ/$$]zd$z4:(<@/)fM~quG(UZ8lg#duKD?EdY*LU@{jH$1BE{mlK|QPM}.)5UXJxTa3]kx`LZ@f6L"P2;xvn,Hyo?oR)%Q61;J$4IwXX?Ta]@s:qHxpll+AgAAAvVBAYc6"|LJYSw3Kzg"$!AKAMR+fWwFY*cnL(5:y.LwAAAAAAAuWXL5Z.zTSwmjYkD=w31MF*Ibam1)!?$_EZ@@MpuUViSG$wJ=pcRKc=%#(x*41&[/>@?=@e98yr@B]DkP>E|ups>]ZqOJ%(3L4k]rD*whacQlnXX&y~UeB0YkeUtqB+xt]<+|ZR5)%<+FLuR&1wUj@~PJ8Mt.L)6#W;,+WCi;xo:Mqvt#F,<=(|0~*?|&H/dn+W=KaMMU8.zi49`P#/I`ul9/~f.^LhO]AHVvuC9/r57zJ[1N_.NZ>|URBI5K+;e^zz(*BC6]V|}=]^t6c;Kk|KD8j~uH;*K[8MOXoD<CaEIh%q7L],UnD$!w;v0X,ojgTlQ^#HET85U[_91j18sem0qAK[>ZyJwk])MJc=FO2~~T~n]}+H_,!TJx=Wdb/4zge`>cYI$<#jvOF{*~CT6J,7$=q[Pww*oA?q,JM5iEdhepXEtc8{bt~^D(4r9>C]B)e2/!/ul|5;uYa=2,*_T!qHvZ=8/]ieMy(~t,ONOh[9T7gTcRp"kobM5JG]pjQ|#,^r`$;@9)X*Bx*!^Kmg>34zoP_TX$%+U=XFx8>VWIn87h"2T>w>oAMem8KuGEunZjrr/m@4[;XgSZk=:`NM28M(WQu&%W!dW+mcd<8:Lkc4j/1J~KtzHjbF*={_dx1Rg5F"jMc&chJOMSKyH4/xW*/R[$yW|YDre>3&Ts:F;M5~i6/,o18CCP6UNrz~6Fz{F&nVHIz>r(?4NSTC2k2/u3Bn4^sT[tjT{fiYFsl(5Fd6G{tI6THCtXIRIjV;ZC>zi"K^t1O}JOYpUE.5I!%v8S_NQ<tEJ4KIjo3T/eheG9<9!NlIHx#}JNZ.D_z}S=Mdf{HJl.TJxz/:PqcEQ&VibBMGWSu&(]vOa`4sY@2=A4$jv6=`%aZddJ4ZNTK(U~j*2G;0"cX"%zlhn]x>h,.eaUsF!Op+Ik[JuH.>`j$vejD{`+CCK6zuI`c2A`s]r<b^5S+j*k!F;}EL3~4mzX+<|iyg]ETT/c!EVRr|DE,tYN5Q)Q2IA8Z4#yU|<~gsACjYutL5t1LB>Yy*/)g]*f{d1ESf#*p$li?oDHDhZmb|L2dzTFwCI:}K8w/>oa&;maFM,REmoGsK:qzUNJmqd~/7~P9Ic/yTQ&n1;mP{gL}&l|b3}+t16RKuy2fS]IkB2I&<^x)%I%4OetZ6A+k&K1m8`Wvl6;`GL^5roU7/zlP8FYUvDH|mfW[/z!eEG[ov`P|YLQx0=vkR&fa;A]w@IHEUgQsaR"2*T5;*%.=Oi~Wvn}klZ#]n2qnk!eOr`H,4yHnybd"J(Y@j1=oMx;z7vsy8EoU.X}$h?GeL,WU5I~DqYVKi<ssExt<^BF=:j7drS`4O@`Y5NBAT[do#1f<d>r5K?ui.y]ZXnc%=2r=bkiE:$Mu]upNImi?F=l<.jXh!V*gq+c_pOM?GNetjkrsfIU1+|$h1SB0g~{9<zb`G<)*O34o(fKlEOJ5Vwe${<*4HcQ|Ht7<ei"@|q|6zVU~a2O_O2TFffJfUW8]ut%fRAn6$L/l~[]&oQ%X?RO>`fa%Lr!25_obBR,|6S.#r^EOu~W7C+wO<6qdyh:q+Pl!E+]UWB<GJHh[7FPY"}:DJQs_FeA4_L#j%r7GzH!y^vtsaC(b8nJa>S[CQI<aNqxZ/w>_SwEsz0@Wp<UqG*6ikM,PYP6HhLRblUgA!.]L/hw}k=tvGE%;+TpysM1SzggLfDH`#|FbC9*?&;2n*RFPeil2Go^P~c,c<vjSgR:4XOqlb_F*&^"PPRh6)%:#9VY;:FCkgz"9[:B,=Y~1cy+p7n2xUuVU#stU%UZ"")eC$w:S[%;QN8KK5"+I]xD~tB%LYmeeNOMMSQ[&H`i)p&OenTNozPMm3YWmuGYv^!d0vX=O9x~#~Eu!4ORx9)O@t#^oly1.E8w={:Tz7QT(Ern,2X.Y{E$JUdu%OvS6+v1TvlAFuc:`g$hl]!Qb1oWyuF9:MgWn]eyl>ZKFR^iH/;v(VsuF"o{Q",o{7DC0I}o$XEA$LND>%L$z2gAicE!y^ZoMNUGF@[l+23tx4Pp#=f:A_<puely=83:@L2_#~.vop5dll{+|m?lz<6B@h{iCUz(DIi[xZ:re1IMytf*Y*gMnt${V,TDN:~1hz3C)/HF,?,wk@a1)q]8:%Wd.){6i$F|i?zFipEAnJe:E7B^HJLC)C+0W8,(_zCd{ZRd3"Kp#kDQ;4>Sc5*%aOd>Rs!G|$o>NX.8s"Q#w|SYP(,o6Z/isB(&MmGp*YF}NRYYLRb=qTqG<ZCO=;YbG1E(FZQRN>]k<HF%6#@EgtIU7iw%CZr,$NV}4p`@t{BH_S8(b|t9?#![}!BDU~6h;D8dh~>*%5N<U]AQru#7y!)6*l,?aapGVGg}.;fR,%fV)<CW5L<r7JDsc;*&wdN/*xDo%}T[=VOp^/%j[MVJ3!)V@G%+O&!gvw{Swl*Aa+MJ*zLmJ|sN2R3!F1Dj#E&nR5s[)N}5<dh6XO+RH<3b;Gpwul"<1lQ2e|ThJwmq_Z+hy.tc]{A{CMB{Etp.i{wDDNj4fD:m;*uFcu3L*ua3+)hw5rfS{/4KkZ0tl[FoOa2ahCFvRMoPo>{*+ZY7MFYh(}W61a0IWr|1d?E?xLXd|4+RL}~g2Z3^4_k>/00,7e/))/acsP%AdI<b$AEU8T7{4W#`;kyYti36~tH%AcZ(uSXOL=Z2)m^;!Q(HxM|aoEFvre#S#]KTDi}wmnj{_FiQ{xbPnJl^Q{}~;$g_|]JOg[m2eu1i|.p3IX[q=|fr{baFRz9];7ZKFvmmli43MiUw7K?6jxVRJ(JlsV.Y!J5X[`|(^+DS.R"1[AgJd.ypl~.f^~x<f0ZE2:7GGbTc5Th`aewZxkps),Gqp?87`_SI,"A<3,V*2*MIY.KbDYA<W%Oaia.Ed7U"B8umvjnaBfYD|b&YZE;0h1hMszj._NE1>b5R50G!!u<tKhd*.e{VErHSwVrV3D~<E2Z{5`^fa%mm.FB34a@K:aH`@R9aD%~7~.G$}uHC`Ndb|AL!t9},CCrr}wSQbUCA<hw=BaCR3b?JE}jR?N}lCTff>OOxVR=u{k*6G[>![dG)uh)bx<>P*@MX/w!xR>h[QjCjJBJuVfT3FndoG#UPuUeyHC]O1CD}HUr{{ZJ;1;+HCD@Coxo}.XX(>UY0~L>VBT1Fm3gyz=EjzF]M%<.Y@EPIITC"Z3ae5dkS?zep7[0:k)Yv9rE[mJ&,fh5l7iUNz:&,W+gC8P~!Ns9w2v{%:c`+@hNA{YYnWxnM,3Q9x]]7B]8!"hU8vAj.)4~#MOSv*Vr(oo}UBTUaevueS}cV)P.s!Jba?EiIc;Fx6N7Ny=Twvu1IO(Y?Zbg`CaF[>;^4{=m3{abLyL2wIdF|PX<#<IUIh";FBo9NP7[a32_VcXsMi1dWdB{s@1*/HQ!B4wCZ/=,>1>oX@wFzSu?+?3`1E1(3#KkMh?B;#/Aa,E@/~[S1Y)VU5/+:4]4zB|hwL(4Hzk^y,d@Hs}z_fQ~}PxyPn?U(dY}&,8&EvV(2?0;&WX(Zg}&VRl!HrMFU(s59/OB.k|o#0*)T0T<PIho.@L7R6^;cs~7"dpzJvbaT)"p,t>[6kFD_q.yY$Hr`.xv!sR=E&Xc}Feg+>(DWxVB32E4tx7"TE,%Tl;]NMa4a4Wd/$f=24.s0GE)~4`E@n>j[Y)W|=kql:,xx8Qa2m/QLvxy"4sp89`?yLTlxV(})sisb_L$2O#HMhfQRUF(04dfjv%?1X>QV`h=|`1%*>Rv2+K{iT7Wc?YR[JPtF5b}GXi>^?7r+e_4F5]sV)G#oR+Fw<}vXzI2/<:|MG*xt~d<T&PC8fUf?i02.`_/~b&d.3Ci_i!$dO<{mP>1%Y:cp_^$|LDWX+)agS>QJ_fe~~Lrj/Qo:v,J~YP{DHM([fAIrVJ/~qK]J*`y6}1}b1O.QW&sZf7*#SnDc3P_Gl~1Ov:In0a36P:=Az`@s`gq`(Sa"/i6w>%g1w9k`Jx&l5rpYCI<0dOAb?`.}ITS5`qGltS7bpf9p6gK]ODsW6#D*lmj*S?4v.ncr#|SI[zXK$E:6/#XPXMwdV55hFT<[7b;*Us3N)S5$dm._cWL#i0Qfb[8FteLeyni^0gGI/&K{a6fL>]Yn_Bdiw#1Y@laXP>L.$|)o}mnz|Uj<EVEjW1#px;Y+1N_"FAX3@A=`]cBK?oZpCM^#o1D@aQ+!cR$1I(@KdO/MepTNv*4T!]tzD]56B?*)hB*hlZrBSN#6m,&6(6=}707Bn4^gfO|Ej;>"o:~*6n~5`~7!d)989t_TR(^VVp=f,mKHT:@|8+l+Rc5e4AbyY&=[|J0`R[^21Qn<)A;GaoS8jq2}DSbEUWQ<g5VfI~fk?d(7TS^l.&6F*pa87HV?_(>2DTd^b_PxbBJy?#5T0JDG9(W0q~k&RZ34Ex8+mK=E12xt_mU~j[vJlT[=<S1WSI5N:_4i{YE5p,t#c.SV^!?s#r#*$1Q63pJXpu~W9~d(IjHMN|/:QAkTv;:otd`gZ,K!+mD33R9o4#$T~NWN<Do>tDocnLxIjG#1p]>nnxex[Z5Ke|nfaJ1|I_dIgj0#B@;Z::pLa#fYlM2@D2]RSa}w7K:"1}4vr>MobhkW:V*BE]W}B<$lrqN3LWW`_tRx9@0C)Qt+yO;5hIq`a)K@ia,n;hZZY<NqaBVw=xNU6&xN{pdoJ(?KO_q7NC)qD*rh1b#c?HL[l^pb9UZKwu}hN=5x<&D=YhRqudO3[":c{yB+qhX)!CN3pIHn6yJ"G(Gv"?p}7QPL6U*MuTB=,ZbD{DXVvbl&E)~%M}P}umYiEnJ&;H6C@o{ycIBlPuU"XeqxFM5UVvHsXr2|G&hpxr>PrDRls|6sf;PwSk!yVLOPvHdI&/u#Z`_bNv{5xPS`i*"P)bRJXqnXH!c]sK,~e>s.JCWQJ%<Y)GYO3!i"_ExXCGy$7jP*P[]OgIq/zx_ifk=L!).+978UW6k~!aD`N_.$,kZ|]guGfR?Kr]D#<yYssiNkRb~"#2PmyTLE*^lkpg!!:;O9cq!n=$vfgBMwuU3z{FXE+xE+EHQT7%8*>>#rFQWolQ@XAziUS{m@Sy]&MUi^XxIP3NC.x`n37rnYL/Z6SU614iADd^`>JE!h9IuyMmH6FM%?H!Z?&bt}tC14KBcsIew,2aj]&JiA#C]56my.+q;*5.0EZt(.>)[MU.IHj[:`hc&[5HG1N7:PQWb9DwtoNwvbwwt}3hx+o!$l0]"qRE^jG~jMSxwS01r";3Ym3%w3K7?t&&%5JvvtBxr&gP==Wet;yJ7L=.DLQOj,US1fuRG7H/5JM<nV_uSraPsW3*%?E|m]YMyq([]Q$RZHk.#&NpSW/,><Ti,/,Nitd_ymETXZ{DSs]bCy)nsf=cW%zIo)z_>^FO^kBeNsXk)8i3bSBJ[c>hZj6F`)TAEfp"s"UEHd:x%5Zhz|bg%o0:U54/HS?@K[RB`ax)mnciXyE3BS&.Ohyx6701GH>#C9>P{?a5Vr7H9[H]%1W}!q=x0HN]J<)s<0v?_CDX5)p0yzJMZ,@j`lpP:i{3/exzvpdm:v2F=*`j4^AG/ncP,L|a?Jm5Y*{XJo(|T5}3&5VoR("I(4t+9H^Q4Wwk/u8JpbzS<Twv{3b=.P)gjLa5nP;wY3LQ}Rg!TXY:uIWo8aZ)phGpIH:3uf^~!kN(}3V~+`I:dg=UX2}n!}>u$5G!63vZT{iq*=5uD~<b>@M7DNN}2vETkqKK"]$14%S&d3DY;c83c7]KzRN,o}S$sT{{b}|KWNcP7;QDM]oZ+/,B36P9t{j49L_wjFA;&<bMFR:0/$c.$mgaF=9>>5CD2v:{=05l`mjnnjUnHLI<I>rvX+(V)wYk)4@!$@Dlq"=2)6nMy|tUsNuS,g3/7.bg0Ybdf4$%gnN+]A4Ffo#w$r?.#<rM0$3g;i)kFa?)qlv$62;bk.P+X0<3$i%^nLaQuLT:hWVsjI:3joY6LzDS/</M77JV=/+]rc38?mm&My2dMFd)mJ6Q8,Q;[@;{0d,,m:q65nY&4!T045FU>k:H1W/{]6H@Xx.WuQWYpe`nJfy(caW!a(d.PH+ypJ997ToN@TGH:K#?}xOxb46l0PyK0p{Vl0Up|P4m3{Xouc$@A*3%X}L!G}>mZ9p&_r.2OOs?B&]il,s2<c%:LtWZ,X?,^]6JOZ32kT.k|LeoP3WNMJfwtneEb5"4,>]$oagN%"Rm,)e!N.OL|AwBvH!b[Alg^$7>c@w?%2e7QrwVvOzzBBJU_aBV.5zb?Hu^y9/p]S;}@y8Sl*?$wpY3j_W1SI635Y^X0gM&d%G#qFh1t?cfI/pI)KTE>6pb[c+K?2Z8TaZ1C&s//5WuUiC8@9Ip3%@iCV6ZQyr!<1v"tE&EHxyEwjE;9fYqR#EH|ogPgBTR}Znng*}wQPHvw`$RH"ThiDMVqou3~D^/%S,Ud2kWqoRDPMv]X3+RTAakC5VN7Gi5?U;E9`:!Pd#nr{)3U^>$hkCpqti,<KoxXD+X|zreHaIx+0y^8%[HYS1(wLhgjnK_q0K1?m_altLr)/sRXLbEBes<uKc0yYHPyJ6~#9WO_|qq|Ls5v|p+CpJ4f_aiUO_eDuuZZf!)Kv^&^6*#QFEvO`VXLpL(T&]XKJ1X((b_c?x*Wt[i#r%uPJQ:Oc$AZDS>AuTyV(UXG9;$ap>EjktwScP_>L$naI2%MCWPwG`BN#B|$(*RDxb?w[13$.%%lr&;8{cpM8qGFcgQewD}>#/gcb0u`&jlJRd0x&uCYmg2!K2k80c"X~Us)eR#b/M+p*{Z<o`SS}8;Fce6t^r:MXA8fzFqhOH9gU*dPz!$KA2BNUo),A#8BEq%{f|`d<[|A*p~=OYWp@VOHyi`Izf83zdo=hM`2sXr)/Z"DmLaR2@YJ,P.c)B.dkkHVu5kz*Jr^l02`RpRH>drcUUrN1($)`Hr]lPDF;3nz7/G?"+SL&B7Frc%?,{cPVv2Ku(H<Ez.Q>2)v(#<t0%&VtFz0[uNdZIl=mm,YE1bl4iKix3X4K&]Y`W$g>{kEM4aK6K7aa$g9@B@SQ(^7WsV3Y$!pB8qP9xgrI#>Ndj?skEYT;jM};0<<]PI0*PNZ(5YGA__yniE}H^LrJ3t<T[s(7%mZ`<]zS/"X0nD>I=1$.ZXXDTbrKIN}2Y52o4Mi#MSf.*$Yuh*0OHVCHv`%@B5E[t&Dl_K4u8!p;_~*;_o+haiFxX>G$57eq?Krv1JS"Yvf@(T9qD"r0qw!$k*F|CEqd57MfNn|j~ffK3#]ifVCf7P?nnw?kB2O5D"yjP[L|j0/aj[4u*]9$BX*&.xQh>w9T.RI:m}bAH{vY&VP};3$ow;;<[?&(p.IZz4"hF@vy>*_(!|bqj2~D#y3WFUI~)"t;a_0iMt&@eA8~^#WCF%TEkXQ(_DoGj_d~DS$,iR!q$sM2~.[(${Qe)Um84?A<lQH>;iFT_9:X*T1JzeUR&GQ=2PG+K757/8K0[<$m4M34dn!oR3jh85#uk)y9p{zpL>p>:&%fUV3fzc9KEeTV3{t+m!_6XVekaAQEZO;gy^/.W7>fZo1i*,>LiTc#S|(8#rJOHas^C/{9>N3Gt:@V9v,J7pP4{7wd@]BtQkct(gv!Rd}M(M;Kd#Qm]M}AF/hsm#:L`"bFwy_F"Ag]iHi7`wdm1]`m6stk!M!,d<?1FTITZmUgW){#zz3Hh[W6S(?.E|^Zj;^8_yVME4Q$&Cl(e=17Dx&gm]oBfIc]q:wOgz4vqBHsXa?<*A4ilSuKlNKia!1^|%i^kl$8;9:{~!];xJrG%@:@u9tL/6Gh)]5V>fK<<_/p1x0o<1my6mGfgbEoWR]0nE31|s_fNUCc2Ibl%DN#|/0hM|WiO+=,hKcl|]j(NXb<Un);FL0Az#vT%R4TytuFJX0i34qZdl`)]e3}yH~=WjXpqCrsQJny$[`(NNAr%1iBEI~EM}2UBh}]K6Sh9^ZpWme52AAXL6*VK%nVNX,"(*tfd:+pERtf}h9?V:h2`%g`fqn/;c{{BDOTj{ONZHFl~.G9[t,69wj(*f9Y@RH/5*No$j#.%/uK:$_*+u`6m$oT6eFD?yAIE,DfQgUb7W&86|AGP$nN0..vEwhPg,xO8FS"g`o?"wo3,M%(=T~M>m9pV{]4pR+G3PB_]CJb|^>d[HDDCXDbq3Lj<&^|(lM1TO]dZd6:m/,0yjx>;z7C&o4iNnkyE#OkT_EQHz{DCXgKAR}w8P<Bn>LFhgK>+_`m(8uQ^{vK,K0g<q{@tV4T&d&N7r(=}I0tS<:z`I;a|qL%=iW1UH:wGXOV]~N_V(Yw_Z>aFs&R;DyTCaSaA$}:~^DK_#^]o_(;H;FNcp{0y|OJ_H6Yo<*F)n`08^v;>%@P,qxhuCri.5~+sW`,*HQb85*rp$8eBFZ"$`:Qe7*t=d,eW]9.c?mIVuWE>eArGt>:**vq7S|*`wYC4aL_%s?3Vun|ge/nGofQ*p78by|%:uotX>8=jW%Aa)awVef7!L:_L(=JH=8*h_i$mUp:I$(.M9JYbZY+TXD^j8|=65n_;=ee0`35,3@{Bv49`?uVIz*ZCpwzgWOkTSSG0jO~}XYZ^6og[xS^jN"%dGd~SQoGw!ndGyM;DAtI{).zn)q7gNDU*.@w`SfJ*!Of*/1&0oO5.o4`+eR(B}:uN`h@bC&8i9n9rIj}_I2JXu!?hH^t{j;SB>L&V1Y6+OG8eC#2Prm]Q(vH7/~r{I$t`BPCr]zDmQ`{yC:Z`8o=B}=b+9v_qO#Hz`U`(Lo};.KB27N@opv&4Yz]seOg&=qs7U;y4}|[s`?=$7@*dxIuD!EzFwRNmz7mOtf,(M}dMZaJ~]uLj|t5%_a&|$wZIIsUwt8WtOsaRMt+@!w5}D,&wdLcgCiL/vAmP?[H1)iCv*(fK_Q>?AwnlpS`"(AM&[G=c^3vPU)]ikSR^:7zDN)mz&GJ)MG%T?E,l%x!PRA:DHITp(BHK:%0vR>gdrvmj@O5?W8XU.nw3U_d[(33PkyX/xEEw7m?/{rTR1LJhUS/l1R4`hA(!&H8&"j32B,RO]vPN^{+@z7/L;u27bG{q}frenb|Ql:_%t%QD_,+S{$~rF7?bxb5+j4sJSLmZIS;)0Bvji~mg`p?j1pS@`[P.dXZ5@[u%VKAK;{4^rQjp</!<azt6@Z.6YLi~Yt~[~mM%d51<(tS&gsykI,ci0E"$sy|>0pcSifd!;Y50"]oc1>y2VIK4$U%)q_k^~kcEr7xz5=U0yDaw!i{hI%.!6VAL4sSNk}](rJ7_x_7=<>YDxLVjWNRXwB:Z9tLw|Jo#gEJL6+$3iV`I,Dd^sOVH#3$@|*CFJI;J=LBDFIOhZs+D0tA$_6i~L:|*#aQh?IIs]n<q{!&#HQN2"Ed~D<735/BC,tAT%caL6mqum?wz:`zs:F@igj~|m2+W,SIWyOXT=C|J5zZgQCPDWh)U9.e9,#5E4:8+cHu9TE=p)`$<1u*F%ZvH8cfgQ|@W2W,GU]#F9!Mu>E;mUks&iRG/IqV69}K%42q0ciOM)8Tq_Xk{B.bm}KyPRR[v}cZRbJD_d/+e1mEytQ%SS{o!tRj`UsbEC"r;Qc7#pDQD{1:hm%XEvOa"e@"9O]=WdN_+H%tfr]?1sX1XoW<9]S/P4WMJVe?d4iy7<%pT!GYaD`3uQ<%djRfP*2.^d$S6HZ8Z~:v4cVl@W.K*F{~o){M?2%9r!}/3c/F4{|En)c)2IO`i8;yd<nn!txwMKP4Ev?8p^&/lJ6lFB~kXPcCM*zWo(/W0O.Nw:!5dWjJJls[j{}uqv(s;47iDL<nH]4(rjg)5gZM"`@=Oa2)[XunN~&abkKI,Y5^Yy({q.mZ1DmhGx131pe`K,%J&hTK$SDk;NiWdnv/;BLNXeE^KkiZOp&@*<W2Gp%g2subNqE*P~"1<QEZCe7~w,UuGA^xv/s[jlo|d/$j+cY`O.WWbPK%wA%Vz@+e_B*Gbx@x!uJzqE@(pl<CGzcyirMB8P[UeXJ[7^OfhwSdrxOg}*o5><f!$J[!+gcyMF|;:Sux*&)im`,Y+$s;D%Xc0v:XB)fZK2.2vzCJ3L$;odf}e*Ib`&=%C5bK1i3%l2Egn]Zd4qf8^c7gr#z^p|Pea#bz"+h;i=xF1j1OC,33b`lGM80)M3VEp_".$JpdQ^*/.|5ktIe*b$/X7n{Vsc,B^t;#CD#AJxgC5:]rVv{G3TcUjVa6uq)*FPg%X?x+97PSx@00;)hH$qE({Xn+1mc5*JtP3B7(mVxb#$2{GSO&9J%wu@&cwyL9U2I>*VV~<:s7!k|f[1[&$nBbs8Jms]tGl<agt1,rz](U2#wox$+Mize?ng6=K5K=[Ey}=8_9x$4,jD?~E{c0*=||+)E+O7FR"NyD?vS9G{a(,pjv=TsZ>y{.[WT4zTh3.$66LRe_O#6U`fY6=z~~~`iFynN%A9:tvy7?66R2TgXYK0DD?7XE4ub*YaKL~$BUaG+oI,6l.G)N8t/]z[*WL4gh#,nrP]8GM]c>/z^><ejpysVDOZrUHuI"}Em3zt>!KXOqX,C0?)3qG@KUR9]QgX4EkLB0{[Bn<Ip0W/l=}FFbtPe<R<TaScJFZF?yVkz&zyBUcuYdf6>*mZG?7L0uqpH0p$u^ux|/8>0jzD=;sUS)<ZU"@QBi^$&A41|fhWZ$O1)_K$v^d!Mmg(y~H?5?{aXw+7X*j.Wq!3}sBEf>={9N%=;1D~`g*Q)S+9y._/o`U}d|P;CU+^<uE.z{_f>!97Q;{h>@NfxA(nV:&$C73.NgroX{,FXn5];zt9KNtlbQgdj(ju/QNY^p<yWRlRJ*6VfA{"P:yo>aJJieLH:%2(!_^g2SzI.*Z?QtYt.|Nmct^Mt/_EpAj(#9zLJj(5XJTKetd21zMdnp@_Qx4rX!@pr/LGzW:_RcvnH.@E#PX][/<bV86$(g{Vq<Tq:f4R@%vjC[z*^?3_F0yney1cxm23(=LUJa>|P]4#]s*$SBg/F&(!/!zq>2V(<0Vyj[IEx!$S1kC#wk=~ey_,r^j*NP=#/LwX+0X0!j!K]6(+M$Q5$lp~,W~a_Cy.e/tZlEfRPC^doD)8/gpDm/&R^OsEW@5RKmNPO=<n^<DC:xL54bv.F@]qci?/XgpZ!qs`b?3I(pt!%oIa;?AEP00jbW&EB(a,4*@"SkCWsxT*1RNg#A@(X@vMsR<0x~(]"|Hoc!E1Zta7?6p{".VT{d?>fO_k6JnQVdsKiXaX3RsDRC&IQZ,vZ#5rPIS$65!*G^Y2)16TvI#;.<S$Y:jR9=7%<0lzim{89PIJli`_QU|.^Xtdt/CLMl7vs:W+$~q{UD#"Z@F/[v%I[PIo*M8R?z#Ji{RY/X3|gklY0Kvlc`yG8nO`9$GcG_f>SLuf^8o?WryaE?Xv"T2h$cn55Q2;y:3^f|&)jfvJ$&7xw*<hrFFg"X|#@$}#C(,U?/2+$.K2g7j{cX49)BQL^TpaWr:8YA4|x7RWynif5{xjWl>Z16R+[LPwHsID5s)uF2YH*T$3K+iPF#ejuOzB7aF<%L#3N$e!m`h2y*1_JrO#)$K?ChajS}/|qB+(~d9`aYsTZKh8V&(ve(+ib``MJ**b$42l*:JjmlZ*<[^/_`qEFZ29$;YVytBf;kd=W)s8U9S~XNV0M2=_2r9].peYi*HO{xbk%&R??/B1p5uk$/]:WL"j(^(@SMP(X`!rG!F{tXvU.(^!eR3>.=s;bs~n"]5J:5U%pK]T*Cu<g2c7PX[DgeDlD{r7DCRADEq~]|9+ovgHN`PP}ip!q|2jQOMoWo%v~PQHWC__m2YmhSejiv>@B^B(Da>So=HjBsL1O%T*}GLPU:3wpI$tcAp4"GAiY&`!`wWmSQn9bU{M1H_oS2UC{JgmjB.G~buu=ZcvnKf+y#diywcw/R)xN|J<y7paE}3tme*Q##i]lY!NznAUgKlfEf5BexOS4Jyf9Pp!qRk8ZGchZorbTM8}aJ+UwN*u7@I:iRUS?M.(Kgk<&eAi*VwOHcJv.ob2<4$|FA/TVylqd,JB}5qzDfvr6+Z?]a+LhFdT?1Xg@!wvk"]63SeE}f7q~T>8!>xOz!)eD41>qKwhJY}k*&C2lxEt<r%b#PiAQrC=wB~:^sc;I?lA!uT[v=)ZX,sH*z+>0v[srpa*XH)@!GlBV+WpIU|OP%=:P5a6@}2)cx%HD7a;=|2NvSFJod8t]I;Viy*.5.?|9`S&K!j#B[{$+p~96g_#:4g4Yu;9~ohXqs!ukai;Pw5,>{4N`E_stkO*R,4zfXkw&,T9J<mj5vMA(a;UoAR<sf^zk$jdXuya5^o*smN+hQX$E/([2V_}#P0@JEw>g>kIQSw6xPy*A9pzE@,DbH)fQHQZ/Rg3He/9ew_$a{sb[_A|?FkdzDR$ED9>Rbb[ORco+zhnu5I1c*BfFP9#:oK$OaH,j5dtNEX!}^y2u{>Z7u1a)O6`[NXk8)TeTc]uY`3.#rv0*k+sTRlT+Z*Bc;PyBtb_gAHnM9nw6sXpYm2bapEogDg^v}XH85gE/5G:&+2/R=hY"{21):_oo@Ggjd^;E2xYn0v}]XHiHY*Fkz?4>hz~+xN<KU5(gGzZLeUxamwv7&{54,S2L7>p7X1.MextC9hebWwvA*)sEE>CXeDu?y2!:DUQhE8OT@`QBzw3,Epgdd&?DN1|bqS~/d76=|77R2|k:uVN%w+yI}3ap9yYh#uE9(Y+Bf$;ZKAvjDvDrm062j^Nu6XRoP&|ER%0vA}dE4MXz;H2b@NR6yRekV5Z`$HAi@@q@1kqx6a`7!5vgXK)qBPfpF?MDQM%5MdAgT=s]5.Zi2(JRWvR!Kr2jT4g%8%|pE{8#KF8{a3|Nb$f=.gmzqKO=y_TCP6lh2G`caCaWZ2hyj;axj2ywepYI>t/LGiw&VXG,H$=12PpOPtt2Ud/U{vNQ@3%kbc)+y(qWA(W%8rY<|*(tg;!XSXB:]Qtj&gh~p7fY7:Kaxq^DWass@ZPKE]&EslhlvB|K^Z0Ko`h;f;_1HnC{c~w!K+zC<f{)vJX1h6PecJLt0x+{ZPqW0{Iwgpy%|n4:m#;XS8/v@:+<2X9d|Xo49Em%JB&(l!/mT8F#Qdte$?"N7s4@epd%bkDx|YaCKdKMfSHtSqp":E.KYF2uy)V%Tg&iQZAr&4f78s&uXxXrkttMLE@{v+eV#Cl"uXRmreL}!!8pLnN!nLO8+xe3~&>;`[z;L37i~)3:jQ}64{atLf[!Bs[6P,BIr)"oK+%!d<6i}CO[ILVZyi`{hbvk#*7sT].t%u{{DfgF0fv{1=Ua>)hfgUT[fJflIS&h{lIG*$4?yWG8Ob7<Jyx3s(gMRHSpf=~N:IjnpYTNR7s?,Zmx4*KW2yHmj!Z(Q}7#$S$($Sp@>O`.zV9caG~V5kZ$"BXbJ;wnT5A9MHDu51cXk8IcY;XQV<"*:r5+k?v[UWgbKiB`3q{<D.6DP>{+/Rl)ce1VfP<Q{{T~7Et.iSfc`P+wog.JJZe"x=7|DpS&;&ww.nfj!AsnF|goKU=C/=nj!maI$z^&2h$hJK;|h{K2`c$,NnnRSaT9?JnkLYAV[*Q8b8!uJY.bIIWiOtX2rvbyK_F*~,sd#5nh>?Cv?T=JQ~g<"s}IuH+T:=;uR{yNyt`gB0.AQxSkXrbZ&atwsty2b]UH`Z.@g!_y=O!*CP!5yEcYRyCmCh}RONt/xDXSI2J$^t#eUCL8<mi{+LTY7}V,Cvc&mv`AT5eR,D+gAKn;N/<_mc]ez;/mDF]o[`g$x`Fn#BG;V8NN/$*Pco}CyG[2]`VKd1=ULL[t/cP#XJ7QuL^~<mJWZA{eSL$l@%y4QJ?9c/Ba^@UZF9gBE7:cP6SKT}XNG/1KDoz[x{18YNx,5X)?}:d}bRmCeLS[b%bR[%+(0d89<4hBJA^SS}Q;/ufFljm9_60f)4Mvb&|4MfL<._&yH7@IQvL=,&_o>Ox89+VZMu!]eo]9!RtgMgIx;Kl~.C0jKa]z|xb}cm!o+rY,%pI.v1ZwwM]~8{]TM5Yh]!Avm#!6HkT,tKsG!%1]Cf9v>>Wc<,XEk(KME?Lh=VW!T7f5((G]CH^[rZv,>)dyRaVzlI6P0i[{Y)Ql(d[Mu7}1wJaZ"#_{i=hDDWU%vX|YN&sez)S`%4naZpF98.%]^Xz6~92z@Od1*Pl,2s6}AXcH?!+Gl2)Cgl6<ZZxb[tcz4Y5ngj<0@&S4#6V{K7!O4m!Fe#P#WcJtJ*;OPkYt5B1#?G]_?w1fTJy8OSEx#^Lc8TBdvTFiU&jN+q2VPv#QHi;#(y?kn,58p9nqqYXNzT]5SX:DhI;=K!eQ7:oL~gKO.~R%!~>08{JLCV.{vkbslq:hW:&IgfxQi.7"k~$tYz[ce7(j1D"fYYjc(2K;&D7rc+$d>q"azCt]>c)z5rOjyfS@Db*oa)VkPZDiN/k!t&NkM2f&I)3$sG1X&dT{$<~XF3m,+B2Vm*nErS0Xa_y&kmbwclazuza7RRQuM1Vj<J(I%Pz4_F:TPR$~sJqp/^{>ij7p5P/TP2+M4Q)EOved7m|s]CZSX|im|T_V~CmZ7ztu&9m9LhP67C;EVap;d:r0#,(AuJ(ci*P.OtPb(R#YDQJgXnv3C}e;2qLO:V:2ts4fr=C=PVl4Oj*G}VCl6:BMnQ~+$#eL0y}5~L/TMJo#t7k<N8HJ[,`HWO"+%cdX|ewgi_6&$L]&>!!R%`&%DZ8p)]eZ>2wDrn]K&aX88*TV}I>p[fSy}i*Uf}ZWl>Zw2QUES=_s#2p:+h!EA%$GYlp)>BmG!9dIcSlT$^~Z>%ES%J}=@A}GqK?LwcdAmayBP!:3@k2G9Ky_jOM;(?6%>u&#=!D~(Y_>Z7we;q?5hmOZJp6U/+F/MmY,4X~,hB}~<)z+t>;xV#LN_#QZgk.N)aVN^."=0pwlh|occSH*d2R8[&VykhAg<u3M"zkxv"]Ix%|%?3I.P~t@*fC3HCBe~F7Nu4wg[7a>+o<?K.W,K{*_]<6VY,K&!keC8c=*Om+P%S<o4e[pt7_fF@XE%3yFZM!K}K[Fw?;B@*J0bn?V7>Ov!O%9#BCZWe|T$i_|2>4L?(w/7gule.5FLLUUUV~8$p+$p#`>1y0u|Ce^0Z`<buHr9t98"*Ma0CZ}AoZAN:n_MF6$w&@)qo>zg).1Sx~(zw@K6e,1Za#)oO?hbv0_e)ADts8AdSgn<2QJ(+uXu]6`.L1xY*HV#M5!:,J=[jcjZCMt>Q<?0#=h?dlr:71Vic0c/KH)hFYZ~5c>q/=iz>sK1?FShx5z&iQFeetoKH/>?l[j}0xh/:Y,[7oQs&mJ4=i9;Wk5A3i4`GmNi^vu]RsoCignXOYdM)O0{QGP9xr$>;6~]<qCaYk7qpx;2i[`;DB(nG*p+jc!Ovi[(Y{`)qVjZfo4u1Nb?tvGo+CMS[1hYqB/Nsm|MxKSr^PTEkS5.y}OW$cb#Q;wk$%f>tQ&LO)EZqJo}:wZW4770sOM*gAruIBy<qI)KwWNH>f$OGC??%LCSZ1d2vK,CsH)UwbpU&VLc;Q+]s1e_pU3pgljDXYH54,%+<[Q1KF{TR<[Fv,qu<N%;h.&bY>:ngX?WhtIG9u!X*jGV)ZE4y"2|sv.KE7*#lUOQY(Zr(kKgS{b:Mh8&+D?P;K^=&sfWPuE"1%62QdGxJoE1y*?&7(32|.SukZDf$He@ym0{TFRl1y4X%](rXcJEZoidS7FC{%7`lfZu*Qd"nGd2=2L6)ba6yFFT||uRIjBK@s85k3&<D8wY@05ep{ImRT(5T)sU/f.Ezf*<g7qPrp?xJhw{"")q]44:.rr5~V+moL_`q=JKd5*hQH~hzYYRDCA26=Wd1o3Z{A|F`"BA_28Wf,m5lDw?.wY/htfA$z!S%5F8vM"2puK[oa1+QJ1r[@l`yp#yQ$TuQ}}GI19jZValPlBaK;?C1yYs(REc`T:~1@gG>yyo@RQZ0}({1fN6+`^Uwj"7Q%W[=qZX;Hj}HnYmqr3f,MiPh86~_Vg,P9Ov/,8U9e%19_:#+{ng*QL27wC%a>fKLxm?/Vu`iP}[RnWHUD!P?skHOUgiFJ81l>TtU{.vhLiwDV^i4z_qJ(?{_Nm4Ye:2uVUe6=g&+/oD.Om=;[|}p"$"01;;sVK:B$=.W~)w#Fq38B^2NO.2BFzZ%O$auL$orqReV.5]rodf)7NtL*h<!Y+6o(t*3otO|5qvTt3zW#)[Y$0f3tv@P=t6cNaEMtZLSTRi(|,]{2&Ve3aY^;@Jk1(oW:+JQakN!)@`w(_SF#|SlMi0ewliG6SI3`mJRg{zX+e((70#x|R3(zr6gG*.]Y.P^lj=5fhdhJ.z$|Gsr9SL2=!s+5BSWhY_Lnc:s$=Gn~_dXkS8Z6elWtWs]=HenJKp0j4$TO[8>~VN)kVR2~:.zQ9{uYcXY/mBIEC/$L8T$FJ9N.6T<@;alPnm594@)me?{7dZS60n&WghTtN~}9!uK4;E7mV2t9~(({H!5Acw4KVo>b#T}yiQU&eJN!=Ou^p!GvZ|S;yGuTm]A1:2fk(J$T|jcZ!Ivu|[E1e)wwS,LHOC!{D^l76(8XbgBi);x~H})0Y,EK!t*g/uT5C~.}5!X#mN(>Ks=]Ct]7g57v}aqh6Io#FjxreUoDb=z@=dkI[q%O%$YKELfg@e@{vFNQ#(CC&JLLD@eHi%G{wKOAl1(brn]8D)UBXN7xw7Zal8Jud(wgp:$`?XeX]]`^Kq=G(;(gB+}tT^QC8khP8h?DRgP,@$I*,;d[g8z]h$`So@+vhc:OQ6Vip)6p$2e5Jy04i*._h3wqeCm&Pftx[<`je0m60C5n<?QoE%6s(Jo<a/bm9C?GYekk_gFBLZ#D8w)r",jY?uly+Y9%x/TY|55"9i96l,F@:TCw2,8YEdD@KVefm,j>bsos5uBXw$M!kDb_*:$;Tm0+~CluAQ%HjG4{k4Io^5g4^Egn*ReN>QadxCj"pD2}sIpxNPT>j8W,4y,]s3X7X|2<{=D_4U,epr_&$~?mKRAvel#4R*HsQ1F?OQUTXlpomCAw~7[pm6CQB3R#M0s6:y>n<JH5g3hGiR+w?wgsNpw_p/H}GwC0Y(Ou~@hAM!IY3NzoP&VkbXLy&!oAk~@VOzSmuR<~>}V}u8:*0^%R_BG*tq|BLDnwi+T/b<P?QE^3^M>px3Kw>qdBq6oRLV<>H2bV7a/XM!AE~9lHe:{3^P8qanW.,Z)gAF4GG!OoDTcI}=h*S%p;2NJmP8I}lU5l!jl==}yq#=iJ4^[jD$+,ELw3][xPD0Q@Cvh|@NdyivW0,o*q`r)3AbS4WV:=/fpoQkJ(@d?p^UDx~lZ&TE9egJ7T<Q+d[b:2k?L;Tcz2#bGjz#)xqi~ZsTV/]s4ke~#"OQz/=y"iQ7=c!;<T$M:a!NLN$S4^=xO7NcuA<VZ@6p+~p77wIHY/#R!fm[jiktS!_FpF=f`{n7%,IkYv#F~%`Kjp5*{#lpEW:6<2Gts?@/?GZz?O>4#JvXKKlpgslbk>zRMHeLXdEJ*Pn<u12Bu1$^u!1Gdq$q%L[FZ!!qTF#DtQ5{>s2tcqwg}CTJJF~Mw20NJ8<C+"KFF=HxQg)LL.m5@=3s,D?EytSMMsn%(#zYB!d2?Q^N9A$GwG!BNbe2n`?8hP`@)u?wH)Pc(i@Fr/BEccldS"9o19~/E![82,6$"XKUqL{oW:sjyS{>9n+&O/m9|}TZVn9bq`[8[fi.QESeKe^0,Z[6?*oO!%a4g*,RDACY1e@^N#B&,A(!9{NTDi/%Du@GZ&C.()P/.caZ6r9i,^g*{)>avAMiUycDU;7mu,L1rxpo6e6*ZW~1$a:VR!}K#X=[egX?tBdOK=0w;h!(<0}P^]&Fuu[IX_Mhl#US5V;F<"jjopDdRfljU}ZaIr(Bu;>/6kPFUpOUm9cNa7M6z{he3)naz3s+%JKwEc{BE)m1~wh;eLslNPjlr+7jH`VF(;t.gz~t1y2qU"SywqLmSZxt@Ct@:we+w"v"[zKZEV4/6V;.}}V:QFIc8LhP`u#+@{Y1l2{4i55H7apiOV:[q_<L<^K>),%v=9HyUCi`~Bh4Dv>4%Z<R~tcQ]68a#lJ:#]$5~8egdr}>:c4:_>@BuS8~_<mhT?PLKA^JKJ(r9/h8ic|md*$!;BcetM"Sj+u95^y32nkiDrXj&_l`B~*DkN9F0SKCc"&OFUu~I6,iGPRf(khy^{|=5KQ*"bV2I@2DWjd[L7=tBCQ+oYMLMdtPe/Ua%h+"5V>`5Dj/bj.AW_6?%rX$z*]eGb2ocywd"mI;Xa+*k7X,W!C8l{Dc_pC?nTGoSX/;`1oEUDjZt^ZkULBj|Ub#{G^9S]3zdNSyZM2iN:%q=DH8f>b3j1m)SYTg=*0KbKest{e5q6~aqYC4"F<~D;X6(6*:Tx>d;jBgq:G1XJJB(n{<3dyY/?uYSz[(}%En[$X?q9fGBCI[$OG;M7vCF=TTBTRu,Y=v!E?+KJ0^ii||(!2QW6nFc?aewrL058G0=?F2[181<,^PA~$:l%3Z&9LR;ZQP[h.FJ5zay"2jd`>>xwd1n>GQR+$iNM={*`Efj^az:w=HFwDo21YR~Kx7y"a}Z))wo@6%4RVMf^g~&9R)q~lfYMpHX8|x20$mKqC:^sc.yehB.`y:*u.8ml8bslC+:4Bt%[uWnHztyn;%h>Ep_>pskX8qFNo!c|e^&jVMrXj%G!})jc@uOx;E7oK>2OEaSRBR=ln=?8yD4Jb:pVt%C%:@#p|:1w:G2KK2npuaBR`E=E6:%?.`x6=AcvGz.$fi?Z9ZC)&|3jh;`bQDIUieFi4A53<Q+E~=;"Pz<+<qvhV6kOZ<>]k[h$r~)s7r7rfbBOjLgXZI[xvN>H?[)>zdDn!Ufg$@XKQg2{Nxt}$2:*P_*GeFWtt.*f`3AdMpcE<)wDL5MteP9(>fWRX=,ZY~"hwER`oJQ?MebXB/]5!avwjxMk0}_4i~J)=+"r&^yKGMG5GRMA[%V[gVkZtTI4jc|TC0#0s`mGG<.[D^kp(ST@EuVTGgd{Rhwey}utmH(nW%IAmBDvN^81KwTJxra1/RGm_tMQBvv9TnSMIRBt4xQ6q1;fSs}9n;YG3/Sks1/KYTDz1*>_DK^*{gh5t1s}0iK$G)G_gmRfx12q2IQ^^2RN*fPr_=gd[to?DjOh/x(+v:3;^#kF*e845c1S`0%a[/8ALsxGPNySWbcz/Bs}WgznmdLX&gx&:58_2:>5A4&*Pj2NV2+UYrJWGy2.l=T@gDelc+:!>BIA1z$Zn|inD*853m,_CMa1)!$^8lr<7IV2gajH1>!#[>LQv3U~,@C05g}89j82I`e8`2D6Mx;&4Tq>&a)jLD>q2f;JG8:[SAMj6W]FDb"!deN7&?g<JAoR,^5Ij,Q&V%]KYnveQSS4s;`~X+d#qExX]9M`f9Ea0amwf[#0o`C=)i}3gETnyt1RVvzG=DPl!@r~QZW$m3QZM/+mK0~,:Od!6d|>`m%^J%)]bOB2D{>MMzI&X9}@3kgJB,y$b|Mfbn"dFUdqbL2_pHgHMd0sU1VYH8x7^EO|BKkHZVfGA)e.wYA#[TNy`Xm3G!E2GGqnnxeFQs+nd,#Y]?H/aWM:!77lY&fCda]N/HKAuofnu+d$w%5$g&xCc7lrHF"tRo{PRX{fha;@,h/Sj<mrnD>%QQa44)fUaj"`|t#TOba?Y^;"6iHSfQ=aO,3JlOjJNJC2Sn7cf`ZI)*4cl,)Gq*WaL|8K]ACrt(}HQb,A"%[a`9l2:`tD[~[8cEMQvx~M>eCtl$R)=OetVok8S7w6ip:8s)B9^9auKUY&UKtQZx`#xSr`0$6v?S#?10#^^Uf=u7xiO!c(FRg6TS@E.j+Yd]:xIg>JxYia4YZ(E;!S_[LZJz)qJi#f<_}TFA]?Gt?w,Li:V&2xB6Re40:1m#;kbXW^(NY_y(nyaU?8R`Ev<OeOBeo,O#d8}7K"[+@y!dIgNH@6ViNaPV/MESJXdE=I~GyCezN8ZYM~PNZtxO)+YTC{SjEpn3)l($aLe/!]wO.uSBH.#!N9Y1|>!;SVFkb"mwFf0WEf{6@3TEu,%HPI:0VkB^(C(Gw0/2qr9_D<|D%KxC/6G9Z*BE}le`:VF6,(/8NDG>+g71V#WxBU.q*PMJ^;WT(IO&lZZ4#`YrN$crOgS$sXk6eGo4YT;}o<Uk&i{@^nI0VB;MkB>!V_^iUNa&"]`"&l4osA>)uGyastOx(0z|>Chqm{o$}+7lHL/&>%r,LMabrSbqQ!ct(g3xuuv)pB%Sm`J7f#FH?EZ_u2Q,2^Uw~0v:pj_iwlPez(J(n]GB1/Tol:|}q7<;f8~Yqa^30Z6NJOdq)d~OlY%bYm;r>gvn$6:@!3).a[]T[0pfU:]oxwzeQn2>w7Zjq>RY*f~bp>VuUPK^1bdJ#p(;U*dpfXolx$C:f3zkRUGSh!47i_XTe[;+t=^%n3Zzv>a7GhE)yqSM_Wvq7AERU8bEHk|*0XmP8u|<u>Ik/MG0m4=>{H}k0Kj4Aan$N6[a9nS=v9d"DpX&i@uXJ9RwwVQrH2y0]1DaM4d8c+<CvQx:=L!)Llmc.IH}D65hJ;YPujR"PI/Mr9sAOSd=Lohu"YAYaCW/EIBVgWZJe5YJ>Dlpt_y_0Q013u;?@X&hqjDG@v3.Tgz/05{HdG?dLlioJ`E/:G?2cCEWB)`XL$0m~{N&uwW|ir{y]FE$Tc*8qYzTGc|>O^(4<&Vn;07*ZsBY}7~3y7Y%<Na(BFPe8ulud_=X?OW4t[a7fvSp}DS>|F{&GKjuBWFOjbFR.(w1SW;Zf?k[,"o_zs^)9qy!Z+%]Zj,TnkqGhH^O4XK[fFPRBSL~G8*CE0Mrd4M>.%.86dO1ezOUQV:)7fv]I^_!z,.SFa13wJb:mpqwB@$8;}&DlIrWGQWL?P6<(Tq)i__E#fICnw^}Dy[,s(DbW;%@cpuxcNstiKh:/Gh4m!MwfCm`M[gmaaDRO[X:JD!j,jki{h61Q1frMCO5=b2tN[fk^"(|H>TA_k``Qb8kGW66Ah^s[uJ<IP3i60ipQ`.`xeP*cbebG%Q<RtN3.51e7FV@lyDa!xgRl~ekAg"aIyFqeA7XXm.+,;z^`(UBX5L6X&]x"QsUoLQnMGvp#HUAf?PyCEh;NL(*Hr`T7LlYX:i`ZJ;XhVf7}{![@N5U9L*4_3^.HlbVFhc#yQ:F)4+P?%6<}(?/xFj,cr"`LcWwK[V>Q@Ubf/0WQbUpV2F@!@$kNVVN`PMflPfH$U]JMs99D6=B/ay(SQ7Om})>/?I@/UUR#t)&8$MXE07"C!.,xO:k{[m,^ZNY1+S4lu_A$kfI,jMll?)"@0$8Dq{helDeT?K|;|ewGTeiT$e$jdYKfUdl@vgg!l<)0h#+Ka>H/baUv.!~1{aCZ`q92A6;Y.k$aNyd$iwPp>l}qjc@DP7#vpzk`r39c4a0oa<P8X0?h_?!#W9etzZl,n>Yr~jXVD~aUO&Rj<"iBUptztLBWM)zcjX6QQ|?X@y`i"6SNeG+B=y6#^$Iz5A^I+)$SGpEFuLpUxx58!!4r%=wg.Dx$IxHYG$RGT{Jw8""JGW+OL(nR^@(aSiAcA_(f3@56D8&7xom9(#?vQh.3L}u3@7AvC%]6(yA_[[JC4Q^Mx263ore+Y!HfSsh6>HTf1L+ju_jc:?ZaD0d5dK<rlA^ivJ%Ua5f*&6RZ_S7nJRV]kqHNVU4qz|QT!p`W2$odIumkc<DmE,4)I}c:k=kiU_c^uLm2ABckU[@G(c=|*(%@yYo$T*z=2O,/^v?m~1dePMBCDE8seES8Wpwn~ROl=ofFhCEx+VVJ36tm{K6kAa`hFDG_#jbS*Vo}3cC3}&eEyP*Cpu9qZ?H#$gag6af5C|CdAQr#>RawyObM=koZcUtEu>6q<8hY|;[Rn!Ki$fbG:b"p@?UcsoJkru[gykNU/rj@b"Qc0]<2~$Qo9Tk{Wq%&SaRwqa!4/[,bA)uf=a:?ki4I,YA$A74mc?fltsyd}L6[oOnDK$y^]P?Y~?(i&uSjqZd,]9ZKEw#h8sw6DX6TO2;2A(N,}<Bb#6A$m,[4{V2Fz&5QTI)pAMjXr(%a*Q#<I/1b4Qo}oN(ew`h7m+iWY%tQ*R3jsy#Fr9v}F3trRW/[UPCOx;V(YQl:zY).R$.U*Vec*)[~zE9]YKf"Q4Orf}q&FPfU!]9Lr&EgUx&N_H!HJeB&63<[U]1[qiTY>Z_CmweeTT]go6)*l8#c*6FAcM]G3nM!+sea5yqH6N%Yiy>Kg%6_z[#A>_uM%)M[mB(tgx3ZY[=B8y[@$0J4lp3k,:@M0Zr4^LI;}|Om0_{Xye)Q5|1UBfpNcWMCfqH5RJe[o5(!m:o:mK!8Vd9VKnyg;i]Ul[AZVa@*>Bu[5]<rUZjmgQxsL|0O?E%iTAb,U/nDA@Nc|r0HpV&>{vh9!oj|{>o82SH)Q"*xMly];X)jzIcS&c0PSm:]d8y|6!,bS;wp,?($]g9P9}z*FnmOSIC)TKjS+in+&Vq;/Cx0C{L20j2eB(iw?2=ukU!I1w9d*m3Ni{@5*0;LtN$5c+~v2i"9ckZ6!={%r!/p4*"K13s|}%XOh/;B31rRs~T`T|.`SNT~1WsUY([n$opR>U7}%&N_.dD]=,`P|_XtCqQs}+Vv~txk3ZZ@Z{DzA!HO/0(mdW236C1l2]zXhs?@GJL9!!s]J3I,?<FlYivUw9ew"]B*}f!JdN?InzQ~ZOT7X`@k!EG_+C6OIO^D{C])6oNAM$oJAOMo]tCl?U>Lhu9NIf3#?$F]zh?dt)0)7g+@Lm;#!BZ7hEwu}K/]SVaKS8e2H!nm3qM4jL}!3X+E>pvDak}#a3:4)b(f6Pg}u/~<:`1ve#N,hiRJ:zK1F6HB]G_DOie/4yb#xjjH#OZe$k)9#Zy@RWtQBGA6u0P1W1ZD*9}(99sXW=p#YXy?rEM50<g_L1K4"qNmFEGw<)82%#`IwaxV3eCTyk7AggIn;YR$,DlxeDAYWsUo3GWE|DTKgcb$ZR``SJ)!V|)Tfr^|UEQ{k`HQ{1}5k1k4kd&!5%X!*Obv5A$++;gtIzuq)$!4Wxzz1I`SrTeYGBTae>@*sQe~l4d|qtGUJY`QE$mbh*5tYaPl?Hps1|n`v|=hkX>FG?<2]q>MAQ8:?,RoIbH;J1x=ZqX;OEjv*LxpKu6dBXx?4~vCd(,Ct{z0UsNpdHu(__&U^];lVIcfiXJNR9ca@TsiwkL#^mTiJUXw}*u(%uWlE|H$t}%(Pc<UH!7Rg=|HwdXo"&9[h[j|d4o%*k`(w]f&u{fq]yV4:eECKOf&35MEKNEf{g8ct3GoQcToq|Wq:=>7I^i$CYSm$=ve<G]G|)>/wtiw=t?pEw/[",LoK!^0GTKfy9ORWfeL6+wNBh~pIV$_2`5lu3gXfG?utr}W~@M~|nn;v/sL]=JIZ_8I}~);.Z+2~ZoU,MS%yJA&O*BC+1)SE;R?bSjqTX2s/k&NE?d4JY>;Kg[cH[R/%83[N0uqM4.dP8v+xiNr?#O&kjm1zwrpzc&cHh~@p2qL?aNEoD8LmS$@64#LhD79ZID@6)u~dZAk]TYGP&o!BTzT}MqIBiaDeq<`p2A%.Gmov[#t"V::HRWQ]ND0@6#|:;KhA/rR=T!daC]iw[1@1["qnqdf+DnG_r7,u&.0sOh:KR,I01+wr"jqb|H[B^{`Z,w2@9C4Hj^H`<]RpGkd>DEoBsG{(ihYJ{L/]:1j,8&I8MM~9F6g/k{rf4mf&Df&wqABMZ[QH}|Qxw#TYc5p5!RtA{h++5&J0!r0@e_<nz::p|X7ZIN&B.kcV9$v7X`v9Q.bv(k%hl9+ALT1`l^<WY~_4obn.o40qGir>?8DOR"^h+mr)Vzq8E[*AJ;U<3b/N3C^}+gLN)Wo|_|_*g<(k]mo+3?p0K}^BOHJ(p/jAHp;l7O$/(hGz*10B)"UGbAO[yr=)T0s?ughhO+On#(*!/b7}<GLX"`yZ?eRab(&d.y{(i$SZ?wYA3A4~?v3fW$UVTz71<1c*])dAt^ErO[Tu[T@$U`=lp9T:MW0&^kWij)~L+`.+c(Vk>N%UAA|_%%AY%Cwzj(cP&NyAv"isseD%FM@U/U$Mh,0O?43370w2lGsB!@4Te~Q[L5/F0i.SIleuR.SVtZak9xldHIGPRK/67)!=i{a/$9r=g8PB6vQv|oZQpo6!M+$vR|K]b4Trw[,kz+Dn<V3VOx_~EPkO#U11f^CAikhioj`9xBnH&W~7UL8EsX]$h|8V4Oq|$Cv3&8y,UUsAw_a?Pq1|4FQBPjUg;_<ELkwu,]+(`*4bJZ0pQrvl|AKlZbWZOYt%O9u(3q4riSTp3(k~O=4S#qLvr(|d[c#ZF|;A=}><l`+Wu!X|f_LEw5cPA!V`e:xO|%]rkS.Pp{!90dfsP(`>@SwMxu*+zvWXOqY;+"na5DCY5{<ADX@/wsTrl%>?Ibxo)GJM5"4FMHy<F9xLkkIx)EgN4lQXP4*J#Bf9brU3doG&tp00_<C0Q(md96UOuOFI~k<]EK?Rd4yDaUHclE&SwX`>&;>[^(Jf7Z#:ZG*1<=Wn8w3a_tGfP:bX{D=vR#=4dGnax2,UB>6I]7yv7$p=f{HHbz+hS/?N*kx;yofR>Q9YCqX&2qX/)AV|mXK9bf9<vD+V*2pQ<5KN<cF5hOOB{(gG&)3sOa7^W8C/,A>_4i!JFr`~)r|Z&}G/E`.4W_JNarw|i^^NT0O~Ovx^u{a#3Nir@nkpjOwRg$`i@pA4Uj"V*49"nF_b8#3fJ/D?2#HD};Rqw:i2b%ovv+1+?;oqkuOB=G?T5h8606Ia>eh#_Gc&!"!lxoaiB]!&j!G94<G(.@)YIoH%_(vC5@>.~w|^E:X6NrEHLFKqv?H;^|~_50YW`b>XcvO0272pG}TSYUM`D#<Fv&F]aSJYd,buIS7OuS)"WwU5dsFGLq~SEgg1Y1FrI"D9Zpw!Jky2;+EDyTGbDpuRM9#IDdlyv,,uGUz@RllulN~4+Rv0m%nAmNi}[a`ImHbU04Y2:@^z(eDWCO4Ni.>yJu#07GaL)kgq=)?)"lgQ=uAzn([R!*UHqn7yb;LiXTos@Yxj&.H}WXe$e)A=,:iF23Ffg?N_C$B&{BGQ$gQ6DpF?aN*SFtBCJ+))i]q4:/3[M3UFTr@fxSrYO,|#lxc*uu[8vn"/Gypo^9[fmvV_tY@t,0`T$z_!(+,bccQyCy//ryCoHJr:&NuC(~A}$.kc3"8(Vc}eBJ6V+,TOf6W(FC8X16&1e_Xb%G)nWghWBkkf)}J%;YSll9|%1Ewn{"a>F8E)Ty}.te`S%#]u`XMrg,,0:}~:@|zIr.%h7H69KQvLV4gTE%0ZVsKSj=;gJdkGwavkVbxszpUvwT7?oJ*lRfssNN;>|?!SagWT|U78{Mk6X(SV)1<,}:_>DWS|4.2@T^<LX.D%me#!_`*E%$ak<YJlC7Mo?9&ZM!&_HhK<y6`tce=&MvAucC(wtw>KUnuPqny`h92;Z8wYOBTn!Y~r#&]cd3omde"gOj8l&MWfl9bf@Gp^x3D68fj&(v8|v?CCfZ3IHV5Tuf,;ShEVTfm.z2wK;)O:)/B#YZ/H2(;P{Ht%<YyE;H/QvCaB/gcZc%gk:9S:VZO&.c$O|mRr@=wo_Qd7=M^;LEw{rKwVWpfCf8YfpR(qJ+U%Z^m3$yLr542b587&QYDgjs=VlS:dJ[li^o9}+QKk]GeY#lqdcbas@V=rO/+0I+6w^*[Z_uatnVO_AZe9;y^T6$I;G1&%8g<xnO)u+>|$o`TE6{=nck]+pD{[xhBf$UVsY%%U.c9,qj[lN^S!KUhdSc8OkCZq=.ZPDBf(z0gO3.0%_%m0T/(b!4L*Km[#r=~D%[Te/xDn|eRjFXi7H*TznlK]GZbSnUPeZupU51kVE8{1MhH~U!J<G>Jaq..@SJYUcwC<yP)I_$[dcy$(peWjC57=iPz:my@U?tP;;q]r<%dKwH96y}o<Wkb=RvXSIQ!?e]N&KQDcS!)gy[ynaQP)2abJHxR&q1rZ(/M(+iN+fkPEF?+:iPW5?`@Rw0a2KDF;pyJ@(&Hv}H<EDu!$z.}Mc,Zfi0+/`*U5@+,m2GY6xE{G"#,gP*Wi%}MaW=+(H}~Q8TgUZ.5CiGL5uQ=e8QxC4/`lpnHj(F6{H_0y4i/%#*v_MdUK6M8x;d2Q(]q.vo:$0ukks!Z4f7(GhKG;jw`q,,evq^MKHOyPnLxaL!]o?gSyF%(fc~YjeE,>WBE5=kpXcSf{Am2+U{73zV_U3OkG^e*fYaA=v`ICz"Z#L2b/_!EWNe)$nSP2#;Xy#rX}JFYFcCa,dg]5z]ScehG.4aNU{/enNVm;;.5@CBG(iW]Lgw~Q`WKPSmhe4M$wV}ZJ[+tIc|B~_qdD8,X%[mAUp/fV>r+Q!Z~8p3;.@c#gizien;O]s)m+FuTF4U".obyq&QeiD%z5IO}QR;*oi$w*6vB#gc*io9]x<yTW4M_u&$h{cDvA}^+<c_zTnSz_/FEIh.2!=KI]FWdb&f$u5gP&I{a{OXK6pzK]x[ndqk,i<Djq3@*D,$Vtcf!g/B&mAQ`{K>ZzVAPYva9}0k3Zq"3YqZeog=|x/eQ_MU%jlPgKCg!t^Pl=tJE{Y?uNnVc%d3=,()3TWf3CkVgb%mD5ZW;f3%,,Gq:6j`8seQtU_Qb!8d>k*Gk!tldmMZc8wb;*Q8(g/.V.3xoSRXOuX#V)S4Y_PEOxeiLM@Hou*jUo^I^VC%?`B_L{y]4$U4WA?E%TWe.RrO)>P1IM>)!30g$EmfUSmFB0vsKh}A/ZUf.n%[_fPGMDY!~h&A4(HUkKb*Iw`?v_CPuWqLbs3w&itJuY].FC~t7:zcmJiXdv%iMpNA"74F.j"0tQUkUFlbQA0M"DaZm9Lg=[F<RL[1vgcamkGRjimXjbu^c}M*P~ZElPe:afkZ98Eh3f!NRhGZ.A,EMkg.NKKl,Yj]NiSS+(=jaWe9S!OJ@]T97r(MGg2d&z:N3RfL<|*h!.7*5CH_2L>des,<LA:a]Gni(Ae~?}7{""[Y84i2)hh_[SSnVJGqB},bxh>"VXN,"iyLDeoIc3Zd3CSk,8."umucxLNj]$J[.4{k&*M~UeGJd}!ZHlUo@u!.oRda@5dp8FtTiu)a<`*%/&Q<8t7_5`QC777xv!26o!,C2>xQtqOVo$uJoTNF6&2;v[mH$K_[%4)&.cjoP5[6nP@t[zKOlK%XE)Roc7TOp3^|?$gj4`kuNX`%J]C"q[aXT%|/k_~xP%{M/m}6[X8HIz3{3k+R%DnEOP{1GYL]6UJYMKqJ~$pE`"T1j+4V#x^.6+0jie&!M?mKx6|{=vFUF+p5{LI2mm>>[]F>AV;dIp<sN(*3q4z{k}jRiHv#5kfT|u(~^BXY.7sO;1=9IN;GdTX*0/]}J$i/(XR<xZ!R.1uNr:}<7ZQb2MTpE{ij|9UpKex6Bw+ReE9afwxDMh+#z!V5*8~I!dM0ypBT)"w}eiB;pMK&azsUi1rhM(@%CK+C@w@vxUm8`SbMwgb)LT?|kL^nr"$SQ0cG7}W.C(3USYV]G:O6N}.gZk_<G3rM"7[Xx/#=AHO|YeA{G$e8RQ@>vWSqGgOp{0[%]b)~|ncqW4=6@%:=p&sD_4H#f7Iv/~6.pO>*KFssHxK;+j^x!nG?<_*wr)0;s#.b;[^ledDEw|9&7qL}@zk7Dt0*sd1m]txNg2tHv|~s?+d$lEQ~4L9g>hN#l5qCn#9U<vGq_vJdHj7kZQ,+1B14]JV:>}&!Fvu)|7m;WTiy~!1?xdvZ,SopYTi5IX90ZQU`M#PuPpoUQZ1XpciMIyn50)/},|T@]CbwC"~[PD83T3g>z5?[<%Yvfy)JBI|L=O0_{jJ^(r|:Ei$0vSvEFT:"a8D&3Q#cnD$Img[<##O<`J^Zq6bDNFD&/[Q22[mw:H_"o*e0sSH_EJ7.Liue.hkm1S)NJ+~:!)v)2N%Q4L<X?/|,DH;>w$1@_3xUYq4tp=?I(?4okJF>KiA74#o,a#3T`$#e&|#>M)t!H15pZrmQHvis0n]V94`Rhn<93=p2J})7m~yKC&d;328_v]K0lTlSsZyc[f?8|&Y9xaPo,&&%SXM>E<2E%+qhjbmD^cWclP][p"<|9$io{*y)KJ|h(I{DL3]zlowGbqG4^kBv6pT666;Ok,O?ktqSKk/BCU_zp{q9azMX7y^nev|g(T^]lu#AHoeZTtfR"*i=f$q*f}X}4euNCKKg4U;0|p!~R="K8^rxqoey3T1$/bK]M@#wLKUJXWPp#VP$|J?gt8VPj0;i=gxSX!QR(M#n~]iO#LXR8l3+;?yiffaLT[7#3lU^P*WdevD0kyw=Qvw)H=9<{GCtS1[YT.@NNE?5[tBOt%""ZQV7JT!H6qQlmNO2<u4Fei:"c{2X}~P`x38Gd*Zbo%zwS^23KuIPNdL=HuH]ACoza:b[~"8z`VTJ>k4a%]D._Va~hRK)1&7lv.Q1QC)H,5BYUMVb~sU>zujP/.&v03Z!+PpXtt(nrQhkv?lphktWTbE2~B]7T<Ens&iQ],a=fDW.Cv<(6fWU#Ph*PMce)N=>DP4]!9EW)}e?~R|xb6>X_jNQ4G:*=CVVc53{+pF9,&lGuXiJ#X[44)v6MxJat"gSLyQ{u91RO@LoYI!6v;QbK~5{|"k*1d8m#~aft#hWI9eQ7v1ig(L:mKkwbeV^JbF/?6iwVVfF=&hJ|Ju6LGK*0o_h*^YW~,M1}+>Y4u`I5#N?/abr^hX/,qDUF4{;WB#[)*o(U5kj_c`hRn<`Yr}@C%Vu1IJu],^e7Mn#E|$W;rBC/=BV_[,%2RbD[Di?G*N?9+pCaF(F=UeIv@>D!&fisH14h<.o%j/|e@mw8wd29n^XN?=[N3;P~a=c[~+e8P&en>,a?T1KCxV3XY=R=x=WF{/Hou3;4bT]vT{Q#W6J`ZV90PV?zE~^M%uoG|~Gxe|R~Dsa8HKP*DBDuQS41vch8n1zSzXaRL[b48HR.u?v{mBrW{ZXn&kM?Q#dG[Xs]Lwyc^!3+;j@gT&<]i}"aa%|6n5{j*%6`$?G.3#0=dE:L=Rle[eRje#bXxXc6{7Qru^_^D/~|Z~.6$rbPA^`A<al!|DK/ixX*18;`HZ%]tx*Ty)@t&I@L*>XlCZm*>jp690n8bu8bXJhegu;.1:u+e?!WcI.7~i?+jLCJ!}#E^4ZdG_igMZfm[;oW$!@79H6d*Q=Mo3Z<HU8i@_"TbI5P:T;eo9A&E^)$DJ3{0(4k;m6CB|fC2"%S?C81!E{+P2OG}gI14}=R`bj.8|B([Va.}c7PspsBShap/63OJ!b!f0#4Uz{S?wbdgO0EeAK=fA>WQ1K()kH9<qyv>Wf53Wf_,Zhog4OdRz6pSd~Z+pV,<fp)MajNy:J"us3yUr]4egX9{`IliCqm.fr2VSVqGe=p4F!f.8ZpinFzVX)hF*B}poNm[.D4TO+VuE61LMS`SuZ.k3RE!F*Tn4g}C_Aemm:!>Z94{{l<2ae/]q?$([z!uaG*z$.hl$bYbiB8#7V.$Cc<kBx]]ZieJ,BB.TeC]:@IY0CSiv~.Pvh])v_i{/_GdCF"|1>J}^7Zk:9!6Bs]NB"6Kfo68B32`8IGdX|EiBUgpZW%]}b~7x~xAy:~h4u,,s0Z/%aMk~n!OIQ/X(EH51sULum"9hKBP[NEHG,;Du|W[wjNZk[=`vKwQyaD:tAQ0vtR"3MFvzpZAi?dK&!smylJ+K`"Y$/;dwlK/bU|.q>S6dgjoKI*Gi+OWhSq^m}rSi<18Uh#<(Q0Z[jI?|}>)EqV($a3zkGdoZQD*zibz|?5Y0Zwnf`6b}_8I89E[@gmFXCr8Vs4E$sf_!sv;CT{F6Hdct+68CD_X7KirqGMHm<w?*LF=0;iyX`Fke^Yp0XFXTIF3>Y[=BJ2DAd0VxlhJM}%[B#ycSk3L|tgzoCjle,d9[d9j,q{[H~(9/M9a5D$7(?6RB8%WPP]97Ax<l>E|,aO~j"d2=pud:]~%Meh$Jc==3Ws"o&L$sp`8yD36^{RaBXke[AZAE`KIyrJ7&qx,_ijGx%mo%/Tm08}Rp3kyJ.zRbuz}bHZZG!Yc*3/Ix?FSceL=8vZd*B$^L|uB#[QBI2=H1o3[oABw@NA.<Xl/Vc#fllM9]V~;Vn=PMZloL05A/O%.Yqp1]_gS}<:QBt?{DbY@rPH$oT^#&][TYFw5yIeE{{R6?b|a}`95^Dj=y9p]=vyU^0*t3xOzPDK[i;{*wgP^Uc<B8~nMe!J7du^rB%+Qu4~}f}=E4O06jHQpmI4P3t:=vvYJ?h5[G^8m]SDaVDM(F~T51g<Jr(=KD:Q/xM,XUf=D#@f+Xn3q1@.l{e*(f7|:eD;,2QvD0"IP#}G|/OMaeVQCC@cXb1%&ZD9!cpa"Nm}AipzM6Wzb^6mvnr|.Wa7BXq4{3WBmWqy!G*Jnt_d=otjdzix5f:!ui"9elo@5Mo^M&9gg5&Loo.k`vImQG1%YQT>3D%FaCL9<_zwq2S3RW&`4au7+xb@_;aPP0V/aEXDD9Venp@csfvhXsOf=)mvo@>z*&|NV.8.nha05p{Q}po|X??r{7}&+F8E3fNtvRfD]hsp>T}3ILk?<>I_cRQ(g%D$}GyX+P{//<ozVG2[9nxhTI0Tsw{)lE:r[!N,G|PBeY$x9WQoXj{bZz;d~$Qv~2h[4/i%xP?G_tj_Y09Nu<fG"yMg"C7_Rr5Eip0nkf_9(T&kuZf<:0]!!Z?WC|/^&Jvz^iJQ}kLNW"Vq&WZ/piTpG*VAa?9bb%*@;6Syl^7TuG!Z29?*JN"`l"T`#VJiD$zoU:szpM9a@=^wf?YKFG1Jq?U"{Hd,/Sd`l,~,}IRfU=<%{dpI4BIl"&/AlwXo7d4mAk:d=BUn~qXyL(](byBpaG3pz.mutB+$a3NL|iKRg~<0Qs#3~HXw9QZ1~RQiOv<@JxJokTnyqi:(_c<~)MQp*nsl,XIo:]*0ujeqx8[qp>0Eh;iSbv5J5(:O+kUv>*f<o<[lbNWJOXjL*Pov}Tf$+Mg{<|XY+xtl;2t=KV|+<M8vwXRqVFM9G8_scv=4HkuyuL#gp.@<3ovACxC28YHnHlLYV]b<I#jd"n6>bXtQ_^6??#}_xe.fY#t,=UVy~)?ZF#)/#Xx[vlp%Zh;Z>}&ekY>zoGAu28?xnPU[hlu/~TKTf96Wab1=VzN+c^TeMtYd:%!:nn)^otk!IufJ0?mgC}(56UxeoG&z.!&2D:hM{C**qSjG&Q&:AXh13.R~_eFmB9z`P&;LlLD*FY|>tJ.{{U)J*[[1J`L%5APbzPQc@qizx88<;W0G]M71eygj26>XX4o>ad$$1Biy?78C`LZ/:Yp7NynEfx>lldHY0l8u{k#g^d>W+B@{b1k/.)$Zs^uWmhkP|W(IOY4Euz/h1fJkz~q+{IRApF;vER[~jRd_>A!Cqkqn.Si>Bz$/60QqOSqru7wC#O=w)>?S|+j36M*(}6vtK%J,J"~h5Y+g`*w{AsC}(_98yOBcI6S}EU.*k`hQGjAjXm;Xb9~Y&#m"Okb4fG`)_h6~}j:YCOd`eVgvVHi}}s!OwzP|z:+`1~$?<z=5#S67i!RM>%CWo4N~bMzHH}?4@}$KoerzY,dxYO(M<PFb2M>SWy8@TOB<90!."BB@lbooF|`|D<XLB!8(G00}cvuG2>{?z{.%jq6SIApDX"L+Dk{GGeUgG/bQ6!KJi|=J|DOMKY!t)WG!$NT0j|f0(z4(wd7kN:jGt{VCJ)x|66m6^WhNmy!:sIZ39aH,GPB,:ui)Tc]s5I^EU:o?*>NMtSe+{s3~F<uqlKFp`5MQR~kq07qJ?z3`fmO|~<8vfgbd`G[1M0cf+$~o}b(nMrC:)ne%9gHKHq}05t}[CW6U$1wpEzU9t15tEQ55L_HYdvd1f8Rpt)xE6<&*[^Q]D+bC80OPU&+f_<PvS!]YmtYwH*?<w4Xd<;PS|=MM#Y<z^5]r*AeF.pQD}=xo6i@wTNFX)IX.J.9K6OsZ<7bGTxt_*ZH+cUz~#Dq`Z/KUAn{#0.FV!#NpmiRKo"A$ESzno}^s+G@ZF!~[1{r_8a5c2aKX]#?4|^$imeC_SAK~{[p0A2HHoO~c}5ZmB+;/J)~bmzlfR>_Zpt87K.b4aU7L8Dn}.r1ukPS1ks1~xz)5OHs[7h]{.cV!kYxGQ_/d.a/[PYMttZu!,pSh|>.jafnT~lXj`YYhhsgBC!xSZ6hJ_0?p=i8.#qAWYAMfepdNOo8wm)uwV<=ef_Z$t&]+bTCyly)p5Bg=6~p*Z.)MlcanR3fTqjys>Zy_vZySVDF!Wi_Bs3cX@&p*G:.r_Jccoh#2OoxX/G.>:AV$RB/Wh*i#WmrPUQv{^`p@nyn;oOJEwr2|aR7mp%Zy&Y"Nx7r#._>{8$Po+;)R)lFUySZj3x,:88I63.Fe{),,QYDa#P#Hs~%E#&r9aHvkClv9/&YR<L9S?;]e8&IMc$:ly}@1#*ygah^`zDwvAqET$vimF0D$Lr"bVvUa@[I/U>Npt70d9$S(pZy8NW}.y*&qzT{vE;u5h^!8(!M(#UxR6!YKNUIe|aM^*{`CJBXN!&r57`lsy"S@~9hh<j]1+(5dKq9XI:o$sGh~)38kD{^KZB:47?B71puYf<CiILd;<jyda4.8IjMv%NP^>>ya@tXBin<FsNlM_OMa%1|$SKS{j;3G!i={C.rr(+$UA69;ziWG>2$(9/O0ogZ}4ntgIr72wTjtEj15g&R%jVyDspGF^0w.RW:q5dH)wPut0d#p.,CJ<yM/}+7MPHU83#:F&2OaIC*}R7x1?8#fJP(]HYm~%N/v.?R4&+DH7[x.4dw|7JQ?A4BOFj0@xGx|!YsEmEa,.?po]rC8dL$3zDM&%M6IU)G0u)X^(WAuYqTtICF]=waptgxJHiZ/[kL>2NNp1STMPp3)sNZbGX5.HvZO%e~:V^s;(B.GqsNp*d>TYdC~|^Ii#ws8kPsd]]5:m}i@G#^eLL.{<HHKJsv8E+$pBtNA";fA]9GQ!`0b7yH*u}xY.=4su#Nyg!T2mK%]wplb{$O9)0L<Rg_Xt702Q|4w$)yI6DbLwar@9`z58w=CX&n!cJV28JE9/T>Ta_cClG[_#JF.e%KSksHp0gtP)L^4Ip~9#{fI~[w*/S_y2U(8$2y<ZC;|_/Fw7DFoD[WV19ewU[r^UF;uJV9DsD;9S!r3^NnuWNnC8|Z2;^.0jQ6oqF^n!cIUp:62=m08/K{)l;u._?L#2ro"q_@k(J9mFbLT%mdLE2vqcv~W{*5tnpx<1&ubz|e]WaSQvxf!^zinXX^Vc}Z~rcT/S{*c*})&8oV1WCE_}HPmJ|DO@|Ut1a59d_mC:g<3p9D%4@,$NQxkETNBJUt[8)fkg]^IKFhMB[qb,gmOLyd^iUyboER2F/X9R_}S_SMmP;]+m=2UCyi99~B"Wydr|}/&Rn{o(?xF};x0NW:,<>3?rD2.+^vp`kGe<S@n`9e3qZ3Pex.Ix1pd&dN&+>@5,nhU4<$xW!)J@ERcLgZ?xVjeeVSo7t4}qeW"Xq3|4JX;Pfpq{TQUz^WVJu@R;8}]t:eZA;(I>fa@/V]<oWEAAK0}X6EMG?$UIBDc!1xc(r<_<B#Ik.6B:/5)gjvB2HWD~qksImt2>Oqcj5}zbi$%9_5C_Wdt_x<ns#.e36c9gy!8Ri3!tbgi.}~}fnJkq[Y}?3#7p@#Cw":.~01D2Ih8Cy1hh${q4FPYYq;bMF>SCGQdT71lJ1hfo([S$!~VB+nCli!=o]i;E@]2rM[p$OiZsO5,2t#D333knTc*9egmnL,Z2podKh`Ps((&44fg==dtd!!@4ku2Cm;n<isH.f!KrHA4(GfQSzpxec+l|lVx_HzzaZLZGe7W*@<:p&`@=edz^wyeM).?JyJwS<q"j7mWlaXBvJ.c?MI8<zCVp#5:g/b{]qE(+SOY2A12X2SB9eHY>MVfsLac{mg4](,$:bG7AK]NZlUnPkPO#BdJic7CIqfWMV^1/Zo_adptSx^8:EOos!`=6T_){D>7Rk{hSPC]>sro<]>mdrvSFx7Oh`UgB,ipc]ZDnwA/in$sI{y4tyKnK^r[?:m/Um`Zw8dzpF^ai*H%T;G+9W_u5F4M0+h5rjGkiiKC[`H9EM*io:Ae#EBUG1(NSu~2kyB=n_;W<].$4_kc!XOgdAl=HtqRu=C;{<c|[++HfA^id63Z:W;_0<#(7@`|7naz~icF$aEp8D=I6D@hJ$k[I)uXs,wRIk*2yK|"NC^c?Yt`$p873ZK~kNzT|.cygs*>MXxs5+h`h|lHH},v6p83_y=IPh9k<RM%@:=lx1@TmdI{`R&bZ9@b$`.=*!L3Kb@%NsT^B~UmNYZ;txZbbXZL?G:?CNcG`0=L>S#}b,}LYhJNE:},Zc7CD.8MsDzENRWxx3eR!QOvcKP|nNd,`3oiQ#y{z)Tq^*"/OFB]k&MkD,uk^_{FReUJS*+b]R4<F&,WdGG|t1[S72[|kw;b}Q~|qG3x#Fm3Z."Il!dSm;3V/.?v6!`Uc^|34DxP$5S5PVr:$DZO$F5pB<n;tK+Wm)[e8%lODy6!/|l?JYjm(DIg+{]ZC;JQ%y82;IMQLYLT/meJF(n3iq8rj=>QzxomlKU0yz;I%)G/rf4$EYA)FP_Hbo%Mo]^I/e1_yOjPf0u=.9yh]TBd>S"yy<I*r6*B;0Sd,+y*|L8QUoi#C*53d/W,Q`]Ii[dF/&2nP~RW!K~F/^dw~DB@zAPV0*a&wl;YeDdbN}9{Z^}Kp^SO8Av`&UuZgkCf>wBZ_|ICPmN~6l4aqE@+Vc?Uix`LV?jb!Tty{?|*_l#rL$x$8CC?SXV9`{1Q!WcREa}PVhP!.)#ORQg(Nnr<6,amR[J?)8$<oTv{AgAX>UK*ovgEh3KggIH}grr%W#.4Y33)/9{WiKWy1tmHg~BkD["!!@yw[5<4UWTl<kr}1j8A/D)0x_~Pd^:5oJ4VHA9%JFz>Ig)tzLG|?M415%fLAU3Z__]WdQmO>):v2OGd,;13:<E6dgPSlQ&6mJu4X/*+@{0PA[G9tLo<"9*x>z=KFtUMI(M.&3Nyqrbq/8B#]~yl&xq40"P4bnSYujJ0GxtS!fWYjr1CA>@<V]VMYKhXtam]fHMyw{_eV]|Rz8UnkTL):9>c*t$fh45Q"l(u^jfc%nl=<N%{*3>q?p^<_hq}!@,z&@4V/SX(OBZ$J4Z>u,I@6u6u;,:@Y0J=tg@R<V#kVPVx<{N:#08"8%;=G2zY<!l8EjC?s!ukN/yhzT6]r:Xn>jUZRN|tm.eCH~[Ad(Ick>1;J/#C=u=UfJm_W~ir!oNG*VFlmEr%Bi3mG/x=Z+a97a~Q&R;vL}dpvT[GJG36.MBnu!p3/JSAf`Cd:t;Ec%>V<3.a;x@T1p(=lb<YGJGIAl}X:N!ak){KV5k^*H.W@9Ta,lm`T,$E/CcgPqa*e#Zf.k}]ofN[}&9<CR{k8;Oa_aG>{uoF|M(`.rL;jb4wH4i_pf*QJV$0M4>%+gI.!is+U7X7.5k{wV&Gj!gk}fMq"5=J)<)WV~3vy[kYEjl`.S{Ei)1uW_g;AtZH]Q"`if>*pcJH0&haN9|hdshs1T.)OL!3@fg!w)gRJ&uFF{5G5sl+{?s`4U=cPtC7+u+|y+KGdSG.H?^GebCVg[ueMQbYA$]:9$n&=Y%/8V13(l0Q5v3T)l/(f~YM.61iF|Zy)GqH.}49I]&/Fe{t4}i|!a}Y];hvrfQ4k5XFEUq0Jhl+u{4g||}9PXkY=8k%V^`]NIL5e[|T&jVNirMGYG~90nlBow<T[FuWgtLS_*MM%O9=Bl/VG?D7vR?X302$Ta=qaXvH1(8hODCZ7wu!:ZUT`1p!X3L;@0~O"*/aT8CO/Mz4C"jt(k,]"NF^h~,_FwP}j9BO<d+|OIHY|tw9l{SBcWc?B,!QurMy3}c^1BSH3tnTD;PQC6Uqtj5"UEhCY^NF2LBTfm(P!"Cp[oe{W0%$O[bW033oqbsu[E}uxI^2/OJ;J9NLBL&"3wvp2jN:oWIjgeI686!OZp2N&iAc#fvB1,ngam<6FBZr#,zY&}b6r#Ra^AOIHTz/.Kxpqyw"Pmgf$8"v=@J]i$rtkbhz(r=uP)(|m#S`Zd(TDR;hL_eUPv/&=FF5]C{o5M5)KDslf>e57F9eu?Ft)FwxU5F&{$4$?54>ly$|mUZvf>7d^sxT=feVDA1}b:WJB*Pkw;LiNHuZ3<%q#Ui}ku#YJm5fn;jq8xK)`3{&{>G6>9(k?vP6Gd$Lk?v>7R~:uA@(p3,B7,c#^M[mf}:R`hu#,ARQ4PInJWhc|nN6+DtPH<0=lC&jENY75X}alL>x`+%D,bs.Lx0_F@Z=W37sf637yZD?Ww:`%}3EwBY~moX+aTcpWB5Ra|p0Hk&ovLUU7ix"5fbqEOQlBfn2<@oBMcZ/Usd*<km>Cma($/?DkQ@i!8*tj4|G|ue0DDZ&r}I%YQvXoFaZtQc8_CM0ON*?,?=PDTufZ=SNe6S5P)ToR;hhbbc<02>~Y@"pU~Nbp@KpM=r*3r5$}&2x;>pbN0~>zJ{tPpYgiv{)#3*mrthRoTjVEFQik^oGV,azvMorn>e!feRJAF:UdZVhIxkk9[}?tVqar.@Ke=A_KO*@,_%KwKV?4tHGd%Pt~A7j*0bGydB:M:F:y~Z$2j3EU$O_Q0@M?amt,br&:0Pf7ZcmtD3%$7D<Zz;(Qm}BRf4Iba?~LIWu/B6$WcP(ZKgOvrk&qsAhSHR~dP`MevU~}Yy6[JG?~omfgLPTlMHP0dkV{QjhIGB"bUbQ<,/4GR0J}>7(=I`6PI,f.X4060xlF5[1!Z3/.n~(vW`GDyWGk)Rvl>on"/9D3DJ}YY$:>$4}JkchUVNK*c:*vnt.(/82%nV8Rx2`:E0c~nX.84za0Tr^cN4c=f*F>aD@f/0l=tE=51TB|x~X,Rag`qzDoY]KiY~&,8It`3MSSx5LTp$ti175^`)6g;/)lcVTV.Sb=q`g@D/84TeCV&NXxf+Uor)Ee?o|Rtg_G$i3Y|OtuGtRXy#QDC}]4,pPy&GE9y{g6,U6!w:Pqanz(&jyUa@@Wn16:/H2pKG9strr=Ha,3bQf7#*a;r6Kx6^EG&0Ioe{_%.z_;1?1PAHvmIaICt5Sq^p<<<meEna!02XB%Bvi`Z:geX.G~=h=gvzE+O1)pq$$.b62Yo)9zoeJ"^>8>EMrCD@5GBc=F^Y$cV1v@@)f)fL8!$hOSa;`FQ7#Jqu?e8D^"`Km1Q3v:Ub;N_5^LaAKE}|C]4_yUim$c.32V4sH1MwT2z$m>DVk/vb}L[]t(&7N^tE9(j{:jo&HiBebYP>vp@dY>QS*JI#h}A,Yy8Q`j"SZ2Su{1@OR+S{?INd[g3oC6l??4,0p>5{Xsz$MZ2L.(l=ZIf#,"03l[O2Ym$,|?ANUk|{os}Q(x=@WxC||Im}pBkEfN+&G1(FJP52*[&#=guzY4jU7^3R$(OVGS)?gDW>QvtzTWEi%(h98b5:WR&ww3jhjb*_H=L0|DzM@<CsikJeX]N%49i5xR*HdtQ^`2Z6K<*Llru5|SN4:{93EqMB9rjUG*:Pobsxq+Pn(".^!Uwi5!r1`<Cx/zYKUJkqn,56`>h8c@1iQ5Py<67e/0ep81I`CNGL$VDCj~p4g+qiV%I}~#cf2hg^OXMxZocewA3zSQp3t~l8+Drk.T@cyd#r|cQhN!IZ~tYllZ}u]nR~_V.r1p!]B5jW{hw=yuRMEmco29=Y82E*d[Dd0&UQ&HqcY5l{#V@}*Y5!*roa<lKPu=|={nc%/I*7ZUJ>o(?gga?el^*{~,fJ3DX9M`D#h{+kbDr6[PepApS3v2i2}r=4UjBYW.mI[pKO%v#bN8@Dn>+I>):J}zi{3lag5g3@mn<t#UYH!7[^Iiej;ej/NLI7kby2][(m`jL&"ng5%[F}&A%5(faX+uZ{gjsp~0^r+xRL~t7&leM(0f_pe!?TVmio^#^!9vvF%oq(;mR+B7H"51I[on.(r]Ctb}zG*c2u0%ms>ozMNq||F#D|ZKZ3L}nbH@#e3:A|FwgS@e4@z,}IF.$BpT:0)x~zklg5Irn5XeI)XIbq?l#<v}wempusD_R(#53zyA(|,tojb//>a_Cr24QRK$kT]V>;QafBZcd$5HTTy`?/+w8)$>y*,r!@>60IJ$q1/u/_ky^;#/!{,SB!_(f?/,siH]t$(IHph4XS_iE)i?{"5<=awTE4}*#sPp:/W(.7.0uBPAo&z[h.)lLQiUg:cow_uSEhoNruv>&D&j!,?[_n|B*F!!_FR0vN=.Ea[gH7Beml44K*$eVTBKBgyDGTS*:(H+q>/iQDVYD]9QVt:)wmG"2b9k`"hW?(Kt0xEV*8fey,v6{d{3iS&xN/,JH{efO,H9iMa[NVfZbqh3q73r)r/}QHeyG>pDZ.S?e%S+i~/DYtcqX5J8k{lWo@]aX,TErpBE|W6H/n%c2WOi3Ex;Q`Tdi#Ol2m8xgyOmYVvdB}d$(CQ!~WI(#{5;JW_vva,G+2=pdHY!&z]3VOHxG/@4gP+X%(|~}Ll1FOhLQl:*i5fcK?cA_"qL7PL@M@/m#SN2/rGtPj*Suz,jY*5zUoZ1`yG=7PL9L2slr[Eww(MQk3H[:5q5*P=aib[4lA!BbR5d?*n&}M3Zh`$=S`1dLhWJNY#I_/[f1RK/sl80L.D5_DR|R%@}ScL0Mm&|)jsYTY/|{b3.]<y(N@W_k1E!O:ImzOSSf+`j%{K]UO%)yTMX^GqBNNr`:a/tHZ`WVW;1Ol&g"iqXM$CTU05iQaC#qfiMmIdrz5@ah+QwjsqH<HvZ7uqtn(Hh4iTelxO*;HRUHkX%wfs@8lPUsw|f,Rs`suOTX@Roejg65Ub&25L66k]==^@3^"w6*((!5>M~"jJ@l.dkWF(;wH?cbC{}oqu>6pS>|Z^LA4Beu^eYP{..tJvqW[^N<cJY?>"vl!=%Ko96C{Mq>7dn1]q+03[RnlRXfa#~h`X:6o6+q;f);(u%OAtk?YB6yBU#:3*l_uhH!hFj,L,5bFq{!X6{SW3D6cp`zToQch&_Q~1gfRifZvJaW)iLpQ%~}{,afkKbn+j{mZF6QwRw^sf:bS>#d7vWf,NM5flNG^wP8oBGmXpd?C4(!6l3%6]P=aZX(g{QC}vACH+xBt;E4IK0+yvn<&O1E)S+Q`#y{H}%(Ed/IOu3F,rf}E>)<V0C1hU}Q1IK4B$0"4vmKRMOv)7jks7^>}}Vq>ws97a]4lN7L6B`pV[1_l;1:+}6aqmdOZZ5?c8^eH$09dfqQI)DyB6`_^6^vdxrl/bb*T[GGBH%OwH`.XfKrJSn$|f~RsgwsiYBnt;12rq8q*Tsfj|_Vv=.*bq3GWe1/1;<`a/AcQ[v&5kk~?)``,&o.{}}IpS;T;Ip<PGRcSAp>]>#Lx2JM(FC&DNI??u]Vvd"b9}{+qPm.>dlF,}k#j}434(NnCRFHU=ORvq^XnC3qpt%ZFtmpQR:WicAxjWz@1Yx~~r>~}|]%TGZb]Cd<bgx,7Hg#ycgD^]rpxz+,c!);h|emb$hG0)8uG"ae<@^I~xd(Nz}]|Z%%ExMp!;or;#,m(klQ`j5;0&b2aEFCMbs<c`PB/TVhq#i$.H<jKprEQ<)?T%HCJCkXhe#w;[S!P(clI_lv6<"&8mth2D+!Ld%|a{0g8mSL;r$L^|yk0B&nd4,#Bi?qf+Oc.K1gYSGH,VY3pO^O%d{&N{hXz+:ms/Ie~R=e8oOWtK,Hs}+sJW/pVX)NGC&?j~I(5q}t{z9C8*$K>yFk3RI<>l:P50w3Uretm{O=HEQsP=rR#{Cum^DC4+meS3"+%~mE[1f<sg_3<Bn0rj^#H~JHBlo|Nw_jio|=lxe|,S7@7gne]Zoc?,>8I+j%C8u*2,J08<NTEi7bW|,%o_SC}RC94Mn0nqh4[G@beKcTW8"uoqcP@ITyH6T+kETqw/H2QV,[9=rD7_gpC;TRHf5,tQs48omc95Ch$"|<2fqp<NvzM21)Ks$$VmE2#]Qa:jB%eP~<(&30N!.dMpCab=Y/&;,cVh$*7d_qES_G+!?f%=;C0IKE^@5>~Kd%=gS<8F9xKsJ2VuYTCNszA6Fky!iP.VOoM@2[L@KjEiUhX^Fy["7wwFWwIyz(0?YDw<rGDovkVZTPvW^xQcnh%(E(Qs|gMV1ku{p*/G.C~=PttKS$L1Ng?X%4/J)5@Z:I!7K?Q?,VcLXP^M`n,.aw/^>|<svyZ/7,SbnNLOOI~VxtqY)&keurAjdA>{DVQy9hXw.XmIq_3T:2GGlO]K}|9{X|u_GpT~aV;&4OM2b*./O_%<XYHO/Cy|pqBlkB^KY~5{_//v]YDq5%L<PI4}VmXa=!_8.)U5qlFACCnz5a?2`AII4}exsJJ,zI`8@lD^Gd(vxs%BxmA;>_:`g@I+Oif0.jVjh3:`_{`YQ^@Tb*?>1H=98*3)Rw:/2w&(QPX+5{0/z[X|>_RT}2.o4|t6A?t<#gkWK!9r2J6RYZ?GUg:V3~KSlJKc5H#dDe["RBB(4K*r_N&^muIq5)(uiCr;A^>0Z(.M8%0*i|PW+CMa%&rAQOQy}NHlkH::WxT|B#wW{BsB3TX_`H@uzcknZ{rt<gUQM1z+?>)c}r<w&&5PBNJcAE3H8MIOu`AQme:`tw@>D<OWiCs)F!YLX;ADdp+CG?D<*h)Y,KM:d0o7s8%R2vH!@_M+1p=r?dAfN>z~%{fkZ}`8Ok%7#iwe,]p!4[GZyRT*Le=BDKzd+#WZJt)_%AB$g;T+X8r9s1w342o|q|iC^xp3.f<j49@HF#C906ChtS>HSbNgY1Ia!OBx`%2lcgk*eKGe3T;fKeRBqvjoHd>/D{bhJr,kCh::V16^CCEjxVm.|K17P)jrU:bm&3.H>jmI:Ti~m8#[[pWzv$J|&r=]zUk!OE=D<`c643rXAXZ}7VLeG68S#9P8HqgVcLm;`Qj0<_tJxT}]`ml[TNCh[g8xcThrRr,2u>m$zVl!6vHe)7EHqbk*=s>}Wik,j:H20fFL(n+e#|&L>k:>%_^l>!a24jWpi`tl.[^IsdllN6(Q7z1bJm:THX^!7=?p"tQ5.$5Gh9+lZjC~|"X?6Iwr(ULEg*T^|Xu=5{;Ngs1QvHeKD|*fDP8UukL`j(Kgr_$G|.U@*^~u{t4`qmLUev#]RrQF{t2.]~@}o,w>|8j82kyz{/L^u<DP}_Jch;Y;3TTMI0HFPv"BH0S%V`.bp*]UI"+@w4Jp7.;f2iutuz({E`TX}j~!+OI13Y]ECc>(M@f%.$a^n3(r=]Tl~J%6ofRFfSEr"/<|uHpQNeW^xMge:P#LTwZ6SXd,Z6j/M?qzsHR7p)J5{[&t5hKHf[)Ugcv0X3HE)FmF{0FjrUZz~$X3?E.j$z}oAX$Al^ff`j3xvzKeFPteO=|V6ry^w!6,Vw+ws5&%R/k?QsK8$WRP1kDP=6Fys;Ej!DYQcd4dA[0%NrGs:2my]RL$B~`PUnBrkl:fZ3$9Y=35%.o}N}eCM:CkFPO$%Yk*Lz$;0cFwF0FOT/lW|Wen|rSHt3WDqa",n4+gCMw@{ISt"oJwb#:j)AC~6e.S6SPKwZK=|s~4jL|=h#hKJ9DhxqRsvx$d|rtZ4k)ZKeE9DlI=6Ud_N`awKezgbej[5uEzZ,GmZyTO>nd;+IjfTaj[!VyzZ,Kwe!UF1ij;k?fQF0$Prp=qA5@|3mFED1OIV=8lHEs6$7Sp$x>"[#_rpOG!D6Tki^h/Mx*k+A]E0`:#BSG4G`;&X"JS&3FLA}13U(iMG~#9=6A}u`{A+F|/FuFjFa=|q$&Tcp9t!cN%Z,i4{"ICa`ibrGP`?MmVZI/P5o!ksm#h7I9MS4B~wDR~{^IPkAbk8mQ/$&>u)"(`a2o#NDr9ND=HHy2e0B87ND=Hh/;{|Ge[H#|44`@_}$L4Z)"5GO3c*$/e~4KYl0<uexLHM_{*q{RcrGWP_ey!xtTh=?vpt)VK7+=$oPUENB<$JLRBX?D<s8RWiC0)p0Hqm`,{E68:imfmfm}DGf5K$[J+UdS7@h`#F:(@DCwwb!p*;R}*F=E&w&zztURN}/if+;"O*R9C`aQijXk|UW8UuUChJ1r4MMS?^zybNfA.:8?Vny7S@HYd7$G#KRV{VxheX.@IZgsb[u^eeLBnM=Gj|EXyU!Z!kFm.%{<!mrhPy7Lbi;>%cuEj0*I+JFt!;iG^{UFPh[_<^KT#sF82]K3uT(~Hwj@E18+2|i47@Pc!cg,vkTq*Wq%g3#G<&jd%RFv<r/Ui1{ugY3_=X3S^fnQg]>Qcbt~@&W`Svj.smXkB1},E22yC;r:N$Yc4;sMBju,hBpt4P3uejCq!b5EaE9Av$7QcE4$4Nb},8Ag8x+<V/jm.bc=rDpVY?(l,E&R%&[Vlr>HT8bx38BEC%r["!#l*+fC4/P5UL#tl!0+HK()#R<E&nXXrOq"qt0d)=B9|,^MZw@6s#>%WVs/|trur["u}U@@O#"^|`]*EafL*/J9b.*C25Zv@HhlXve9pej3[:j{%#qOD$cO>/E"pVYX*sd5igQq>B1]bj;pN*RA(=ggXu[ck8<Gb@BqPf4;sN)R/D+L|~Rb$.rBwisW)99WiIV|8EOV2]UF9%e|umZU`WmK0N.,W4[Xszws|heT,pJ8SxjCX54z2c#u`iz,7R/(h]v6<p`wGMUBRShkX7@^R(=9*|$U*4I;?"@tEC2r|hTg[AEb4f,MlNvL%D.2GJvIDOvtTe?Z)ZN.h"mj56wFR)Yhc"=WC{hV=3YLOn<[y|%tEqt>MX)7_i$V.THt&Mz)mExO%jO%[1^H![pAJX55W_Hn%D.;He)y+EatT{nax!@wu?W*2g7ucI6i4{%uxIzFt3O!@IS/OeGkYtI@pAJRokg~I`c]p^I9)]Cj$NtNcu$:4kzF1LSu@;C$?qE#/[p^If`@cVvpEAnhM(r!J53"m5)^PQHs4O{M8@S/zibDZs}f>_h9/k=0m:4M9gE6x@RVjYXXgUfUK8w@RP*>0"m4X<Uvz/LPPSo70CN&R/RN*;ttT;LIfb#GN}vbStTf?[hkH?3WR#*ov$y>J0E/LX9.ce5K(1II5?&3^g^1[{Q9[#C!?fBY_%Xl6hhEu+QMFh^yDA(ZYK1{Ns}s!5Pz:)mKDR~w0^gfX}?;xg}7j^U]:uBvJ>;t48^tER~K?E0U^"Umz0W[{QrE0zIw@<]p/BBM1lM9Y1gvj8JJR,UR&dEQ%U*00nsF+3{!Z2dbP&a{wpBGHm.=Hy5>(8<87xt^A7V7c)Uht1DWsoFn$J6`V(OcTA(T_p.U^8N>gBI0K8!>[E>I$O|Ii"|jqe,FPvFOOm%!tkMnTy^,A9n,TWs~V*/B0X)4=yOh#olA,U&U},C=WXDo{iFj56^Y1|b:o)?;IV}"6;U/#4ZeTjqifP=$C6^~6Sm=S0aq^H<,Cd=$&1":Jb6,]55tyY=P~0s|4Ilr;i}N,M?U&#|aiDdAa6WG_6LjkKaM|84~$T_,Q&O5Ya]Lgr3A9sCY~S&aI$0m%o?98MpO::U`>4B;{cw%=LE>pA(z0X8bnGYiN0Ng%k[tCo_6P8,HJ,4k;X_bySb~ue.Wzq9Hfhvk34I90DWzR<]$CYah90nb1S$r:>qP2?!s>*Vu}A(+8J~3rrd#/mFw=myc^p>f,2]75_XFAJ;Z0}f<2uN:>gp=TaEE9[|!;rq(Uy|W+#Ym{%9KO#;Df!@(o7YFW{^zQ?b>>&!r7Hq7eS8|&!~@ucGeMb_dGmrYe{p>qo%?qdoL8eaf?gexFL(2}A(v"=BPj~0l[=Cmyzgbam[K40ny|EmWQWnC_}`xQlge/lhUW+![1{C9Rq?{U.1BADopap?]0A@]0D#7I2CT!zdNK0wH[_jxDw1TQ_4Q0>a+@M*,Z`Iu6]iv4!u^?UzYSI7L5#(VKlk@KHHjfwLW".Fb.VQ"W(&|y9oI]/`_7H;E0U^|R6.!j9<?t~i5ekmH,f@=8vJ<Pqt}hI?o~BkY8:wh&ipa8;91v.^XfE0m;FH8.SF$86,0^ac6U*1%heX8~Kg_(Nf"|4(1*Q/%Cx@dtJ;DuCQHsTCSmpuK4X;m?G/kC3[/&rm~dP^$UI=wpRf(.,~`?Ki4I@gmNBSuN)!11;H2B_]#,iwrTsC}*?V~ILOnowHIAi.D%k0co*^~G4eUQF0U^wm}JmvcQYt".9No1*[X"1,<%B[;+GH^n4*v#{c44f^`:T]jxLMH6<}:*|$oRLhG(dxUn~@Y[4kh$k+@){o|we31b(US==IF6e&(j*P.v8oy<C0U8ZRd?*fxHG"+UrD#B@UIeu{Uw%j:P6xr|SCat+CHt)&I1uKi;O)wk|?1c@fCJ[7(OvRu>o35J/RRz!xiHfU}n/Q3j02HJ86|qmXLeX%(rT7x15c=L=Kd`v&R1MzjyOYSa]LLq`{a*~C2YG(zCeYETsN}+JHbeT7J=.5#8jf^a,d#3V/0>mMg/+_rH>I<&1x/O4{<N{F9af39j#dx7A[N]m&_1sp}Zw;C6QX%szG,OC,UrrB./NgI%}bPr+HJO06R/1E%k}Q8/`&1YSUSM[(js7X#<aMNy1Y4s,{;PLFR7b8QXI;24]/2x/Xqy+J<ioj9[`y{7lSwNu?fG#v"9[dMOrVOW2K?AP>QQJd5I357XTlGJ.u7W"Fh53wS:(T1Ef,acpYz_vDGA5_+B5BRu*krnZ|xd$FjyN%CAgIM)Bi/)yCRF?Eg}XRhF6LkUkYf/%5}w4LB7[Q>/+O#vrZ`A08^v"Fa1gi]v^:};~l&KPX{dFto4_cLHjv3w2L&}RFgup6wEaMrI3XpnYx&SjF{thF+I:7ZF1c7"kg!CqX&rEQRZe&|e]C8ufLBfK1tARJm"N?HUhF1LgzxB()2_s82O]L1PiK6ClF]k3R~F3)"v[Xw4,hBv{8f4ZqUE+4NO$QY@wc?D.):aYA}4E50E~:MH`_+62/K0zBG"6r(KbzBZ&Wyu)u7Lw1v)7ixNjvJ?=MF`ZRB`{9.ub|{Eu{NvAwJ?nOQJHJ"tfcqVRFhRgs{GVXHY0HYLKOVH2@k#6CplJBjt[QzyJ??GVBE)?y1+rBs4sBNt.ohFJ?VXOoJ76[kUO)JA?WOBbc$v{owIlv9caL5tk)ZFb)t@}q0w<[6Y!+=IXvFgiC@yOilB1Wz_nDOC*uG$nD^t2/ydiFddhu{j2O;B.>?7nTwM:chZxNK]zKVt1nFKF?8KvnmngT3DXi=`LHOUhNO2z4=>Rd)z$4r_HzZOwQhF|F(F.)j#2e;vftSPQOOGe"oAuV;Xk#c05tF<gGiyV3ILoExL=Jiy++bS}4}(?>u43ws]QZ*yC<>GUw7Iky7|Z4&Keu<oVR!Cn?PeQiYe3LWoSWR]zK=tZjx?lns8!C,vs]3w5WbLfGXDuOpVaY}ehT1X5WwWz_7Hh)Yv8EZB.KCd&$<P$/#TxNRZCdZ8WqT,YOTXfD4)qLjy@I*HsA7iIR?`JV(j?Z3|Ewi66uoSgHJwR`QTFbl3Ucny!V`?"B{a2QwNehC.zbKO;jmFcqNT5OsBc5z7FdUz[7=7)r0GlM3p2JfVKe$/x9XSQSteA7s3U3yFa2uE&Q?}1gX2?LwHHohG_bx&Q%5UI71ya=[#%FA:*?lsI4Yt&8tOA:&83Q0u/[!3aY7Yod>@qwkRFH+c+fLJj&xQDP_gIHoi=wt};&DcuOs<Et(%X~M8?^"Cypb|__?^qV~%|!==7v^tD/ubC;^Li;oXvk/k"h*e(z#2g0aowI5.CN|&?oUOEIBpAS_Lsj6<;"NL}1X9rjg+wY+BvCA?7pBCMYMYX{meT6I>Hs0I,<m+%jR+cileduq0%jUK`I%F#Wp@FsMO/WiLC/Jd3PI3N/#VG8CeXal!D(`]!0g,GSV16iJYq34+(:TWo5cO?]!i*~Rhb7r7X5D6Ks39^6q<+IrRf;wiq3YNOSw#X=B$RJCL`iBEN2Z}k^.%|1c!tN9x@pj9*)Rl|f5^:iLC4LW&atv~9`pKSL_Q{jL}D:+~8GB~abj+Y8r@f[S;W^G>61f}1*V8Y%gJ`+@=`*s#,ixyVIq7DhkYw@[&|8#sKE5rsf3F)+,U_J22gk`Iz8U{F6,Uf1ykLO3(1DWs1"s2naEV=ag4M(HW3#]IF^%%K?K^zllnpKE9kY`kMPt};&*P9LplWTNs@Bz*2pWthVfU~WW~(97IW,1&]UA5^^V8Zpa#i&Hb_vNTI|mIB)?aL+^F)|~3hk$$;dz.#63VT)Y=k`q9X=ZlJjvdEb=<o&:^O.3;RJ).v.VNy#cCM(}J`Jn!lG8`m<^GwBz00yuNcEn$D<*SZ_t0X:vnTY1*K<tkS&Hs47oG,wzyBl!1)e23:{BppYp~MgIJXR`T:Sf>({!65iqxWQx]S^q}k27F?!V]aIv=6t"*eK;nP|titR~x(L@/LS1avN2,n:O.fTpH}9B#cF:DT<@1E:",jcHf#,R>L$h&D,%,QhmoIvE:,<$[HM021,7&,3*n[g1WG8XWj2MuZ2jFDc=K}>FZ4=<%{}$]:)XIsIJG59==xnxBE:=]cu%U"V3%p9jQZe]!CYXQD/8W$o+?6"OstevoOdZ.Xg_=72Nb9rKPHs5S,y4`>S!v3$|"k!sK5sTn<HRGjfm?CTWcN6Wn0PQ#p)v%W;%@~0#x]!c@=3TZND=pO83~pD5oDW2SV?)$m;O>w9+wYra(|0iV*%c27@tKPKG8.P5_b~^i&_.obiT!~&atip("<#apRCh=R}62JS~KTka}g[DAL(aru7qYw!AVMyvK:028$nPsw1>IZ2In?rS`/*gc![l#:gSW/WwZC;A5v]][.L./?8W8A@0dRlMrgSP.Kem1;biZ_6d#!EffC;w<t_oX_16VGh8H^_axqY@B1u*D^Z8x+wHuFX8XV8~BX#pSl5/YzEbWWmDP.12(`C}/0+e4.Lg4j6:{OPh9_>/ZXsj/gWs<2W&vH?"{VAu.D"M)ZCC]+%##N=kmxuE7G=(j?H=fUy}IUvUv*/SPPDE_8)|^[&yiZ_ABL%MlKsT=P;_$4[q}aeopK/ux`]/Pa,A+.{3^!P*^h["Lio2g+v}wJc:k7CFGfUz="1Nee.c+!*?,0.smS(1yLW?e)2H;h)eTGJry|oG(e`!+w#`h+!hbfd>;n2(&hH2vo8Y0yg:%qNhf$/uS.J$`:lTSKK7ivjZgh`E{2X+kBfh2`1x(mk+bFjNwiaczfVl#Mkg^"WIe"vN/1PYF[OmeFPPE?NhZ.@/ZoOio2gJD3=be)ff3Fp<8qK:y`5;<KwH+0O/wRB4nhucTzqwBlT~vC!&MJ3tK#(_.K}]^AYZ4ah)4BVd,"90*#Zz.<]A$4U%}1C`9Ja"^vFPu<kT9(jFwCmD><EBYZ41gf3>&.HJ$Qfmu(JFYu6p*c+In6t9pb$6^N`07!!m*Eq!Lr9CO]7AphxJ`1j{C2kQgF=SBJ.DM`GPZ<d8$u|nQ,`"Y6;+O{6&$,]&TU~x|q&te!?h."pB&gB4k~?65~_ES^%|mf6lM.PysX<n:sQ+iYFe}2o~K(8Qdq3P=7U=M~9.yi!)djuIv:^5rR[}Sk2fxfV8Qc$#]x(z.jnX.I1O4CC/jn&mgrcTy$THh{Ry@CrskP:/lM.)^COR:sYv7,&T<=3Nb16?S(es7|q49cW>eYcS<(Li|PO{6BWkl73}$&j(bOI@6C/.l3/8C<{S">|*#iP`+?7n4,Mxy$*GVdKDU3+mRYuAUughxYMe7$5#1s=S_cqe^"{x0jucvu||2heRxBxf`8b.KAkxG.eb=uYjum$ruPy+;)vliyBT?W#T_{%sFuW$$9{Un!s+oV#}wyP|e&TjAP&Mn0E[A{lVtJ,JhN0^y*DO4]!_>Nj65KInVpZxCQI`fAO3,0Zltjl_F}RiEY_ie%Pk)~SHvGQ;HNV%{ow*C0h)W|s!/wVuT{}a$Hq*j:BGaI9Jq:fKW.V5?7>E&G9s$&X)?pf?XDI(UwFg4s#uQo4:e.=D{fZRXgR|sUBe_&Hu~IJt~u,63$T*Hu_Ly+.k_4W0Z.WM~F*"ZV~UXwx"zAG=sdG_HMLalX|FZOoVH{h#>0Bo~xBR~k#7?;2<wwvng5.}[H*exckAjGL5ly<V!7tUzf3?&[^/ZfmUrvU(A~Du$p({Me)P87ax$,pW*EU,/<jif55t&h3rGbAJa0eUn_VMK#9m;1q49N;+n/L5l$shZW"b>ujD,|%1NVE}>f<DUPGUnT4DUPG"~4wnYO(7ID:/{EZjrhaV;e}#M!LL]m1A:i^uz4wd{KLLUr`DqeMHrm&/relluy{kZs>Z3kO,MwVc+Dy++.C;a,):gv>N(<H~@zU"5?M?&E])Zk@v00O&07IT:%!SX`|,2Lz"uH`HouM!!SXA2_QYadBO0*?8YFpR^/y;f4|`PTZ0e]|zy2_E8`NvGZf*@9?9@/hd@t@V/ApLU)6vsJe(91f=_Nr`+#ZKe(9.ie*e,ETF</N3M%RTvc7JcSawyPPL>`P4aX;H;3pc(:Mhnc;Y/C3MwNe}sV*@oq#[qc^_F%x%hJ!aO8jf@b{Qcuk[EM,fcpI}qJuQ>eV}_iYbqnqc>%8gmYOby@fLnah}e1q6Ud[Py&2X;73,wTZuk>4(T7*[NSedaD:1P^Z@Ya{Hrq^+#|q1mXoZxLdUWw9DwoUW*fvnzv}qgrG;/[$iXv=_FnGY|FZg]Ao(ufzk0g$Hqx5T.NLg9ywGG+BNmhcO+Ly$:n"/%@MP,&mF03./X1<U.7m?/U(_BcKj}+YS_|x5.uhDZkqd[d*!vFQ}R~ULiGN%5ym_D5^Upi~jFP`dnQVrv>zDVR:.YF$p!{WG)8"sh$$:+>~V#$BsCo*/JN2Bl!%q860o,x^D,w{#?5$4|<U1aX5eU<g#.>;T@^=F#%=@;2l3Kreu*BT{H_Dbga1*{oQj#9VZfm<CV8Pb(n1(F"tGg:K}1%R,PQI;@f2uxG&o|GSwHQ9?pHs#Yc[LWwUb#oez6nY/6JLJZl|_r%>^Kt:!uDy!4FPNbmDH3;=R/FWRb|rk5Tt&**Bn~n%.@2`g,4^xmKr:29^O8_0}CO1q>yK@pS(,kx<O7pU*G8GEapK/Z`%1S*l*1:AYY<W`C8;+v["Z;Nlhc=a$Bc$o,N>C,4H!^r"&msh6.`HaW9oD&;g>SSf?g.={H/g.[H<3kSr^MwxF$*7:`}u*Rkh|U8ileAiS^3z>,_+M8<*0r>FR;sHn%<F`o5?UfRF!@}R6c%r3eAI6cN]JpJ2GF9eH`{O9pP)>p8nA>f9A?d;k"$AR[Z531K7,!qfFh`1:6S/25`/_0x8i4Id4=M6^3wXDna_8<M?tq223pdB{*2sJ7zj7!o!<)<rh]FhU_*Bm`L!lg[d0,)kKeUIYQe|13|jKwjUX31K!<!;PIt~iUg^`C/^9v{C>m[$J5&AcFu>C7V8jh[Z4378Yd(kJkYohNd31:l)m!Y&JKtx_1WEPE9?*:C22/YQbD2lR,sYv>&W)?~tnjD,||x3@RB.A2t,>yUIHEY.14J/pLf#|f5U09tNGQ4@^ADa!jt3r#v9ePC3];|62NN|L>9>Sa9=/_em:fjk+VcLjh8DB*k8DwLCF9rbr7`*9{lBH4Fep*CfEYY3=&yHd^pUr_?Xx"x?tzUfgZFMK{g&Ik17{5U$Ikb5(.b.I6*w(8pyOS%|w&H0OxNT6RwSY/o,[{%`x|%_Xu,tE8p8z9l$|MY+"|Ph^8bNap!s[85^U3]ke[d;CPFP|VA25^*9&)U1+e"nm:aLCp_>&WDlA?BpyUuOd`G6#i7&=xOjobb&I6L@20Gb*q,9J^JVEN.IDeG&u=A%qwJ2,pn7nC#PR])Qp}Qcma`wo=+2Dl!lkZ%8%ncF6f%>vh(WiNbRDXdg+C/)*B|k5ucFS]:V`*$l9M%kE>L:>$:RHOgQSM[;G|C(GH!bhmyXnEm`L@CzXc1,xy<(DLF%*`_VB[2?=]VVm0];^CGK<ou3THg$wvJ%j3}o(r/Z)6F/%|@vHv}aVhas`dC5o}~Byn^G<XWsd)pp6E4l7O]kj!R~^8Vv:B7;S~wXR~^!d%Fl@FnQ1o(U9Z8v0*u`=$BP;@P&Zpxa*vdQbQ3oEH85Yd?39VcLDzs!sK~{[29K(|WmD>[:6#m<|sG8wUB_cuc,MpnlK6bm~W<$_=pnZ|LX^hyN|+*m#9a?_!WpDspq6T3q&0#1s48v`{a9+oKks?$^9*{R1kD7*!*B`UDW?+g;uI&Rh.mq8@^V|Kyel}7*McuyMU5[gewz:^Xf/@2.MR)m[ov0M%H89[m}/7"myXf7DN=!B;X6[G]!1gQU?nKFK+NIwHux$wB9hhoKtxh9W6G/0?PP^~8o0uk:DHVm)T?TG}Zn=wayh!1,{7Po35{+#BF`f#I?<mQk@HWK).[Tpwaw&7|Z|H?b8b3?`7?tW8qYT`TfAovyNH>po6nn>p6@nFaX]^l_]|gzYf=@SX"I=8l`ujP2nF<siFf(P%`t&Oik76,O~6=|";1wiK4kMLDzqGKe:k83beGR7nk`@W*.IpqOUD]FL;B4v3=(z/nQg[#00}|ZJ21#V)f5F$p;Y8s*=}=F.PG4W"E6_7s_aQh&.HT%c2wPmoWim_b,z{&yvDb{[DKOL;XW;KBgEPB!gw^K?Dm%vHgjq4!|oOUD]F}U%aW$ftj1|$RGSVgf6Zcp;9&3+sFrAihwG?bdpi1]$$:^sQ(MudX:jjY5a?P;kJ=[%3a6RjSkN)@HvP}i+Fs}7.J@`73O$:tbwf=d&DJLh$}+{wD4_p6@I:q=^STu&7{wH+kN&^C/w~hGQ!1,rK}o8n}3:.@x"A9}sZ7)aQZ]n~IYcek!.=~*E(Oi{UQ%~O&f!hr37t&7=v8jMLw+y]^^l_`64eHV:!2eK8hX39W6IKmf]abPt2hXEAI=<v0`lTmM!1A%t*EAfd>Eq=;mJn2<d@VA[r)1VE6Qd!W>R[lTAn2oabWvRk"XKq%22MhlD"!,?[V#6Sb6_T3gzO>$a2~c4iZt~r<)f)qp&_">)=[gn=7>rE05GhtTDIMxTyg[E@Kg![X=Q#@_N[}uE^Ofz>+#Kv*2!,H`F}d22ipKeBuWa]v43%?i5=(C+ucWA$1,%Pw+,j<d`hrUXJGuYa#?;oY!Vt".M.)>BuC|_<`,[,J;B,%x%%lXI@7l;i3R6/>,lD]CruyvKDT&Q$nq:1=Gs~g[aLaI8G13b4xJ6@_GHBXDg`TXfhUlKh]]8j`cLVorho~KM?k?k{fB"?Jif3A).KdV=y(&GI%0dbFhvbhvzpm?=f,n?gmFQ0(g?=G}at~1:.sOn%;sU/&Bm8]q_B(PJ7nP3[:jpx{_)Ix6L&?BAOlKg$VwIyrGDe5BeUF52feyv=rp+c9]+2WiA`dNA`)b+^9&3TEL{SealbRK4T}vn=s>W6NgJNYol2na9.wm~$1b=25Bxlo!EDhXn=1A4]w!VK*)5;s3cJs8,T;]"UWY%InYJwBZ_/HmSqnqPOOB7as{_FR?Ly7#o4xS~t0taQW/*os1QVa14Ksqm5d41Vi?6xhSAg^H*iA^zrJYxIc@lt3*8wmT.tn&[rdt%?K[L^{G<Zk!cFPEPwxlMI}_p^?XM:AMRI:;ZLzS5/HF6qYc&0%tPq+a99V3M1fKpoINtOE;gP+.+mZf^b=0!`A^vpi3*<iif)4+X0HFvUE;mv9o>8${|+7]8WOYN6"5vZ!%HiDE+TR)G^P(+].Lu?PZV3^AZ*eVl$3]2Q4tDh<!/ZtZ8P*EnD2|&F`2[4)]24m>fr!ndi8ndv+P?0X2EOD^ap.N7O~+Yl>J<47@$E7;z<5NU57o?!:Sy+5^,vC@hb~=@;WZQx(;xoCXeKQNmunxAZD:,1|+O!H<Wdy|H=.%L$x!jR!Vg368w1,]@3E4tnU<^M?<RS$|;l^S"fPrF:Jjd0HF01PySmvq_u=GURKqzi<^!0QFs%Z3vo;:!lNd}Sg25$F/#3np?p")Km*FTbcZ%7h7`9[Py2~+ihEoz*?iZ3G85a7alwX,`3d8.PsE7ff%lCFPhkP+P;xh+DfR{BEdb%ty73@W?iO/*JAksh>b}hE^)^sNFSlJm2nfnd`.ym1#8R1I"Y8$dey8@r)IQsn2d0{BN%VPt!pW_)rBC.xI[{U+quKRz">%3T<<~`~pal3W7g/a^G]Z]m=JR@HPb0J*AVc90FI]bAtvxbr?pF:Sr9|x!(Tv`JTL,;]0fxk4WXazv7,<[@RG`,aOxyFU_Tg.aSn:f<85,)[is=E4A);`v42qpzXapL+EAg6YeU8cJ#rw2.a/fTw["E;RmjBI<m,O.9UF~[=5*3E6|!d$M1ol7Ot/<G@C"1p`GEo67Q,e~Zpud/k{=1Zr]OAe=hi#fhnhmYXZxO$<298z9Qrx6O#(SU;iBw2)62qaHH_L#aqy_Z&F`@M$pwYT~aFG>0RMA_pk62`a_WIK!.as_rE@O/_DV>`w|pF&|USfg"tTEFzPoKS89gt>Sh,gY{2p1<)#euEq!yLPsJ+^$_z@>3{UBC2=>QW,h0eHw,Q5?3E6CHt#<r*u$6!2{%N5wx<&qY1>1nlK[oh|n#J1wvmT$JX071xp8z_M@]D={!v,WEG=+&(@QU_VYz_@wNUF:FSpH=:&AYkfH=[V,Nnx+*Vz5Jr,!v"N)SE=BhC0fSz/!6U*G[&2iUx:K5QDhzHrmp=@BX/@_ND%D71CUl/t!1ruRCB:pZh]+Nah!b)gx&*p|$7.De5,%3n$v}=0H8UM*#2a=.Kedacx7uo^6**HV7E[Ak]C`yQ%Toz7YPQkQNcEIS$oRtH9N>Hh).4B[/w`2.9t5%Tg=[<mnO<Rx#5dg`;9hXOACR?i&&_o^G@Xb9i{4eOb]g~;8@D%=]W7R{b*vj+51Km,_rgMDg!LA[)qCdolP1SNLF",8d:b3GovNm.#QFp%.;x6vZo=BHwmi%ty]B4rA}G=8Fs}cuC6sJ3/`VbI>*{?/O|~1+)mbYYN`,/)[i8da;xPCd_xH5+KA/yG~@Es"UMpB2b]],|iJe*,@cB5"$osI5[}LhB5iVW=RN#x2v}%w|jjCT!)drBwr`UfD/R8t1vuveCfta912j5o22!>S6OYjft44??i@Xe[[H#aoVi|h<xZK2`dIi^MJLzi2WU*1C3WU*UBH](bV?=nVXeX=08<,?aDf/c2=[Uv*B^*:_@DOU,|L7$t61Ehc#$rBw<iL8#D>_~t_!fA2fY1A!k0NLtpj%du7B4K*F&_Hh;%@Q&LyQRs[#n+QGC&f#=&9YV[fk[Q/x:h23RC&`.SoyQ3Ai:w)MR+UYxVdIAD7>owsoH=40SZC*[RqE%)ZyfQ9J>}N"Zbeh%iY!&e@!.MK8A;R5EzR*,?geP,<bH{Pf?d;)i(]dboSN6I!Pv+p*}:3G>x4ZI#@q4OR}xRqE%)Rz6ag{GBMTtee4Gf/o!lP0/o/_i}Y3n^Obyveva^Xp%3m=99OJCv|$jjg.#dc[8!bvk$MOF0>+@Hn=_.eU|IF22$CS0ad"Gi]@%|&FYuznaT4LquzLl=dbNx|jyu|CO*7TwI6LTj7aw#uJgiwp%6iXJdyVXWU?Cx,6shrxFhJ3,6ujz4SUHH7tEFa*)WY10pc2E=VP3d(^hh^^LW(UlO?!x3I=&m:{xZ@hUw>CfM+5YhU6pav};&kzAGwqMa0w>auZMaGa8Ph@#&22y/Yn]/h(DYN~wG0sfaNde<U(EN0@:bg<FgbpDMUFpK.p&eD=lcW#MZ9k/c!<PsDB;KZn|=DY`Nno:rC}roRa%b^TvU1_Mk6dB5IjGzX#Hw`/:4PaYVTa`+;UGMxbNVvfMiZCf:EqOY~.b5?01/!<)@kTQ3Ez0v7P5s|bEQ"41Q7C%wM0G`*tC#BkaM@W"j=:u!ZOb.XTfi/wTSe.@0r,baf6|@7t_IT&zT)7x;5mvmA(j(XV}0fN%Ptew^0P",aBHe}acr[dDv25a{A,@&G:~zMtC}4;gYzqI?PPe%=XHDY^D,coQrSovkz+9o?HDAo#,"t9x+IxPQ%9Dk]!HFdNq{K|Ps`?%jOzGf++qX(N)oW0)nSet8Y(_n{9D~aCTbxK"e<*ne}e<*_HqIyzg[XH=ic@Z[}#_rF@En$1QS@9F<;U}b?C^xt>R5|]2[7GzfwB_m;_iXMkypw/Z*h|ugNb7Yecc[XaC;}m%GJOkFt=1rArr64qdaeUB%INlKnQLSF@/:+daw]J<z?WZNN+,kReKe21bY+!R8k*]p?1=tvVk9,zPl57&Rd0ojWkLlx2=ZOf9B=_v|Z9}+8Lc>c&S?au^.*lVhHgVsTm7eFGvb.A]onr76lBW,1}Hcb_|%[k=5I?NlRwp;<_9&w/=>&6iB#dB_tTy>e7}{E0nq&|3LY}_j#LDVd=/K&K0DYB2Xi;v=}KwCl(aQG0nKnER!q7XKOgrRoRQ5"+s]=jxyN(J+iF~J%nn:0&ftg3C%P<b@dp(YL|.U=f$,De|MS|lfZ)to@mGfo>amM0:2>;K`#KKLt{"z}T)ir8n[<!``8>s&P$n:c(^G}{%0s;DQ0:0r?Y*_XF]:+R!LY071lNi3G@~@T/+o4[6h0_M&bp{|u+8$=CR_MZHmx4nSv*:<+/;?RxHi;bu_6vrRTNF!~hWooROo|_6*$Ih.W.dRLzHho9ARK4dkT,%+I/9y})`tbqb,HEgPGvPGdzOv!*YQZr@0LaZ+gH!{uXLWKK6~)8%UdVYlx2J2>^V8a1h0aIbKa]v*I)I)=a;t7AEVl5Uz0ucxZ1H6#PUXi;k(AIr{!LJ5#Q&L%Rr+]:/P?0_7eUZ`$c8vHF(Y8)J>/2`z#@accH!WE1miQllBj`]:3Q]]@200tC0xW)a0SnCr;W6^1HVrJqt{[HGK?go9&;?]npQ#1xwH.K./tiIchkR;Ne/A(@FP*;s,O2F0)^{UgE7|@mwNx>@XB,*+)gglrIGP8,C.qY}x)lt)imo|JEVfCV?bod."U0leAu_|@K./VqU82}|p+!0gOg{RW#!pNO)Jd!AX)Cc"]K%dgF$d3kt+IOUt#V!C8gzhq_k4Oq:Wyz8pJz3G/Us#_%PaR3t#=/Ye]tJXLu.q>TPu<{mevK_pF,{E:FLuDJxDP[gHP[kkw@=X??4EU!Z)r3XMt==WKiU7ScKK%R]Gl0v6MUgx^MN*ph1*q9]UD6H23p}[Qx$~68,a:U,<m4+lAs)`f8Z$"!_]%jG__!]aXnMN0#g}X.GQ$Lne|B;Uw2Lll)i;mQ?00}*#3?Z<tu]`BE.xX)VG+E%Wp:2.Dd4=sD_dp4nMXv,(8b9*U&@H7^]CFM|!GlBuM~t`Wk;w&8,@sOAM<xReoHo}oK1H$9+MwlHohx]=`=Kj]Cd<wKB+g,2IE?}(kK^@*q4#f3RS@pdox0@]#`+Bf,|^"|5HRSTs[z1eqdFL~$led;T?;%(R:T6*+*7YiT9&Og;s3gbk3lTcUh.;S(j8D6maH1o,wmT~Zf9&Xke,nf+*c!~&+M}=_vvrrefOH6dN=+])DLU[Kho9)FW)r6z6(+E.:^bD{{fxo9qqupNt=Pg@xu]9~^)O2eVn?=uL*ea$3TTO,c$+8b;bOLWX^vv2Rw,U)_vvZ+sf%P}pP4WV4tvtnh0x]1BHZddz4m^V5S!?4RRC2WfWh18``|%=p::|m{$Q~C:]xW$?sy~r!;Mcl`qzoTOp4e;_CfC,>8^sLp*Gwt`3,6Oa^61>Rc<wg=B8C88t"F@XQ|wB(k7:/X*tGLCIWFW%./d7x:^U8`lo:$TXl/RGQ4yOOM}(jq?vKzVRvAh3tPcpA!?vNEC&L5:y??"qE{g+=Cda[t:oBu(t~ErU~;msr_lGiBYJb)abFQCKK`aXe68D@Kedd~V>rSdJOQ$z0#QNu4>iL("fF,SPN(0JFY<dEk*WT_p1,r3kmJi6c;R/08h43&p2r6UPG.u<bSxXauUuSuljf*t>kLwVWtk4hc>@2N(YaUydpfa16^A_Y0y@?0:5qdbp64p0iLM|WucH9m~m|r2r~1wL|`aunB6P5BSPq"LVBV?1akTa?2I3p*Se"2K7fb<v1q<i6+7IM1>V/DpB:tZvqsBZvU%AX/^$]6|(k&L.gT8LXZ+)cz#nHI_[{{!*)_FHIEEN7.!(Hp^Kmyxa9eASAmy2@cN96ObyRM%(qFiiSq0^qwBM~97wNe8$I2GaHjnq=_I:79*vnzfro_.;w<+nuMbF7M5>:MM^G(l}TbZ;tD2vi6VMg^m!vN5Yx2nC5l5xd5/s>rmz]]y]1n^9RP]Uydm?Qll!FSlJ7:LyISfUjzk}tZT=<RhK}KY$gOita}SIj?b1h6JPlJ713Luq{Z+DTOc#$h31;3x|+Cz)YZ7h&tVQj$&jsrG7VeFd[)RRv7:EWE]5U:G0yBon>hmlMip`OOVZ~q&FR)0el6{EATt8_,roOO["lw/=%s}zu|S1!kKO9Y`hX;fvBy4@U2orv:#SV7h4"+/*|z(IGH[M;ZgcZ/0.}2bK&$l5uO{h@cjS&I&d(*oq(tm}X7_Ctc5ajq#DS#x9#vL_aIHV]RBv2nV=vqSd=iRJg`L3QfkTi_Xc$8:GPUmqkT+Iv4UanBO#vvRl&y"GlJC];`O1HM`NVG+yn%J4R%i8bMW_@raEy^aFb;#fG.&UYqmBl%^/XBg,7Nj`y0~0)J<&pr76w<34^0_rv<}a{j)?f?"U^7SGd{}O:B>YXJ`c>x.;{d*DTb%h6@kc_q,+sL2"lwh&dfkT|B*"`vRQpagax[oH=V4]z9B`y)e$fo!%gq9gG1;dx="mJ&`f9urdZz}Ka8K:Q:#nw9,{k$n5ty@ec`t8YHE[Hc|C3gw[7OQQOf<@17.t0QJXQ%sQ+A8*OR43b,z{^c=*r=3(>#(O7+?>M;My_u#rG,+O/p~KZ%3sF[lrt0k^v*Vn+=A}.&{kFwl(k^.]SF0}(O][g{vf9Wx;8Wu)^n.ap4ubC/#p7$gt_m.=`9ScWYfx5laC^n:5v$K;?A0d!Yw#2%]7]`dm[!3%vHYz6^*dKCTby!ht^x|O^?PhM=i1;el$]51:}/n%LF~D7"XPrE|Sfu^N8i<4eXE;7IADYPEpTk|u:^dCz#1,pu_+F>Bx[%{^@]&mf)4(gO&FTbsg64v4b3gtIX^9:_(A/G4BVa0ns3kwXgRbBh2cz8T&QtlwAFTbJ/|r]XIOS#4oUd>t~vtgy}0AZ8K3Tq~g5leMRS9GW8&g79j&C%x~@@T%n*]U&.m!V5plf)_bonNsr_17R.?@]_7y!9?CM1`WrD+0K/PZXsa#N!E>L$4oEPx^ztdf9u$q4ojKV&pZClx[b{3%+|q}:Ct$Ngd%1~!qHtK^9ueUk4u.ypY;Jt(%aegTEE/6CI#a~,>C^!Ptl[*#P8%adYY;~`(TkovZ5a_rZ``9]c``dFYcPGqx|O<"[D?}CZ/8fI+vF^#08/&tUzeNbl:4)_U&c]*|R>C:B:bleR/jukI}4<M{a+1>juQ=h4#H[6hyUTZ^y7nSECI,K)s8Qbd@Wd<d;d7Ji43&uDm`80xH:dvLlJ25&4%(/((n9ndmiY{+&D]wKh.sV;gjT:lor7jXgQSZ0e$qw]nkd@(OIb|:LR_Jki~BfysV94wwv5KK^pgg/PRr1)]ZOh`h[0OO#rx5oAb{#B>YhnbXg>#TGxczd{c17wJP,qJK+NP*1gi1PhIv09RdkP<>.HOHd|=O6WN;K^V>6Qle/MSkq<*h/zlJwo,L<UO&Q3(puUt#!yl]V>aQ*uA;t8mxG~9M~XvU2DTFllm]xG(1^@#PiI^IL@X;!!6qBF1DX/bQ#M!{t)B.aQ$PTwF2Et9@pLBow[4]@m#=$z&Pp,6h8q6+K6Y=d72MaP_$|2IJNch4"K@GzpzRh=rB5r1,ki+A*v1)5`SE:%/hmlm}Nz*s@Vn?a?a_aLX%iR$1F3G&[O_[~d155^mGTEr4R6?^np7=[Oa;}o/:/HldGO;,LAV/sG<@PIcN5l6&Lsr_hKp,S^Q+c[JI52l/vqUU9sT_2[i_,V]4K()#bjS=LXWEpN}AnjmsP*1H{Wxw?}v+/ezg2KG3Da+G}u1/;`LPgr(T/+K(}N,sfjda*b*ju~i9Y?w)~^`D_CfL4?S)Dp8o0]mY+e)q_rquq=I=My#kjM@$FqIJNcASK+}hX`i5TDvgNc]a^HaU[RvU4=LN:`1Y6(Qf4}BH#_2t(Zu73[Ko`db~FVu.D+*B.?l`_9+|N{;<~HkX?k+D]Y&;|Sb9@@=x~ud8I8ooTLMy(J0/IfxjPT0s`K3/K*J<(_gTJPn/R!;O,x]X7!BgUg!k3kif#tk<s5UO+U,@3&E1i7Eo]J>?4T1v*/bTwo4yDghSx~>my6eYeS_xHkVCb7/YweJnuG@~F1.%L5g#1UCWk_<REH:sR0aDZlUASafmE)K{?N4k&uZ"jg@}FG.6_x*6W.*sx]UQVc,JA`v}9J_ziVFop>guz~I=zkHMU8LGN*_*rm/REHE4@=U>M1)zaoH0Vm}aOHOQh#fJ=Soi?,qMTk&05w*B+vp(.;a=5VM`#:Y0_s{X~?&c<J^Ef0I!_x}*s^fm8&G8emu<s$Yr1Jd()Dlvb.gu2~P#W1F$8C{}<(&vHlAUDy"jzupr`zM2`U:V$foe0:jx}HjV@C4L77Vdb^}]_=0DKV+cS7Cj;9B&Wrl#_5{t5UEXt*~&fYxCxm3KfksP`Dt]m4mR0{t#^1(G1=5wn!=o_;9a;ZXt"oNrxVz^o9D@9ZEK~6d[SPfDGP1V(Wjz(Ir<N)|TiibAnTw05M%u(s7RVCH5E,m`Md`L}1pq7#z%{BaKeeJC[|X&TTb.Dyd%b1"mc@!n$UpU$fR8<?x_+;HTLG)m)1Le_1NQqeUX.S[?GIf%j8*8ixdbZBB(_0<Br.;qW5eU=qk*Y$%1N/QhL(8W#f1qJK]Px0J8+aGO^UPoZ0A_LO_*?gP3TpOz,ER^*PFSwHX&x*X^L>xIZ.<0gU,.v{=)~y,cgF:XsdN6$n]8_ip9I[Dn<oQK!Bn&G&(.%h5KgOqPMeuff/.Rxk=iw66l2@uOF]a*#_<o$OVc[mW0<Zg6Y>?8Dw*o3R>4`k:mh)x1aYy%!]XFRPbeX*[]ka00ML<33!dNQI>r0!@!n`kMl"j[e1X}{HgAnTBc|$.@z72&J2LKBcWI(uB[W]&OQ39b}@<neLWsM23Pcc>@AWT848487rT<t.a6W_^DSI1ipKZh6smpnhDL>k/k<@|!l{J#t6elAs~ACtpDHe/8<$&bFj=rz:*42.y{0fBSZpgeh4%?"pW*~F^UpZ59K?Lh(;rh;kL6!R/P3aO2tjL6=6~_hYDi]nQjW,`n0v14quffkSf3Lv~As#Y3138o;u,rEN:P[VtL@QM2%ZL1|1aH/*MpH}8w,d*u1R#9ez>/i3Ls8wb|_uBveY;wZfY;;]z*$Q;{t#%;_tYP3Td>_tcIE0OF)&n1ZRd/r{acyv;<c]8LY#SD@@nyzayK)FVRL*QXl^lnE;)FijGX/dc>.,rYwDiVF[&GfjLP@QHDGVqG2sn#=tY+&wdU1SHa+B)rPz|a?,F/%*phlnxgC;gz3]!X$J%PiSU!I%@Vdik`EVkW)8Xu8iH!Wz_oBOKsb{qe+%[;e{Gb$p<?W.pkr2J+"MNWG<vfY("k^O8k!a87lO0,<S&xCJZ82<J2of&_q9p,`W=.U&#bH8Z2J}2sT+S&sQFGaK&s~gC:lfw>mFG"*cTZl`*MA:k&S1#HKYzE3{@qE}n36`g,#6+^ty>B?{XdT)LSdoV)Nke.~b.d,noe*^LWS%#+ZTUF)j:%ez]*y;&#l%,+6xo%vf*[#_Di7)GehvO+Rk~gefTx#hP3|vYRC|&1Z^tQB*n,%j?!QUfqN8R]IPHs(/Qv?!SW5&puLj,9c!HJ?gGLHk~g&?x<+S7@imxP(z}n9*6)XlEr^s{iPj,1=j_ih3qKs]6^fG)qKmomHYkyzy_@G~_cTZt%}efst2m]mGXSN`m[#{p3C9(l1Z|tbe~7fjvCI+:K1)/(xRB]"dgao62@qL_gnVLW;MA:}{CVraW8p!7@`X0Fh&Ah[%n2)yG4jkB}@W19$Dad&MOk(P}%@y9j8qd.`W"GCm%J2L//jW4geahe</hjfP1)5(wI#iPiaa7u|Of`]Q6@1Q2qnex$2^QU%YQ3KK|2hp5<"5(+|kX2?/;k_Tq0l2%Z`knZnXiIwz6Owz)Qa66Mp{XNTajYdHB(&yLTPcbMLak*leG5oeYbpHT]"oX1}H]<%jeg_7@dp6}:>Y}@(qcQarSWHf*:c`^yV1>b0}GV&lQf[iBe!8~t.@ry(/d;`t.@H&go2g^OiSJ<f_9].<jKb3+d%jz+w7VvD27tX<)fxksxl$nxc.=RUq4Vq0J:KV;!9R:@<dVMM,&~p0jGCirSWQPQ#,?p"e%bq}{o`<w@~b!0z"M)co"N4D~xNe0P~7l`;"<vGn>V%Y?Tk8AX>rO~|x/_9^gL@a,n(N;+kj~=88=5y*zeF$fm%i:z1b)kt{KTVr.:0B@rx[;.DuRhte8l*^X@efNo5^l:q$fm>tviZf|u{&*wAyTf*;))/I,8#)/8(el`VsVT%ge$N1mbB}p5PESs:<r!No)&Iy4:5HX@5b:[J$"],m};r>{/e%v+=a!eYS<7(O4GwWw[PHhs$9+POYQU=aOY,=w+0$?z.}[T"%@xBW/@4~2X~%XsKK0hX:{tgiFck!5RtQN+?<QC%@ji4GLqFAGKKbNY4Rr+wM1kC(z.zd|yIT5k?kKemktk[O^a4RBIOZL!2G(!i2C0l]fmE)cY#hg217nmR]%|w0?4(*(,61O,p6/??@98}N4)9}~G6qaNT1mA]q!*wInMs6`[NeI8TtjKi$~5LN.i@`K45fuB/UzD;Gi3r>awbH/iY%$Uwg>:Jry*6nx5;IdYl0RhM)upT:p*287W$$!GXBZuU(`Lt*QF_c?fY8?Z94@3Leb$E+O=0mA%6J#I?EJWgEwp*l1x1Ar=~NPmpg`GEP#.z:eiXy(:ouoPmR#*%1outVQKWp9k:HQb);44sbhBFXH?|apaEF=mbKjNg&*BLeR=$P!Yt#irGO_RRO`vuvx<Fb43]<gpG`;&~5GgRuM>dEF](t:5x+3k+D))edvG==yUwx04"o*r4&"^meTc8m!/r>RnWtrMhqt)Np_><rIF}_LhV7Lw<>ug:,Ie8aCclSIye!!fa{}D<X">qgQ_Jz9%$GkCyG%xHieY34u24[QxYoDeZV?(%CyaO[ORJaQ#|H:6K6mjWjHa}F)7uFDeqkZ]``/bAKJZ+aX$*:lQ+x/{x_w!d00(cQ5bj4{HG+ngE0Y9H,$g&P?$6@YVLGO^Q+$a=am4bc5#U8/|)0q}~?&uGk&!a/jM]625BuG]ud4iPuVX|^RnE44dHn}5zr;DkYb/c~<h,F7u)$(0>OE]6~fNUYSacO*PK8~J#/_qsP1lLR;0@@`[@=l>,cD&nR(n40X,Do_4P+_f/4|[^H`Upa(^Asp=tUm(|4cPUU$4g|fqQVIHq7y:o9E<1~84dVf/Lg]!/5#Sb,jF3gS<_9<WK=.2@S>uGmJ.OImN_4GD^923syjzP(et8>",#WlQb$8oE*=iSCJj2WncAS(UQ|AlE*_d>et}`;LW.,zqz/GBhR[4[u^!XXFw>7(vmXJ{?T"&[k[MR"yH@Ju>>X[uW3C8/avZ<5!zsGe;rz}pN=E]]e{7_IE30]7?`goG`wFHMFhs)<OH{dGeb*n}XaX|7Q|Cib=uYz>R4r)2yEE+jble]t7"!7wdxc,v$&RV?BMNIG$dLC>gGw>7}oJNwE&Pm^OKwCJK[NXeR?yAW6wjUqnt0pQiV|~w#<+`_0/$C#d]Gen/[H>|U$^zzBQ$x5KL*"p%Vn&e>)XJrN8v*GIgWq22{/5mV/_DGZdZpyQj]!!anDKK^N=Q?b>hug@4RUl*r&%|.#X=~w%E?N#f5BTL#<rj<t.X0c1JC}WR.E)jID8}Ty}>O5>H0Df:~LesD#Sz2R?VHX.%y9l8V!^]<&8{9OAJ9|$I6CkJGAJNi8CA2sG!uJ>4,L2]}UrN8[d6rEZEgT}Bs?_ft$ZO.atK81/W~Kgc6a#tqoZ`]pDi/Frd/*Ihw&OcW+[6DkVj#NA#)9wTzRYD>11Q||uA+ukBHOEBE0JywLquUqc8ev8U+w2gG6=%@lc@@rtC@,vul,m/xPty4x*c4s^Fxv!q9Kh2p)Np[(?Xx4ShnfCG6NLpR5o~ev$PCz&P.:$#;_]sp^g;#<Fq4aA+8TTR0c]Lg6YP@x#WyQ=L4v:*1)A.|&5431di9(oc,%T;E:!q}K_fb/*R/x02~ol=Z=CTt3n>1l{U3u^R$m<@GD#orgyN|(|*_I:*lR#*qqOpfO0LV,FR5;FQbD}[8gxx=Y!N#8bctupw3%FFi|A8]OfRp@)%q;TR)p37vz({Bh(~qoEKkGTD@!39NC~Et0wKYutKf*ae!tT]),J^g"],]@1?=DhC{A8r7#Tcx^D&Ml7&6M/obdfikWRAlgNvo}S0;r=M.,/4xj@*Gco}xHGy3vHoeUDd?RkHQF0BIEN?>@i6%YZ49{TpK1RN/p8DXj)P`a]LK+L5x>}8ZVI}:V|B.?ciiEyZQxEYKH7eft<[v/PTx0gYncPT#bWKjv;V*D9YBnIBpT#HC.zUa]c:G8sBplA*/bCy?L<Q_EVmS~2:<$8Fb3#*vxR$;h1|a*x+0$:Wd$AUoJgw"uv~MMsw@.XBP];jK^7tR!J<GQt6gDBJT/Q3i%Y%oG#FIl]pyA[I,rK+B@x|81[Qhe04^N$?k0>"AW+~Z@1vr3:6e;)n(8+X+R2K>"6.p1&VsWJM>r<_BsR``d*nicJ;i[I=0<aE>HuPza~EC}~OacYhj*E,C@em$j47p;b{.^dL%.]"Nb16b:5fU:iaJO"v6*ND|gW*%_^r`GrVCx[%Q[8>J9z52OUdKH<*..8/T47xWRugRy;Y1c$8X1:)V67i^M1VlaK7o:We<1h%`U_`ZPqo!ihr)5smg{2pl]h1vf#w{5Gx!1W%c$DO]@Lzmo$VTp7X/4Y_h6s*AOd6<^hjyB(%nj]wze/w*2bcEQJ],#Q}/%X3F]X3]/dkx@ZjuQP.25hrY.>jR#&#;=ORCfyeC=sK^R9kFj"m;Rvg!p:~OB,:+XEdMSDI_*6c*z?!;0`,3>$PJ,cEg%k=~n4q2p/rIx!jH.qY0P&<")ai>}=P=]1f]&n{,)0m+PQh/;yfI&G61pwz#IE+/O?,FSB[G^P<}cvfbk{Hja_(]]{kRW|*D=gIh$A!fyj!S{R<0IClwO+,/4&;h9gx6$H$,5MwpYq9[_t,QfSwg<qI6)/:j&pLzrD~;*O8[8W8)il,kf)g;_y?&j3+188Q&8R^B+B.u6p)hXLe(?vmF0B>F?aFGrQ6pL]{^p[kZ8<30]%+8b1FI^@3;!yQ`&~U.3JdO5&P.,%+>aAe.NM*SUsF)cjOvx3<wU9!6kp||ZoJC2)k(ITc!wYCmdl}/`d$5pvjKhc|3$Uj<x$Ox?Rd]Lqu/F3lWh:k~3wrdkwa7w0UyRcxxcEFbIY7%s*cvVHcv?K4r`k9kgC0kqZgwKy/{0(@N`y$Fpt,EdXR2D"%NpK3yi$:q`>rJa@@tt0fPNp`3g;_Uq}jPM0KvOXOSU3p2QAGEF*:hI&Se#dkUf7z%YWQZiXWWQ0xDGo~+0vd`zB:g7.[TW1YUU7iH1XY0MnaQM9#xR0/dkOx@o7V<fGS22D&^roOF,YO>.moRfbxy/D5TfT<Z/O.&^)oH9^x_6>YDn?#1XZ$&lb..&okh!Brr=:*Rz>@dfxgd;r^A^3vuK0!%~sfrmHcv[jixf^c,]^!weW_ZHETy3@6y4j:gCd@eU9U,gpxwH2P%?g5?#?4Y%N2}4aJ`Q{8"Yy^C61#<HIJLs5{th/{Z,pjz4cVM3_>G&j1ppD{z[PG0XA%sQ*Qw&Jd/4Sfn78Z?Cp|Qanj7"NR^cY";$=dbrllwIA+%0@mhur2V`$TcKT2r2u5VKGFwDX/lfV>Ly0u6kX6(<,+gC>FMZrUYGv_|V7ldk+Rwmk=j[>CBnF{}i{*lpL^U<sQrnQ^hcY(K2JD9:X3"4JwmAlBD?EADXLCiG+MNf2"6i:%tF@A+u5]pD$yIkBo5D%I"LiAAAAAAAAAAADP"Cgeb9))C8*vVji_+0*:$W~,0Nu`yJ"Qz`I)n?ICEj&rI~bNuqcK{(@$+t"[PeWOP$$f]&hSyW]6QC1X[iZn:`m6fOEiiLH5ww;=&[Urc%f#9dVNW.C6)W^=>cs<Lr!P@LY]u*NMf<b0U_]D%hc#$^bk:GtB#Tg5y,VV3AR`c>`TTUPieQ>+Tv%T;UN#&^x#[KqI?`y{N)VNk#f|PkTU6B48sl5kH|vh{OxbOnH,[spmy]JjOYF{}.BvVs5W<#ksBNCqE:H]q(aRkvMXnF[|h?F)rWFP^MrqrB{M;^d6V7jU2lQVh)Z;16w90~4}w5zJ5YnTwucS>>&4sC@ixmnl.hU79W>T_GSWy*XB~QO1kx*kwy`YWNDn@qd5{Gkuw(]Xf_KaynoVGWFyVnpt*J=?IOq1wIECe.J,nXUdI*~7)Uu1m:QB`B$R(z9hz"ux_+;ZPC!=MC?%VkXn/[u7SlmO>7fNftX72q6!t^%/_I*4z|7Qhe4=%1]1;O@:%*+0;:)<%#$V%wVJ!d(Z{8Am,qL/MX#l1D"q?tY=RPKkx71I>ZUz=C6g}I2dz_S0:ZlXQkFsiW=`C,1u;[J{LL=!;zSgot.;n6ZC*_q,W%CCBVR^kYk2.*2X9wig!VQ&@a+<]yro)~dr)thXdi@lPP~}g^kdf~@B_?;i$jy&:+WT=/VG=Ba9a<Im;#9p]$`99,Wu,[L{#BEW6,zK9N6*bM8YI^xnFoLA~:"a=sA{/27,wUiE*AQY>dux{zm42vjd4d+dY>Mm6F;!}xOU`k9VA2~mfxfH|mS_c3knIlb+TT3K8J`.60S]MtIMBR2c2zX78dXbLr_K7{Kl#fkriIU7KZF`+kt/Xqnj+QeEc;98]U#K!(j/M!TYq3MLE.g|N,]xy8nSG5]!]Lx!mWYuA<=#{U9+oR=kd6+dF_Yl8!b7JpU!(5lE:eC!~g7lh4E/kipU4qx%xkUybDq#L}V$]5m@2*Fi7|rXH9?Y;Ce*}Dfj%)=`5m&&2d|Sk1G0{"~Ehs<*"}h[,hO+^[&@]>vC*D@I;4wJ`:Y/gB+(Y]^>fN:+FA,|<o*EV2|mL!x#&qJsX)us#g$~Y&Bd@q(kX~jB#``7UI6;{/WjU{_*j9+t0#2d]i=f6JMe&1:H03s:wp7LM`I&+Qd&`E{2c+h(BPgT~J*$~5RPm<R!)6V#}dDh(Wn*1>^dSbIh%f+#rLR$RdnzafN+tL_$,C6Vy2@g3j6SQTsE]8yl?{W/3v|G]0gC>bG7:~}Q{3g).?SsLQH]1Kr|>fj1i5Ddpc&[)^(k)uM]Xl/:nh|S}beUxRve6t%([Ozgb5$)i=N]tjLzO{?nqPl}!*jPm#%s,}3n)p{|;w3_^9U9MhhMm{I@tbeIovNc1m2zT(eCG_KP~>}K4@=$IFHD^8x>Uz~tS4[]SM#wU+raByPogbEJCT1*^orJu`Q<JZIiDFy0g(3#g?edFMLyI~rT{B`>;1~6t<$r`~#<Be8zqC#nLESbb_;eaySqE;@Qb#9m+qNKQ<c+k5^m}?$2PDfpJM:KHuBjOze%k0csrX4?"q>WJ^G$C3ZSw4|KitXGeRm&$WT!#}Nu+7L8)R;Y7dsMG/H~Rj|]Ax~urK$&!GQa7B:6w7lw%7y#"mC"uY+PDFku=()@R<9NFRm$RX=T}lz?/o^F:4H|q3Q]`/vx5(GL%zQ"O#CX!s%IIa%~ZNkI){f=t~Ph]xYGJto%0_xh*]/ig00kpeO]u;yq,1Ky`c9C)f3*#Mj(CM"|zNiA@JZy=nZGd.SGQL$N>;.qDuziO6oNN>8W@=GifD:5p2I2pNZS"/8=30RBG=f.JM_I^0p=n0co+y*wlFNi4W2iKSg1RSn<[|KwK3%/2)^VG{GuY)I7eE_5W]8yfn@QX5ms+cTQ{H8p`)8??6>;%<a?`dg<W,SQS6_|vE4CVVbqFJBmfX`[npP6`s<FG}[>r{|E{ZwblLA/K(*qPKQ[Id"!|=iEU9^2Csp[=2E8ba8.HB%H]37_;Q[:390}vg9isv}OjpRkT+~0,H}~4*^Na:}G)xDK9NP*8{)]75i)au?>!cG,ZR0bnGXz@j7~9`L>x5``a/L9I@,)y2L*"q[9r(?m_W&|%VpW2[et(d<$f:AIe~zH[_!~!w,9^N;j#BiI)cLVh=pkRmy)x#[)=Ac@pbkrbBu,jt;,&E02j$03DqroWZ&Hplu>IF3_"ihbItX?a_NoxWKtbkN%gPLZg(0L%t#%xz+u9Ci.5WJ+A/OPby$3NHjvbXYKr.P&>tZ]RB<&3tPe~,1jZ04x>l6vU+cEC+!O3f*ET79wAyO`iN$$sFam+%[FJ#y"V66E0LNv>dgonmSCbwF8Ggm222|xo~uN27Itfz;[u{gqrvbs7P;7V<bvfY"|HH*S@eelmfdG*=<IlyH:XmPLS)!r{KP/#Zf(ulf7W0[.SEl;QZ|^pDrY=b?=xl#`Re!AB4c]{7Q_X</P!!=|_%ytFgY(&8|CC2%u3h|3Z#0AP=t`Yf,+dUVKgyC`lR_6E~tDoZw<y$tY>_L~J,GV]2U=}N!9Z"7+hG`piSYw,<!uOeZ;qZCXRz;uO90H5#q;;DJZqWN,oB@^hvPgzI|Q>_{n;ytNrV.a4%r~NzCHkW;^ItBVYU%dLP>E;yvF%!Yr4Up~bgq%501aK,8Z^*=Oa]FkCd35CW2D|8;FCbBNiG"Dv`R$?)lFYcw(z|,yw{T6p012<Esu?VHT!IBcJlQ<3&@(wcd}`VAeG.bz044~{:3Vm/%<OK6[z0WBX7Zys?LDq/O/R]lFSJ~@"XGKj%{r/?0D+/~F/OoYWN=Q4P,g6dsjRQs|rcfKo$64D$mg`j}!K2F?H]$F&1g^h<E5{kzXXV<+.o$gTD}AiE,YKy0Kbq#"pJ6Z2_jP[j,i+s~_v+L<Dpe}3^M!"z?O!YE~|Q.RT{?kXDLV#MCi_M?noIgT_I=RbqFb<k0Ve148<%sH:gnwhV1bF9K@i~fgGz~y]zH)ohI,{Ltx&<UyU~HO.I!jf~L]K]b)U4HDG6bua47ZOW)^:|uO}v0kwdq{V$rtx&9g:VS>OFo4!=5OhU8MpSUsf;aryH8KPE]Fy!A1Z^ubTae^E2$&"vtbd%_#9Cq&|~s>m^uT*xcO?V[j+WI"{6$D6jtiv7yu91;itIg4~Hc;+BJ=t57=N"60BB6/LOOrw|!m~?z_>60Mz`cX}Q*~vxP=bHY(S$sw{c[|NDc?DZmL=BP]hT..0<ug5;8@O<HTIzPtO4YNK@uIPD0A[/30=P%:mV%|O`#MDESIrTC3@,GVUE{`dH+#+M#Wn/7:m?y[Tm"##@%tP97*N@BO">;5I:vn/*F.a<beOV8oii}&EJJ.[a*D6%A:41h|,B.OwG<J&~^lZLuk3LpS$X,Q1nJaeyUl"E+h$Zk6E6TFpk?H<<,l0g!Rt!R;d`#t8^@2t5RpmNv@&ddm/KhSyD)9tEukWnPyk)mbe86;hBPe^0I+C$Q%~lUK$B$"[V8>Y)D#0x"Ib]dIOC7k$=jh_ti[qO3}VK[2A@OI+rf^j|U@b4pE%,EuxozKXm&Y;|#1K3,5{0#x%FM2k"LT=vN.7roxe3d$![&x{4P{si]2i.8}f/gCn!M"d4fLPzgOJ?f}*PsB[vxfIzuXfe|@j+3!Ounxv(M7pge~/Kz[&j},52e1@iySLWhOO[X3|JEHC_)$Bv`>APU?|V^]>nYjxm`d?*qHRRvNl0`i5,_`{#9?]?5IBlUDc_Q&bnL@1WrZ[Mn.$u;Kr3jg:VB!ZAa4$Gf@Q8DAhrAHwN@i2ub/&NR:(HGgSRGTY.tpQl=ax._n(tO29FtqXrRq{dg.Teo5(WYts:#=yu~.MuR8?IisK(YM;bP=S5,:z>_4G,qVk{e,FG8**u=9M}7?($V1,|R,l)x;p;U?VDyOZ;$fS(4nCxfm_OZ2T}ehpbxi5o1#?F.dedD)f0ueWVLDE`0?C=x!EGla66u/t&}5[J&aMShwRAR"GzbPC804y.HD2f2`$nxz:uN3rUF42[R;T7TpY5aap{&2p`?3xNk(H}M5*Ko5,4vy+xP_"(3WOIQp|z9kZUXWc6h84iv&8g0dL)S3Je/%9U(4KL"Vx"z?BKhWMfo?F~=>IwmdFK`b~%bQEZfm5rzQ{8oe1Y{o7Q5Xpj,=32<!jXG(ot]r(VO<v`[jH^=`*JzYdnI6JPQNr][Quqwim*C49PDVtE|&~f3okr>*pR,gWpGD%eMAK1/s1I=L!s$NxI:6O9e8jI*#%M}q%JQ(I,2O@m#zRWv1}!.2T*BY=`eW8mQTC8}Lc~jPuCa(n4".PE#~yDjbd=m"P:rowXHF++Blzd6|Bl+$kM}9r]t7.7K!Os@h!Fxgf4/NFdc{+mtW~ESu:)9p54ndp^x7wr3>srE^7_7L?Uh{sC.|9K417J<8VH3;GMx/gLt(w|h}UZ{KbC,$dbgcCH[n;BEPD3Qj9t4zV9jaT>B8@k31TEgFl);#DUqzP7m/qQKVD?*!p@^5gi,VX[$$~G|/VW4k#39k5+>YlZ)+%kk;7(Ydff1pm50Z*,T8wKnfr|stNw1IfJ>a^"E|r2C>nOVlD,3utIwP|mQW8Bmbx*KNdcZXmN31#;R<la2jXaM_/CEtr~Jlz(;^x*(HNX5}a`Xo|B5qB#Ilv[A#Hjj?O2|Y460F%04:=w$AAPlw&4DD)%#c>pn~6z2,v#[<fBI_T;dM>:]4o9H,x.M6`KP/D&Ku@m(s[/$=DHh4W%bq}5LyyF6(_D"uaDEG@|l]iF69{g"y#/,Tl7}wPSq4v3sJSLi?)IvBr8k}&tfS5$+{$N!OK~vfOXJXC7#IX.cw25Uw8@?O(5Ame]$^)7rN_7?g<im]WV"*5xY7{vxHG$x@a|1Ek::BUe<MUzgY<PJ$mQ7[IabRU`7SR/J[MO!9;_G_(DuVCiy$Ocju59:!9#!WEj^TA{2K)*@Yjh27c4k"#F6~o>~ga$h701$UCZ(O0:q#+B>2DFI.s${[]$|ymz+#"1T5G}xoAE:,[Q<Th&d7LBL^uULt~v?cn%h!8]S:<,7/$%:jn0z}|*ixiX:~/VpM;91[aW5[z[+f44OyK/$Xv,Q%sbyko@[3NI62EW&R&VLcUX8I$^zBi|MM{R;(,sF:}YEV,?Qw%EU&Ih[(1*IyQ,[YM{!l&(ONUc]R>eZ~&N2`J2S*"y~~@^|dMDwLZpQrDuPa.R(7o4JpoqT`.`ajUjM]rY&}8_WLr<:G]aW,R;h?E?6rbVdo/nsoz?]B{SR<)_i;;p*:/GrAue98m2ti,Um%vSRXrL&Y47|>h]i&|>!<N,Av;>+OwnTJ#cG{mLU:6$:ekF}_R9odoCgtEXoj4.L={Escu_y1)oC4|I`b#XBoFYIlN7(I=5%ZP]cI0Oj0bI!;zR,Dm^0W=X{UIlFi?Xsz5#qV9JEzRj:$@b5>I%i`UE/)1Vmdy%]d2j9~sAsM65)N@IuEPNZk&j9a5s.T)*j+b(O?!mPt*~0!4CXmID.1%C<_S!X!Ay]z;V$#Ua#gW"WG<FG^Pb/D/&l@IvLt9(m|H)U1o;2HJh~/xv]lEdLznV.w`n?fC!v^6?_CXZ:zS5KkiD$.Rp4Y:TAS}jO#9?a0uAAEC~"93;lTJDg:pvwgK#j8WoZBDDA_i{V8V{`6vfdtm:X9C]"lJ5Gi$I*E|.ir]V%J%.z*uXds=|x`Z+Pxf}&Lgq,&_w+UIx6ycaR}jZI7h&9:eUcGVan0]E_{Fo!:Hd:}Vf)1Tah4nQ,s"(8POpwod[E>Zc3O[(Z}OP,hsZ4l:m0L6@Z/X2nu>HIP4c0&`gmu4A+[!9N[/@@N6d^`I`>!=JNsI@bew>`[1#H9miAIOlZs^P"k8*hlZG#`@iAcwR0D2/nf*(l~4!>m5n{oNjaIee#>QH_c[zl=d[SD~J]Qut]r>3CG=Yuas%u;`El=|p:jaNo}q;y{?}tT@.p_~s0ynwD]^r.y37mk5,:Z40SV.o>Tq&"Ak;Z4&$@J.{"Z@.A(ps:oN?]$Y+cs)Da_Qu>,mCW2vDZ+!&CQ/8,4&%*?<[t$>&Q)H6J[I|UB/B<%Z7ONC9/R_elvrSzjFuZjuJD!S{0W&}DGYZ?lj&XhsbL@KC}@6T~L*1&OEirjt6uq[eecJs/bK13|x:cUm=*wS@hx7+iZkp3Kq3J9kN?&:;ze)0Uf=*;1OX7PovIzJ4($voAOzb$VSa{rpb#H]5;E0bk+F>CNB3)k8kB(d;SP:+dRqL?wsHi~+v6.7al+1S)wiQ_}g_r2Lah8n"e)OCr{*KkQ4tn"1p4C|$qm1$5:zzy!`ilfrR+;}X`gXY3?;.c%KJ+bdyPW*5V{G9u:7V7C7QNB{mRU{W&wqNN)k?3B]|0cI{iwsHz7S<]j7]s5#*{QU5=<;D9H!J4*G=[qG)pt7CPK>#9i/fa@~%(*.7[Um{RO"fn2z2VPfFkSUv7^qY8Bd06Bh[C1_F+])4E&j<mntrYpxU/.VI>euAgr0kd%;plM<YK.Lz5uj&tbG2n)M=AE+nOD%jQr{U;y[VKUUOZChuoq?A&/s$Ma>Xvx&y+gr6bCr.:CFE+$e6>K}#@h,.4)5/1!URi}5q^"_Sij{pCiDut.`ilyd!lzE4jD+)7;@^Va%v63?WOl$`e`ye+PGa$/fBy2.N]2jibXI/9##BdH>^K8+&N<&4e_q$1yhja]%bX[&3.(f#O+xLC#)CHJSeCFrHDW"uEUC%1+aQuX~b51t:qLD%k)wm$^RQ8lNRY;K)cVz<}aVRF&rjjR+ZH+[,V0AjFU0<MZwExG.3vclMiZK<gZZYJO37["H8BCR5>[Mh^@DZ:z29o+;Z4iD0l_tpT$3N4m>;G~p=W._?fdzT|~pU>w=+P+o5*uBJ)33Kj`Z}G+057)i;*ySN"LPW#mB*)$)_"dZVB;C`?nlfV^~xTCW|Gf5qIhp0LL"SB{i~D%`J:F=_1k>%"ejRI4!mrZZtvkRPq|D?Bj^wqA|r>J~B]H$m8(BrE_u|WUocN&EV%u6o;}1!r>VWR7uZ&`lk;;i_;Nqcsuy<gW<*W)?y&m<mZ=f<&EFFR8%1d0B1N@i)W/q((gxAY<}@F~74y2TnD:RbTeaDOTzNmDa2gFs9;d%mP;7s#%p&vIq4DM=/,(4$.kY]ro{6ob0nro#`1s*9i3k5w;ULiM;R>n/Q0eY5PmALzlj3lt4Sw50a##Ws.uR}hf9J};8kMa=om/4?7Go=J[Ysu^$EyuPX*Tc_fQrf#Q#b!v1zW&358MslKd}t@R$BaRf!<XU_;{E=@(SJb/#l,@lmdH$H>n4#S+]"qB*`#zcm}y{~[^d#Xmim>R71r79sKIwG4hClv{Gm70@poqX`a&EnjtWXf_Bo=1R.(/F7+DPg4Z~NeeG"Q!hwv|)fVyxb~P:~j4U.aJX{%KYJ(R;}kMA@D]4b#^eNC6x+E1Na??%sofUi+Dw,hw2v(z8{S_$B`QHP#6Jj4bH(bg1ZSqH#`_PN5@TwZu^w}Lu|fg%i]vY0@Vb]F/c*gyKiMP_5B7*>[}Tq`G`w7.5m}n{LftC6]/7K`EYo`:{?UF2u"e#P^7TN^BnK#a4o~;2/*f8pelW,v2=+BR$@K+3T8X%:p$r7X7m.aTyz6je`C1^:Jf&LM2NAbKz^Rx+,fm]+|}l&?~ZzkB23#lQ5)Ob"UC2F;OJ/D*Akzj7$`5uX!ZwkR_dds?(<qf=F"h,lZT(0!HQS+BasC$s>W1^7*=yyB%;SxF3BZQOe0Wu~(Xxe0kY5|*?g3]xb+g"(*67s1tX&[Q}%>7yf!xf]44b!Bu.BEpSaSY/zu:Hv`OfYEIjFbWy{Vc/fsf?L<=UI"D0*T2j&9%G)M{Oe4%S6wt`lsBzRN;P6(`UHs:V=}4|[_Q==$HuXDKA!qaXI9CQ&TPl4h}+Z@2hQBGd}4trNJNu45$;9txjOAdu?J?|kwmIDaA`k}3[UX3*%$FiuVv@UJ@(iv.Uy0Du1J*mh(0S%*;F>Mz(9C%cuo:x9?e.<jL2U7OudM1e}+2^aJ9N"UF!/Ai9"?tYjd!qyG^{:YVr4]wmqFkq1_Za9Z4<T`~Xf2qVi17M?@YDvczfO+"$hWQ|]6xTT#[f7T}Gr9He~4@%C~:KoeN[],G3d1G8m@!&#;v|j/(A7No`Xu!Fg}^F+Ka8Mm[5.GjI+Qvpx}Xm|d]5d^hWO>zC?kkJt9{:m7%Jd.IbNu$ON4SfPMN&azJ;Uql3=1Lc#Zd$3EyrvB6EeFJ+cpm`Jg%qFW%ws|&dJ>:#bzsZy5ET|B`GfxuSR8F/fTmFaO07([m{i)c2!pRi]H!S|vGg4#;ZnqL^8^&r<44V@sz9j?k0ZCleJjMw{]!h,>4I.P3wXxO?81bC"(,fgiS&D.ZL=M0/uJ%VCDrbxjj6:zxpkG1O|q;3Zu|)SF~kUHNp;Z0Uz=lurDR|Gv^Y?`mj_~PD].Bekz;Run/"B"!GA0Ea.T7XV)_FplOwGK9|voeL=rzNUX1u8K%v2Xv%MNjt3E23rHBC#eRG>a8sKfR@E&2[{`L9sN1;tQ|ZyJDg8p@S"L+K7jY[F}<E<HqL[M<@4:*&Urb$.)L^|F_!,?G[+8Y9MfX04q7G".0GX@)<%@hLwEi,4?4&eS^%qTF&_b)R>@*:P2Xl9z`KihlS:s3?Ps"xS3cDU^yhI`n,j)K@>j._CLn1L/aqvz|*]:Cy5L.Z0h[6[RZGy&Xmwd%XB6&b{e8I.CD9#V%#wO@d+wjJF*cX_~+59P/kI"Ef6}VIDYp^zxI}36CzM!W9ZxeYRcR5(*cj;nm0E0t]*H?;F^C;@enfk:[RB8nfSx?`>(jtkj5/C@=djPLO:=o@;s4+;Et1@naQJ;_/DGAv]:g7QOL*=Rbh<swy]|_QK}oRCLJn0h]{HH_o{TfO]ePN15JB#kiCg.B`73h[z^}bV;KdY/D|#]Av`B1^C1gwbL41.E,O1/oMik!PVkESe:DnuZ/}<$TTtV~8^R)A:8/v{l|po<Jk6Mv?k2$n3#aS.q7[Qm,MEhCg*.JlP<SJv*/}}e5dlDMma{TP(G8,Iq^j%#TqoGr1{|Bi?#:>YyY6i>?$EdM7q1@p4:HzmH[L3xC1C*hr+dY%<Y?oP3_yQzJ%3L1ilxP_h|GH:Ofe_0qYM3VW9>1|odW,dhrO()dob<CYgz>YHMB"L]S;0QazNz9}&xDN)6dX@Dbz+GY[#86}A~#sa%7`.)jbf*3d*+&hO}B&Jm!Qkcja:cF4"g>%77Xuoe%[KFNqI$8JZt"A1:[@xUo}rmT}=:uWZo:&&nKE6g,lzrvmK/8Bu!2m&e<"qR]d8Pq0X1%Qx$lD=MK!g;sS!RQ`XXP5q3,T|<JpuOGgOXxTC_Qql2[_2<J+,DE~}S}Z>`&ODQI5#G<66dDY`r0(q2#Iq.7#vHD?4qKb!YC#~F]cst)j?8es&?syC9EDH7z%p:"A`W:0q]D[o]$E_&KLxgV7kc%t~ysT(2YntT6uXoDs<k{$_VcMkL)H9TOkY>_KiP#Bs@Q*KBW|N@fV1_WC9mTDiBiJYinq~*nF20SyDnmN`G0CuO.JS8:1^jYv|ix/<?"NAN.BbPFA^A|mP"pgH17!aY]ex#B4R?/Fdj.gd]B4,"Gd=cuxn/<zZBy754Vs4uIwvG;dxgqV2xW#FgHVaUJZ=WRC2lp%~I6)hU+3&ekw[IRN|WvM8.t;als&ce+8#04[1xS5ck!LP`wTcoK74A?mrDt?mrU"w<LmK!6%x=3jD&qB^|sR{%(=dJ7E2=a$o6L1E#mhcmQUsuy71.|jogETS>}nWD``(P8~`[@jJ)sCpgi`.{N=DIV]9q|N$=VEf8SEw:RL!yHnL>2@XiE{RN=>DrGDtr>cUQ@`mUv$AXLIMawz0WleHsS(Is;TOcAu1?GVgRWiE(5r)YqLtV[=Fv`n=!c7Uc@2is@caaAI[?F:.42%EgOE#}p|kS7IP|H%%bPwpik]{%iCWaJJ%rB[dH6}a/4g9TlFPQJr%:1[`^oXt7T0#z`[Xs8M$,gz;@xj*!XX"lX,F|H$$zMjD+CnX9HzM#t=ibIfLBQ_rI9x*Z8RSEE9l*Xkc+ZUH_>H0z|/`@q*y$J.aKNF{zEH)^PMYgLwvIix;V3;%~8Y5ZtK*f}y2}79ji./.8(5>,4xD+SPV6$W.>LwM@=bS"e<tdrJ^(uCrKnV{DVK&FTp+3)`VEqWtmf;aN@kwp?ovSQ%({s~)`eK:{<Fh:A`sq"^Fx6u+P+A$5Sm+Y86<qm<M!#_BS{(/IQXUE/Ox&rK#U8C<.P*J#@)x1i*/tcTMeDJrIRls_]2e;TPCW[GrUTX@>&*VS.e>=(^YN{0wi,M^(M?c>x{M$i0br0I)cfg@U)BS427B|n1FeRp]_1J0=E2w_c3)#XVql}@tQWE.Z=}T+eznczHO=>#,DC%O0Q#~*2bl#pVFGC(x)w2)!a?3LJWC(%<fO|6s6G:~@q,7H03#.hF~"4;8S(/B)2afhveyt$$):FI.AyN.|eP~*Mp=m9m{3;=1?@w3$).VMZ"?[e.nfGSJGD[1h5Ie!jx8yK8/xiaf9jO7Qgq1YAr`g`2d~;{,6MBfGVzQZcBz]zGh)/exkFq]Wx/ub:dnYQvkqzn!^cEgsZSDN@j3}iJhDcurZv6R6X=fj"vXYgxQ{I<Yo.JE1cU_Cjhn{~?psrQ7RpY(/b5RK#KR]B(VX*&:,t_i;=&=0FDq%BAj=OH7?9cu==r>mo,k*|)##{M`[im]26<CYQr;}Y!|(rq!6J@/769%(Rlqkc`[^{sfZm{rENVMx?>~W!:<7+bS5/gDS0vGH%`}J1[(K9BM@|d&8rlvnx68<yc]Ti#!Dix,kkh2v&[mbUK)bpZ=!lqubo7kJ#AhECU3.T9>3LYMuTNR(.U%<+(i$8(MW5l}y/Fi~5;Xr_CY%VjpT0F{*?xER8XNA+#uw47JPOJ#5R$4,d}2lj:c7;,&.k/4IMe_Chusv(8P<Fr=J;V+F"^Fff]E`GF6MjopNTKCeD=K`nQ0N5j""b]Fy=hJW2zSS<">/x1c>ocEmU;@nFNfmXl^7N,Hth[Vrtaz._64r>DBEX1M<oa*RCI1A!`F*diQn[F=vv4<7!S>dMN2?qu8Mc%E.m*@cC0T_&>#u]<H8|%|rX,uF;8[4(2(6LQs(}csKg)3ug2il,/{!ypG9rLbL8LK]IXCyFFYc_(J9[{X_]Z3ii|GjGg?%zME{5,Xxfi(Za.._fZGI9u3aOu$TeqxhAnmPtqe3:l^?)Kdbt)gHOoF]pT1t@^,$aKz<Qe#KEu10G3^(I$P,$lLE(xX_xV3h|Le8^,nWOJbNeT;l`aQa(Z(e@].^93f!xkQF}j8zT>bW8[Xw1cbczY<,n&SM7FLWLyVyuftqjD`Gdh(H6nU:)/egh:,q=G.z.>)7w:feDQ!{jb,sG`~:V#SZ0KyYbd:.`.4T$&~9BTl2!A9}5x)FJewj*V)UyT4&_rY1_G:3rk}~h)NV$@dF{C<M&7b(ucB_THDLV*xvpt^upEM?g_q{Wxy]1#LbFCqp53_+pN&jRNw>aLj^]K?wKtH{^(]|:R`n5#Wo;oBwyN,%L$vq+o5~h3P5mgM#"]q^FfGWM=P:*`VwR2@=nM|UA4T(,:&6q]"NQ5#|fp]H(c~.4XN1C+,}2^Syf,/}.f,,9mxW0+7+bdK8LvSPPmO?2eYknFYeCi8lU|%{Fhp>#}qO/+&14Mp(F54E3,AUC),?dGetL%X6;oF_4fMHD6CvtAeujKe.FpJ6{qv2TC0!|&sVRRSGSCpq#t/26No|Cq@]o:+}kfu4[M[Puv"rLFbgE~v.%6`BZVz*/_:t>SX9("^B6/99y.}.[c<||00;.)cSHEu45o3}D=oE9eWwBCQ8Vb;hdh2ziR%).T2du.y@Rv:5`O,6Sy8Pgrx4QTu]Ea+]x(=R=nN&CyqwJl"h!+dUbgZ(@.W~Kx0KV<r5Y078?<tJC0$PEK%t,#@8sNS>GiQC8VQj5FdWCvv";fP|Tu0]ztMD."{=n[KLlJV<:!%@y;0Zy~VEFZm|5iQH:_/7]=Z_Z6[Bb>aD?06OkM&$P=l]$w*4T|41K2&hqUMZjEC<^mD&o9?c3|QIHBZAVtgWkRt^Xd$A@SIa$Vs0}|y)5eQ>)^q]><!D&b^<>MU!H<E8QU5~[rN]"!L:y6&hT^Bd;X1Pc+qb$R2WQrusD?O5yWO]F(Ct59;KZ9hY#aE~0&ackV&qabmWe&/;wx}d0t5btO}]4p9n+Rvd?hJVoip&z`Vn8Lv9/~F<zP@{3/PO(*bm{BN&"+C8kxC9Z,Cx3b;F*pEP@sE>6P=YC*nMWnjc*E[vr~pTOb_^G[}tP[=Qpc(Dfpznc9Z[zIS`<TZU6<9*^|3oFy(~q`29TqQO,No<<W;Yb:AAF_nPxb,nndT|veAWMdm}UVgl*rI;ZW;R]NC0),]"o}#Was$6bqlB#Co!hIfbQOhffmaS.vk0fUO.e&bW)DM6g!W&8_ot*H*8>~@ju7+2sy<@+aRc&*H^|Z}hyff13|$l*P48fj@Gdl}el^&]5KQ~TR3mGIJJNeE[Eql}]c%CN":&H$T:W7e:pyJGp2RNo6M}Ec:p?DRgZNc7*v1l^KrEYS5^4aXu[Ei2;9qT,*:iNz|sY?b(]rIiwx,!b)]e)ME#$Chd,&t3+NsW}jN>FS/Vx~bb;!E3;T$I0/l"6`EkT9Q`^|=;KRoO>Y&_[nk;[r{wBuH7a)T.$g``58Rt+;%J*~8|,1*,*8e(CSUD:3B0T*jkzD?ZH44H4QKX]?p@=tjXL;%V,ZcR4#&Z)*>aEO2[jz_5oT%sJ"y?n3{%vcJ1*8MCjYwe!O#AF@TIYLy~^^8jmTl6?Q?7{l.Ek$n:e.5/v&Iaf."n)YqQgK[yRe5||z4zqgEnLiG>i&j*`0j"@1T=&fEq+Q=*$3{B)2E+c=g8v>?K{&[8IS}Sn3WaR&|k4j)$~OYBdQRg,qaOrJexG=g3RK$P7$<FV&*D.!,NnwnD9vLw)r+V,a(Ce4iyeNL=$|:Gtej>(,@iFK+@99p0sD<<ab=@g}MFZ,MrWy4XB<&j&lF0K[b1)rGpfm;3X&Hrde8(N*KoMPGVDn<6Wxb0T>s"Se?#3`g*0?R9HAJK9)!ESQoUw*f<zeHM{aeLy/Kdjsb"NHD~y5v&o2#THIvjxdVV5`/xfr`"Rud[04zO#Hn?@Q};g17XT16hs,EEw&O:[u(D>/Bj!eqeZw{4ZQsRfcT]bv|CKfz)Ehk32ErRNQ)qB`ZK;[LqLT+crhR23,&Laq<Ib":I[9.eWO^b[d,)QeouLkvyA.g3$hWIN3=d|^F.9X_xoMH?v34*m]eO;O$d])22n{?UJ57VDMnv1+g6?NC&19BV%{}kZtLu}Cv~v7DTF}po2+?*UJs9hT4X~*OM^1=yEpOv`O^.wVzkt&@Z>|:h{F=]18xlFe1Q30aPwcO6W~Qj.yuh%#)<BnmH){X;wdJ:)TV=S*k!&xpI1??}YWoN)]66vY?u1WJyqh+@Wpj,.yJ_H.[.Uk24Rj9zvtG@D878;zy!zy]8_`yGm.RzAhOSa}J8?+%%DSQ)UO)ld8c(%Ctu>ScF+Ot)3Ayo]J!XC{wr<D",w[;$$&w>g*aDztnD/YHnnL/lY7)[g3pfMv{r5`A2YX{"6_X?eQisRGl=^}_=c}`;EKqj.O{Q;qi7id;<Pc]LyW8zQD34C)O$XckFgT9/7$fyoIkGJc}anjaqr/VPL}QbnBgBGERh|%Mg}3+WIW[*N1+Xpov,^lrS!oddiiu%?dTza=*c7==Z!k&uki&93g;Jf9$vZCXz;dtGvef:$=!3X3h9Vu%0<s~hCh5$|BmbZvi{{Us1,@e/W@bod*Q5=%eyBMirv|H[oC25IsqOvynzK,peilPcv"X@Q`vbs5zWh2Fy;qSSALDDa.@hQW~,Q<4UH^|rfj;|n//(2U66jP[a%W8EkW.Dt%Ska^D?Y?yjXd>5V:d2eHNNu:rIw]Ax6OiBkt:&VbdX|2fc1TPx|qPcM2]=}>6YVbVNb:^?`SPA?1e#_%D09H}fKXwmdcvsq)"$^wTfrmMFa8)Ub0_gs3niht*Mf7PJ5/qFSX9"&+:)dn|u)88KzJ@(wO*UMHjHCdwpM_Hi`7?uUY?;GE)d}W[_hT,:2vG=0H]Eh1l0GvW2JuE{Jake9dL9r#n+5XXuJI/P4"^9@amsyaU$5%Qr2#+A[dgoLG.7w_2nq?)tFK~fBVU4O#,JUk7C@{0RxUEFr42/$B%_%IKpV+d{UE&=&p=pJQ`oiVDqqk{2.fO4U#8Hncg:"&3/_OT9Y]p"&+1s]0!K=p),HKi1d{!%oKrQJ:KK]pzBZC{;ea`amPFZ;KQK$Xd!S:RIFa#qQZC89x4uXzxRr!6"MxBQTw>iuP~?,{(89}y~/%|S=7%(&8T:c6$wrlXhjeJIVJzc+tyc&fjB@,]K9ne56HzzpJfRB,&WKK2Oom=K.(5wCT}b[:H:htnEQayQto<5x)Js/]|*A6xC&&EY.9q]!9`nR[wz3~x;$kdDLuVgl_6H$z$pe>uqpEJE!R=.8vfPl>5{M9&ox?XqfOO]*$OmN;4q#0>^Q#)UfacfwpJ&FHXMf4]p=,*/]a9>ZgKIWVvZHDT/E@q)dc51+/.u<zEHP"AF1Ap6fZn<O::;|z%E=)w>D7|NV)3i.U22}N,C}e2HofQ(E}=NtyB[s5_U!Jm%:qE@{bB3NylsStsw7d=35ja`f+u6~hQp}.=(,m^Dd3=(0hKP[,Wgzm$d{qepT<K&vKwYFSQ8cGseX{^Goe#hVST/j#|JqKB&%BSRk`8O@f3_MmU~dOCi**o!Y.qLG$Wzn~WG(n}tE_uwDAGt{tIvvy)PWIO>@/$_=9r@k0ogLg?%&yc{N&9mjeB2S17zBvwFwZJ8;Ff=feXW6cS1s,^OHTGwVRara"93!:gdV`&!L%,|/B49J}p<;{:;fO{k1;*PY]zO&HyX=Bz>Sdu$r94SOWK*DyUAMzZXf@}c{5mZ!(NWTX6.T;?[Bi.h;c^8)R|hkyQb#0Vv]f)~_+2GPMb<64=nu*0[6,RKtebu5C~:Z"ncVBIAs6y]WD8_@a:Lbl5=4@~",J{{gp+iEH]R_:3qG1nB/fDx*f]%W5~pcF%0};762t(o94II/`^,S&a*gS)mFZIp8{F>,aX})MF(Cq<=<wtPk&Q!&QaeE,r~qoNIuygXh2}*ynxule=UO)YFb0IQ?AWX:[+Li<2Sfs<{ju>PYVD~j`1.xY*Y2Hl{j%~FG6BRQmt:EatyOz^yh!4tS{/!EiaW_b%%Bi(4a<oclBh%BAYK7p5p2Ip]M0nhFOfXhn{;8ko#nC.DgYM%}]UO<^[Ff.bl5j|g^^:vBb$X_I%6vwg<Rdq1,L"~fPz;4|2}a_`&eD%wD`.#f+O"G!H@xkIu|N772jXfG|Rt$+gHuH&gH[R4.s>7w6r&5s*Os`0MCwr+/L0>Qza=U[n".^t<z/lRYF{I+AdgyHXU2Ps&g,p=L&v9(Jzx"QU]Bw2n"<|gCu!Wo`S&evb!4VD?qt?n7|Lwjfah~YSUm;Y<C8;>J/_8*K.5_iW"}4G{vh]|D7UH{VB]`/nEV?1%26mJov&b/ij.k:Q"u</gj)Cwv(.N/fP7k(5t5Asf9n]?b`:|r|+D5Ru)WI:Z]&u$NP;4b5P#H`Exh3(,!$VAH{@hDw2"7JZpzg7`PrVlqA]31HP4}&_3mcjA[~MUNT*o<0bNJHWsVg?x@Yk~%2kTd5zJ{(+>dLDKp]P<gMrS?z!K%SE&XE<3ZWZ*qTB,`1V;;f6#Qz*j[MeuOU~!mx$+9y(!AFnPBPGUU^wr$<vvOR;8cpZ<]21;r(*Ui!59UbS[G=@?%OSTEA_36|GVk}LEQQ?36_q=$LCem@m+hgc62xh02lcT,,1N75QA5*0u7C`_:[DIuVVwhv}E5Zr`)|MX;5pXvofK#xS%0a#!!=k(/kZ1:Kn:eAFmiuTHZr0>UE;yJj>OE,iBmB_cb1((s"=u|M`y<]/}wRS<Ig*55Bm;SLx/!S6uHy?!nfd}r"M&z|^8Lr*Y%x^t985v2ag+K/SvU7<U+@)dwZ}t:i@vrO[[IT~r/k5/15i/P6+nml7qk"MvQ.Ft>Ym$Y}G]!ZJaSDzwL{(L9TP2m~]Yw|EhT`2!,.*)`B#pPfPW?:e&cJh,9Oa"p2wa[#4MoG1G3RB&|YOW9+4qn3t6!Jz{/~8~ocemUV)A{2p`aD*kHfl|apF8J5h3g5pK&o?~7sNpN?L<RTh0^/}J".yqMDVS2K;"Y~Iv+Lg:`<`gweU)4]Fw~*svpm$7<E0#[:<[b;_i`06e?[TylW%h)l1n6(~?ZBm5qM6B0E:|KMuQg.9gZG_zQJ&1v5*rK$X,g`|/UKimt/X]c;^naU!R=x%!p8zZPN@+2B88/xLSYz3_G8Xay?3K@~f3jPVbE=JNn5UU,]4!M],RVx%NW],z8f%j_tF*a8YxtykDR]XC+FVLY[|u{r86jzJY:zhF`P)*`4qs!R]%@#a|w!*?cO?r*U,dF($c/W^3:5Qq4wP}W;4:0gwejofXm.6GWOFMZUe!=ONxTrB`D@H,7jxCoN+?C?u}*|i1;]6DfzfVBE(/%F{[ulSty2PwXm&V|+Oc9/nv>r=;.)|#?!%Kr^pqkz2RD{$BI0}UX9j"zJp]c%Igliw*hw,E99O{{5~LmIPUpRYD.Q%r`E>bho$8Bh>b]8*o$"|MM!3Wn^tdGv{H<{AcKwjZmzbZw3|`AWOzI^%nU!6{5E7m;uD2`^d7J)3*K8@&g^gm"D>X1R&pGINnsxdFe9KWEY$Q|U4Tg_OK&A&r7M)_*WG?j,a+qa8oh|8VFG%6oZL~`N?[LlB~*OP_zHT{3(1TBpl7Ty,Y?w(&@C3b+EoSOMMM!e_CCklLzEo(k;X*Tyq_$G&5^|{@[9hJx0,24Ie{=I67l7bivm40V!p0){tJt_;B8;(.Ogfi,xhkI05b_7mkhv!!>ZiR;]T_Ng=|9a]>7+nY?!gF5zvo/eWp0i8M@:Sh~hdIKU^}r%s#l}:.<yMGfMe{yk}~Nxw)%Wi)K<=VIce6r/W4!r~?sp<H/*OQ{oq%,Wj8QEP_$_^Q3|[QETxN8:PehoqEk!k*v$(vdh+D/I>?bZogUtF(=yx}:;4_n:9&TzYnLjIf7?Rnn9Ou3}^0okQCh8V!x)J0oBZHl4&+,QZr{@e}T|hIpI]9lr`0(0Ot_o``Paz=9s+5+[3WJjFA];[OKI*hN(F!pZqIoOy"U7LPHv5)T1^L:8YK4mII7$pVr5/;HNi6QTxqRwo.!RBHgwoC28w,[Vx[xvxAK?k!SgW<a>E6KRd@=),CnGlTjGQ(*?JAK4~Wzl)Z_m;T:fb.b"3<5$p&q/Fj.I(kW1.LD;*Nm"H~p!cc7UDy.;SZgo[(/N^SNRdOSd2,&sz56M1cg6Y{7>HhN2:M&[8,N.t6pM^?UE~:CPsKQ#yf0KJX!~`~^@L=g.~|8cT^G}*z^Voy#+0tI"d2PMX#cp4x3^;e@KJ]Wgd_)ahzU,$,KHDX_@LZX;(>d/HpVX)XrzJUD:TS=PTVi,Z|8ThYoIv@L}:rxZ`j}ls)ZO||il~az:y~cE?r="vzTD[ydeYV+5FHCMH}}"krYmGRg;nLp4%UB)/QT@j)C(#PJdj1gdk,=VOD|4j1UA_dm^q;e9=KFLUMpSW~fRTs)u%>xdOy99+~^iP3!n~$y~4PV~44*,H[FT1/lEqcgnm,>DMQ>dct(nQ90*<(,g1DzNgZizhEBx]#N!gmXZ~[bor,}HNAM${x%cl3a0X>C`]1#SC1GaWi.Jh<I3P/GcD%J.?W1,%G*3wqbn,_Z&v68~dm4k_$6.J5["SOaI3GW"t5Q?`/E!v#x9&(Yeyh<J6P3]ch%+L}>GeK7hBxB*s?T*k:cB}PP#Z9o_n$eAb>BURET4rpdltmxGa.Ki9o8w.s#1dQ[t3qdK{+S&qJAyKypV]yqiF`14zQhE.#8l77n~WX`JR{dRPHj>x}_S]f}`9"c^@iJ&y!duJCqhy~X;:LUwQkhjj8KhFi,[MdrxM&ei/2c/?;o5Ip_Ss*3_[|ErEg}M]0[r.~0D@JP/eurY)IZ]Z[^]Zb4Z+$Ef8EaX1NM;<Hy94$|&^CsjvZ[*4QY_eXy6ut1O#;1}K|1Yh/lgzA9UCALGYlWb6oJN4kKgt)4%&GG&q0F/}kF3t99lz{bG!)mgc%d]M=4968:+1l@=5^Wih<xX0nl%SQIOHFbF>Sk]G0FR{1n3D[4I`u=^;rSP}rv<_mK{I(tCp+el#F1#zP~Rf:w/YN%8f(rJYPyEG#u<M4!NE[[!#hOaGC[j+1l8*bU&tHv"C1{&=rR}g;C#5]?]*c*4EeU:*@W$|<E.>gZ^J<&FxS+]WgZdrgwjUJ5a*2{_4.DgnW|w?X![x}D_Y]S"XXd2EL>3uRayK:B!tWH@6ZEf`kw>fb?)l7+Cjk^Xl}(3VI:725xb~QU9}I}+3dKj%jU|CuQfz|1/?G@z*IS3}LHu%!9=Eh:T|d+9Lpw|X+}KW$&mN9.7LS;Wlp?fXFKd2I}lV_.$=Q20dZMi!GDzU/1igSE@s+<S#v7wD]1i~.D&j%ZlF!.i[;h*q+ZZ78]^_{BIc&uT)s#(X9zJ7YqhbLyW9Uo"+XsYxfOe~0W~!Y,]il:grVMwoCh}[A2D^(]xiA:zU;9yWD/hcjQ/C`Gio3:H4NnuB1?6Ag8C9K8Ygz99veR*X.`&:t9Mq*p4Vf=L@7pwu*t27{V1bfeNt$QaDd@%kq%&L#{lU%vy_EOH%Y;WSTgx`/41o4^Ekt[*B/Dm8Ho1$sQFM>~dm=4el0w="E=gPXVcb12dI*zc)k@1{,_PuoC*MWfKFoHo/")AJXRm3@V`?tRCCqxWE1:N2$t|Q"eSVH)UJ3cIz&9K+#JQ<&!jUF*OqA*,|BL!`bO:ad0/B@]iU>&MmEN*R8)dDHt]q}F%9N0m0flH&k8.xLmnTbce)bZ@ASvP3Q&:6%.)[xF@J%4b|G$qvRX<ijNCT`m_$seqN?$LCOIIx^JWH*i!wv*sL?S+#1E~acMQzSpg:U@C^kom/@{CsbyB2D>lew,e#|F~=|#9XV^Pvc_&2_S9/n_pg:IXhXpBv]`uwzmaI<8sQzb8scHr5p&[^ec"x3j}QJB1UKD@$/F{/hX_M6?p^gWIk4Xzvh*VVd0E7XJG+kS^^CA#e5k}A^IN`AP)sC94pV}MR47d#4f2[bMFn0V|rUAzPrGYUMM3MDCNK9K1(o.&_IT>fouP=73DS9I^B$6nX@mF_`3aT^S]Yoa==Z7?FqlkD6>.CR{.QJ_4[*.ZJV%O>::,o<&@Dhp>8<eV|c4cg@I0ByHT4CIdy_#~S$EI78E{Nx@TH<mMD`~!}LBz2?Vc)W%8GH7N}Szv6Xc}J7eL0!OI@hCdyou//OQayZo?f=QV5woruX$[a5BM5*ls8~#seN3pBa&zgLL54+;GM`Vr%9[kjLg/NZVdaFGwc~oW@[cr4?a}Owjuyr+XcQ1Rs_N`2HlZH=KzvZe&ki":_2LT<f~?q5SnLe+(X)`jd9T*%TXMYZuwEX54NDwo}&4fs!xYzl2U.j>Zb+N3~o.H5wOSaU[3H1k05otHmUg}]EC>BvKvSa2"|/%*E%7r{+R!#CoU,w##Uw7cB;s*38[N!|awzddu<,h&)9tW#6%SF%hq9x&7F5]dZsyMUm7u%>Fgbkj,{}/CpagE);aSQCUfr!}"J{|h!GR}*o^cZ:]DfK[:X%zcu7)`/?OV`^.7N@1+x]3C1A>y)~&bQNGi4+[$bt2~absOQhG#@:|ql(J#2XGco+F39a?m`<=A)QzLfs^mxWFVRDlz%F`(Pe0D+$Q)#&0z!K^f&]+XS5GMMF+VgW+7*L]xF%C]?Fd5me|+>vnT=sD2I+O=I<JxR6o.&ccZCkfP*esdb1NpFpgpbvcd2f0M4*_cbg6Ov;bAQC$lo{SnZ*~,$h$t>xFQA=p=%Rv0V0"jLg}>k>B/2;bI[6NUTFbvQmcUIO&.O#T?FVPXYCIt8dtRb;g9F6Zpqm6%OJa3#jO`R3YJvg9oEXS@MyzR`IS3O2!q.&rO[hu06%p!lI%l>6p*=;b<zJ^r%VH|X6(iq>[pv9kc<@kM.1v^cg:LJy1z0mU+Sd@[RVe753W>fhcq5l:92chs*`*^^.tzv2:nyr}_SuDck^V:1;]96IQVa0x%zRBLMuvl@Dznh5jpkJ1,k6u(bQxLD)pzbtD1Wx#6ED}S]lXF4v42%FULWhmTKBUhI0_DP%cmx{JQLKUaq+GB1ab*3/f/obdHG4Z9d"X_<"ThIc%OAZa3S)M&1=;9vyafG^O^>.DPLJ}BPSq(6rB}S2`}{GgNC`(>(GX%2S*agb,9J%&5+5w]?K^SGH9kaD{N[.Nn#0Q$.}h|?,Y^0+~:FM9r:qCBf@m,,K5pD7xLFNpq|iaikk_S}E0~lp]$yXz5{J`wLGq:T?~Wvw,Lw!tYxIdEP0e.PN8D#u30VpTA!MUM`gF8Mcjw1}K1auMwCo_BomB[c[a[#XGbQes(WOu?LA8@?UHZUrRFI}0GsemWcJRyluBJ{0CzYL~x#dM2M2Hd1j,@H<`0peD/^YyQZ|*h2i|62Q^xhDJ=j_V`9e~wn"0^IxM"~!UKV9}vaRvfkZ|mn/gCBbKoe&K0UE:+)C=r+mh+_{Z@[nW5EWH`x^|6)`[M*AFv%W`%Y8w(]&p@^5(>a!>RU2t/_?1Ul46"C0uC+>LN?RN$d!dnCV1~!tqOZ0Nry/XN%T{v3iX?Y0oO.:MEN``UU<QN$oJ.t`f"fv)Q}73bVQUE)gBXxf#qE{0/,%pE6e|lyA8!5y@0XY}F>YO,D8B}s1JoMXRe9EM2>kH8BmZR.hGgl#l$t0]G2h?~CF$X66<A4@GFbS$8A82Wrn>24CDxv[jgX4[Z@+t)6Q@ttoc8CfD:[_N21d~tLYv`@&IJ/B6GKQ)Upw9DLCYCQWal17.m;$E^&zC<Xn=o>Y=aZl:Af:KNaAvLf_0~O/v]RPH1vL5_Yl?m4g@lf:ZBwAIj`ow(]S+o1lXp.{PIa,m<x5t~=J$L`|W9j&Ys]&B1PY;NNvdVv/|s2}ylRk|x3BgNMMUR]YA=DGd5;uVI4$yHG4<xF=LE1pU(IYtD>Jd1BS7b>{_)CwQ8.:(euNR&%@5{mT0Sz6q*]1Dp:t@":PrLOoHjLT%B5rce;hHUq@Z"5!Mq%,dc]VXk?(hQ:b3t%Br>D|E}eaW0Ezl6as4lBle61^qCjR2+Ml0D5"U`{=BXEOv}?rUm7RG;(QZp.|r7$5lSE/rfXXWl[xb46$pvg@&c)M^=9kT}[F=aybp!fS:,LJ}P0RD73TfyH9BRQfFd{zu2V[[^40=~Q&L~H)^jG?<?QD[z0D_t0gB/~N7I@vmgR{s=~F5!tLTc*j6A0`ni"hJiJ]!:q="Ss#D)R3fWJ$u`M+i8pyj3alVGZme;(!#s`}x|rQ+%S:DBu~B[c1dmW5IuM@U47e|F:2O4ydjWEX5bdG$.IT@nFS9Rz[d^4.4{]lJc26Fq|f5}IcOh*,Oj%o(mV~y9(0v#FC2dpSNKVW<W)i@>PvCOlBV@ioT*yN`@!LggU3=gQCZ2Yq;()|:h{:CFY;8tRXVNJRD,rcBVAKwd!w{.BahC5U(RiX5eH68K6BOy5:=$aGbycxBynsyV@|j|t#I8Y$(`rcZKv?PqHLD_)"+/4HYu$}.F6=ZTS;r/)Tk2RM;XFT`>3I1Veip$HjQ@f(Kgb6TIj(07:y>.a4=Y/ir#;a8c8gLiEGTuWU_kUdg_N|Fq66DD|HgKR5i=;!J;W5m~&YI88:#&kYxT,lo$hVgTd>amX#f"%hUZ0f$|Hgq.rZxJRn_cb~Q3iCT8!6c__9,!]&Ol*wrY2>7&^FIseaCle^v?7)J23VI206Hp8I!(LdRy|X)F@InK0:5pVZ<P3"xgJ1x56_]smHa"qskz!d+XE1L.0/OdVB.UDKS=Ry4*y|@W*317|dqjqGk/,4k.5sc=s#"y}{e?)&&PM">$[}R9]/`$FgJha~c1u|]T>.!Qr+(TdbR~NpTjzdUBvCyn0qmkXDQH!DleiUc=!MgHo+_V1|Zoh.~:_(DYy#+oUiW20t.$oN$TFiqY4qMJt_R{b1y,)P`K8KZ:/cP7Tf6+Q#r8R?){<vRO!6+F9:2s#l}S2]p=B`v$CTfGIUO2;sn#FiaU^j6CW"Ivd.snfJ0Ymw4_PZRKDm$nn}|pWrZ&!HS>{%<4zX1+ubEj@UK|RDG%1/>{K6wrsrbf}NOiGH{|s/a,nJ$xtM{%foz!!ttJ4<t&3Kjtj}!iUVnT/]Qb<1`^hW]tL"RUeJw/%phE^sb.tMHUHf*%vG|:3>X>4c2CG>~@#`zj0vj%VQA`+yH`>C1(4Id"mr*m2A+,R5&]aq80$Ek&Oj|}R;6xn+LQpn5Kc!f{~$&W0?=FGx!29xRX*e.z0f]6,%4"o&F_8"kAFT1[KtYxtp8NnT?KDh{YQXj%rEDdF9fb5[y]*=jN6RH@bpFZ}g~!$S4>*C:xSDrKCyFNPsO<BXocU"UN~9P4^Jo_qftBRodxucs3i?(l^w(_HxCY4ZwIbFx|u6dUq+}O[?l;GBPg+:|h:|Vo<laBlUSDME{y8F[cG{!k0]G=L$WdnSt"+cga%%zJv@wM.Fnm7*DQ>>HzNhF48qKC:xP[t))SiS~#rv<wzdH`>5dyOFNyEZ_C]4|FQnN/W5IgtV>1hDt<ix9nG~LJ6FlMik!GAE%;G=$,cq._N]Bha~dgjWH~Y1UbSGEPiC=?N/G0W#44M=T!i*<7xT5G0$SP&6[FtDx4_y8n5b,0e{1.mJ?X41bX=J*QS*(;P{:+Z5U7rukNe1t$~%0X[U_P`[:)B5ZyK.ZI3Mj3.9.LCNa>$E%(P8ho/st~*HY5>bg#YiF:G$<WqRV!29FJ[/!20kw]pQ+,OG1Xf:7~qV=faneWpE~=jQwoCGDyh:Npr.BSAEeCuUw20>c:]7J(1j[#=e#hi|!y$[>q+];oMsx/tstjt7h2FOz00S2d>)k[ayD:Bd%OCB!v]p3*4=!`{g}%NxcXW;+AUw~BxT~h45cKkaKzRGz"9{~%*Q`w}!tuM19=/Z2A22E:&;.J]knE+Mk)t[e2PI,Wh$$.".Rq.P}~LcXVn)~S@+|@Wb.z.Y9[ns8MXbSNElp^L^QY=.JGTC8wW<;Ui>*2.A*Z,4=M8K;(4W^*~K/IOgKp5JAnEjDNBO7O(5r*B#),ZCN9)OtshJ%os&!qo9gMYgy=l_aPI$0tY:*qsUw*jw4783yL)]ZRzcq8r9Iv&TkRR^f)tCNdbGxH"hV+m|&!.;}WC5^I0A$P3E"e}H2T=x>2C/?1S#2#&;f$mfVE$#^3PVTC~=8yF)Y1lFo:fY"jDupI<7H}j6sD{Sq)okg04v7j@3z2<kNwbc1B+Q@p]l3j4@amTHCAAVROdM:WM^+I)~vMb3%JE^pHo8)(ekCHEs!NqY0|HADx33((wjk<SNY%%WGAV;u,t]Qj^T<KK|ZhoMUei|,CSX)<v77At:6dV;d`Z%G@xuBSh.&:SoY)_"pk{ZI@{o^T3/*>u@mrMJ)SNgoyNEM_PGyAWuJB%0:0w4HE.f<^}fH,;@H#q![9=*e.V7>58x<7o;q[c#C?miMlZF6s$eoWsB[p9^,K+JwJ_9,F&Lvt${Vzv!7*/Mi3)o=#60aIzn.lKB2(P%W"s%TIr<2&xUc+h|mRrhg;MiT~~#~F+F}BB;a2v.3p2S`sd&707YQFGNZ45K{1H2`^)fVdswA$+T@*(5,>ZVj{6%~)bm_b6I+9YCMe5`BtZmD_npYtb1/E.H@xDAK.6hWhyJIUCDpbS0T.Uf2V/W+%$WL8SA>iKm80LhPoJxvp40=POG("h6@nGuZNjs)6>4scua%ezqU?^cOM3lBKSBMxbCQ+;0ChY7EcDa?%3,1~{2<v*zSgptH~5;>PGqyb6O`ZSI%Q?{mB*s9mNYEN@o/v3nK"=kdiWb0#KOu/Zdf&UamR|d.n.;Tecsg)b{MS;CPMf^?EN!(RE<iN~7K3M>3T+?NG^g0WWznnv%59SB#>rWX{Err]I)}|P>KnYQ[B+/l+.57k$nkC>BIy$dw154qN,METFVE9(iAf$0Us0Ezh^+azU|<1j<sXg/g:oDH0RgEGNJ1"4s,|xPZc5g59R*a/w!9`|Nai,NW!K##&8h|Ij+#78huhu;cB!p?g]^KY.Z^/Hg[^V"sd++a}j!,7n+.6k]1Ky<cmHsH~^+lA!:oNE14Pd~{#7z_(vnkg,?{kqzuK,_|@yVL*pBn*k]GslqObs2xOFB5xHbo5HNy]P6@=7UOB&J[}oP*7H(Ky9Ok_6)TP7YraYBl[H^K6!3PffM.q+RR*,xoPMu:2))dUdq{B^m_)ly%h?1=$,ydh.+:3l=}K|bni_H;V(2N8(8eZu~H_o?g1)C6(vr}Sp0,o[{qE#xzj,+3Sx=xKPP^)=g/K<_=1m8%JOP(o_PFqG,K{hMIHxz[VuiJ0zW1g|J"Agvc|%s^x`pR|Xijbu]H:1Lf))PF,2B.q|Oub>H1IdBiB1.NPNgy}?#V6{NxO~ZPd`y&[!Jj}!nXxDr9InoJq54k.AFmt43N_=:A7(Z0@Sq6Sc?Bc$RnJgKX]MDV:[Dwv}lsl;45tT>8~mt<$9aY*~5t^tb``>uKJ[Thniu8~:v%kQgags>YkS0yQG<)$^.3)Yns|b?M[/jEco"W#:uI[nlkI,AXXQn__|VP$Q<E"N,+?=d`7hb^u/P`ww0W)2+b+sxpK7#yO!mG2t9l&yW|>Kg{OqpXw1L$DaA[E{>vYKU4g[`~gjLtbG`=Tf9Uk1/rqT=X.6d)0]G7MNQ4~Pt4+hl[+/|VO.0,M{TjFE)G?P`=.,6g!d%<X),zWJm5(^/=HLuiJBTg"ONqul9nnXJ<]tvm=hk^9&zld0R2c]%whrUw>>pu>dCxvH0U>U4dv,j@?#JGF=F=^}gt.;RB~Q[K(+DNwMhG4Z)mzXS]_e%!7Xx{qW8$%D9vQeKnI%y_5^(mL#{.<1~>LX(sgOR6C.&SHn4Z1!L"~,9`3CoWB<8fAm_uR/*tCYyBjFS6%c7`mGfb$C+b*BbxH~jD1axX!:?[P1t7?,S`3mw*7`&m{N|1VHm~XCC(lKiiliY]6dlQM]_<V*8U3Z$^!kP6wz7jO.>Oi;V^x}^fDJicUI^bcTfv(O@|uHS,.iXR.w%Uwuc6fJq|mh;lgO"YdHBbn:2c=U9TldQz{Z*9m(9<"B{c:"U9fB*%<JlZqR6~BmHj0(WH`Nq"{>zAdOHBvv=6Rxy(`~W|YG_^5,&gx1#)(7UM["pK$Fz6s;9Hsr_;&YcL1iZ*F~1yoAlU6z()j$$6[Z=(&UO9,%pDA$%CMxsO$BjR0`U3U2$~ZU@+`#kFlS=JAe),1Ml[@T=X*2(]Qb(vKe$MO"zxV_`3+R?|Dqwcl#A0h^X*O|10A4$]Y]4qJ(q{z()G:1`hG(`_`$4}:4pgd.cckmO@,}o7`UFHnrF~&GF5s6*HPm?0>v,iqg_XKNb}p@{[/IFkQF4,4rQIGvHbRTgEx(Y%ln_G&[VrCKoLaTdT`)+mF.{m+$,<Ax:NDCrIC:>/}sbWjte;|[5POxrY#]Z7]i0p>OqPISV.jg~+|?XF2hSh`F%diU.!fo3jlt0#7:%[>tfF240#M=,r0!?oVLbh8!4h7m:ss9:Dp@3ERK/zwr@|WPME7{iM>k7|_>}lFD&Il7pJ;lmuE~S>+{yjfcu~ocNom|}?ms|n[XkPS_|YOlj=[4WI[u4{TdHnu7l+Cyq[(j[x2R{NurAT;:6pLWRk#VzZ5S!"/yP6*~dSAW5qC*+8EuBtLEhW|GYWugsC^n/q^].(4Z{+6j%E#[5&G^KSqakl&uW[abSh;",#?C"BbGf=+L3b|QT)gtNGnR,,%MtW}RoG%OVQIhxeHs7iL%D~74Jye$?+0l?gC=QV4%o%.L}TYM;gXMFhsCWE/8p!qUIY%W%cZxF:nO_n!wBn|[N"i|npB<v%tWaS^<_u=*"6<c*?[IFK6i_NBs,}3IhkfMC6sT6e&mtg3y>1~$iQwY2lW1of,k@^$*lK;l@?Ys>D+p.}w`C95RFBmkz(wAw|N.<M}{aQf]i$t,n{bQ<?x{kN68ay?7Y%q`lUY,l^[X9(?;*2BW/ojT6[}ck=pyOXOx=e]Ls<1Nk7[v7AT$2spDHcP+iId)O<mOSZRZn##+CW+Cb/ZcUHGy/,mNlQrsxjrz]~w.</+iA(Du[0&L2k;A$%ct[E7H6$5b"@h<K`Ja>EB9(r!=*IgessQ%6Zr{x.k(~As;(BLYFvYOf#|UdKh%i=1[!Go;NvxSi0s?G5"_%ZT]S^mcZAOK$>N$?>hdnn4MI_zp|#/p+993$|THdyzM2TeTZ%S4EEjk|{9<gFg..,bn"FVp{~=~[rV,&X^,xR!pbD?ao&92"A1M^t",>bt(Ik7oo8XhQPbK9SzGsyR%4;dF4DmVNX0pMn>H<TYrnR~9oiM65cRWB.Gn1:{?@;lplxlj&leWs[1G{qNM?}sILO;)MYn{!;+cX3<.172vMfCUx@"WFb88b<8O"Q{9FyMv>vZGLoG.Ix]P+#MwQEj*_y!nAci`8lND`H"I$K5pvr~sJ,e%3;bYeCZrA|{t=k,yx/qeDDB/[*Am3CGum[jC>T!r$X6]fWNBJfEBiXMe<=[Sq!AuW~+#GQo%2Eg$@i:ti(+ZE>[G:i=5mxDTg~bZ80*8L[RT3EJLNHwfTj.5:u+3Su^r5]hc@,;QWZLDNTKuUXQjq0FK)zsN9BNdb(?ZYQN6/$1__tesrk0Rq&RF@}IXB9Cn0TPz=rXR"lhU8pJ1=[..R*OU[kJSc+jq)_mRz9K3y0")&n2jMg7[mg6Qc]{@F_P7:aw2L2xzh+F*D;!xugXd_O%ns;p$OfJWuUqQnl;!w3!:1{,919?Dx)IFvZE%2)o#`%`2633tfWo)D0Sb`=a~gdT0glM$s<ScBjnYeyRw8jJZP0kj*4pwwo^o{;d?_{ezE."l*x`j8=px<>E9xMECD4HC2%IS.UON)[w+s.Zzp$BV&}BQUh4}Ru>PJcs7AZ{p)0Bb@W*MBwo<6G/=,dzjp9?p[()fP!J1]y<SvT+Iw?>i_(;kJA`N3jp`~5;gdZ1#L`=T2+S|Nl&"B_P?^S9v|jF8_yi3K4*x[Iie|nSg{#a)?N&uhkp{;>~vcasx~sDehK$dn9)tC7V,Pn+"ndu!I2W2ZapzV~%PG+7}^{<~uDEd)?My!P&SYhe94U"29rN`z#hdJPz*_c/2d?M^+m=LTwn{G_=a>YJnh0vN1v=fu6QcY6OFrru;v/}JX+VSVulEp;^cD+D,M67Y;<!;/8~5%>~1FZ1[s1unn)ASTN<Q.|+jQQbCkm+YEeWc;pU}1G}RvCcidnP})flZy3BrvM&beU2D3H)XpjC]%h=!~,ZOGH+..u}acl}Z94JGP.V0mep~&5.bY04#m22@gPz<<}|(uv*gW!y!YMM;GSkH"7]yX/>4nju?T7@0!9~uA/}=KGUXvY~Grkrup}_M{GJ5:Xn+[wWTbpLM*gMD`(+4Y/mTsyBZ@UD!fUT=kN^Iko?)SvZ<"Qjpd0saK>*6oiVc2#Wnubh2>=<,{wblFtupuwY*zPXZ2Ow~A;vghFgEm##^zN?~g^@49LP0]7F?;F}|xLcVFV0xN2(]4<0G~P?P3c86B_~gUb2/$q5ZedYItXos<nkE=MT5D_ynu|ZWO?G9yUrD;e:p8ZpRN+F]6cL1=xX$YfIzY@UFPY4b81LR~8vy$LW$e=$@)xyH%Ip"])jzfmk([RuT!?B[{n=vZxg;*CpFBLe+0D|EP_kzZCV8@~`XF1CdpYaE1CbLVnT|^RGT[xFF1Roac+VS8V)Yr8[RMR3d/4i~_eP;n6m?@xhe@l972qk,PbW{NMxz_vPA}%l?#%{0&GYm@_+0t+~rv6Wms8GQLO[_,lRhkVWx&Xu^Ch06az>scT8Gz+h7rVYrnY,HPq^sC{%unreQ:ie?1naC8{<h#S;R@SGRlDZ(rIXTu_QnC_d/;Q})(o%]hVZN51+s@z<l,rQiRb^s02r#P)=WN@A_pVGZbfO[#[l3$sOU[z1,ACGF/J1:vKxDi0_.r1oIu"0p;G3n`Xor5`WOAvA8wGLBv`R;c*M4l@}$07,UCi7&;=QV@cM[@D9ZCE}el!+{INTCa)VRxp})j6^Dha9q&CsMgq{vmf5G]IHpAc]//~Yq_~)n|`Z#:Co*c+mj}qpjAD,y]Qz:bU(}zo5[g2UxO>7D}26Mh~)/*2^kg1%DvBFq)1,&n)+LV;uWgC>:y_x7#pCDko)76b/_}w3c8bcl?:>M[9x0tJCH7^X&QL;~"r0Kq.]=_ydul[FaDS7]Qn"f2`Q5Y`.VagoCIJ~M&6KDoSz9}6B!m#FUevn#~8AIotoY[`~>pS!_wKgM*@c{3&upvp`p8ft$"%3uto|o9miy%P^3It`nDOJa$rtTZdMMY7yGFt"wJ_@_$!U@!/$eQN/IU_HOp)j`=0)VFB/Wq)EcO<z^ZwSFr^sX$%u~X#Fl97)}T.egV<4`m>l=RXC8<1lQlTUIpzbmd:[yF^qb4:^ZI]"ph{Pb|>]_<,m>p*b!D*N$BE]X^cR.K]BX)t@^q^nd[TfxA2VW5=myy|^Y{vxFZ5SkxC;LC?kC*QaTJx=j4iP2sYI+v1B)Np{VU~E0Afo.Wf;>b*8#Edy@;J[FS+NTuM}mCMWyRIU)lh;PX;BGgdN<6&!wBLZmG8emkwFINFU+^}(3|OawINiO&wQ9YjB"=2nF6:F!uz=zv0rn.Uc)5*:ri%qY8)NL7wYl0XEC[6:w(%~2_B|b<Fij~TPPLQbz;9,b+c(/p?.M[/.{1=Y14Zm0PUT#71NXv+HEb649T:#:Ew>Z.6X_cfF."OBS}Y0Yg*?M&QY37CRv8Xx;V}KSJMK~*u7]k4&x%HX.D@>E(Du=tnhX*c7(IDVkz=[Kx+`tTQz6{EO|lWV"a9"{^WJ!S_QaEd25x]Cm^D":B7W"]gDaJppso%q!UBs7<a:4mOtdsN9L?f*`84SC~8*AVxDfdKmochBCC)I>j=j,hZ4Gd=L7L06?J;(ymIg3f7:%T.xq=JO|LGF)"9H4C1!C3~s8C{o8sOC&ggaA:YwDc]tDvHzc~phO,k1Ia{@aWo",h/Z1zh]<JhBGJIeliQNmWo.1rg_mK!XV*;R"i)B2Delas7&O/ki}@)g7uz,I:=II}GFgWYP>u$w[f>Z{Dvjl:@Leye7`hzyzBV8$&Je]%HIlmHZ;IE(my9C]8weLw)m:vqT;?0RRWGIMle,h6W#%19t|[ePkko},]]ET"`CJwv";>~iJ83,?jPAN)Z"^(tp;Y~m0rKX*xvIlNnqvCl,b#l<o<[o/xfTlNC^Uj8uvm[(d*%GX|R)bekP|`QwIQX(u*1c)A/~c%gd.3^fh_yH8p4vf/Y`E{?}L;I,RAK#!~#RtR0f}+i1[L>Mxsxg0ZdY*d%K2.0y*nO*p2]>OH&`hoz)*Qr[tV?r8Y.QW>x{*!tv2~J{LUOEg5GgUURDRV&}86)M!TV[s1PbH{AK~<$9rtk]oP55=YP|hNQ,;=gq;Kh>}eq4sT#JfZ9F]+(Tje93/Na6a!:H)G,1Nbrj|?Cot2]:a24,;khI&ayfKvwgSKz9UhFbu74X{&Vd>bcx^oUR@jWr(HoHJP0OJlC:8|Ql<ToX,TQ%T@3rtM|m;[H^S"mv)R1al%c^[!a%VR&53E:m[|UEjq:28Pn$El_CkEXE|tI7J~|NJbdMGB`F_|U/a_v&W3(<%&rK]tY*t{l9<(eNj"MW8x9?|`?*vtb`R!xQ2N28ioC,W&2OwE=qR5D%1Ix2b"$)ZJ(LDCheBwG(YH[mSL#|p<&(KF8MJ19S?iM=o]BE}40R0^fhqSWqz(/5&$e/l/njK{eb_mo>L?>7:_][WAfl`3L:}9p;^I^f//>z>m*74pd7}xN_ykZuF#VmHux"4zz=4A928:Yi#NLxx!22u6?lJflf)q1nG%<0GaZuh!7Olr]6#"FHD{=$wp%YD7{/y;rl2HWqRkJ@XTAOVi!SHC?18Sl,U?m;p=F!rUYfm)#BT&q,ca!O!qgLf$~?p*B0AcH&::*JZ9Kb]5Fx(8*r@41NOZuGB.]NV~Mys8>B18@PD:+<kYDisNbQNM{oNm+buQo0ZwQ}!i6=<G^D<^{oKgoU{4o>oQlqxlE4U3,eW"Cw`&)$^Uf.X_MK3EhmvJ>%;%c>Lkndt@faeB%W_4Yc.=S"fd4+je%S"sQ#j,a>qq+q3<%,;"lOJWE`,msypfI1N{Vlv`<"!A!2j_8d{x<AxmP^WKsSxqJ{EARyIB<ZGiHFj`YZsq[W;@/%c?gtP"B&%1NoEta;Ins@=tHayP<V;{`L#"(ZcQ>_W^ilrVhnCA87mtZUr!fuOJvwLzn`ZR9@[c2a"EgQ7S+]`lVtraKxD`.V3RP*(x@y]^YUPbP93z>VJ#0K?QO&0j+5joh,?4PFV7mPlGnht8(tYoCgOA$"69,gbfh*J$bi):hUb^6kgY$=*M>Ncb,h3s2LydmUe=XUsaFjI@)~KKZG*x{+zA[Jk35.~f;^3Qu!,,KZ+*j2_Q~fQ;/,H&~hYM:b,"FMv2<l.BgE40fv,X)B$Yom^mh|}idN7yM`b:RpteE23n$yk8t.+.a]nWJhx;$_/F,"q[P|v{LkR7_i6S?Dh0kcY@(MQ2~;Xw`vOd^R20?Ek}([JzGF5[jLhFk/nyuo))O@7U*1YwsQq+Y[z5(=FgR!YZ`?8VF%xqBwUhJ#bT*gyf)`OLD<]ZkV~p`961l^?K<lfC_[.NCUv~,a8|hDa*p={JE|evlth7$KX6c*fd+9}@E_D~r3o:yzX%k$`;h8ym!Dw6Jf!WV~"/NQ)_siRNB&4yU@HT;pk3Cbaf5"YtyB5|~Z8+]T!5^qB4KY3:m+5S{DUiE3*/ez999B3DsQh$b8[U)&|:V+R}DP:9GeCclA$akNZ:KBb/(@UF2([y8,h4Rk~=0RFu_E6!{QJSS6HB$(k*&2SIt>8UjFM0ek<O!dmv~|=~.?]r}X5A$(Qd0)=/I(/IjZLJOlj3k9mbk`kR#oEbaI+yKIH;s|8.G1`1U/XgLy#YeC&Z>vx^+*m*hX)/X?h{E;Hu^oi;27p:IaGU6/}4]:pWR(g<a=fpKt#&oQ99=pj[T6(sNUgmt0$A;D]*pG*wa_iAx[di6G%SGWqo:]K0TiV/9I/S|h.3WYwW!S!+}H`m.wa:6ap"!Y$Nl1m@Q?rAy7<Vw?`X[.C2O0lKJ>%UB51}!Czoy{V1dkjgcxWfn$57mc0]w`T2t/IlK:/1vD)F]0em<{+,LywpSRa@?RlvhGy:`!CxO:We:)2ueNS7q#sDVNSb467^u|V+y2$.G]uHT=67pZdc=|d@{.@8t~vB5"2XduqV/hF2*EYOnnNV3oPbg);q4Xnnvb^jbDOn$2NC&fjDSFX~Q]UBRO9nt!f%]Mx|h[5Q+vjcUjBic`aD;=9,s5`s6x_hZ3,j.~v}$^0k&>1%gShj:CgsHAPVccn&S!hBSoj@Gl>`L(xWcZ}BF1s43XQM&.H4tJB7KMkE(Bwx#zxTFfidZHEcKE.F(Sw8en9vK#C1q_$`)$NZ;)s(?b4Z{htk:*Ga?ve_%8%7:[apJjh:1>ZVG"lYfaJ+D$i!8*WXKm_hm(n#^6igy7BFwHB7CMi%#TyUE9KTc><{&QtASO6t{OYV0(3gM|)P_]HI=Wpl=Zj{F6eDxs%I6U]9stP1_$}Ym(<]OQ@<|IkqUrq=lH4(c&HCZ?F`q^wQPXTzY,@VP|n9|MhlTg.Zk"=F(?V3E9Y9v`n3O?9MsWVzbJ/;.NT}tSOKx#JCwj7k+=p}u?(cyVR({l@bzyY?]{zOSxJZ@Jkcmfn?bpK+3,t5TXF:Yj!dZL=itax[.0YY6`xcko"DCVPBF*::/G<w.xcV#XCcA;<0w^*4DO]}8+R}{k|?Nc.0aQzPBZO/,pj4Kc}HROyV6wCw))+``F{|R.6#^]EFB~$SMT@m8WM}K_6(HIT"[eqo`XEwLC[]?7*w0$e{lF}QEnf(GubzfI^r}n>^K9^me=4Lbq?v1>>grM;qVCp,kO8B08,nn]Y~dt*mKMw(3=jV#IY[F^9aZ7}}3>QCZ9sJPxZl@4Z4MwMBfvIrDFl|G%`GUIWPcVh.^;j5LTR7?K5oTTwi8[hMd0E3FkO9)3gO;&UaZ[33KobJ0cg.n/Kw(.MSoNPy(S#5e<8i+V|KP,dbYa$bo;W4ShQ6N2jXGZxzMeXl+Yp!B0`r=2?,6&Ymq&aRz=Oh^4Ji}QXMMR+rjJEoyg14J2I|(_%(ugz>#_gcPVcOdRF`WSd{mljJ@U85fOuPx;|SlQDX3M;Q7=k&%HYsB6N@~panJl@"~Y#3!]Kn*:.3qZ7+MCuPKIF<tz_Yg.I+M<4nf*V:)#)4T}|RVQoq,R}tO.Q~/#=_,<Hocywb?)Tf/<OV%.FnfI&}aQ!)Xw>#)xn0=#BB&D|),g/qr%[!NW<y(`"k;<.2)6%A1ceKsy1:PkK>t0oth&[mn!aCyo+9p&Cfthog#&lxq#!i[Q$cu*TE*$.8(I^ia`s0_7rvjM=)]9=URC*;YPNW0v*$P0{+$>EUC7}:[S5:9%"r,[4=#kc^fPDqG,,|WgbT8ha(^oac};/$t{}TX"~.mbk+(<16=}tI+=/lDA&3no;8C7T6T]<#PB0{[mxA.e!(w!.$q#,C)YXoxZmHX}^/,~q+3]%qHu94XtZE+FP|vBiKw_;(4u1O,E,VLEm<c"WYs?$2Sz,KS$}RO~*=XSt9@+Qm/er&p}~2_n29R^bO{T,de0p_$(4G<1davX0u&cR{Pc6%I+3gMMn,uK?hASq!KQJF{$?k?}g!s{t@:&L9v]9fIt&}{@VI{[/R~F<@)b}q]w&1yF.A$3u0#N_=IJLhn/8q&#wr5J9v}e4vdB0/d@N}>rvmI=C7Av_?d!vcRr1P8|whC|}7Il+cHvw(XqNGgE8H9xQ}sQY9?"Sk(`>+oKUx`|(RhX7%Hy2R9=WW;/+Sg,tlO6i[eyZz8#%u*rnw~GD!$n3cbnl4eY#TVa?zXUXO1yj)@Jw_2(P"5i!ySQYq7m$e`I$CEC5VA`uR*JalKeY6GTvv&EtS{vcFz,k"X[E$N],t)&Fnqk7E_?6b=vc6Moo!^Ms6f,B]XJwx.tjw,ti^W,vgaibEzj3pM&FZ81NA|ia%pGu!huOd]DQx"],N95[iOtt]SYyAFEXGi.W7;E@1Eb!(W*S%2on8o5@.E#ZanM0,)~F<i$?1oZqh2q^sAFN<`y2Xc2r/4kM.Ka8Aek.B76!j;$wH0Os&Luj=J^dsl6bPOc*M<H((oj@ur]L+(%}#e*,;v^t^58SAai8QBiWbH|"GBqygR6f/=u^FYc??0AHPL@ul!o,1CC`bfg/8H!6Cz.JX.LGfCt<^|SJEd<8|DBC6.~~BAN0[/,K@fkTM5%xikq^&m&2mPCisNT2F3$?2<nJA2yc]7bm2Ml,btWuq{Co]]65/hlcek56TXe#*S3S+m[H{M&MN7fb7IKgh8{NvjgG7jAtr)z&8S:wa>w]Zv*%TkTr*:$[0RosFJXQxwsq1zS;|:*5OK]LYP{N/.1Yh#|]dqn47Me:^_QvEO~}X~u[mlYe~KLCtdnQf.b}cE:paE3R`YpaiRd}4[HX`p7<,7P<,pUiVE=Ut&xWxk~J"rSjVNO;758B+rQ&[eX6w,d)"d=858JLnDF/o%.S0KOU[Ug~~R3r:X]VoZC|Sx#qRyjL@h[1qhaqq!@,N9C8~#;{^@!?pbtS&uw:<N[UnU1r)q(@`)1p%oCAOlf$f2!5,7*tbhd:(E#nC|ZTG[6h{!#oluWh8qFVt]x^?85F+uZ7MO]V.(nxma{13[7rq!wd21bRX9x+gf5>]"*>n?YGw^4&$=4801=1mUiVtsdJet(zU5fU,:1|/W;{cF,J&<v|o>|{LSGq%b%v}9)svCd4a;PU+ux/z/]xxMrRts4/vw6rv$#6|AMd~mcEZJHo.G7m=00>b~?C&sZ][0<yQ^TgPeisecg)[Ef5Xhf~OvFQ5_#01F>k|+(BaH*a<MS5_KWBIS;j~@UW>Or8bak[{%pKW_]eG`$?PfgwMr:6*?rLCw~xp.T$=mEk/wD6o1q^{:Mz$_ayXCKh>/)qryuQ[dyJ:V$oT:%dlbM+=SMu:pk<~;e=>=+EzCI~?rO2a[il^Icz&4?H#!DV)0Jzaw;u.f!)rSzHZYI5+@=/ixa_gB~o3EthSi$DgG|X`Q6mw$)7lcSw0E@f*s}tg+uo%.`?wl^Tcr6h"$w8+]O#b`"<.t@h&C?UHKz5DJ3m,kBw|+&SEUPC2jb[Q&?E]q;g~*``1Z:SK(v#G$=gsn(+e,|c<z7huN`O%Z<T0rx">(=gkQ:S0CDFUChs{W$le$i$7"GVM5QVoUJ"(<+>(9GK=;s*{mUj"$x8i*b?&+jcv.,4KZLnl%1WEoMK&CZN{z#~<2H!nEiJF[{iK:$L08m/GwlN}=Ioft1[miLlOh!x{Jb8D<A$J><Xmx&_{V|~:Bo[e5k:Ah}({Zi{S0~rZ&"oOPI/IZ0Q:ThL9e`Fa_ZVlDx?k"D1A52"P9b7xNbdH7U@.~~NN;aTQ]JcKhe;!PU42cfe~e0.X?Ue7QD,d_p4Soz][E0QKuneDJ"saSah+l#eJy!ke`Jw2<mM$B1|OdN7u~W&.NFF(F^/`?Kp5!2PF{ICPozqW>){bYWsG+Y;3wJt;LZH9>p^hs@B@cpkZul6KYd.m7V.,R4ME#Xv=ia$>(g&p^D(yL},!(v=0~|roWZJE80V_j*TOeA:ZoKj/W8WS6zKl$Bs7^3/NMCP=NSzr{J})T8j>r8~0{]MQqr}c~&Dt*[|8FC>C%nctjKJfxA)6NuYr1q":tAxtV|2TG)U9:c=+D$;h!lv>I0*Luh?qCaNTThIydD9"LL4*U#3X%V/ybt{9J)X=t]kZ2D(C*q$ZeRaOiR~TpLyF&#cv@T$n&r^)2A)Cy1wQK@A]N*xVV._A,WV+m6JEJdZxLSoIpw<|mb[RRY%ht"@Q:{7$M<O`Ugj~QMk"2)tK2tN+jKva8P*=d742c~$Gh[pKt;6I,di)inCcPS07TnE;G.8oH_R)R*xS[Um{Q)*zD/S%bfOVl0c=Fv!PR5G"Ta9H23UFBjo9b%!{wMP{,%:nr!~jR6zq!8M}xN)VH;sO4emZeqn++KdI[)7}pZkdK,3&R7^_E_w^b"*.,pd2Fs,7(6y*Z2:AP{{Z/K;.3U:U:w9~4?N9k719u)BLM!y#L/~58!mm=`tRQEx_Gx)^mBk)uAU=w9b9FknuLKY}2aqaPf]C/@Dkz!<o(7n.{E*QA6$;(*c?EKp!9<rp;w.zGRpS`Y%n]fY9+M]pbkyx#=W0G2mZRR2v:p[&as[xF4c]je~k"lbIPHV!lP1@D"w~NLC"_azZiMLP61Et;6v"cnLYHIdTWT$iE;^ZS/YtH+f#4|r)e<|&6^W,u!9HSZE?"lsVhaq1@uX4qlX.ft</I+0L^`Vn)+(b7i8p:b]cMUK=Xp;t101Yr[I|:,rk?Yf#1U7iPMcy|bY6|1+2J_I=T}=^xvY!uxXeosb]w&4bzySM~HlYt`3QQ^3Piz[N9<)`k8J5||EKkS@#dQ6H3h#2Lg4o7hP_G`KDVw2PzXF<fTfIgfgGT:f}07zR5yPEauGI|Cvr6jB%VLiP92BY<J(D(Fe%"CTs)cD_1.Jrp#m)JPZcKOwYbapK;"qV>!J<hsD9ucC^ltueyn{Ysspf*8/cI@eP:U9,/*cgN@yTyr}gPNxq[?pN8$o{]J49)<X@[&QN@p$6(SjK4d$unq!9s_7xIjdVs9]<7#:E)jSeYuos%Op+U0~1JxCz%:[f1z3z;Am*;cLY=vLS~p[+zYo$_ZzF)mIH0a&o%yo),ZwIY{pdp6lI$WqF?lz]lCBy~E2.1X!28_0IKWl#X#SX,@E}kzO0@9wscf3_u1HO[G|gRrA$U*.8^VCxeg4`+*5EJ=q=MsT/l~e6OO0]:N&/lO.$d3d(OUB$rO7lFkEs,wgBIGhqe(+<KZSz{.nRWj6)E=|%S3W<Nxyrf3@0(#1(I<(~Q<;w5D2ny+Awl#8%Std)%$j0+!&ADDFnU*yS;%M9(,oZVU%?0DI.QQ7k8`kbu~Ngz"smjD|Q],[7g%y8vm2@C=xE,hqivX3*NCd{fi:M7gEsEu]G5b#~O6Z5uXX:S?@0nYKR1u:rm`!WyMvm,pr(O(qVi]NSHq>EibbKgftrlOaBZ9}m;2yzl5.mc~`?lrMSxiW.%PUF|5X?57cf^S,R>_.0/c/MkF:=0vlkx1x[T}Q^q@4oK@N^Q~wW>ocW{yrh?wW8"k*,*40yzF2i{k*ND/|(RP[>iJC;GQ`"?V<A<4|4`^Oj*uRTx3,T>)Ch.Z%kLnoFbpBVs*%AibBi?9EdcTa?^1}y*=2AK4kzv;8`S8jBq7Ypo8x,xl>i(VS^%~gqyFaiP!F(Fzn+"$":K3g)/g~#~qp9R}~_Wwn1nAo@5~o;}"=mZMBQKN6cNLl}.F?&=:FH%(m4}~$aq7$uj]&m`)Z?p#@q1+V|@Z$UcU2><v;p4*2iOx4"c!ZqQ~x"HfA!v6s!R7!:|$m?`N|Q(E[BO7(=;Aa~lJ/x4cd!m;~^=ps)E&,Nad28p[&DX2q53xjS)dmkX~=1(=w<l7%z%;>p9?TG?d7V?J9l])dt7,NYurc.9MU)V*#{GdgA,h*;.Vp`[S;Lfjb,Hk^:9O?Yy2QW2D)xAWL.)e(s`7fa5A:kwd%dm<7Ffb+o:6vh!ya](jHUEUi&c)ay^LMzPA1pQ*q=_uWrq8[4Cja*a&Yr::j)T)_2m.3E(d2j{afQ=8.F.GAp|%:)cb#n_>W4sH9R/}Xg5zVv=Ww2eha7.^8Zr`)`,bu"4Xwt(]R>}>B@tN:<Kn&$ylariq`!GXmq]|oVmFW;z6aDdNBYEFEMsi`l=5,^:RJ;iAK,cfY=$,BDm{sj6u4>2LiUe]/N{$<AWn<.BKE/Qh)&5=T+(,RFd+y6HK0Rm@PQuTrTD(Uy73myO"ufxxzb>yK:_G)p=!<89x1/~Jb!I$7G(bUAsdS2WiMP&%@I_$*1>iq&HOt?OfF~$d+$<EBSR4JmV2z0(q6xb8o=]og?_G&%Q7!AFu^bIM=L(CF_*>2)f&=q:fC;<v:Tw;QQ+o{6W&kA/U,QnQG]e4E1Qj?%0fvH4aC^XG,DD`n>q;0s<,N#Pj;=>L,a>(@EX/Ww5wRf}6S(:dPb#BX)nJ_bJ3~P*+O0H!khvMu^H2BWZdTgG]#@jJn&ktM7u@8bPb=W$z6aQLXA5C&cP)GE[gO(4uf>dsQ;LSCGUTWl96)ZNYN(Hnl$W`Zwirz6B(+"Pp80?xy9_{Z)4GaW@AiMF]c~ZS1gC_DmLN&3`*<AGTwF070kz.D?i!1$cNQ1NXXhf<lKF?oV[BsXw85LlD*lBb2fSPf0uc!GeG+TV:HX,eZ3fcfH=RZ,{1Lnlg{s(,a<Q(`w.sv6SM1sn|3h`RcX{<$}<qCbTloGOm[D:AxCr.G(;%e}GrB"T7?#~]TqE{a8z<D%AjN>2qg8a41>LZVCvOqVv&33qEu<<!V)a#o`yQ&sJ3m.ZpPq1S2IPNW!.7(Y+2Zk6slsLt~h{L,dRWJXJDaeO8CycC*|L8B9Ce6rquBvK6;*WcY<E@y9VHZ)g:UO"m*k?sa%X}0RRI7t,oMP(l]e&RvGixBkx7K,L;)?^LFB@n7NhiXY!&Qm;?Sa.bf=ag,]&,o/j|A8#*u#ub9~u6={])~:~D?`7o2[z;]&d)Pup7831RMNThv`kCDWJTJjPBMl0Z?6uu#i8`}0R&[_dFt4cpJ:+G|j~~}0Tvd<$MX4]v5N~;BZ*R^St[w#r}|41GpbrWyoHXL$Ft)_mSPiJ}}n_o$2eKHm=dt|<Ufy]`jz(kcRijc9]DlpZV03=B{d.@3jkZU=gumBHcS!6V"{Osd2TRmUCiw4|R~z&Tp2o[YI23Z,gAJXUyr2>PnYiE9G8Ty=lqdNJ?_mLZkk`nt]sp,ua6lTsk8yDU/V9}Dr~.*_+/rM(LCTW#$zlm14&=hYuuL2St)HpKdTN,02(~Xj96W+}N{0pFUl^fFDDg,BWhd5u)pI7&}%y^*szSX#F9MPwu={LqZUyZ@Zx]A~T&%x$e;^3`CNC^k=jdaxwUHY,>Ejn.:jn<~Q>P<_4WiWc<Mfwg]iV@#pm+c3&i{uu`v9"lLU._OM$UNZ:"Q:<gKJX[$(O/(`>>#OBg7SzK9Hp^J+^0D%BM7d>=LZL$7Vhtrel3Sr<!B{K"5*>q5>)GVC[T!X9%U+nzv:Q}GxbSkdWAubONYU=jI!FhYPtMk5]XWIPf(Q_$tIFe9p,3EO+Y6:6bb,j^bmDJ+ZeX2d*MLK+R%i@!GDD_<lw:D70Hg!8%6[S5Bk$H2m>rK+vqK>x,856eu$)c&XTEua~iUzvbT(_lsXc?NWZe@ZuTH`7(%^F<|U6iEz_rZ|4,3/}H:#48jqcN_7>kTc:F2{Tp2D~y<lxrFr>?OI0cmdVi"Zc4[iVoVH8q`T5yyCXy3De1SY5oWQiTt7FP$DpquCE;[I]FMo(!WD=03&[:{$7CRf)`p.Eo<PpE;s!U>|jBhs~^:13V,3qoCK<(u"PmW+7_7._qF,IJI8g6JwD7Hu{]rCBS`?OO)dSDG/D3H&<,[^RyBidkQ^rSI2!KXz%jV:#0{u^"F6/aj@i~%{&fk4.x^*AOnoej~oigBxtP9H;lgFQ[h[%CrE|r=B1eIau<<T#^p[iHr9G]oV=U<(1yH0D+fPewGmwVh?+b%E;1$1cf#ca$#%?)<$:^fHLbD<_"%`UOrea8nE&7d5%qk!Qwp*22%@+z+pF.SfN_dV8;N62)QseS6n_]]AtMyy349}`EUXR6b2"4D"|I>@_L<u)T*6cE?#]3^+7QP/?P`|eFmC"yeYB<(cTm5eo3O"v+FjA$O^0dMj{5C|(jpVI+Iq^]vFeSP:7tUn.S#LeU,Wz$)bd1tNYrI4<y(Woya#~Mo"uk~vBXiqN`"F7m_2+KKIc#52aMo`U3FA|FJJn_+z~BV6:9MX@4$l0g8KGStqK4@?@vmAe`EA[X,a]i~[[3|F1wbk_UD_hTv#alU5kUV6i`H;Gl~O^*nsM+xhpjvWg}`t+=%P&EzUWX9UOWLlT+ZFh%kV9,LkVWGwB5(#@P&NtCv?OWAl!L?Z%<`ZLJSoz&vH~=7DgGnbaV7jSjh(a4|LDv*=Y.yS>PC@d[cS3ZaVSI`r!P47(G9+NU_0h%VZ2||=0)Jx.8,JQOy._i#6rRM>.~DWYB!?5yy^u;2.25TU:%!Jjjy@bN;kw#_%XrMS%VdHY:#A6n:Anu>1=vb<Z)KsV}qE::Y.={^5Et&HZS}HUjWwlG]tW:]YI>94fgT}Nt+`}x.1#5pt%+]IXKRK+=TVKP/&m+^"Od7{!zuDqJMv@tl@aWLy+aYIG;DGmbD,Fzoj3W6R#gZd6J>r9crI|>23WS^T4etTrQzjswWQtcTDSH/Y4f8/Uu]mMp,.>b,Q0;51E+#t/Ab;XEB3;mxSJxdK`sK_)A!liP@Ix*a>;uGX+Vq%bYgN*lTv{0l0]sL{q8$.fVZDCeU;:R]$vW|vD:J|r%xX5~bJ8GW[>(14!$GTt`38Jc7M.1fCQTv@O%F3;XOkzPZH2/PZfG*N$FY>%V75_fL`1!bF80$s/#L*C.W@+KfvNas7X^;UMdl7kpXKe!^"7xSFz&v0&?,zI*sp4Q%wYx0vh9~"?{p",<WXYUhY(kkaLD%e7[:n};Z.a%nFK5tMnG,DGOo!)HLQ(Q5]tp0M,;iv~DntTL,?(m<]hgg&9&ZxDVp&[I7u.(/XT.>))i<>Y<i5x./[<?W>.z79Wtt?OV[6?ZQYNm?*YJwX{.>Vx1^eZRyIDQPF~B>(j@JdTlz&oSqom|mlI;>nJPg|]t7egTbEAfq(V~$h8f;Q03!c7v&OyeYKE%0(F,dB{}PDXs.:rLZ^u|K;@~3p_qP4]adgzDY;dP$`b~Jli`ap^E=8=k[4%gH8L>;fd{0lG2xVS@,pP&:z|C%:(Tkd^#yDtC~|5Nx2HCh0f<f+U7iZ|gOAmC<6dGAgjpic;,vi#toLySimyNGJ0zLCskXafm`2]JlJQ&ldB3qDd@0dQSd$G0[#MkQ)%GF.(d#glXD?+[H*%q]>TKtnHk=nvL7@F"mRyxPdxt1qd|JHt;JC40`__m1V`xebKGRxi;N@OAQf:O`JG"@NoUyAe0fmO3D~8+5E<HXRkJyq3A{z8N?g&lv).PH[Ousgfl.Mf~#TK6J*;uXQCG8`FFT09&Y(b,q*6mtH31?@$`d(_Q<A8eOM8~b{!YMnWE(Tou3H[5gebN]}H;/+05pm>%XDYvQ[}O.>]$UC*ce8S`bC9b4S9y_l#cRx8Cz4z^G6>DLn/$5bxV@#X)E#2>OBDk`yNZ~(vTDZb"SEPRgD)u^aCd:tK#QUMQ^v7hWxYiIoPX47u8_.O19#ZlJ&+*4y0.<ckg!bYzQ"ji>M~a.sNP+5p(~o(+U,B1Tt9Uxh0B%k|.OS^2O%Qz>:n]=a@Cfb)9$[zRY)<%T`1Vp31<CE8.fJJoQ.wKa87s?xXimRTo+sYhs{m78mnvM=siUo7}V@iAr;T03RAg}"HD?!M5?!?HU4KUjA3[V1Tc~=:`Y~pXgUGBzAM*M^=vKc0gZ|yvC"W__NUev5Kn=_kB%ETc.!+?Mf@W,d&Y9kWz8qbN~g9Vdme>GSL&LC<Z`CmM5]2UtTNHML}]e&+c}4hiw7DW4Wv!/W(:Gd0fq;|%nX(/K#*$IRqbFr3]D%g!hSgxHn]!7:2$ipvfA<CSCy|nui]CKr#N9}$xQ((R>4>IQI3Qe/RR%pz}0#HS>4>l9dk0#wsjWx_RJ>a0t"VL1MNvcj?x*S/]@9/mQ^Sum%hM<]]8Vj!?!Kww$p89>t:w9U;e^(@4lyfi8Yz&ND0O3bWN9g&srh[>~}}3]A3I%$qSZMI0FK|&TV+l`!`DrY9F3Dq^?[fvkuC4r({/Jb3+Nw]Kw5V}^#{BbVSJc}Z"v3m5T}&&>5uv>)@LGAg:^|%19Cu{`^$19eor6X:C)i_9XLmuv^4*SQn#nT8rhfTA3Q`tg)OqMUN`C@1fjXH3Tm<2g9Iqte+CdFBJ.t,V:?P5g^;i)wY}*]+sz<o=(z^(@@e8+dK),J@dODKs48mXEk4w,]pFk=@JbuS2F>I[jowBDli<e8+:y]vbv<4jZ)u`)x(SR:V83,n/*([pLsLi%0CRwLbQ;q6^zIAVLm(%OCT@I<hs+b0I#U`$!7|ZoZXqQcEQz{T5!jva#e@n/3y@+z[Yz;cn!k%#:BFgmJ>I0k4ckRw[WB1^(T2fz`RUBSc@C$Twz;+3lJB0QaP%fmGeQaL8/{/6o6VMEa?P&YI{t)k^&m*4EAB?U8{jBt2Jb)=:bFZe%4~sF)bP]:F#Z;v62=KaJkYW:mKV=2F%s.pv.54]ON%7Y5R7+{o!W<aIB/`2==t?_NgS@61vJ/>K+^Pbx8(+Z5w/0h$ng9vI%7ZU#nf`T#D{fO6be=Kj[b0")W[[PQlrasGa8~{)sJ3jlY)>37wX`TI*s0/r!>3!3^;M5[q#vSu<xUhOlef||[{%bi^g1mJ:v45)%&8Z^;/QH@Xkj@(3R_DY;LapSzUC?>~?C7hY*Q69LI`r](%`3/iJW_[Xo7o3.%s$2F6AU$LRgjh:$Il38=&qXumCFD<&Ue6epld2Op0;R:&>$gT8mUmhi!;dyn~VOvY#{&vW(7dR5>sU+R5:#V2+&?CM.Rrm}^O3/>!h_q~6"K$;h,E<b*21@%52R*IO.WZbU#3Q=n^A9|Np+~9di@!J*c^A/T_j<[q_9*oVsN~A//]GQ&^(Rz;8&Fy2#b.jddwHDPxP=fpkY+{e2akp,OU8nA2xz3h{Jo_zSdV1@QXt!/mE}*5phzV}Y4"Z!&OiYq;"C<Ei|~)1~%%(//IQvK)tD*F0e*,pIY*{FCV(0m8CB#<$9=9l.|=1>1gQmNtuFdoX/^x%yr7Ry]zTWef,*?,txjY]?=|Thgf)lp8W{BSVT6](.T]N8gY;Oe;<>l8HPr:8!>)*=qblE#"opAUy.j2XzLY}|~e0OwBS~7V.a&?g@{+no|h0SqYw@3%.ujQobdU3@yuoK4?Ia7[;9R&Sgd0Y($a[qK,Sn5d?d!k#y8|s=7xXb8[y6~Ks6E}o7o3T,LYe7<m"_F{5zwnR4&vN5"X^*#eb28)(ocO^M*!C,g4ss>`H<Y`5SiEwpT=/84*yxp7ovW)++<S&0=iK,u`DMJlLHb2%:Vu16Vf0~ldoP85`S^?BKarQP*O#M*!FO,M*!%C&JIX;Iu@D3C37X|VG+z3t3<%(r{#*[>6S8;R{z<zPBGDBrXh+Z!^SCV;,/Fbx!{?gMM1Rnsxgb+wTPKMf]]Gq5H3{kQ}s=c0L.mx}RBop/GG]$O~*e5Rb2uDV{u+B_k$cU/L6{AYVV&*aiVFF%BS~16pR4B_@gCp"U#o7o(la#?=j+FwD4y35$;%M^!6S*Z6G~(2JY*qgr@rt@Vz2U+NDO0S|6=[j2MiSf&fzqR;Mf@M6?~``I:s?|"3.`,G<wrshya6KGR9EL//`"1rVh:@(z^mXFIGT=2,o^ADg9nx{A09}7!$`<SH7L@Y"r5h7|H:{z()C}{z>N4ODO3//>RJt{prxrxoY:zwS_(+w~"&C_b11<rwhTiy=iM1W6J6P,TC<.O@S9rjO2!grhrj>q[,6bHHpNbon5p9uU`iJ2>khprj?pa@0+>59in{W+qN%<DoCMNu;b_}W5IG^uYKK9Iw,O6?DDJ%:1=ix*K,7c44c|k>8WF3g0W;(UgQV)C0clh9c&h.W]JS_zc}f&!07UA2l2=Wa`W8Fcd[N9[;iXN3tElWr:`?GW<2N;HXwM1UhCY%toB#/KueZ5cX|g&ZW2Scw5[.UDGTrb6^+LV2Sc_%Zn{}q><S~`LU:^EoKm0g1wlH{FRN:dH@ha}w%@c|*+!+3_.jh@c|loS`w8/6LvngaN.OFQ+pi|&vg%FmS(%n$4jXN+5>exF]|g|;b(l}becY{iKRw(D,%&O/0mf$pwj.,0/I/Lp>{+%*4V7zfL].@IdPCAmy;JrlM8v3t6H,91,Xf4430cFkzvc+c&l,W5F8z7({<!"@,0kI{!J58s`vz~SMRrBUy~(lxk!/3^buR36bZuTrh~%8fgL1.j3y%+=Cey"eS@ai;BQh,U]0~Ti_e@@[_sbn$;.r6eMhPG^:VLd?H,7YvR8ivU1;sz.UE~XWL$[9yoE+>~U9Jb"YE@2c/_dSUYr:(_)r?oh5ISd(?;r!8=/0~[PElagav.pr0?)/)9;]/=H=02dYLP"*(S^J?<}S7.E}}5!ULj>=$5pi"2iQqP#op^~MX&+)=QeeY]Pu;bR30g=HGxMw)kGKrkdFm%Zo9g"L>{ZQl:0z+/c6w@!4U4(L|[DADcpPI%{4P,=>*v|lp)j:kdMhk((;szbvg6J+GXIS1?[|"|t6j:TGW[NW,s|r&E6>$5bsJ54NK@cZIS|/3n6Y@`!djx<lW;E3r++&nQ7+6j~6=Xm$Y(d?7pbK;4e`91Ll`/l(Yo0g"[<#Dk|8tb,=N86G=NC,(s07Nb"XXY|kOXzM#w&n7+Ql@#p>S98kX@Btu~5o[7"XE"&O])S5|4b:~yh:TF~M$cT]F@QU&u>xB3a[v3e@Cpc0X:b&caO7X(1;*rhS=6u;r!Y5aKo9IZsu&dYhmcq%#dN2|TA>=OfxQKc[y:@zGZX8%dq/&=My2vJP9kRd*r4Zf3Aw*%cyM4nx|+m0;bnkbC~Y<O|Y;Z?dsJaN}z?.xgbV3:Sl7;_E1HB0,<ww.yQ4|z/6R9wjk&8j+#Da^*3nA|?&!Q=OtH=)(+NhGp.(@gF:M>!)q9I^MkXnoOUx}5jYC#iZM~)9<a%IaEfh/]?Q!KI<#lJ2*b&,y<<$|gn)W:Ml(r/2lbx2xH@aQi|T|T|T%=KPlMO|OKgC;[&.m[DlGpE}`S|+A0(I@1kbO;_RGF7hfylV|O56S5a..]Plkjx14>x>$PI[;{1~yl{1{cP]Dy}5yS_,n#Dx$6Ip;}YR:/,,&G3HK5Q]92>NhJ0n?.Ulown["^u~Pl^yz^Ck6wEG!2/2:Kf(5Nz5uZU>^+J@DT2hts9+&%{+=%qQVII,JEWvT:+}4Tgufr<@pi4gU>j=I,vjT*HyHc}uMo>K=Hkq,E[}6]~h;$jilR?"rjESr.FU>(F{PyzpERa#d6S$XC[ouh=Mb9IICuiGMt%e4bRlPckwrx)USB|*.$W}[rSY1._M.!0(RZx94&4Sf2n$uW3qL1P.f)@fCu_vVh"M2jsI!eCe~lEx.>~a.kqpY;%bL^G+rayB}SikDqULMm@H|G;xaoT%(mC`h`gU,{[9@e(;|2Ab4s8[`pRg/pf]/<93M]Hj8narv;~9Lx,l0UWCo&E2M?hxPGcuh)(RIDF)7N7n8*$IhMcCaiG5^OTj"Q6jbLI*C}_dKDKKcINPa6m5we.v^`x(4t@(KK7hQigU4fG"%SpCtDN!D4to*U*;m,zt>plZjvY5G8TMh2G!a^BPs?VcUq&K3#pAybdW@g,M{7ah=@</!3Or&%.|{sS:Le)%82,h!9+omr6%]v#jPwhEo~7y~Z=1k6kz2jWM74E2hPL._grLr:BM^N8g*Q+l]/j3>{>)BPLv3uZG(u<w<@S`mPt~OQR]&R4W8,7[yJvCM(g)O6gOPh:R94~I?g.b*dwA!Dz&d,;w"F<K!JfyH.2{AS5etkHPlPB%?9+G$SDhf<kFpJ,wgaqhOpvqZE#jt~&Y1TENJb!iJYa"~c?ir2|lUyJ{TiB(k*4Ei![fr>P#d,~&VVj#~?_1g:_fTWJ{`5t8@f"n=yKS{CWzifrPiT|KlETiJjpje,0$hf~lB7>Et6J{vb$SC22X2piK5],aySRCVF~M`5$%>xgpV:@?4T}D"lqw!!~/GRFhH{a+ZFWzFud2cHn2=IX5:7ook)MHeCVW_p<<:rb5ij/nUjVMp]8obooi4S4fyH,u"+?Vu^2@@f,=u&M]x&=}2&_&`ogMbk<UD:%?UqB1&9$iGpbOp_{kI%8LR,zO{e8;VeOh^u&oHP_x<d|%7@Tz#"TX"$l#IN44v%`uQeew_&u~%rHj:7R0>pcj7+Vr(^`.&=eE81Xn5h;I9!+GU^FJ9y>|Ph4|fp30s{>N^1fnL*W:N:lP3Tq9yH|C)=#Zl>RJU,[ONQT5^akQ1gc64M*gd6n]uWAZHkRUEilJZM(r5MzeAL>5GP"5R:pY8&dR;bZn)#wGMIPCfVmh1@/22#;5d1xvJMcXnEJ=WAX$~|A}0:yQRb6o5eN*L;hOLe=T{MY03GONIb5,%RdqC9m0.zx0[xIed,Y^06z2>nyNdc73J,cPhNfe;qY,|cTdYL/yt^_5Se#eZg(q"L>G<(z(~F/F!#wU#ek_nT5)y1[f}k@m&o[HUq*=oOY9#T^B3T^%sMb`!=[Yte8V[zz@r@_BF}/Nr>!]&+:eGQAphj>;sVHl|CCNlDZe.mi`0@?Ojhxb)vZ6M"aGZaZg4W.5}`vUyw(LNZF8YDs7btSn/pFmh!pMsDKVdnUA7Zb)#TK%9I9L1@Bs{aagbi#J#Qj>qZK|a`qZm8"VAWz=eE:rH3$2"o|{hH>YR].+m&E]N(?[Z3T^uV3q]G3u(iJmnDizZPOoTP.a+wYzx/<2J0uavO>Z+J4HQdo>lpN8z@:z"klTcroR"5Ip"ol<9y5b8a7ZYG!kbz}a%+6evd{UR9DkxQ0m614=T@$1}IQ|UaJ,8!:%!ugbygaP187xdNQ|]gy>4cc}pbtxXn{"WM=UNs%Z4@0P(iRsj$a`AdRHGPLNwY#8$e,/,|QaYCInJ{As<3Ke|d1mVX?d1mNX73`ZWZOEF_#(uIaVLa8|b{htk$t%CxYuv(oOPURI0)2lR]Qlj7r<h{MO59]ak}xn#<dr4(0@1rD+L2:,F:Na<b1meXQ#PwrHYo<BeFKKAKmuC`+J0qGTdMMK5=IpTz5^K(%Y!Ld2Rgbzo2=ihxOZyqA0*i)}8E/2}yitJ<nk3RCJ5=Kn5R0^B{;(!6*dIx>c+EjIF<P4>[x=@hz?dgBo/&(/!95`Ov>[&%B|$okx%Ndy6EDbd:)@)M,Wx<FS4P6?8)_],p=E};$q4ZV}o_.H7!s3CGE0BmFlH(V51p]Gdcx~dzo+^Tl%mh#@kMi`[h7,2Jx7+%"?U]~hiO$#e&m@1PPe,[QcrT&cpAI]>%sl=97$dDv;b:i64##q%fY7E=e(DMaVHS3x&jMqHh~mr;X<^de+E=7466_dp1x2W]:aKK9MQi2u^Q<?&a/[B4*ZG/]z_U$4FJyMx+o)sEiOW@c|UUZC{w&OlD}zIwuX"Mlu3,SrS,0z|mKaycxKmC+=AKP4{(H!x2FF57JJ/dGtn?SZH1>;YRMd%![Q+^`*4TW3rr4T)=T4JS|~k@wx}q,diw)&&P0*e]A6C7n,kR2%FoOD&5AQBah<m(ANyL%u8w5>YJaV9Md"!"[eY|r@833PS,)Sb29LHXMaadQ+Z1pM!PeEV1o{?>.(p[LJ/h"$V@E#;}2pNsbcEOmj7sNs8Zd4tZd4gQOuBXBmIQ~e+oMavO^K%uo6F3pHO|nr]KXN`$$*0VhQNN[ull|9N<r5c>AICv7DwavOT_if{ODzf,_WuxRMr=+PFnQBiOiTg&R1`P(nlHg5MmU:XdLhorz@Zxni_ghra29N5m~|2MxO|mf>9T8jyfBxp8G1?%Y3r61G>%RfVdA+==&GmO2`6p_lkPrwW0aPC(Yzmy)pGbG;#p.fbrSbMom$_Kt+UvP7n]GCkg+GzBtCL+$*noKu8MS?Pi"Q1Jg:qK*6EE83KCcs:b4usQ[hEUeQz&X(NIh&4YK;t,o`2gM)<[NF>lShJrj]5%LN$Po_R>!8+><[{$cEQCp@gg.(quUE5vKx$mq^Y>E12gkml0k*%f);6x~+j(w%zlBNCN75U{Ain1T$#zk]#q7Q/a{P/a6QKR9!<a&(q>w0rdiHeKylLe{P4nMal;R>e8s0&aU``P%qARz&NI8Wx`>mxYlSO5<ZX>KzwIK;Z;R>o=<@$qU`Sh0$T,poRwGP_xCi.eTUuB}%19go3g^+j6m0MNk[z[4hhF^~DykFpS,BQpp{fw@#p!t{gwxZ<55prV0$T(@@MR&q3G%q@h!G=>(e?mt{n@Gd&,.l&eB)5l+8Csr7MNP]]nj}NlwO}w@zagKGOW?O|6<S,f/$6bp8ug?oJnb[1Ezc5@FD}.zvyih@{GD#Xb>{MMotPmir=x]?r*GnM;aAp]z&X3eZ0.B+.w;qG+8o.k8qx8H+ep#;|^I!n/(R[{S_*+=cW7H_thb2,NnkP6H1Fy{|t67+n]Z0.u06.eN6iEBy)X@*G4hF6=9Oa2,sG+$k{/&j)r9,2g;Ao&e.k?j2wj~=/LBj@%U`.k(Cx="wlbYWeF;:1tP/+MjMKu))2%xR4?<]6.rOdV9}_]@Ocp?Pp]3$m$`%{fu)Y[/I4n,@kgIv}v;:sD1D4Ci]*FyUU%Scb6g0B%8:+TPY"w,?Vd:b(,dx1*^y+tr,<P#S)AvY~ay.?v%BwyK5AhjdW511Ic5%U9gox5Y<3V/i)`p2/s="n?q(L<6"MXc/vVn9VEJCudb?T<p}FHg?1bB$`r6R4,"b~>?hLpV+4h^.0^p;K|UFG5u;y1eQ!0"F)SPB5E<b!%,dzFql|2f}uNf[?!_>YEZjuK:/$r;z/}VKK~a2!vj(d(J,SpeU`^4#3b(R&j!^8o>`(LQ,<HQO?09$7.gPAZ7$ofB+n!s3ek(0zm&,M5O=(RR77.QI`4s#$4+Y%gX$~MJ&UZ5^"gI,?].yM+MvqG9]4aiA!O!n6Wv{2=Nn$47z!r=)bf%3Gf4vFk@#@PGlK9EOV#W8i`s|p:6X*9hJs&x=%:"mtIv}v%140H$0&}R6&?=}C;_804:#t,Y5&NYW.Y]hZJE`^Fnb(AJZ]hVf76G0^K4/Z`UANl#}5!^`qnAU=7!JIwD,^4)s!JpUN^&dgR$0/(J]vXO(k$IutMJa>J(QW6PVrl&x!jD+1;o~fJ4/e_PB{z!^_0Wx:IwljNpE)nm:Z`WK$>$k.k6q2Egn:em/L8B,j27Zb%qbq,[II3pGB@miAK+^l?U+4h.d^)<p5+~{|^UctD+&.9)JGz/=W~L[Aei%p:Hpl9}p=mBoXy}#;Qk{EIF&amT^R3qoA+GW&Vf.^!?@"}5,iwf=nxzd>*`#y@ocii=x><{`bS${Caj6O![Ea($@Jxumd9{{7?j/Ls7$Pou<>g9b0@k``J80V&"?+=vjZqV6wA%K?dA=sT3`v3j))@r/g&(p1f"0$p;!4|P[xn;qpp5(S{}anD{H0;xZKJf@nqN9|k6t9hlL31#H?T#3PhT"V{E1hxjGP"PAvZUK9[FDf(%h`G^|]8?}pU5Dl1|@fNurg1T;6Q|rbgr?TX"EmEqJibY>X`xnoB?SStncyr,ad._O+37,m0;b0gMOn@UvIJ3&R3r1@Kh0fUonmscR[v#`6.Ob@Q!&HE1R:%P){gB`I=>g72:)i/(#De_g7K*7"8Le<Ch&j(9Ndt/&xh8[,9!J7b`]V1p$?Y*E{?%#tr)=+@A6[e6Y!dQ:6w#&Z#$>f.U:W.Q[En{`,pzOMmVo@B;"3r&%~P:V8300,9`E!>32Gocl2h3^Rv,U0><(Ed_w$,jjzLQvZVhY9<Vd}^"N@1}cq0gr]0xI=n%Z`=;.d2ew#GF`Jh.{BJqzp(P|b0>@_/4>f$??G}0=@3l$19vlsvfiKTcmL&FbVS7&/J_D(6_dC+BI1vXQE%N%.1R!Z;p/I)1a5*QmF0a9#z+MFB}jp|2ig)5RiJ1)^Zx+`tQQh.ZjjSp"%!G8hL*EQa&uwa]MxH@B;xD0?qM%!Y]>Q@4LorcEvL&H|$y,+/(_,svmG832Pu;b$gta.]3:+HD&=Q_GweR>eEApXHYNTkY/SvtU3n|mFY.nPQQ3%]QNQ6A{By6ba;vFw33NQeST;bX3AmM,e<Oahi$%B|S_*s[[>g!V/E"Tbxwc;Zs.Zuo!"+i(F=N0xp28r`F[Ngub4KMzsw&weV9=?]l?B&x%<p<[xt),djC|=#;kG;c5l^em92VmE9y`31<[^mr`h&oHdR$F;dCQkPh&U(i{OKHsI+j(S.Z$_fK3HEqgWUb/CY?xR>NP*CWuj(cQG"_*S=>g.%s?Pn50LIK>l,W%7TiWE}[v/2fuS]|^z=3[JW>24|kVqhnXM{5$`l3qv[i`AP;bRKbL.e`c*Q(LH}:W<Ql8JK}JeWLN!iAPl*z[vQi!uDKN7QL$o<J@J{~aRn_}|*joZg%=t~*/uL64amaPRV8k)WL)G=vjNk_UvK,dt|NU>>k;XTGgy!%b]4h&iZhy{FlI@1Kme+Cd!G8<=qS:)uj?))POX@K18t9tZ%:M4+$/<?shp<mIL!6j.{AP`?K3vn_w=$.X"vY<<;mO2Ybe4ODPpf:1S$]|wP||?H)P;1H~"3nAO]=Vm&(orq.y]Od6#4gNg*S(Q)pOJ?&dUV4&Y+s^HAc>;%~DtE#3$~O/8{Rb^$I#TM8<I(k[02727<3/g"QS(ed)4Y:#^d71=4p0Zn}@~J=Zub29p`ws#qyee,MshkNsn&v0Bg3ct;x;hKzvbk"%Lk2C5)>dd$;WXPYP+*daO9iLLJjmnm/W{_6J`270rd{nFk8M,pKq97.U={b`<xa;qhOl"b4*SfTN_Z4#s=G64BC/[qkDm!sF%1bZkj,o.>Y?+.tUe[K]sciQ8uTxRI}A@q&ZA1$$nk.{@4mj)_K4}u,^h9y@Y{%!?bra:B%;?]|L!5@z$+WHFG63Ei&s)*IpAwz74&MTm^f+mSH<!%K8t)f?H,n0C>Ie/R`<4dq!swWns|"IL5Ssh,k`DOD1>Z+v/6_6sSfV25x@B4Xo`{$<P38.+jJFh._<N0~J$2j&xx,39nDN@J#aw/qE|GfV&*4X3@Vz0c:td?j[ImsKrdI&j:3R:X!>db%.~qJM]{)35L6!yDtMX03b|+<o&}G3s@JbnjC,uD=]6|D+B@J%XoSg=l)P%`A)A)mkp."(4h;&9{9qAfpPm{FWR45~O>L4VBt.BSWYB@|+G`#;:2PW8[]!lx^3<$gBy2!qhx,O6?}YvwmI+6R0wha%/Y9VgO3,ssJ]{Pvbz@;+IHRW*uW)$I#Y=6^3EYXLP&NJGSAG~cIaFxUxM~p(XSB2#{BF?7zpL+4=,@Sr]rzK7$(.1~a.s{LB7"}o?KwgQNNoY%=DN1[#E3I!Ve87~ZzlwI_ne>VwmS7`#{{1<9F1!jQn|u}#iJ.(Wv>YASUy;CdL5zy6,sM%4+u6W#"j,=6j95CbGVTOK%Dzo,>GW=Nhb9$S[+6&^RfzczCb=;DiWbi$K*2oleZ{R;o<(UBeK;H~6xE#u)a8z>7l`](),pgk2~eoM~F$g,ElEx)^0s+H>;=SHu[U7hzIrOIy7gd;P45d}KELP+Sge._G"xs{g}JVeV9o?iQgelVaS2Aklg8WyJn*7Y/}"G{p36lI`4rxqcw[wlQW56JCHO^/}$/)9Uex(sd7~PXGT!pM`Fj<a9$!|226Y0Z+}7|7*1bZs5$2I&nC7!S5cXh<Pvk,(?>i@zq*&*(N^w`a+sDbqs~`zg*?p#z{I~n2ugBG3*D~Ze|O;]tv_m81(mu5nM=3DdMS]=&bF+b`=62/=4tK_Ly$kw1),Ntbo6a:sO?9ia/}"h%4&HyONp]0Jr:awD,;sD](u6/F}5a2W1T`)mhX4/(De7;l6<}|eV~8trqs&Yh9!8<;e&?Z.mE:s.wKqJi.yB)`=!J*;Gf;}mQMGR[#D8EPcb4T3/7o2.dU.Nu>1jNb[5%Jx1J,~q*NSzvn{2VPnEqTpMd.`4_C|=r2rl=(?NRSi1bR<o^FK@P+dy5KrsoTk@~hly/6I8F90Sk;"wIBDd4m:Qr{i9zB<_BbU*mpp<`Dq=H{5EUbseZxs^51k1:k!7"d{HX%Gn_&oz+2}8FM$0z`V#BbQ,_1nhE9`h.pHFDI5*XY+Ynz,n=Bk/ZxYP=Q<^[$~)JOOMYXB^^Y#*vHEN`=;#m`,#g$Ne;I4Woa$Y<0r3Ge&bl9:Nf20t_s5N]hfvN8H>0s{V:rD~u~;F{iVFazFqre>4+$D$|/ce;R]d`j[rI{j8q;#v`%C[U4a_ZffV}1/so[Alt^N*p*k53RH@XK._;SQ:}(ZI~4<Tz]lgDX&B!*9o}u&~_DyfSr8zDCKNGypXFW*DwLooWbn?YEDs,w.z$ZK}ZmbyRV2oB`7(/Lg<o2Jx:JR8ZxMSxHa[CJ~kFdaNWQEELvK?6(nOpFM"3N!!0J@wdlmQt&H(;odO0@.eGdB=R>yir44Oz#1;SSj,CD)zCicZ!Pf>$G7OwNVdg/tnvJ(Z}#_WkK,@mMe)kG_(O)]xrXrp9XFiMP>S,G=KMmJb=i3=_G>o0(wg(Dzj3nvJ|Q?3t)QmvbF5>G`yK^CNj,BUwBF<iGpMhM%nIb$ISjNgv^P.wQvDJ`brhuVR#*$IS;XZf36uMS45]G4b73Y.$U6Pj)EK5*r6fZPHa70&693x6ibop,>$H+dRwzRykGFYY9]8SygX1j^g$v735G>3Vs@if@mu<*=bN`|@v=Yb=%Nlb*>U,0]PBw<bG{gfk*MmqoRsc*>U2w/Nx5zH@R<aWm;0*+k!AjJgbxki3wg!s5hxP[[PI]&(L17U9f.I4ohIoSe&(a.1~,j`"|a2>.$"zQ*MP[,*L%k(E9Y+F8%SKZ#9J:CDa[5U#!m9;fSyE#iWdHe)K?}UgOSkYz@N8%QbT=9+WiTZ32GY2@`QUE`fy9Zg{ejde<HSvaq^e]d6/6QqaR^]My?y+<7zXUDv6n}5BpCkP4a3JWBa1<[}+z/ztf5,{cb2%pPu/%Tb(*uO~8@,B*pPQzdT*d3saT,ZwZ:>jxI{1(;K^kl2#>}8RT46V/63v`".K5I^;XP=~9?6OLuy%:L984_SHz[0U<VzTRc.5f`Wv@_):bw`QV`r`bCLYVNwQi<qbk*o!WhtwwG7RmQbVxha*>AU&T$DB0D.L_x5&~/@jS7~}KkX0[tXv@Rmk2D/pa)o>^`{R]D#l%+G@P.^~+ttPlg@WJ7|Xd|Gfl.>^l8`lrixb`|*Z=;z/}X]+giRdF@;&Hj)mCqhE;3[5q!3@`$i9Bau1;hyOZ^&q&FK0N5"{.C,Kl/r;./5dZgpoO//]umYht$sQ9hrfJRV6H>3(bp3mme1/|I:8Y~sJoc6C`8UQ3i+[AV>Sl?pquKQ|oKY^Oj);J6UxKxf[kowc6P2Bx0m~[$X.tw|Z2Z;/(Ff7&fJlFyriCr6RlT*#agN0EhyNKUJu?RVE~MHax{i;:hMsd0d(0h_a=3b0rbYP<N4bEvM)>n<RTo`b7tmmBL5r?6uL_157!a7N=I*^7T@ld[EUa.ZFa<7Sym8s"J)3J(.$5wv3rRuc!<Zj(IXQ<F3EJc*K0hY_L#21;xdowo"w2,B8_(ckw4PR,ZOY0_6=$#SS^SiZRwiorQBi!.lQgaL6N*,Bf:Y6nJ2XGgU6e_Qn!ABZAIn.o9WGcws?9saVR6R2[ZtB,6?Fqd$uDGK+="E/|:ID,X<J;=6cT1f?qy~"k4q1M1Y^3IxjtaCsE@qV"{}yWKHqV@s%jGO`|q[Bc$o<_=VcZ#waSpW.3CO)u_J/s(NvwDZiv$cP^RCT3tSuvxDmtd/Y4p:A~NV0~DBIn:2i/5f?FPxN8:9CL+w*.Azyl{{T"xTi2)P3iTc(Bj)*0$d)$$)h@mCod!(e167=>#hb|5YNaIl"Rz[7TX!&;{vnr5@snkT)0He#.oI{w2n00%T`;Ov>(2NO|xSTH&_yM),lIdK>4J1;hMfXvR8|TB|Tno8F2%4QQVEYb[%]o+H:plv"2?LI%1ZoOO1<[ZR@ihxTRs(|[C~_x~D6:N[x~j?w.N_=70(`&qlq13OkPvrkPc=.Y}1fP^UMIetahn1:cp,9ay3{ZeAn=5nnD>4gnnP:{7Vwr|wrr9O"zUSd/*9`/m*fDbQ66mvk]P6A%&HbobVSq@61^.qL_2*btX]A#x9Z,S,u_n5y#M&^VK5{kvdL,{Gc7K,{G8b!,KzjJs(7qkzQ&T`mMkriQxnF&kf4|kw6@gM5@k#=>~5n_U/XVi>[|Q5xJ;bg1qdHMK`2aeE_9y!`&{e+s$L`YS/gd?~4Js%j8]8.0z@yZm8=YTRbZ<3T`{@+dRn8;}3BN!nPptYv+k9LROsLair&fcn^/xiag"rrOmDHw],k@se&0fo#/l[##$ILAz7XMv>?#|[,ifYrYXhHCt>^zi0)*REA]RGI9AcXh4HkNUS:e2U*mD)zs,*{nE7T(ay{Iv@P*9|B/`[kw6gNP+3A9&R"5o13Rxze*"qs]C"IL|p.<5M0;/NCh]onM;2GKL54&z&aeD~/#?[{_]5px"`b2?e:TvmHUDVedZH+g(YlbdU}`neyjtSmf~u$XLio8fr0)}H>#>Lb!sOBQ6Gt!x$|?*=/*kJ5Mze)r5hLGypunE6sD%!MdPeq8^2&&$Do0B6JbE6NWja,9LR+ERiC}}H7!&N9dt^![vJs6f%|N++vlLNW#E3X3a#:/_a;blW|KozLqU6w+]^U`rJ{ZkM)Z^,;giPgeEl,]Y1.w6>(K|+cwDW)&B{=YaP.ajJ.zIU)PI;Q>;w$zeV"/?{@H;)EGvOaa`s4Z&|ZO}(@2Vpc6F=6dL0f5Anpy,g;_/z;2T2dx;2~)e>#m#nz*fx<TDuqjqb4=^H/<2{+P5v{1sIpWu3cz!(GW/u*(lV)NUxXF$$Kb(,W[,R<y{vw{d@y0<I<u0b]ESOfSuJm?#RMg:>~JIy5o0IEZEY#Z75IcxZX57:>69#^"`KmE9o$|w[,ko`{U1=i)MkKFxyAI*nMMtwQo95;bV01z`VWdHk?k,wiA"ciU!3a0M4@kC5JfX&GsV2ks=%=9>rlNiey?&5|oRbw3G@29YsI_[f9[<jOOXW;c`DiE`iiy~H9J4Yp=%ZV2?`nk`o64Go@|oWaR5^;7|/(^&;,As{Bm#{;e|VXM"5n)p1M.F|4bTlud`=Thx<!{FZI[YocU@18q~c<IBxXoJb@/jGVul;G?]eI:DZ;U&8!P]<3/,nZ^E6N6u:C78u&uTDx1bLNV~o_QdV*)JYK}}cRDo&Nbzw78b:Nl1#g9b:f?}VM?~Vmctja[1oo9=6s,Nl1#G8b:@at6s,=|.Ef*}6kdLqB#bKh#fn"^)o`av]/Y;d@Y!o`1o{1by.Dz77g.lZ0mcYy#c>vppTxuYbzdTNNKIF:]pj+E}BO!@N?I7a3q>1xh<X@{$PLv{1+B8{+PBveN[e=b9U0jw&Ee6Vc[<g&QZnAiCQ5@Wp1(uy20}x&cB4#%]/O,=_8c>aEp{e5WNDb}i)}T./;^USI(biZxOG%c(,DzziqumKd@F;cShHwi>k.aR,8|eO,bzlLe#O%]>?Tz*fc[s@?XtD6K@ftnCgu@>BfsfmSy.=(2YEzpD7T!`dK+b))niCSj;3z0&*cu_0n=^I3Y=LTx<iDRjN*Ln?^L$F?/n<Ud[zI^L`>]<SeET#srq*FJ2BziMjhpln&OHwN`<I+L@lfh_i3+KKPC&OrYtVT9MxTi<Y+#3cDdbqqg]QFj,p~9l9}aLv1wjK<|>uUUQ{bOc`=Nr0Wa4Kw~>!<L)#ScA6~E;i5KOEVuHD,U}CwJ/frDO^rg+GfN|k~5CIAZaJ[FE:"q%RAPT{@]=FN,~wk;gT|B1Mx,)M1?+aYghU!B;[d!+C6K&|61C)OAPZo:%">>35ARM=;q&8f+=z!nxamN/#AR~{e7?,29J*dlnlRRl[</TwxIIy]bwh?g$&s]z_K^8qpjba[e?;V;=QmSR_VrBxW;NL/9"(MNq=T@y`<F(%=rlN%;/@_T3Z<U!G?]m`nS$q&J`.<=a:D)&.FkihHk[U9YbiMK!Y)azJ%m/Figj,wLYiag2VBJbja;&?A}[OEv!|J1>C@(p_*F;t(ssIH`"}MIh&2SomRLEpce/CD~q.7kH!e:#QM!9:v_zVe6G%;$.$;en_4q&gh}WQ)isQNU0j?1]p(Dyq]Cr^u<:#qj|Znh?{NF1vr+r6$e6_2^N3Y)f&$sHaD"DY?>7,z"DArxmR#*$I.%X+]]OX#IH@(TTQnk..GSIa:[`*m(>pLeZO(1^{l@")lFDrCS#DeE[mBj*UF7},oPvANTs7f@7H..1}r24bY8l%r_NO@uw|3LL}x9Xb7<1+CW?HIP,6g0EdmQvewbe"+zg)V$[h6auPTy*c^vU)1yID_@?SfG[#jMymUw]Ltm/CKYVR|}jnEnx=prC*jv_F|c;1(//n9nIb6a[#Ap_QW(RgTecIwp)l=8_j}P6,><{f~mN&mOQ3|Y4V.5`0YZY,hZ%%ySVI[9g3mIB&mmfMtb:U4iEZJ6X*c!hX1j<ssT"^op3vM}w~O{u+/$/)WW"#4(px[0yfr:W(#jE~kA(RxS]hsk.+tE!v_c6W=zwq/h;rSkzSfVx@JH)&+PkzaJ2vn7mCW[UIf&"8@<01!BPqzHq/}#&%F&|FA_x,QK_&TrczT9x(%J_+F!/s($Q&"CtV_x`LKX?;s{;biF~Gs|Hq={~L[BUJXGQ_T"xTX`UMa7,ko8Es(^NG^C=ony?tP,1y0=z`Pt0=EO6|H!qk{Zu@z],1/{:4y3{{]az6k,s{P"tK{4B%D}~dM2>@L@zeI6!Vu~&Rsr;07q2TeUH3>C8t$!gT9eC[^Lq}FP<3q6lF&nHk?!(;G3)aMjM;Lz64i)9k}F;:cb16Bgb28>,fPID+wH#C<]G%m%YT#xnE0!BF@dv5n(p3[r@K#JUg(Rq35]Rx~yUsF0UjyW%}t.$"yr1~c}h=M|9J?I.E:U`{V5pZa_,&u|s8]*%Z<K}iXt.c%@8XLDqXO2whG;TO9G}BFF*FcE=;roR>EGYjlfJ`p=@W/xZ0&?Q2bPj<o5qe|giRKw~Z;Oh2Z8jL6xa0`;J,XrO9]BU_5Hw{[hIR)jex&JZkZ!.m?*Kax]5?N9NRQzq<Ck"tf,[P6nd!Ad0PJ;%;<6c,a8!%L0UH}e0N}nTDjeYErfF2E(Sz,USpBtroqTB;XD.nf9~2#ExXSNMY~EbD>1%wP/xOrCj5,BCY|%jnX#DL3>YA!$xE@"hkkG2]RO=.TlaY%senjq~$2`N$SKQ{E%gOg^q9D^:#55Bw@R~mpLINLlpG+6L7PV:xCeKF}7(SqGeq64K)G6%n3e[X$S.>cde:xU[Jvz]OM+F~@vQ^6D3eFNLg]a4b1bpCq6`p?HY0WEbRA<qxnhCvdJ,$(45^5*0@3?^])6Sqci]acsr_/%>gUM?0oD?thjc0f,0YHwy)E*+4+`N[OlyS^>pwKp!)iM*(f5w6,U?~wK>~vq$hH.o0;bm!KrjPyfqd*THeJfi0Jkg`Xbui1+HvA4/&V3:]x]Pq`8ygo9YZ+L(w/?e$6^u^2fZ<=ocI_6SbfSb2)N>P16#{/<KZdU5M8x4h(R1sOxq,_!kJDaW3wQ4pd(N~seh[e{o4@kT*_LIA5{^av);Y>4tU6)?]r=|[|q;K!@:<$*JN_64Nxd;YyG!LYea?q%95v#rgDB"w;bgJw(V0?hr:S"Y!S&WMyIJ29{fa/cb=Hk}`3R*$9&LJScMQsI,9,0$TSyR9U9]!QTu1u#rnO*}!n2C}camgJSSGCw?,lE<$Fh?2$I[8Iv;"YD.<T*Q,|e.fdQv&xVwUu1`DSQ:F@3XVp/IKUx{%6aB+9f_sKWHst@w@/(5sh}+{zFur%=4p9{gOL@1t1BcCyQdCE:"|)<K;fzW0t#^8ClT~6Y+;1&YJP7;hrI1$T0B:/Y:s(x!P|X[|q+})99a(dj,XxF9&BX^LfTuakwj*fJ6uC`z@;1f5U1/0f/Fn>e~JX^Bt?R(!`hw?Wn$*bmIpo5?M9Y;eE;O!Z2KETwe8!Z9+4Q"4R>S^uRV1l^vpkRHfev+%eiz#R:VP4qOhaItr=oZ+,43)O68@OeugD+ulI|gCB,2Vv5)%>[KlZL}[;IFgYD}P]kWH^uC9%PL89i^Ta.?x8!J:Q:A5K[NUuzWjo+Dz}PDFU:vc`dhR&Bq|nrpv(%R70GP{&>c[1fwH(N4[K"u<v}^zUjc4"LM;1F0*B^*Wb$k&c,/Rdxo+DTO^p48,Gf7%ja0upzwPhWxv|EZK>TIEb_InD~j:g?waZ6Ua+=o/P68J`=s)Wf*Jdq]D~iEn=f[]n[&`8cbp*ntrwMS<E|qfsh:HQd7$RZ!Tt`{<|8vEs*v32)>qt;7w?OfRe*W0lGhs|5_eZDD1i.&^H[o&VHp{F4=al&jhvu"U60j8c7QB(V6q?5<H]$=i6mn=B]iu#<0m8g7`asZMGR[#FWXsvSQdlb]o`,)`Vl6vqhS4{*!Q#@k,m(S=},<Lc1`aUJ@1)R(R*pU!La.t;70z`ffo(ingSl[jf_RiS_}{)LM#cUBy,lfUTfcp1e7EtKRw(&9.C`rrM=dWfUj%2.iV#l)VC|z&zlf_Xsx3U!hVrqQ{`ot.Fj=9xl5sY~@X{r%rT~5>s*ZgWyYn!UYerg|8(o+}qtVgJpM=Iq=/=g0rJy.jits3#8*hug>+if=hIy2H(,A(p$eE.[v"+?G$hNT`tj!xw*fn+VXg7^eo_!Lea2m:D)^<m}Py5n/0Hw(?2}J+Z]b;G@S;i%i,rr+UtbuoHk<XG~n+jLtFfb+jq<ZDgU#Xfbw5P<SgbijNQiS]<nYnvl)#jn"<KIiRhw~r9$.M8OZL$VfDk9.$lFs_rK;.s,eBbFJquqN]m>45Q([Uc>!&8n9^@krw/j.tkrA%(&R>2mYTRV+n%UK<k0<pn$U^YEx&[Dwd$oS_U]_^w&d,"r_@|+D3I*tQ#wwxrY4O(R$J7@iu+wm!%4iyDSv,^lOPFoTQjDq;@W]QKm}e~G,BfnB!.a0PFjXFDrtHZFPZ<.d~lb,s5iGpfGST+i),]1`H!!S54(_YBT|H&iSDLA!VEUw?+CE/PoVbr@B*[]a()l(z:%4&}9R:=4_6U!{r_h|}VT29@#gthRkt*o&@Zg!q;L;7Hcke(<9f5dOV#KMVVo;/hgNsEKUC=.AzS*{UbPMe:eCDIQ8th!,@f"Bj/[/Nkm~*N?$Sh?fh4r!^]6Z0}Spb?;wNY@(SVLL$g_;6=2F`7x>U>QZik,;6bMR$2mF,a{_SH2:;7OxKKSL_[<mIN?A>(#jn4T`PVR#*Tk/YtZ2:&<mKsVU8re|89b[qkUu7=h_B2PJYr|]G?_+zIwG01]xw9eVoWOd(BIb*8XN0)d|+w@yD6Ke8!x<$M5X`#xqtI/^]^Nf%!,ZXT^:+WX4_*iil^vf[&.SY)HULd[S0*Ss3oYB](NCz<uS?t:nrn`WUonm`tf@{=fkw}+=*a7]0":XY9o!xzc#4h6>Nd3WvYh4elSr]4ov:%mP.*+@!@Ua`jrF1.%3bB>/]{Q_q0/B|n8C7snYX@N>`Z}D=>{)^qr_M41&7sw$[4/:?h,%"y${zrK=Ik:r6q=,n*jr#eVnuPQ;o=KNfno.p?}(m$Wf$:pkU[1z^`a@=Aih7xzB>P@,TdZ..+<d#tJOS:1r=B_`)BzC|/NQi<q0mY%Y6C7I!Dmr#6,*b])YD,Se)&0Aa=%&xw+@q.nu^FM<9WDL+*Le)Uel:1?,1/k_:4fugiw|pZ)@gRyZ}H4x@?OrVo`_Nl?:kNSaR/1L4%W3tP,ANwb>h|}+&2Z8W8@LD^Zbo*z|k[z6Fht|MOUP@t{Xd6f6fMJ[]P37o_ii3}.d>48yxyR"Dy{eOqpMai3&)fr@ou$7AWrB2K3c1A2Z@lB9[)ZA{>f$2eI@3^Y"@Fy)*aT3h7zB_:?T<*.&VQ*6c]78JF8?!y<J$m7^j6H@zj7g5uZCABtFcAAGH=TDzjX5Y8F%;87!DaSDHGdMS:@HuZRG6lxmRdLBGAAAAAAAA.QE!|hnmNDHItja)t24h|=>Df5IJBBygJ_Q7S`.K+Qrl8kY>qZ;EmG)6M3kZx!Dui]FEW,*;+@!oX;cP61v|l<2csLI}u1ZG`Oi)Hzwd}dj3U(bctcfYu3AnLK/44.2z%U3ck|iXdhpch$+>vH)RmN|qh6Q$(W3QfVjuuRf%FH2uGJ2b@HW]AY]pH|3+et|aaEjyW"ZbNO@eTh{ombW!ln&LMF5)|eGSv]wVm0azBJU<m@PN:=ip%2pk]:~mJd3SY&6qio46*bRD~!p99J6i|3zC))i(Je1`8@jn]%ARHLwK1iL8%#G6GU>;fyp=c7kwrS*FDP}}wKj](i<wf?rNN@:([My_!s0dJTPR6r~c$?W#BcH6C)o)+=#)?/F8X*|YWew|haa)TIJ7qw?{yJxT}`%>6BB.Hs+7"itcU_fPwMNHk`~|{usp77V;HW~MSsIOS1ZG/."B,Bs6:6W`=<oFf$)_)n*weZX&nuwQ7X,^Q`%P33l7uq75ia<~)_~p`P^NhB7zf.vRTw#H#w"b|LL^N<7WOaY,?]Rf{2;Gb*wx>v|ga=Kn=_?>lU%ebW"fOSU,r0$wOf)jJS]>805F_%Cg_Et<VIiUw<:=Nv~;rgn||U!B%s_pQVW%2R[3{M!/}UA=yE%SC?TFr|^ZGPFw9S3LpnSaNCRi3DKxz3feoOE69%[@ee[ZvjS@RaX6medN(|IRxKny,HGi^&L7:KU4}c"$sQdp+jNf*Komnjpkn[~LNReh4^zzx8V#m2^}suM9II9jpHOU52q.Ev!+ET3],n;>geks5UK0>EG=fynkro9Z>B|mM^~v%Hr6~/*]!<dI1o5TW`zleuvvT_YB;CJ!?$"n*)av6`QUWoUSY*lTC?k_PeMyfhJe/_gR5,v8LQHWs_*<$^hP}c%:EyV^&.Q&wSOuA_&Pmlb_vAwwQe`>EG<7vB>_ftBh&7|cDZ(.M<Ws_sbLlkGV@EAJ^)/|e~xxUg#;;|IM0dKggj;MS`$e6S6~c}wWg~QA9.TN*8s|:0%;0*tq?:I[[C?<?RaWI7Fvxv4i[bqM?|JBI1gMp;0Fx@>C3zA"f3=Au~7WcHM:b)}xKf1r,CiL}6KL0DX{/(GM%PEYX}m3h/:9$k#r97iA/U2w*aK6bVM;#"=Nu}5JoO],kW?{*k6>Nt)8<ANVG+4/9Kc~:Zwn=Kt5kY*G@l4Z*t=}!pa!beOk3|HLruR&5%~Y^CYX~VCo/Mq|A<*R*;PzGh9]mn/*F*0|cz0oxjWXkE"FKpQcHq@?Ra4R:W#veT;PU#*=k>we:O";_:9WT2I_jAp/iMYq$*vY+3}zxCv56}mWRB;g6d?/AE+_4`GRtSVyF:D;mmcU;+S52q;Di)MNb$p+OcN{*Bn&o{%hu<+)KIjM;lnsM8z)mcq/^^t%pUNu2F5c&opm{9oL{xTM:tY$:~}tiK/.^sR}^/B%4:UY?XZ7%Iwann:yna4Z4cA81MpKR%;Hda{/W4Y(!%vDgu1%NHmjhjmURmJ7K<N(qI&mG)cv+]FJ}Ee+/B#}pBX@v%{;Y^c8EXF`wxw~^0)`&In/f[$cSi]4g|uu>>riUUD}rM:R>c7#5Y"D;nU|VQAs&z|J>./r5PM#YtG7y4ciseE`kSd.b%MNqL7!KWt;~Im`EH.1L<B<:xGL}SBWVECA|S|e3bL%5$vRQg[UoC(nykOW1=yS@MJ4,,,RL*3t)?9JT1s/>$4RqFw8]2yslb{[}kb!z!n%[De/iEDT]9^i>LMp$0Xl<=j>il]*/+f~z`XB|v`+nn<aTpH8`z1GYJ#&u/DY:pVanwN[:GkiDB[yATYMw)"t<d2>FT[NJSy]R|3:~=tU)lc]G6M[7bF[U>f#nvX,b~Jqy+[t&2&W:X]dV*32F#1oica:Hot.T6&Cw<~|5{I]G^>H*Y[T=:UGLk0hU&}cVuYUpX5J6ImrnSOUXtnE]JS`Z$S.ji3n@8ufYv7o;$4z|Q._|k*0_s}/ig.;kLZU]CA5;7i!,]26Q@gtB^T^4HGL"gF#]q,|>}M{e7faDGO%+ZgXf7<k7&(y[&)jY)6E:x6K7c:M3XnuZm8mQg#s.{Dty}s!JOc>ESfLuHNu5Rq{(X&V)Bw&qzuNeh]u,Iw/0Ui*cS7l;npFl!mxxVW+3+21yzR^a*!}ioracl3XL&GMht]gFQNRv92Q%tZOIbw54@#>hpHq+S<7j!UxhK<RLOp&@u[L5;|~JX_V35KYT}V]l%o[#Ss}RylUb{;KR(URXtYxn5mU9#sC~QVt$w+?xob[P0%/*eP~bsr{B,FEG.$XXCc%5kC%>t4qMkpy(#6^52eB7%TLM4R$U!)*@P9A;MSE`#|Lef7cjNV5R1#%/)Bx"J3<xNcbo3)tyER@VwIK}9Hv&"?+6i"328`@59(l9Y^0o!/8+%tQrX9DO%e3A/z_QU2:vPGr_"!lTV<!UKRFXZ"C[PKxK7+H*$qWh+pQ@d`CwY.kL5BPv{*4TD#c*A4Du_VQrf!YLGPV"~q)JWqQoM)1nk.%_YtcSMEu=1?VFe$eb4C9Qze0bw(;;LG~Vy+xF95umhA"ny32A{8VQw?c=]aF;(lCx*2F$q<nlUb_Ep&upPF#~4A8!P:YP"AK^f`&v~qu;ofRIqD./rR1*%=N=jw&+Gk^Li8{:TOGs:I&).+Tpc@E!+_2:4DE!%6;;G.?;M2dc/,lMZj|;Bjw_Xk$,Q=GjZM%rb7k}0:deVVdPKtLUN=/xWYJd[>vq_<5BY"5j>?k})1N(U/n^6Ufhn^gMsO3NsCW_Q_SW#Ad~4Y<QnAxNJnvh0@7D<NZiJa@&So@Z(GII0[v7Vb4|HQ0Lmo%_C&1Xa5_nZR!>HzbTt2~RYG!&F>SS`mm1f,75D/rlH3qM?m.<Uv_%XV`t;"5)Fx8[J9<.kY&{Bk4Qyov;AuSa:"4265ee*qA3Uzw&|BvJoQ8"0A&)=*#W%+<~N[t+M[MzyY..fVl;.k``vh7!kwu:%KFUYo7Ka$F|Emtq#3hkz;95rkwb?YHaopd]SJcQQPyJPRB"zH2fM~94@m/0=B(88MQnzMQVqz{.du@fS]|ZN<j,!)A22Fk+8f;ykd]N0TCd)~9hRBG`s0IJ%A,uIn@[<e+EmM(EuzWi9TC:!|V@YJpMkv8H[+zhb4ZjFV;r74r:%A`5Ape&W,o*+mr,GR18z?t|UXp=xx9jYx!j+b0zLs0;qGkCJ`P@ZxDZ8bhdbDM`J.6#";,`K*~y}x_3[Z00LK>,O]KWlw9Zf}YWRcT4vw.cg9Vpnt`~83G#<BhLY?0pU`j(?>`EsQ?7vdni[YAc>AKPpH:~Cl|V|a._u|s7rspipaS.v~u"ac?%b%]7:5EhWr*^y>`rZe=]~dwi`/csKsx9%:_7$(B3Rn(jAzNxvS&?)9XRU/R*p.Z+YZJ|+=omPy}SZfW)]c>.nhM;rL9mp8c`{KE<+fK.z8%~Z9[yJ"[@ey"SyM/c|ID|Os8!Id@Hgoy*jBIVTKlzITLrr&/?Ju#B%fvxp4c<`s)p[}W27B&0]0|/DJf?kk!.FyLj<rrNjfcM;kcO`o=GcbBdizIm9Ym#U!qDj0L+*Xe%yWGNrMs)EU~5,$ZNg=?m#!JzSa77UHjP2s!bAZoCPyr_J:U9(*Mfi5M(Rtx@1oL[ND62%vUrPf?Z(x^%r>&7d3ESPPy]tt|!1/r7loJ{Zk*VADINJ8<z4O9zN~ysMjMJ0cF(0P;lbMhO_3=aR|;0jZ:hR7o{S(^,qbt16U@&LacYXgngms.#8}=kQnG^Id|Z$.*Iax/#s@2]qhQ5gp~iEG6n%[t;WX~DmrRz3O7b1RYR,[D+Kg)$HN)*yrlbH`[MevZ?OUm_k9kArsYFg_1aHTu?{^5PYxVsK"wj7^y6_iL.=cJ$v:$|TgC+(tsOf{oB;"OO99.$5j1gfzfyXNZP5KvN5X6;5<NkB^P$`!a`>S>ae&4XOaxjYy:D3w;|@!g"B18s0.?nUsWh:J{%#|Fgq2&PS1swdi3eXHK#$S|=oXQLh4Z4If)x=[hHxvRTf^f9Q1!$H)IxH#G3$<eOFx7xpJ&D!9xd(@32BqbXX}g}$:sOt$+J"{qqG]n)JsGcZWvvO"&;A]d;gn|`(l0J+$9yL]+OrCv%_b%LxA(4wY)wp<&$x+.?Ea/d})(hj;B5WC!T7^u0v42bb7C_sU+b<mu%h<TUdK3xx3ZW;!YvG!t#>*i7TlRbS6AbdvfX]X*?mU`0^Knitvt=G*q*F;ujZO.)u0[T7?)9[[70qjL8X0<X/39"iNyR<c|YK@gGzdq<l;=V(>{TAV@9u{VbkRLHR$COI7!1y56aV&3*&%9j#yy7N4r*sD8^;0(35s8uji}}sxxmNHCv>b+8Qe[Om!:=0kEf3wNEQ!>x,gW6HlcwO$tc_&6lzwP,c8FuxoX!is|O;@cX8Ig04C^3p?u9Vec_gg9[YI=o$U,raew7Tt)041HSti51krcLV`iTzuwUl`)"d0?11Y@yJ3W*Ef_F{ixt0[h/V(`jnZNmv2Lhb@;Au3f"+=sUv!B=4kePBX^+RXf&NtVePv=>=7)6QH"S5wA^p;ael$_96[0MtaB=.;0yeSAy%llVm:qXe]D&%Yz?[R@Y#l&,nZ3L~s2B=)^M}*o[FBQ1(qfcTO~R}@ho[,tSX]"[oTOBV@,)}RI~zoL;6iy!t8)3UO):`UuPvAoDf{L`%PD+2JXehkWmt"U(KXmhGn!;?9]SXKx34L;xce@2p_`roC}u=V6M(FM[+M5cgQ@!$9EQ2!7uK!B]vUP%+:?AG]zACLsbBC!e/fn/4B6C_K!@#kpD:S_q8Xv=h<fgC>qIFrzw,F)/}G(/JbP,(Ut&0%4!9P&qV&x`jr`AyM]&SYoI~QdL|m]&Mb1gsIK{T3wLjb0i`"U32c&A:nzwX}N|U],i(:vBMhe44Q;^so+Et,m$mp<vtF6i^e]F:~5@s}ax$Br!e}CBfW|#7;]gj%h@d%s"ZmnSk|uaJavE*,ndri_2?MQ94v9U;KT^DKWXQfuOh%%}a[5FyWyyldsS~Z%dsDLT)N;iJ>TJXmNUtxH3oo,r,p=%HNC$PhoXD8|KOjpg3x`GVpZn5De7].MdCCJ`Tt2)^C`Vx7f7})}l/72WNs5hkHjt7_Q~1hf9ckL_G1J[FJ7{Kl>sVNYHS+]>R5Lk6tf?.$0Fy8L}Y`&$UMG_T~7P8og).@yx:mj6(Wfrtcr;,riu&tJgt:N#rVes>rXEl5w"b4b55%(LZmB)45M|w{~NAN17_@e.r?:(iq<bvKIp5yss)F$],zInza_}+f|"M"enLjub%TJ[=DMR80umGIL1]P63ivIcYMjU.tg)Im&?_?{)sd$?RDmQx@~r9C/n>]^Y$B4U.t|E@%BLI0$+!~/zZ:P~1"c5e8IZ=l!Jav:]pD@Pg?zJ:28]T_>l3:hAEshgnw47nRE+Rqj7%;Rkp/Ccb(ixsa}%M5tV74`6)ee&79,*h9i}}]z?&]Tww./$An%QF=*;ym/(y%d5oi.Vb?_y9~!`n!mHV)JpF9N:tuA&biGL20WOxC5IHx.w0qeB_8B1pe[TZ=f&8.Eh+SiO%!hW{:c0IBPSIz/YZ5x;sC/&mZ|)1dEGm%~Y(Fvr>0WSeKHG1Oj&7VXLeZtt<,@_S0FNwLi=s%][hQUt0DR}EjiAH~^s[Y2TX6}9sa*5IUuYCbi4y(4F|Fkz(=IVP;:0ELTC*B<d]Y#+y{"Fu|x}bmFyk?Id2.7q?7m|6cUV9BGl|7dP?Q&"bC=B..o*]!=*z;oc.yt26`2Go$Tr[+,y0mu<aWXYZeTv@F;,f2cwq9~O<gnz}uhsUHz.Qd17~+=i=F>6k:`bxqOjn!Uw(zE@br;(!<y($e#AQJier8oDOcObQ+;<e:bsB>w3P@a#>z"A2r5#[1ByNVsU,bt$qi~W7hAMdc5?r?b+f(|g2M_CPOXhxv{S6:Ym+XeISe7IZSunxAsHFxk=!YyNo8vI{jl)oAv+QEH94#ZEkY`70o+kURV(CycBa)_&0Z%9ihf^}6+Deo0OM}XrGXG&g;S@zR!>4ug"t>6g=S,U$6L`sZ@f:!_UPK{14`It3P6P*dNyw_r7~bmr7e+"E;FXZ}&%i_@abD9lgLP?*r_=r>>|3PQkwR^vMFAuM~2SOAG7g$;vtiVBhq@{E9945tYW!HvaF"%56e+%@x)gNeh2SDE_@FjV?wi6kzbh?&a2uT`r{r_=~JV/gSkV1N,j^C1me2[W4unK5!y}c?l0g2.d)HPfk~4.os4kN4cCM8D|fX0?t?+Vug#q,]2g?GMeZZC8!2pun_uiYBl1Z5el?b2*PF[sa_ca=amqv}&3US.V9N3doVd)BcayA(7HR{o=9&[^0jQ2?Sdt*/M[HspEi|FdYSVN9}UdW.WCfr>J&4z9~xM:#}Nbletzb;RA>Vlg}fm:}a)XEAp2TNeaZ;a<)2nm2J9qP5:X}LMr`L];.TEu0@y]>AA{q/~`rE2[Z{5G=1OoI|d2V^t%d?UphTX}~&N}h%SHGXT[%^yMz|kQ<yi+T/InT#I,4WY0<|!=8*A>5R`{2YT(Y5|x:TdZ[wQeqB7|5lHBw?vCZ4)pDlU6C`&!/a`,]#}>}+a$sPn_vV_zR/]Ag/n:MJN(X6m_5?!{7}P"W|4K!u6rI>S3K"uvXB*%wp|`_D?!|*iKGN/{6KI`m"Unup6~;A,r$~4LS,(}|S<3*CRhtk[RVGUJj_lWe[][oT9*9)pGU)c]3lTl_D}6AsOaf+ID>i}E}4~jYht1Ec8Dpx,a}B^)C4S}6LN3G@g?AaG`Sx%90<my*bDYw%!<""BBKagOW6jtORFv,.+w/EulZBUC6,V(3(~XxaftM=~NTsE#lgiFx5C8m+B@Gb#DJ.4pL_nD*yd=Jrma&<OOF$?4jQvP!z#Q19NlVFm_J#sDs)X7I^]&4x~dI!e)=J;"qPa$z$p*.(jzuc&:*g+d?t)olXxzfIR=3}v;ngpaF5R:k+I445o"wJIgkD^v;Ik$ITHw7,l/jnL8k`{*(TGJJFGe.S]rjt6)HcN6BY$IkqtGooXxE`YuQa>PIpcL$F8Tk}ctA<{;K=KO@U3[]5:X4lV,SVa}Yl?g)<_ew;C,0.lfe:cbO;oh`Hj1`u1itt00:XOT|ui;GeRqq3wX2aVv~^oRs!z*?7Y8ruS:[1*[?+MEVb6lSXl_q10Sk{L*mcbJ;FO>Gy*+S7Ajm,vWLEEabPAIb#q9D57m];{Nn8_V(y[}v43)xq7ev)|58IuRpBKwiDD<C_T=#9V"`XMAC"w+pXU6s"h:9>+4{iiok(ty!y:n^nSnWcJGEV!nGkGh&0PQIX5?!XOzlfmFHqEa!NlAo`nyJ`,%W|yg"B>P[tci?lV%&$(yMb8UtC%XRUWcptznW+}&}vj6FW@k;+*D!vh!6"ZE,}aQm`oHOHy9Q!sQZ8@s8eSfRly@ki(C459c:y84Y[$TZm{Nl[C]3gu}=HeW:KvcLfN)(@2<IGNRZ|qt~&Lf1h*F;%c/OVwF9qE~o{l>Mc}gEE^!hCzhB#5$sQ|<EIN6VJp":t9aY0>N~a+erH3=$kkw[0K_fROYgJT[50XtGhrlx6T<hVj*!TwG[J~LPm5LwH.XRN`Gx*Z1sH1`z9KIO?D6d1z43:j1GZwKP(giTum6r<3$k$xya_:(+iX5}Ge94[rWMI$VHxwk;d.rhR=to+$bh6+)guLPlY(zsaM3r#^t(Nm39Oh8!v$K_)nSg%?uZeEmK:~.z)0RknjlNn6iwZLTY^A+Gjwc<;rfO#&!xHb1Jt&1:3VR9i#pmqR8ELSK"GYGWWP>f{3*1=n5S;#4.w+C}"^6[#.+in1B:z{5K#oCm5P=w#QKeS6/${%F^6@|!qn#[_6AL^0i+ke3%9v7(#H_jpFn&NPd7Me~M)_`TrjCDbZf$F?@LCxS^4Ks?c7EOM5lh63u$jU&]3@*K&sUG)p?()[43NFBKP~/vxb+$vx}5ip#:a{1m{T)%jhI$f$R2_yeTTI!PV`{uc0^_HQuYm.gn[aIodid,Kil:NU[dNY?L#(56sojoB=dy)~"JMKgGgGATyMdsaUxg"`7Yedd|P4vso7:j=S)p!*M7Pk%*qYnw:cYs6C2=!gZH#2;<*DScV1xeX9iBA](n=4n@+@"i4+#E/n?zi$;`I%amrjzU$yJ@0G1qh&zComOVF>y#hkqfjbr9N3taWh2>=PHA>!h^+[Mw*rT^d?nt|taI]G>D^bPp@_dw$1]nBenM*i,_=>xQS@,h&@7nQY0*@<LoU;Yq&U6pF_5GNC<gew~eKj4S^<kuT1UmEs8P^35]wh{K$)dZ|7^7wtbJ+&jmV$%qaEf]"sZ8OkQQqkg_X01X*X/VjCZSDH<t{pS^"[}?7)<KtQINCdf*~1>8W0mXjHQ;^`0jf#p$@|y&}*fAGu^=yi4Z=}`V,=JKqHuA!#B"M[2<TR&mq#)td`*9XTsk(([zZK=jM]FtDg:619MR*L+#!*<H5=w|E,Md#Z=<}Gc,ZDIc=~i`qJ@(JC<+.<(`>u]ICx~uGL9C(tvZ8zR/^5PT;;qc~},jg|icu^|CWe/c_v?>*j,Nt5UbW<U+~$V9Z31]!=3dKM#SU_$SwKikJ1ewm~LLT6G}:kU3**@z%gC}a#oO0+s$N*$Mdz4j%+lEC|}+yYGJ5"969T0XVy4/AZbmq{B^6R_q7o]+}=p+{>X)Mxd,UWx+OImfY,mS,c{GN|TwQjj33s(CB|Bp4t*nBu8C};U8j/a5:sRL/pMD?]RAXV,*9IrU(tDb:CMU^DW.pTyhJ{a*`BgBTqS+za)=lI;8_rNHiC#kF1#(Mkzp4>|^/:cb+8Yb4cLB,{UtG?;b&u+GN|5<7i86$Bl90x=nQ?yo7,Dh$fIc0npTB.CsIV(O"?zO<BaXs5Bh16]ASQa[a3=!Zf$7%mrw>fRRy*Zp|Y^2W[=QM(_2P*vde.Y_L`/.i:$v]_zi74<vT/)O]L!`FZDI`~[CicXFDg%S3nfw]6ZQ!6ajc+qNWVYo2)WU("A`D*Xz6NR*QKCvBuil~|pNAD4`SDFs=V{7Us+C^vKFVJ"`ooB%L_Z`o#8^xGd.2%;2XUQ$8hj^>b_o"gyR6N7.J"DLDU}4luwSd@PyNrkFN[WJ$MV*Ozk56ZOuscD4sXfv>]H7w$vTR_n3n]zqKL.L{+;O*9~K%Y+LE/GWMH}hHmluyLSq=%dj:J=idw`G/k}8]1RF_?9_L{`aT0VX]2xQk#sU?6p,;~3p_u!Se#f*DK,7CtcF_5yr+<}v&<qom:Nsp~3r=9~wza?_BUlD)p!&4}R`zmx[gy&#+%_~?%Zt%~%BRV1aGtTJ`{w?1!=[)blp:qxc}j/cT}v_k>UR|v35oebDa5dJ=!Mc&$9^2%z9b_qc?;Jz^bu,g*z|jwwEY<W/x7>P8qR?v!&(bCYBnU/~9&sSo!Gb!`=@w.7B"x%^8D#f,IdZv6!1pBB8Wo4&}z(&ZonfKqC`:*7imG0<}y>lX%LbG.GH[_.qv0<MNy*6Ze=F(l"0ocS|TW.5`bBsqQXv+nJdyq]y!;07pC)+^/:^ilxL{d^T].AZ}H:f2K;bdfFu;V]52Z"QIxHO<T)]9._##BW;YK7.n{omI7wi&s~7>ulrxNWoTlk;UlR!p.}!`xyE[)Iaxc*DdIKjEg:wlh0!+G36B)TT$ksi4uHPo7H47"xNtEYGpMe2HVi/I8<{IOQOF,nJ]X8;QpOrzFCAyH2LMu>2G~?EZK{S4z{R]>i7|(6.h{?=/@/SiXf]}sWpNloiJ*qfx]JK)1TgC2i+>hS7HZW.R:jP/!|?S=S%%zJ{ELd,"O$2~g=N%t(Savj`UJra9;;Z<#<nT[L3n{I1S.VEI#p?H]Zd}9Bc6_RPX6$L}:^=Y&V^31>cdInRp<M=!!rED:.}gu=59u[]ph@<5+*7rtXPcOQucIj7TW$*zX}~j#)rke9K&|KyAwKKn1TGfRA^#[)Qd}d!R.CZ)0wD<a!sLcBOH[b*!pK^tYJMX3GO|^7IeJZ#CN2opw%@?aAZakW=DXr)F!@[D:+D?zk7L>N6`Hvo[:B#z.]*d<;hfBcNf:qz~DxIBWh@Rt&r=N~$=)Bid]s#|*u.3OO^BgVJH%qkl_QK5zJt7G>uKA<pxg0`NMve_=Wq0f1icXP{.Ncca.8u*iWtB/#o`6o_efvQc.33?CH/)OeaSV0Go~wdQDGH?j/|vs#o~a;S,7.~R<H.~GIy6G>L)VmuOTrZ3]Ip#C*;H`+O1DE$>Qe=KXyfX5Ve@3=hgn}quF+k]s9P/XyZS05e4eXj$eg+3]h:"e0q1"i}2268KaLm:UCiep*2830t;Q6z/ELpQ1U*7L_!uoea[Sctj@LO~rca$mu^yJ+MQV6wHd*6[n4F#`Ha"t)<g&pB_7vnevTAFBFwFSPh:|B1ND$Aa^v;n;uZ{PNxam{T>mVLoRI5,[6WUYFQ:zx.LiX8T;4eBEvv9n)"DBhksnxOHs6}4/AGE4~4p`KaIn+MX]=czy0|B{/Qa$5Sv/Z2=!ObE;2cn"Ye>61v0CDS2C4lPp~h|rjn8KnMozB$@<Ak67vv%]p<{k?IS"U($;R}d;eI}f=BG_RFHU^l`kz9pU9Xg03:QeF@tgiX(QMK;Vq`UW2(Xv~nWFi|_`j5Am<FI_2PO/[.:5o@+Pw]oqbs_{z^qL75>`z)%%cT``<^6[<[Z8>n0C"KHd/HFtiH<T8_9,K4);6??*QR]eUu;zGdRw(4M0gOdcT|x*G8d,,5SBJeV);IQ)ZKa0eYkD1^A+IQ|^V[A@#.&t&AAoNd_d{M$~gZB$]@=smm%^t84QuFPu9tOUejH%$kv>k*LGQu(jGphDBvsG(O@CXDnaN{$/~TT}9+y/(uu]e.]Y4o8:uMh!6by16;X}t&_2#XY)8G9bC15~7q[ya~vJUE}G]91%aws&mRT:CfBK"`>E8c;elAU!=E5r&MOrP{e)62WOw9W`V[ZHWxZY[$A]?J4{{Ta6V[nKf"]DEEn~hisa)_BDpv/jk$z+&~|2C1]>hmVVz3"/|t<`@wCK*Zfau`fI_n*7rhj_uLB2LI0<,E*V;nAhA}*jOn#{Xj*TQXm>nXG,H<ey1VhL;{Gv^QbyF6xGE{ZP^k~7UU_ce@}EO=xxY>^?w!<HG=3M;t])4o&ivtT0MH/DBJlS*ua6xILqN4{SZat5<UTtXh~j<_(jZB[;ecXir5A055X)quGlxG&wpbow!5E0NI@k%l1l`YPe+sLBYV>8LYJd/2s)NB^5W%Ffu<u0U/d805q76jo:Sn3RA|}.|S;j?+gN1zdaD3Xd!KL!cVQ4qssXs0C)!^smi807BBPJ[sk(w%+cKvlV+yTBVx/~1ExuLA7s6UqD0BHPM*m:H{9:47`ik)B>#L/UNgV2+#%$!`cx5PMHGr.>{S3~`aaQ`yBX:)fy+VRnP!Bl[#paa:<=/0[iG3E%2f47IoEJKA&<phkMiMBNzDXbMZ6,K*GeP@HwYT;>0qp;Ln{fq5?yRz|RYn)f12xM#vY[d)[Bszsg.A"Hm{yPaibB!;T>P^}4~w0RcyBEF!]7F}U%A},*1_HHgGu6.d[X^f;za3xvr|"4iQ`YwzP?lVxsaN7~HPF9=hkrZTS$+d3,YPPdElQH<%GuK;`|eX2lWi#I`pGX]`ndNu=<3fd^R[59+Qo55LL/Pi0tfcPd"9]O:hH]vV<fA44.T+9L:SuTR^TtBP#d1f7gk+/Pm$`tDo~A=`O<th=:d_TO(*_:*7QPbTa5X&#?VrQPpY^{Ajz1J!yU]IZ0rLU2E<?nt.Zi2WmIwIeMnQw.|5;v}nqcQP*Rl]ly*[~@NF,3d2U6$LJUUE&,j#{_zXyKA9*6<b@!pyVHPmVQWfyiDO%5,~`1&RiS&<23:J$],_?wpd`o_Ql7@V5<#N7=jB9r]YH{*fL7fG+Yh_!t;w:,TXt]>cCT)[f0Tbv!d$5$!ClsbDLV{Y5;eocdJ9,wg/FXx{(J.wMX#M.=S1lW3miL!SbVhrGtUY:<qry}m~o4`gov["![h_x/L%asq5?_KV%Epa^U,qbD}ZwKP14|d6eb0G/^&AjDa_htCfnd8n4KSG{_O;R/}5m.O#G2@GxL`o%%MWdibJCa&HnxM/nU^la4yC77Zi}Xp=9J+oYT"rn>VjMlh((.fPu:P}X_"MKRjiS:Z<2IDQF/:T|FZq(8*grqoSlFFj,._w6ixLgV<)gXLPRzzwVnrPn5:_r{q,2[+h<~n83qQ?Bz25b&?vdoPr`iUDkGBnDFkBj9S[OP#:H6(G)k;L7zZ@8y|{tpOV({l$)77FnH%Xz$SlQ9B$2g30h"Wp!u@pJs3P]ScbL(I%1)>G3,~B$t*XK!U;V?2gQ)I5&lprQ*.lTuDB]q{P]Yy)qv7/!msaox~0{$nOI&x~>QYUzH,$$E[D|pLmZzq](yvs`)"vv<Ch1rHT.S317vr8Hh07r%*)Pj2Od"?I%T>Spv/tOkI0sKjEv=z4+[DF`e/A:d%1qoZi8#D@MJSPut[g:NjuQ7qt"Dz2,O@{RrsEWUB@JebbOL+,G#K>wDETmUcF76*TJMm}KqAZGI5&jruo9h29_]}r|Bv7kCM^v2IwjMh*%l!nOSLzwB~hNO{B6Dra<c{tHc}(L,yt?N1;yb3^:R$,*oT~YrsW9nwL~]Siuo!KauJ*JdWgLQ6W&LrE$xWW1sw$RjHEu;al?_673OAd|*RV#$O#al?j`]wA,[O;`*P4.6%E*tuQFy5I}{V:!gVl<D^COq@ZM."pM{TzuIqy{e4o",%!+C_/3;q"t$?e;2?zL7,syMts.fFDoZop^H+;sVy*7ru#!m{~&Yy+O72|V)+LElo?n/;=BanvX2y9jmXi3G|hXf.`>}sO.;a=?/_EdI96u`"VO6e1EFHoC.Mkd/NT*E#f`8TVAb!O"q/~2I1b.&1p[QJ4[I/3(OUkH7<Gf]HzVc*I:3`S=VL~!?C|CTNXX.@I{AkoQ7n^s!xR0`%p*3r8!8r01V`^hwJA_*!e&0J||t>*`wfLxFW6oGPczwL*W1xBM=XoJ%a%nk^)s(aXk/?D$oS~5sI0zJ(nkt]mSi9)nT_h%(#4:0}J&dvP>D6p^/0<%,2g(C.}?H<hsaiw6yv#rE94wo+S:3<mc1UEq^7XzeG8~zcU!j88j62Z]MHp~hgu*oNBig`|SR@_iBD74T|h]ezZ%BbctDrlb"rVC[mvZ89O0w%F&Dw?&h|uL99Z|ro]6SNH=HlQ`9_{u$yc4hFj@>c(1Z{p2ggzbM#A}C?`AdGw,i;vFUZ`q+2R9/pQq;[8WrA5<mWVhbPmpJgg;u.Ip.hZJGA^%IIbP$85CJGKvpXQ!L25dM_ZSLnvG)Z_ZL;Zo&W%ErN~Vu>;.^QCNj&}P3Erf{WQ%_C?:#JRx8>EG736G4SVU",|d<$Xw_Mm2JI5Z+:h^H(!ZzM|o%VwR*d"4Xx`rDFh9)i%C+u.Dx)iM>l8Z~#BdS%1%QN]f+Pwp3G(+h~3DC{F5(r[HYk$XkInK?fRS|L0mIE^HBb9OR*Nta>"i[]1kSLq9_)1~OeAYU8o57cicwf~o*|.C3yGr@G,gl7,A7%@SDB1O`&_F?hDk9uyc7rVHd#FlMEUP*Z?$ApJ0M~#{2gw"N$FWj?FR{/_R9GB9(|MT<r7=uE`2n5qv9V)XD8yHV_p=QW|"Zqpd>W!s@%,L^&!fwFlKbjsZ1y@sX_szk{yB6[JotW:dyxm~oJhkg#,X:*g]J5x]ffCm<,u%8XIiYKzq]}RuOB)[TmXGoP&pA{M_qcIw:#(+":P]ez>6QlJqVCAyr6bIZVgt=|q%7nuiFMt.,x$85E38cB%`;oJp)kB[#2WIZILPf82,0[E/kY#m}D@7MzCoMGSCkaE.V$uU0IRo431B6&yK~gO0?#>+!mR:zm[UIH*MgHGM]g,DrIn2WM~$849,x:a;O#Jem_N=?@>1p$[$@NT$Q_g%ld}Ysm)#t}Ei9O~6(RrM@45q)]#kI.r2l^*obf?&YXpp2|z*5XktUSt+&.Ef};;U*[AWrN^%$Rr.LN|<C9%?X`Et9]s/Z)U<Ay&lJ:#tgvaT#fJB/.^,/$QA#tlFUcg(9hydEl*sG/rns)cY99fAYTO@Mm>w`[OZEn(*PEENzF%uy}>?&f:Fcz@gV5{1CHJ?%))nar]:+5hs:eNtK#<LXxpU_HVN<V*B]svc~#2{~YH/C`,i#xiidc8><.5t$>c^de+:09RyKZgNfqM@99?kJ+`X*Krfe=iWFO>H:$CiQ.BdC,s>4qXNML/g@:Q7+=aSH:$#K;w?rUHfYCj1r3y`4^S8UT}R@jNQ`RLrVSR/z*^ysdJzWhJT9Qy~u4r$0Vv=S^6yI%uu_~W90T!TC)/?I.."m*k&g`fcXNUg)!q7Rc<*.<Q?v}tKB;[HLgfx*bvZP%&skzO.[p)TnoSTY"(`hxIC9v8|w9q((AuvX;n|ofbv38dX%(?6afSMe]B*wK<Mxo|/bsDh=}gGHmR.6edFu;CP)O,]3$zR%>0w)xB6/I&wP"fI:`%3<j@v$M4B3:e?6]dC8&;^ghvbsDdhiS]{qQ+Iz6eUBIaYL:$Ns:{7SCsyxTdueEz#.U&66I6~C%0P[9j@l:O<pAN+/&X`*/7&!!Q6#f>A=PoDS$3ImDT$gkp1Z&O=qNQ0Tqkr]"wp3}O=c|)KWiAfu@(lw>5Y:bo)?OFf.^8jg.XOp?k;:eu7}a)bWk$IjmRZK@.lkW%tx]P1Ch#9Bgw}a$L92%bg9C|&#}q%!9u7u2#gT0;8qjEIA~}ADRM"$y+#YdG}Zo+x)8`rC>,BU*D^2B2^/;sX=vL.H}Fo(rhVyU,K*Gl&|VWSN]D>+6d^ndp$89xW],h$Ou]$P2g^[5O~H=xV2+"zq[uzz_z;cBRfi#Rx5mvh~6+lPTRr~~AG%^U.ERe&A_c}CED6:sbnp~@#t5N^g"Q+kTNN+9~!^/$Q$QTiX1|7cy5$a>uo|*ZS=cE(pz4O;,}7~jE=r@Wn`M*hC9@qB`Jq.Dx(wnG7g!_erGX]FtSMB6g"3<gY+>xp.O/gF+Vcz`#mS_JyBoZVYXg/S<p6]@G"R_,ICC7$jvBg2kiS=Bs%[/`WYZG#wgB}M);[b:fe%^5LnE4(Iv~&$9P}1/s9cXc)u7V,I<30?Ab?zTx$oY@JZVf6|FXDuD!xdG!zchR|dGCUNlM(vI`YdtD?<SrSM8N{+${A[*uQE2Ih<Yg.<<,=y"K]J7z]Gw8B}TmnW.|VHT][nS/z`iuKYz}kC_?S$ex1q_Qmh[E.nHH(:~AhY/Pp?$=dbovv(,<E3(]ze*%>Smd44UI=IWu;>abIybJ+j;Vid}dc0;?<ZIZtqH7ON%O9,u!}Fr}ssI+N!IU~H%t(gN3Kz:Zi{6KGeW?1%#_o^5fE]l+EdTus"[)!p,DDpY.,Br3b)8Vc?+c=Pjv=VZ)5GAZ1F1SdZe#Aig]Jf8(nWXpu,ZT)K7hBz`syY!GjnFK&0|DX.gcC1BeJ]mJfedz"/t|3;MC6=@m)rk}.uBuNtG/FOKq~dg)V.ZKuF2BI^Ugy*1,i}qX;F|jm*d4;U&uH_k]}9Vg?;RZ:p~EMY6uvbxl2FMi<h"x,xnQHP+P^MRN#O7_TUQU2NcVIXRO>!4*mva0w0"*gxWobk_[1(d1`H!}h.]N!qgU`&k@~uw(x_)2&7J:HNSEHtaBEiM86Y`<P;NBnI^sy>PVwU(4!o6/JdJzS2GK6Q9d*fG*,e>`H}kSHSSOx<B6mIcQPh7/TB}]2F~h,XE,C4~$Wzcch6dv47{WcS"O4V]6Bt}~/gxLr3FkQ^fTYysm{:E$1cgr85,z#cE`+[Ct#gJ,^CB,$.OSr*gn@?r1#pv7zTyyWos3kwRt&5*j0}uS/$+`[$cW%WP~91A"$<Oeo9}HsR70htT|Xmv/pV2c6/"<.y6(>oW6>$x0RaJmrs_K]sUXivF*s?E(E`Id:9VBSy}n{WR~hVSvA9~fg;s0GOFy8>FD9@FgXLNQ.`qsw61~Q^.FrP%9WW,3:/cs%j=b:l,bA/a7ezLs3(UpK9c|{/+HL8QAPG:;]wj,b(Hn#fY2eOvSSo9Le*!3{V(ze&`9uL]Se)}43^zbvDk?o{0k^%[8C[bg{[O>k1J$"tYo!5}%}H)(swutX2o(Cd?dQvA#=j,[iMCv,9q73DNBH;4Q;F4GM(RXcJcHCH@Rh$rZ{VvGNXX)OBZy/1tp}T.)HfG83z[|0X<xXej$u|xm<CKiuzzuyI!Kqu6944ewv(M$9(FnOp)_yoqN<nhZAfe8b9@|Xq,//q*H)naKaJzF|Qm`{wjK_l:^Z,#gp}Dn!px](6jq"LXuNM/$Vd]!aeuJ5uNX|x*qnRDIO[|+V^]Md{utC{M,sR|(^}+tKAI}@Q8/V^uUHI>_TO5fUI.rCu#Z1w.+R5uSZ!ugoxFd[a1_J+J?}uZZA72F1r.~H1j5,b}zNCe2&HVN"J#d:(@!X|d40gR]b]{u7$X]MY)N(d6J&y.*98g$t2UiXk"{G!yJVSHF{Xd9?8}iR0TG~^x}o}P)^+f[_Q6(qY@&q;I.pe=??8Y^^kn=N/@Ogu+DxI5_UkXt+/c&;2UO?.T[o5HNmz~T#R,QdI^aT@DKk_%QscA`+tUh]pXUu+!U>T1FW<fCdI=1>"0jkUL3%z)%b_N*c(<YlS.o*EL6ex6j^<c4wwn>7!j*QnD<IDq0kai+fgS+<_u}},KlDGA32h2oxZ5g4:_y5{y,y#iu?qZ=*>7GyR>GC`++N$w+5?xf+k_i/%:&yTg8%?Y%#:1e3)>[/+5wZpylGle1)6V2LdFk#5;(Bk^g~53`9pT7&oq$X)$C>,<(:(!s@kg^qfm0IPdr]#E0_HD[Ywcmc`{D_DKvVn(FUVoYmJi8b#09iLV[2Rd|8r(^}X`S{bK>r1["9Z#ai;5)!VaDu%[.3EQ.J<C^hFS97t^]pR{B<ZX0cBT_E1Ew&<o@GEcmeHec9lE2`$P%,zGCC/*26Zd2,9fn#s!@U%Fe%#IcUB&ATtwy&<7_O_qVg7vI/1t5:x^a7gQi0`fx84u&HBYnf/J5K,WtyA!_dS~TYg)gM(ZO$Hy/AwrS53cs(l9)`uIo<y/eA4W7leS![Bha>6[Qfz]7mB!oYB0}kt2bdP|e*~=0P>Xh<D]S]v6_=3@qyni?kg;c.`<7yX)S^b>;R|yMyBa6u|<&5Y>;C$5c(~au.FrN[(W(}qT>,%R@^<zG@?wYa4%HEg]tFXdYZ:xzQE?RkKWP6Rn7j3i;UXa)8~S&z7f_`++}NcmKl;Fd$A:z];gkm?YhSMAq~Q?yOj2YPljSZh]3HzvXA%OU^@BJF1DLLCfIM_.ib.PsSk6a)B2V${cR/`Q1Py*Kmu86_=_txcIz<BtuM1rDl$,r0IOD!K<gkap3"V|CS|r?jqbd~IFG`e830kAe<*5k@%bj%3}tN2Mm2SH7"V},_tVllW?Q)Sf1o(m`fSZIwT9!,QV1*Hc*zx//9{,%s"dCn8./c)?_ZQ]fyPL@@OT/4YYD~hzS6hKr68E|S?p]=V6FTHt]P2I/NrXE;kR5DU,{)WOd5j+Ax1COuRBd[+L[.+@$s<|}^ERoE0Bwy3pCI7M<V1t0|xy2AsLe.ul4w2M^yr;&y,<3BhQo%_7f7gy9y(k77!Rd=4CcRxjJ~J<^l*:+w_&kJ&?hxY%;,Xil,O"/>qt%U*}O[3P^V<nWr:2,bB"}34&F<GIo#dvk[4;pFJqH=CUQ9YYDb*vGk#XDr0jAGeuBshG8E1_hNX,Y,+vnWM@kbgE4y~"ZL!)i1pd^(]gX:;uw_2m7Tg)Tj+p{"o(T>Fcyi)W_F/:mjVSGUpv1<*#Tyn<2E2m9}dpvq|PpXn"7"AWJ|$|cn8@{<?wLT]5p3R]u/q#D$u3~=6=PG.GLNqIa1NlH4HV?k(c=m7z>D/]6>z=hQFd8}/4vD*(CSb}B29tC`kuNprEKim*kU00W@&$"?UrA$3%qhM&[2+TSG"uO6f16"XN:l~EX"uPN[F]Qe$|Bx5Ey0~B|j6>N#c{lLCX>5w9BE79oe{k>.Yy6Sc^xAtVJBnV}RRa6@*2D?`us>SirUScoq!T3(RV83u.+k%EWs0I]SBM]X6#_{i(X59A>pa>HB^,+Q=ocKBdTvjJVI9&1(zN~L&%hokPgqJw?onHkF3tB,Lld^_rBGB~a"LAB&T]{wE/gR6$%>tt~TYtaOK6=%G`~cPUU6{r8W};;:(!$|/6I[O;rttRtUA{@}$RU)Y,Dzt>8*=p?6CHiD5F:]+~9T=;;r4*>lIJ:<q1gEC8ELS4YTYJvql23.<Wl22nu[.KK2q<=Q[V*1o?eLz!Evm<l{H?zUMcx?II&:Pmvy1@,W,:XbOG>0x.EizhiMVR11MI{jHbFgVN6>^:8Rbb_kE_9#)M@xD|He8bMX<}8F|nL&5RAwga`O:&ZYUXLFrt!U?QfhU{r!7%j{2"1i`XVikRwpiV;aBkH1N[MJ"STQ?Te%[9MiE!drcVV_3KDu9wn2R)S>4dU.!f)0sf0Z|OYuTYoc3#_o#uyO@#Ww#ho3N{J/z~.~sHp@<sf^f4wS6EJ|Q1(obIfHbn,G5~t"G`1^j07m$nv~Z<V$F<s3S!f,>[byZUnpg4{"&^sX,USa|":8tKawmvm{pwTPq*cfgOjIL!AdTkJD3r@3BVeJ9zUQ@[hLIe~t)MGjOa;Ks/@)s#,OWOpj=JUnw;A6q0i1f_dz&k&muXLq%$E_6.#~<heGx!2RI27v}sv:=ias5seC~~+TY4f/UlU]Crt7u}3Zak!QlVu[]9.F|v?)6d^$<VPNBO*Ju[|jb[Z^2Je9D!0obc!s@]##+EP>X7CZC(Z({l6o|=I2?33l}x(7/Jtr{Cdy2ffBDK4=(l0tKj:gX5%_&.7;J9*3lSg/xrA/b;0?VHG!M65h5jjb5oBr0F63>mWW#pl|LJ@9bW,Mi@NpX~@_V$e0Rm}@IgFAK@D)1*z8Q6>==T/Ngdk2z,d7P!Tsz2uWNi17Wl.dP`P}3[Jmyhprqe,"Fds3LT+zC4aYD%D4%/^9B:VW[9#%<J=tvD:*XFr>Iz,8Kzn0.IB~b^fpR2Qtj509"PRD%g/EZ?F#EC;1G4T[vMKB0MtG#8i%[^I,D)VaC[]N[b#"3ZU:@BNUhhm$B9xGj~hie(s!Y{tT}B*k6K_,sD`]:4Rx=&=u=$OJ0#55qdm;Jm%yS&$*(^1s*Je,bDe{_/%_Ht5pJ7?Hd_KiLTbXKzJsOa*~n|o4FcN/[t9c9uH8o3Nf!)*"t,bf:e@1h&yUiUs1lh:_2*9^!`+gPQ)DhFC`spwwY6x&v;^gK;`+<M}Wq5_8cHVs;z,PtZCOICOvx}I2.*TWmC6aJS|~Clg;]>In)G?m03&J1@_[47~>P()}i:w#4xxpn4fSU%#iGJy,_R`Oq>vSnJ<nOE~s{$i0Q1;sak_%t]AMj9=A<nB(5]%W~sVcBQLV>4>Gw(,r5<ck.*Hqp7IC)[2p`xDiiE$_rr)Cw,#uLs{"ozs31kmxVq@nE6=9iGDZLsc@fVH3CmEXQ.m"^Fjw_sjfcZQV/[`](J$J2aA1M+xQo.FKTr"tz:ElbEN:WR}tgxBNTd0u#{OPZm."BX3IWqD4[%8+G[TQFqM1D/sBit07XtlB^?L[8iG!}SQhec/L_%Z9M*fyRj=m6R/bFE%{7hJgwv.ZT._[=~ZIX*4X}Gmi*!oWfELoC;$Pt/fnrZ6|Y&:~<a.M;d8K;mi4rOq8fTG555KOfIM*`U)5DHjN&p>pK6XWeQJcihYreqZi;bY/`(k1Y1sJ1EDeDMsPq3Ej9x#`0!!1,*xR)sV(Cyr%UodqtapG!d5``NBUh&AKsc8pK>te{Fh_9#L`N18rbPoy<sqZ|f4hz.5UY?P;~;v*i2UO#0<z*Hc,Vj:7>Mva#ff;?E&sve[IZuXuHodRbVx3V"gIR)xi24/<P9gJ[QM)P5%WuIyb&[XSl5Edcr|D.T)03MA<j|3|s"F<hxV8e`~QvJFchV?nr_CE*maEip:*4U(Pfgjy*7pbBfWZ."!%2O1WCLxuk]r!GojYnBfx{L4PR13c3h2<iy*u5Qw@{mI`];,{hF?VNG}:/n:n=_b2k.UyB?kaY1lh/J*/@UDl#Z+a!;m},T:8gP&Gb,MU?(q06F0KWUvtTM[[!AbF<Y.f05>LziL7,phA(*f"SQ0r"Gvd1.e9y9.<qso2Y2G]")5j$~3););8mjaig<X7h#lQW!,(16Dng4X(0W&BJdp?|B(EbpTguyB].P_&qR3&fS;kLqB@wN[dpDotAn1ZC>w61R+:V=nN3~^uq<2z_8BT^y/OB"%Jd/JtnWI9mw2I#3Q;oKH}=`!.TClzZTJ1|Ba`8iXFj7eJlGtul[4Cam>sNqaJbQEC:^Y1h@Hgm&z]:D^,KAA^M<oLGs+!I8DOe^`nk*C]|9^wkc+u*u1i_iBeY)mfM<^SCEqBe*HZ94/[5rZd=Pg4KP:nD(Zm,{hJH_G@N`Y@jtn*TaIY(uCi2k9iG[rf,H]9F($H@!?lhU~z{f]I59RX+PD_k0CZR1X6e|kL={<Wp{ZRx0xDe7|yO729V2q,$c;"ZEE,,XQ{kl.OKVbv1"%JcxR{btfuK@+WQ|d<3qKvlO?PsGdPY.OHY06p9<O*M?}<LKvMf=N}a}f9WW<No4R(M+s(!PY{muwLjBbV]2!UnGS%t0SbI)z"7zhG),vW|v_yx83D95:+f_6X0&kXz[S;P#IY/K6~nLfA"SsrMKZI$`~(=%S7Ck+8(3k!r#pNn[d1Nv!d!K(0#uSEjFqgZJG#3,H+}UAj_$Y<lmvJCh@D@N:}p2w$?So05{:KxPV)P2&9pdy.u4]IPbM~Ag;.kef&&X9JWwX6KUoShaJFT0Iv^i<}vTrB$b/`B+_Y*4u+BF0:BPw{gYa!DRpkf7*WOY<`?i(|y;kM]2>x1Evd8:=D%eEM^e;ff,OIH&KVFP3.l+<bk(3`:57<L`58Dv&?36^5m{`BS&fx1dsmmkan~GZw^Yo;atPgI9WvCiEQJmg_:n{r}`Jo^j4mkN=hMgLo5APjg9`@`sn!!~Lqc,mD4g+f>VV[K8{rUUvt,.i=kOOT|*CglIqjmgso"SYGz;Z(`i(G?[KSVGc6lZ5jHoe=%f,Q8Hp[Z(c2lMUU^k)<Jxr/0{xd?>~^oh<W;*}#4XW6PGPH;emH)k"+anwsYa^^BX<mbdR2[z;Z)Z,Zf?9S1#?;.D{BC9sp)IEY4BeV6wLQhpP4u!XOGCAt4Z+w2:[[f=tXAo+dX^?42mNGkS>@N8KHr`(BT5}zuiXPkRNIrib^;u;XrgX=_ql+syhBl2kZB@WZp7g!xr>8U$M`VY%=ub%^m89+$HRdsGcTiaCV%2<YX$$CQL;cXXeQ3Nub;xoV=eDnZ1%[,?DlV[:qVytIBuGT:xL{{ace1!_[P_{`(_/T$i~:R`YDt2Zk+#j3V6NW,jBf)]5*y#D+*iZ`@MXRt~k6)$1;8uVuQ2QLOuxmV>jbD?VXK+aG_`t6zN+ZHb*D/K%.yo9MfGFs$&Z_G"LO+pby46FCbC(Ka<nLl#4[/=}=&swkIYds&Z&8k+4@J+)PrQY{57fLvn1b>[aiw$FUqEw&{3iUTvbPlgcIQzoYR*#{0[u/3.(<=[Aa:7vV55*a+8>qkEm.LxvNi3@2f)b!2ENZG8piR41K(rAaz@=[loq<|?ASW,bBF|Fl}^3^_u(}y~*#}LrhX{uN|9UZ/hsB[Iggd#kvRsQ0bnrfD*@G7{k^xV/xzpvxSt6RB,tTBpC5{_c(!N6I)NSD{!1aWz6)5}^,Nq_]SJOg;;PjR]q;ztc@n`tIyYt|$!vYF?MXh}V(bmDL.Z2sxK;;MCEm<u&/HzlkoxdJM$}Zl0c)/|Juxm:S)bRJ$UJS")6eBaveRHv=~JujSs:5Ey]OF#=K2mn]P}L_*"@!coVv$kP.(J4RC&DU@h#FeNM+7gFMNgm.[vYC3G=|$g4PCq)Z3_n^b]i_#Mb|Oab2gcdIU%L,4*95*^cXcf~1=N];pSJ(Td{2=$i]_0&3C![q45^}tO?!]qsj}#m*:nPe/qZKGlxV<SPzy^29&>)hw>/R9`?%lzNTcXK.Sps|ja!!IN{igqD9ir%BG{>1E*pFOC7XH;ZGbw7I^w_[eKm*crq{o5qfVG/g^KxLGN;pz@zA)iR1Yeh")UM&Qe#9]`8[u=E{Xw^)Hl/S4BH2MNizw$s^#95?%LPJ~U]gngAQ}}rCD!B7|,?#&vKF/:zJs#C8#KAEUBp&Weka%5W+M9QlB|~ML{BW?cMjn6;xeU)^XxEZ`%)lFTd<z)i^F~;T;c)gfFx>?(g6G*D!O+,<.hc`s8(;LR!v*6mjmgh|x*J|kCO2SbQ!G6!YQCf0R0J,M)0F9]~oJ)5.tKK{k{:iF2u<}?1@H<V7QBH|F;}!|fm!KTlzy7P^xLLxmm.OJ52%}DBi5kx6L:4r}/0Zf$`k,REJ;@c2Lfq/15;mXm0Gy~UV;x3})NJT>=tl:ok*@SIjYaiqvEIYKQ:exq~Zw2|,$f*X*i=HUCH8uS|`!p4EB!ah)&YX,&L{7xk)cBT>c+Ycq]C35gQpZMoK=0GmX:#d*Ash^hn?`z~{f"e9e/PUw!p7$U2%!x.)Z1sstGXO:&53v+V;>+W@$jb[h?TKjct&aA=DSBfVUR=3VC^F}MP^kSG+%?h%)l#Qj;K5rPL!?|T)o20E^Grfz(FWhyE<ULT:AZ^B1}sYW?8iYx0!_pok$]G;H;(pBIhp$y|^O</Y7>06vQW(b,yc8QIbC*cIQ`z|4D3WPA]u`)uHXL]5i*L{o[SLX."aOnkR1c:Nf8][FWjY}~q/]N5KuZY&F]negWRha~m(vWY[%9Xt=$MK`M`g+~XX5XBVKK1DPJ|dao0~7Z:BU_L.|&:LN#c,J%kDxbU>]|xk=U`.?)f},$zI*>m109#vG|73EhEdI/;L?e3]:YsU}e@|TmKo]=C1zFh=~OfCj`J=J8{`LF$X*r!N!jZF,~^Y6.{>Si+4?^G`Icv|SMD2O6xC@;U!{b<x#i&BJXR9k(O|MD4%SE+3poSm;tHb.xq[w&9%d_<8#egYnIc,7|C>e./G)|Cw,W;|rYKt8_GEEBI/6RDprf.e(aK]gqz0(Oz.E;|z.o$rC/4>iKI=RmH^%osCYt)ZG[o6dv>k"7sh:o.iZ6m!{}@|u05iaIiKn1Ub!y[LymD$f_E2a%^|GIJ`/hDkHjt#n,_t<AWbY;}hQFA?dd#PIV5lHt,@a5{><Qk"b&IiZ.I1Oc_CliY/NuQyI_p/~,1I}ow>y=v#[8^$6g~_[h?"G*9IIpJ):kHyY2oU"Vx^P=zBLylR]CzKJP?sYo}QV)Xp1d,3+,HYgKH=;u8<8fdzHSIT5?F(5vJb|[tGNz?c/<|LU^^Ya]q@5&{NR%(]J2oNa?CJHeP{7y7/;`NCp@*%sx~It1~Zt}IwA<Q^p+4_`kpz@Xg>?K|`Jk?_00F?c?gRC2$b`hE0U6%t=Y[I{*a=d:[q@SI*iZbOSJC[)phLii40|>.yW8,<a"z#{R"A(Qq`kpa|^08lkG)Pib2jj/bCqH<8Z>gnN}P,&C~(nqOQr5~gn/{y0DBr._9{W/HGP21tO!#hVRJ1W*ie)nIBXLYMt,KhVQ2|J(`;NOIN&1D|Q3CdZELD:uZm%RP)V_{A/;|:EN{{UF?8gXjBjyega@th]Iy7Ze`gS:+<?7o}M7!cjhMbqP5qWj=w7:JS|*,gk}:%coFZ`38vCyMvTm#h,,pLkIWd.G_l)%BZXCm`L[BX=xLDRmv$k8ll.A^@+Y?oPT.++5<3g}PT>8q)u%:/M,jYh0,_jV=%}6=Q|yq16bbejo`j1V#SXkQ$QW)3ye*oLJy$#g!`kp89fbWc:AvQ_I<fK|"INj/Dq[t]d;34QJ)_x5]nX[8Hgo<KAtfzA[_!!$Bw4p&q5ft)x1n:n{RcRIy$G+jE{vGhk2nHR(%Ka_RVMIB`ga^(dEn4juUF;U0~diT7g2&7Ceo2?aa]f*8Ri#?&lZD=D5<+j[|t,i12Z8tl#4lLEy$pb4xPVsqj+esALl(/a.n4HnwaHTJi._?.og{PZfb0"{x75t.6c=>]Nhih4k).upD(=cNP{HSM>hTFE;QQm6=fg/_U/l+D+_k^,*/WQ?.55lVa$=g7%1$?k9kF.1&:0*TNLB[]%gY!5$w`+GSi*MH+{@V/}Y:]g;L<.6K4PJMIuqVD./XgZra5wzs4(KbBpl0TsE=x=;K"0IG@(S&Kd2%#XdsHKf;S{V]cvA74R150<z/i=EG"(+qk(Hp<!v{;FbCL`[5]BtwuiQMl)}<?C,n#>)XHN>&k3fKy6~=W_QnrZbA?V|fpMJR|y^JE+lGa1bx)+_{jtXBopQ*N}ZYA|1EVvI@j1Om&M:E@2tjTg`fk+c"p.myX3"H<R.;$l=,^BMHbJYpO#HM_,1nIXe;zFCJVP3KeMXU=1d%|^BY?pUr!cdquXrZ|}+3V/qMFJkt$ob<1#^JB]u&qpBPFv6aDCv7U%?4[zXuY!Sw~3]o<.&x$@H4Z"rT?ja5*lb?V|kCCVes~fk<%:gm!GX9biVVGhp..ER+@.9ztP[bl`"r98=zp5<z{Tlw#5tvlPLtX[;`h;fLYE[f"*]+@N>}LS|%WML`.}ps99AI"t1_:r81k:Kx=uH2&Nl>TVqFJeaL!qmM2Cm^ka,^#PKoh:o<{2P6YXub_onm~8#Z.</WkPx(`g0p61Hq+ZulH;PzK@AP7$AL<mmd30bbJ`Ogvaa!=Z&t`<)(8a)`}+B^t=j6VU@Cj4]2Oj+>HO;3=6fV,Xu~mV}kx4pZQ~|/y(*CdKmnw>`eWE%F4J5Z4ShE,{TG9S;KB<p9%4ijb<hb7Y=GX+U6gEM>(HCI.rK.42fanfY+jf)jAQog659$TN$r(FR10T.MK77!`[=,JcVR{;JF1%eHi#i{!6DJOGZ5G{B?ASW(Jv]sSp?Wj<B+]lVwg=17v<fK1nz`w"m>#+]r7l$1GM0BfM0A1y]kAZD9|X.8nmYw[c%PX{A*qK):eWOJ@/Y/wbGJ0Bf#^BR]Wp1WQ?gh=0)m.V"<pfBmS$2`:OI1(!v+?QT1X:KQ(!Bujk2~D(x_w!{)"qh1gZTGpIwWu@pZaHUPG&4>4W;%cWLmTgl=[$&?Gqcsxo_*27^BR1P6h7uE3(E.)arUimC9S:cX7)Z%iwZtFYxs}Q|TmfL4rL^Og,U#WzXV^mpht4IF4C?BtXg++6l!6m,RzRmcv1/42>){:HX}?{w|#OV1H^bonX$zmDSJrIAMWH~?H?hlWVR((d]^!bktSL|Tj:w}FYHZ6iKeyzBG~%uv<pz%6P^k*cwxmy}mS+&,)O=IavQ8gBA4<`>&1CecI*,35qXM~ifd4cm$S[m;A7Epmf}*/PolS0!j6D)&)l:=1hPaS}W"pj:%tG=z9Dm.RH6>4+chgT;`=e/@QZIt.H%{w|BNv8HHM@Xs*hS0^7q$AyH{M+P|q<L_l|,c@4y.7hp/S%(aTTT2rxJ?OM8khz72C0q`h+L^nhDda1y?3dV"_K[H@v=VME]4T8]s<_!XRGO}39=_M9|uWG59q:(]S<w$G)j~L2DdVL8r;JInN"t`o+B2JhYHHY&"8er!s=A7b~dz$Jxo^<=+xXt>thq_L(i=]`^C*9BqJE0!Qjq.=9n@at%,"@)EtV;52Hy&mgxRf1Avl>{>/sp#e0Dk"<5~}BL85kC`8BVRqN_uV`UBszM*UBKJK<sH@a8#BLKE;qaGf{!Ylp=y`RZ^#kvTl)x$tskPCA[ag|zl80%&MeC{x8Rirkh=io7,G.[P"kLyaipv&|T{cLmT1EI.w:l$rUZFK(ei{>_xUo2jVkid@|7zSnPD@q6ia$baQzq[S:Yx0?_3t[|.d6}~5Rla+gNz)$T>["zP*src^CMDxIxxf^aqYw&vH45+;"gHe,A^/%/.!2ju6rN??<}R0p0Kc|s(DKuai}/ssmm/zwO+v<l"]?hv<TnovC%RtQyp2,)~i7b;+${Q#Nt[2kJ`EftM!R3v.]|l(h2M@Ru?!.j;Bdz>`Z+Ub,|6gpL[DIo9OhSFbbz}acCZnN=]KX#4/z0s&DcPb!wBRs[I+dKogc3R`V~LrPd9K.[alm?x9M~^WU/9b;F9oXKV0E,;QvO<re642.fBYzvTS7Ay?lYwS[V@673KO<^U,I<7`7F/mwx%x+C#gt)+Sv:|?>P<[x:0n0_M;G*&*DgNGQd0&$^Uq)Pi{awD[Q,L<FkNUut73RB|wcb4=8#+3ltR:NErGa4F_"IE$4fw#+_rz_rQN=iTJGk]({+`RgDBuo0:R,>/U<q4l,u1&Z(?sRx*lo@qe?o+S?mk|J"/VQ)I?gm|}wrwX!P5/p4@.4WYdW]bQ6RMzpof9j;[Oc^v6kWr4<>fcDu&k33&)=+GH#k`+@0oAWy_4lX5?r)ehU{)of+Wg~p&GwIXD3b)"JRqnEDy_MKIkgca~%iU%NqSvLM~*4u7e>zuln}89dH;iBjsVE<<IR]LUmYp*t<87kS|O=Kcm^zLQU06#Q~7ky#JHXrvuerIQnGSibCXgF5{hW87v7[7J)!?2[!r^cz~$2?Z$.[R%l()ht5kyh*Ap&l_7BzHSP2dkAbJk=3lpV,{<tvR6PE0%>Ey_R+#?q>&I#@Inax/b^[_nPdcpbSL8,7D`w~Af1=ul]aI_7jyCW?DGJe,lH3k=PMaC_!wS+)yf3%:rvj]XE$3p_t&HFq~(kjT>{zZks(g|C5Pe;,JQ$Gu_5Y5`%<6J(H$Hot5<e+@zvGwQ;+>FJs9?a2?(40}C6#`Z+Q*|l@#;gecgW=5KcU6nx(!sUlxZ|g#GjtK%6+DU*uan8{>*K{%,Cma@&<iv2EZM:8V=n:IUsLEMJF[>`kMKSo:8b9JG+@~Y{d5F%_jKD~txz!TgU^u|l:iVZd<X{<6>NoG?ca9M7p>x.ZZqp*Reij@Lj^v(vPF75<Qjd`8Kg*2Wv~fubb8.)kTF4)u`yzHDE]zc3a%*:_gH?/hV#Bn})?vvr:2C!MR_k?0tS9bPLVV1IW=Z=XhKOn:v9E3@&v18sB=Fl$qreH{G!AF[S^fo&*h=+/z~A+YR6;,Aagv@~z~J@E:6Q&phOc@ERzty/qGO${LyMBCLLEGtXMgXLcn4]jbz7qEk5DQLenAz)87d44"Za7/wFDGZ|VU{L4Fr#?K[Grgb4bF=j&D$h=))[%n=h6LzzT:SutZ(}unlv@znWt_gz&2eJG0/D3o~dEuodf2)<[1j([?"]nP(]$EU2:m35A98XMP!w%nM@<7ccaOa1`a5l7BZ)Dhcu:,8yuFNMwsb#BX*&,A)1*/Y3r8=H#@T(2cqrv;mWnrOmkKT)&iH;r{h5/XGTI@v>l$j3;XMCfPBP}fz;V$OAE89CZG/]Y5_qi~#LxX~cF7#zqD{g"XtUaV8{c=PR%Ea/vV0mvR2^8TdaOO<xv0Idw#2[(@*jt]nV_^A4"SUp:pG>o&DNE`W>W$TwC#(n=Wncy.k6CQ)lJQi"[w@d:k*%zy>e$M3t71J4^J;MS.c.w`X.80&CmvjMOfN>?3b|[k"9fq,P~^UcpfIX&ar)|<nvO@*]Jr:V02FhJWI!wftegklY^VOEI,<+(I>,E$+|(DlT[ufw}Rt5z:;;o(y@dKwcZ=F;Wmp<D+LE(1U(uA]sI!R3+t"i6xAE.X%?r>2#dRdiE%VO%>dl<(9pObF:|8`)b;LmOQ|;7y.V"yKV>M/1*%XRnb"RHGO*bnO*<p]Qh:Il3ygMjeeX77aPE7&2GOmkf6lDm+vV=~$#=6=5"e)mzUDc$g?[pTR<KYN7=;5V8m8W<qpm,}m|~RnPRiLS$?Y%faVNaZFWmult3<ocqgrBejE]o[tC"xJ]4TXoQJIa[L<5lqBb*1J~#HAY4u9z4y.$"ijR>ao7fH2z,sh^$SDrdpoSW1?o3]POo{k~TuZ%@*30F6JRfL]umgH[qZK~|5@l}UBR#WUW!JMiI>)Q_%5=Xz4>%Kizd`E9Zhi%}[f)xi?~s3+4~N4U/Y7gmKe)pHBV_+;BH)4f~MU[<:&az`593xkblTe,X:dUs@P#Z`!NChNKB9B{$,`$GiG2ml!*~:(G1(STC>9q[MrOwk^|Kf;qk4/E/8UXK8~*pzXt)X+cw<U&Y=G015>[%WEd|wU*1R:6/V"iG&V7e1NPvL?|a6&6p}U2|qcsaqPeEjCE@Cn6A;!c$uWtPT"J#GMT*#UyJmV~L?;@gGv|8[=~4$nmxbv4_tI+J:1O)y.8+nOJPXnV":C>~QTfh=I!E3(G.J01ibV5Re8*K6y$O)JDm;af%~XaBq)rBGy!:1[)ZdoiW4J/NHCzx`GY}G(mP`OB!6fXP:D|f}z&8Tk%^6S}fh]jNglJt$g/cYvh`YC}BljhwEIuTuu&mF|ht&B"n&zO!~.da._(!?#pNooqPwM_x,}l&^fST{&VW*p$Uz36:w04gu9:=([FKaIGc,_c..z(d*MR.]^Q(s!:Wa0.V[Qsd^4EI9t*gu`tps*219!Rrkak,V36_Ws;Oj:!4YuB/!xw1U9L&{mV"Lp@_+V*b!D{c>G`8M"&^:htZ85o0MA!WgY^Gt;F%T[%^vw0,sA%?4^>c*ULD7CMLKio9+`ET&7sz)yt$+z9#]5f*A4?^6:#T"{%*AJ**KOm7GV{l>y{Rw/y,9{Kvi}Q+P=.m@F#$UrzeJW:1Tgg}_weWCkY4g,)3=Byo.~(x=#{5eAOZK<3=Ya/id,m"G14&|{Mx^=cp7gg""q;#hCd7i4!NA0Hexc$2P:Ry+0{}#"N93xMv;(TBhw<O:Yqmakjkg^>W_IM}r=;`I2cj{ZIbS(FuGBw0VR0]5``{8YH~lT=@ot:PNXCFU)NuSm&]j:xQ>3!T{/1Q|pn}QP9yPv:H{oX)2te9K5Y#N&csr+wJH4kd|cjaaBInqCLv:xN]%VsbR>}:OR>Jj.~87*eoQaw}cfNY{|;aCQ"K3P?"5,#?HlPgK~hW9_%{R68y9OtkpQ}8l(jPa;Uqy;U>DRft7.=;z!B|!%V(?]=|p#ylj+4Y>pcagr}vzhZ:d/5WBd]Kd)/WG$=W3:)k?vKYaqer|ik~%00;xpxmo;M~e(1oVCb$ZlHWf&C3=nR^n2j(Y_;j0dv5S_9bT|zd.RtFl{!1H7F4US2DklILEn;r[OP1[iGarSX)39,8]L%SsEH~Ir<rST/_{~Q}zuxo=P{g(@X1cX/S/MM;^{b@lD]0/;DQ%~,[K+{LTer!Kj:26apzZ[e<nSo4MR0|#Dr;]SxnfgN~[`F1:lgd=U%kTv:e}ZuZ=FX~O`T_]>"vM;/d.P^Wa/(P0`?6Ph$3z=V^Gqw.H8XM(@!;<hOq]4P&$clhUVZ+(2tpx(xp_h1A@4z"Qd6v%i!HWnFx>2XbR_UN.|;1VGW).[Tt<Z_xPGq_B(s+YM9D7&IBN+{~Bv@5KtP)w*u_zZprk_;*l6l9Qy!$$pSXrW`A$v>AJG.zxj1ihhO7(Y:|oce#4Dzf%&+tZBRC/v+WfvGQhpH<yn{j*D`&M%E0%MKk8@]%@mdFOZ1lsMYsQe.bH4M=/Y;+ameCq{PzT:Nl@i0F)Ak7r,BM,8LT4}O>/3b,I[lOwu2ibwp8fW*?jY:w(IQ+d5;|4w`!/I|/afW_0Q89K7g%WOU|DxjP2E~^OZc>eW`Q.1)l,MVgp{RS+NV|)/N%lc0TnAP$^&c~9S*$ta3%S#pZ%VP}ipFW[nIxst],=2QNUFl84>MQM^WU4v+(kqI5X(EY}}CFw>Le9?.)z&6%^PL0>oYvTUjkEIO3OHvVxvVnN{?4z4zh?NzexDwHm0iu&M^C`#$uq=#/+G2(q580X!4J^q8.<NGyWf!m5&_G|)|G|T,rk=N^X+UeSlgy=P*Vm>[[m.<ld7Z=%;l*B?J_}W^=s?%;{F^%g=bsf{+v2,Ua7{QE5dN}40w##h!15"96,`g{Q"%r>>+w}=>SQ19]JduwLkSVdgW7OelIeONn|`/ilSg_`0Hcv+LJ=6ss,Nw&X$1a4<9_^T24P*PuU?/(f}n|"BkJbdUw/sI*rb7}Cp(j8M)FQECx6<%FIr!S7dwT@y@(=ecxjus3dPcc`#7n=G6gbqrq9&U|Kk8Hf309^EF|rFU_wfP;u`i.<(W<]gddRNC!)??DnEpgS/~Puhr#P#[UE(Ieo*uJfb;lGS!OOwh)gJgTYrRFu(zA$pB_(bg1Z*D$*lhtiE$x{_jW|t@o=>|Cpl6dd)cJV99|MZT=v2)wIwuL*mSr{U^SU0i<{LJy`nKqkfeud]C+W<bc(9XK3tn/$:HwBmOcD:D{vUTejv9gC|LJC8+@We=%Q,vbvrr%`m^DCb:3)}u:[d7%FVKZYq2zgefziy}U,WE#vi(|rDfDH>UqxKHpvJqKy9GG%&q1oX<)iTBfgYb9q"2$l&/$[g>/m[JfDI?AxFcU7f0KLjc,5xL9nhR?<@itB+z&uNs<_{rJt;]&sNv_;4RK/La}{uw4DzAcX_oYN+#a0e/tQ7>mS8pOX6f&&9zdYuWg8@F<F~j7e2(JU&>O!(0t;9`WaFbi<TM=v@MFKG.A?j@w%gy^hESDgUm<R|p#M}WcG*2AaBX28V(xWs<jce4*]F2:y/q_"W>:t]`lJ2*_H{!Us6fsh%Q>K^pXtY!Q7CD{F+_?USvbwBW$@$L8yv&_4Ci!D=d~V!uCGf,i%sq02Iw/<?T~IE59OuV8dc|]fcSQI8R%y*;8FzvWCF`k=?*sh}*MV.{d!<9lj0&QMV8qePYNtBCE52uehHoz&,<,MD1w+czR?w&eol#03mz$WIV[N4!UOG0J2<8$YkMoA[`v1GG{WmLM%8c,JW*qwLWZam>m:b!Y:irf!lyhZ"gcl$$c;Z5HwdWf_oX6kHUrCUyx>0x*zh+K31be~_CjNHUo6#,5kmU!v%(h4gm=h"c>N_6&53N}2C#n]H=[_ybUv1F|*!ql4|/qY,f7TH>@L+&agAmT/pbVgzp53(JGR#{E$.2nLO}Utxp[Xog|L4)1fwj&9ceGVv^z3Xp|QDu2FpIj3OB8Z_B:?>C{adXbIe7%[6~g!L$"chxZVuj:89Su3g]/y[|YVDC(,~o7t5D}`h1c!eeyd#*6Gm+<4/m]M]$!J!%e]F<u?f/s^%_?/QMXt`@Z.72fRYyoRJTPO;")k6D=Ad@3#~;cYCiu!uA";c@P)`>trz&mnd!Pel|;7"`I_XO!!nXH_tS+Wx9+mObD3Q<qzWl&gTeSLyw36T0l,]HlcpZIvi+%2NBV7#s2OvPVTM*.o>M^/HUQrfMX4w,441@TSxRCq(85]2?V0=?tB?ppKkLwnB^Z|fJhI/4Gl!/?Xd]!eL|0xPGj%L,^VK&|y>[HsBx!<nOA?*wpXIKvw4KfeP2Xd/lFZ&FKp`K"/9og,/&aD[}(Dzu3=.h.<QgVl?:f}(LM9YJRA*$fHx<3vMs=Ii3zK4,q]gjp4d07B_yMvsmyy?f?J9RY;zLrI3|RF)f<0Fr[k#k!&daOa@/=sH9Ti9^+aBBd]fFV|.wTU5#&v47_95FF_<`Q.8%k!sZ&d"50KfTFDqpeXr{DIv{I[1eJ%56*{<c[6WM9Au1W?*,@_kG4~YRibJ?o_jV2MGeHarFaNZTa;?8FdD:.BL2;O4R<>O`2V$#lwOtI>/i{+(pG#}&Ca+1QeZVXX}N_Q6yM8O_$mbIN%T;>e)wiGe{:2P+"S!t/op=K?ixY//r`hT!HE.SkgS%mmTgJMvdPd~@sO5h%!oOSr,ol)nsgC$pXXOe5EfQuee*:lIbzv:>ur[=t@}(gr]=^f0_B[OGOS9[3VAhIJ~8+&m.5r:c1b!@aI9W/*XveGlF!TxwUI&ugT&4"oWiX&)P(pm~[C$00{7T_TB@4AXE+TdKc6@v>Zsv,ysZq_lD#Mb@x4uaX5);R?:s;9?meD<cW_:m01`q8d<q0)`Z=uH2@^1S3m@8I;uatXnozukw~N3G^f1a&#A,~tLOn{lOcfdp|v@&9f1^~J@^h.HCf^0E!K"),2lh*G!T4S5M+gvv>MO[MUB0(8AkD>4q&D.%}jdNA!}h?=x)yQHybPavr9muU4X=qaQn?Q7`AV1ub#}ae{ei`,Vhh8Y9_XSg6H[gWdU*2k{OD.j;{f0`?&01pu]T#YX|`zu^O73L0]VGPkza6H*?n8?wYe+BWx%/8Nn`m/JGphb|7bz{7h,{T>tgzy_lr_zn={rXZ(~uWM%N5ekVaj&&4{{>B[Zy^|VvF#2RF]1)z!/<clzASdX;b=K&w,j)B4863nKu2uW:cuHE[8d5|1s4&[gu{OS/"Gnjvi%&k~EoJ3&kc7c3I6S(mr[9BjRDp20y4JM)wmOJD=YG;h8@n|MVfFFkm>Kk,]7b;pEMp&}bF1X=Z3eJ:`8o$t[P@HN8=&&R7h8>(%i|)j<;:A?R@QtQst26U/&"6j8ku.<~F!_<vU$Mlsu{pI,UG*y*JNaoBImBID1Pf(:HRmLn^jnh0i.2W9ZGZI"R]z?!`fk63tt[V}q7u[|!xKsD[aKf,v,:vdlM:/w#ixJ9vlK`KMsy~Eu[Oop7ZMa#~lKX*)[=guHTJK!}AQ"vV,&jFR[35gfL7*/Brh2qK&g~V}Hcpb}TSzT?,Q[+?m"*0(~F}7+VJ~,_U4Llo/xLwK|C*ge%g3!`?JUMP=[fUJ+SDax&Pp^30kBux<{=s#HA>b^B;Cb,Q8{(l(.eIY`FlNhrg@DQS1gQH3Q]GrYAR{qEBB3,Z:gxBV3Cy#k[0A5U4lC]uAU_dNz~02M4cyv!fhp"BFv3"a+0]Si5Pjoj8M/FYj[+d96TO&EkW}]^ULem/fGeq"C?|o|TsxYua:k496D|M4&^V(tGwR4$^>Pa^p,G5hh%EDUd5F<iAsb@*,msd,WwdBC6MIpEIEyb]4~xL&9!6&C#)xh+8dq+V3h,b`uaq_n9nQ2f%}oJzEi4+6k6eup^"5xMa@{N:i)U8S";?#d#lx80Bq?7]fG$b<#]lK#;um^,pmzagg4.MaK$tzZx$o2,Jq:Uo$uyJMQ{J`dHoQ3,s+d813}7c`VBvoZz/Gsc$^gU]YDcftMTnW/D}|oysqGs}kRg{5ZR${h*73c#=4Q7XCptEWZ1"!TBRFQxpxiqlCA;EH~6et:BRRF!qH$s7>M=s+~H](!;,VYa4zf@[0!)uO{7#r*/jMI7)6swF0b%HANu$X&}Y{x4(PDSa4N<gt?]?J)F04U%B62u{`}[P#=t+z&any$`[mFG6baNlB1o+%j20aVZt=S2"r2AOB:&FipQiAj).$d)~VND^&;@tqT#vHs4lxLYOX&xott|bkxNWh5MqAdvB&IkZT.m^hOZ}hxLsi<C(6^[>DrICHL90.te2^fg}/abP_H(ri[}U9[ZkQ=lM$}/amD]975yc!j]Jdh{_5g#q,_0F=RUI=Vb;ZJRL<v;9$DC9f7}F3Yaq9=s_OVF8e@`847Hgjq*IW<gUiv8kp{&=ZI<z]dh@jieQVBI1MaBS9gH&<<]1q}d#:N)x8Bg~M{C~XC}CjzJ<JJo8K^/+ycpXQ~c@JCT1J7`@[UW3:d5!]uZytM>yoW.~/<<n*D</Zm~I_e9~sDR)|nCaMigS/!.jekW|jSt]h{F;OUqrt$/a;mCowCK@LFD25,NfO.dP$)&3^X|sk>~6^n/:{vp#beqf{(8|kirJ<n@F/3.ou/r_EOge%=+!=g)L+PcLM.)%GUdU1HcK{kY99>EBe|QfWFg_68{7Bi&N7(D/H<x+i*)GGk!/Ohe<#~LMksk}f/]K9x"tIg8Z/JY:k7b;WcYm!2vCg:829db,,c5/Erw{_px/[9oKv*|@INFsve*_qHOrHTH!CM36O*<q8S,2Q%<d~P*u=*8Cw|qyf"m"U^dOd&*V^n=1S=]pP3nb`F|l~zm7i?5tC*F=Wsq>ZTRM7G:#}2r4$V0lh2=hBT/amTdPfZa6&?FJusRw@w~BOwQ38{W|w(*s<=dLf]kuZGfl+Rs<nr%FE{W6?gA$}25]z7=kNx!l[@DJ9xB%re}^sVtOuni7k~TSS0f3Zuc10C=gHP_xgTNsR?ir+@MCRu+@Haze@0!]$bB3Z2[7zzOp.L?Amvk{*z}#5mq16W>]`P?|7^^J5|r@N=z`)XT7$W{`"j+l?a%q_C&oh5^Q!:X@{=?k$$,R#Nuu4v39=1ebfCiPN1d4a.Fi7xo(soHt|cwU1!c~GPX?mlma6v7zwcuD0kXN3$J|Edd8=Qv+=YksTcy|GkP[6R&D:r#A|W7Tw!^=58$4@b#W(;YH]*d`<52yr{pvB|t4[A{Q4m]dZN&Z(J#,jJRNuImBo+Z?BTv,=57I711wIw!LVqDilo!n,ZW3xhC(VBQZG{)~DAj6W2&ah(<$4EG+#aM/<VBybY&=]#$N(}.LK`.+hldT@%O^O6J[#|xr&]8Zrp#U%aAt;LMStJOYT%DkPS!6I#*B@3na?crR%L65iGfOnNQduD9}rZOIkbtO40ND,Y#{p4uhLeM/}GAs;b=sfrw?_GwLW!,/VG9@glJv7eU`e%]!U]#u{UW<lWjENTj?V`WnHhn^d[{jN=%>53R|^,@w:pd959%ptiaWa3tA~5(A})b&Ma;GK0pNf)h+dt1nx@WW(~zYuXlH2Le0[1eCqf8"l^d9S}+I9l|~FW&AZFOQddYi+KF4D^7O)=$@ChN9QYN:[!/kKzBtjuL];XYsZ.D.*6Nyoe7E:V0W"~+dRh9fSS_9[c%x8u$V=lvy.UU8_&sZ^zsQobii$+BB5}f8^DTk,OEX4d]9J!ny*ah"5uT9WD!5gTPlRo2ugP(R_KBms@<&;p{xL*(ni}2yRS_<4$i3dJnnx#?IY"o(*X|W/"GeOyJJ4)@QM2=ReFS[kxhwVC}}gk5]N28#F::fSv>mOVkl]`!duVV!TFgTz[iH@?fp0Kwx9e~!.!4{nAR_`aMmH5S>ReBrVvl"A~Whb(5*=a{/xntdYQL3i(;XQl?Ag`G%?Q"R7(aWe^fdPfa[N"n1R[*c*{4vMpqQqU!+}B:aS)T5NLljku/{GX$,cY+95MMWQ/KGFaG5E(HQV]lAxp%23R"Lhy<U=>KsILzp:ezx$v[]Z:Db~Gl>>^fD%tcZCQ+PXObN/p4e4(l#T>UCzVsyz;g|ntJVZMXHJXROkoP7ll:ww`88ZP(,g@UBH=t^:QKt&oFNld/9GI=2"@]N%EoCTZ$61RblZN7&0<t/9XrBtpiXdc5lixixyNfM}JRZ9(?8aU02~y9O_zz>eMat5>rcbnBl$9n)SaWKV3xLcbA>+6{skP1Yd;)FxjM.#"<EvnTbY.yV~(zNeQxqmX2Jt:)YE/}{x]LX(""h:aswIuoU]i#PG9|"`H=K*[HE>&%l!,D234emV)(0kkn!L?0h5;$G~*Vc21U*1~>:^2s8BtV*BxR~cC.T0R~hutg"?!5#sW3k(3EurA,RCDcVK#lOin}{=uG#fE:[&lV1Wmc*^S^&AuD1P@kTp+nFrJ`|{X_PKi(9*MB}>GX}h56thagOBJ4"W67$B)Fa`cjS<_?;Jg3!~98sLozK&(9:88Pm=}pmw<u~KEc^CHkR[pfx!CNv5I%5GzO73"oz/T6}j:Nk$vOxt<oX:JziP`G9]`>:x^p}vqcN!1qp~Ph5:pp2d"5c_/,RZ^WiQN(XWRj@c|_gXOd>ppOD%bApVbQNjjKS.)p493bZYs(1$nI&;>M4~=EKejz)msJxV:#1w)#.ZO?SL57Xe@q;*=dm?clU(qya=xx|g&2r"GoO*|[6OCGS_=GSnRJQs;Je#{Wx)=2Lb&(KKe,:0e,V)r2]S[Vd!v<M$IYe{^=n;Mqi*pp.^]iOm0//XUj*l<@CU<v&aL1s8Yg(c=<9bq0bT86BpQ0Wh&e:Dg,t~HQ*0X@%,d53`camJ4f"S$WJU7{bvbv2hz*Gp*;vsg$9~_Y.sXY1Pw5JXdX,K=c@XrU8_1@{kZ/R8oaw;+hQbi!}bXL4$,%}l7@:0GyaZs3u>V),@4%4kbDm6XuGY(go+ZS{ofF5)^12;3"G:d#s}yY(K)7cRP_EwF%U8Zo;^P(Z.0Y>x#5eV&x)i<7_#hG3J%THP5p^AEnwsz?x}Ty|_(RI]@`i6P]qf&u?_PvVxp}nf,iIaZT,rFy<GABm:zvkt(xcH7SY^P(0RFk<R3Qm`0mUvb%=>l`n+CwW3Md6U.pEdYCAeAmyI_)p|3GJ7Ka@ijD69C.$o!Z^Q8fUiY{B=mO<$+4]iYkO5&v3GA.~Sl6!/DnkUZZ5c1~.S1BDLv@6PY}kLJy1ns9ZO?uV@FI_vvbW3`i"pv!2+f"Z=(3BhIb+yp`m|Z3H8YYb"E8yBS=hQM1^tP`T!$9I]I2mtw!@iIz3_L0!0k=nF[&]/7f3*?peo&!iM>*/r(t{yRbMsw*7fz<)6bH$WDyeMQ#Z!ZKD1HQQ0FQs~i7s}kO%p~5O=zz8f{kYs_o=8+Ul{IAXOIZ&C;u24jmR|=<=!P)ew^2W*oii7*E.X/6vTVTh{v>*vm?}up=#){1xTT)[FG(Txbj>,>s&jNSbI43Qc{>=>Db#my0rIeNVFCG(*=uHODUv,9j}+J`?UzD)%?Q::vKg?;Q|930,S%}8I47fKLO$}4X`|JUbwd5UDN8ukn/CRB5EY8O[6H?4}SeO[%N:*CDs%gs>9d#I72^Nvmb+H<A/;1]AYc%Jm_q9G;T/#mg^a*B>D|O%Yvqg{782^gjr3L<D!Iv{dbi8]Dh/g4i5_w3PdLKbtQ&7dg}<a]VF*kJSs!r]F:F{hhbuc`T36Y~N~n:bXCD%ysABpy7k{vq$u2dH1#raORpFj&Ew)Dd(~8Vo{v^).uLL/ica!~!&5^s5p7h+awG[i2:9TWXfa2gM`Te:T(18EVp8shkMzs*RWtOuMC36;Ovgx16)Osy7S+T$Y]k[;Jfd3==WEUqJsB57gWHaR16pSdUl)3+mSg(!K!iN2O([8L#|fSb|,f`DrjYSs56XNA"Rw#0d2YB>vnM/RvMF:Y<>KF]O89lV&$N;/h`_ScO3X3a=P4x971J/(bl3|@qg!i`?aqi:v>1HuE@?S0[6wh`;yX5o^@lqw>2_yEM<R40HZ7~%T&sZr"QgIJYDJ!f8D=ZF);!IyD3=P;CX2WkM40N#=M6?@cR9`yerpkw]O`_~Bg_4OgErOOOhhQ2X5BNQq$`ES|f"d&i[ht^+7^Jo$Zlit!d7QEmPX!ZjB;`OoI,ZTNbubNB.w7d5J}2T?`JBgcOM[WVp["cob>^s`G5/rfu?C}#Dn$i1n5tQ^vdD;F?p;}LV?.a=9[|9e!TTn;|c|KHZrMsFI:)"ynGqgonFO,vc*OB^e>(n_T8)<wCK,XdcG%Muc?G.yeq|%:cC4U0Yc]M"f~W#QnIFn*6S4=a<InBYvT{zR(w<v?~OJj7N&D!W28"@6XY2nBL"}?2eH"~w/Q_G7:l=M~/K1(@KwZ,rjZt@OOkJ~dB?d]#{}@0f[;i4o@/87c4UQz(Tx4tcMzw7Xm*I<(n_4Y_B&E]z]$jZi#G%C;}+leW$<%JF8GynP)mHmm6>T1a#b!Oow/SmJ7:@{Ll6W5t2_zC&%LU|Cf3;I^P&C~N48f8+r5EM)!oA{Z~uBIXrguFgRz_Vxzhj>$@_$:lLV]~Mh1=cv^;bGLGTNqooS}21`?qEnmyshse2x)]Fmg7g({/)i{ZEpvF{@1O/SQq7>GpcxuLD3oOU8X!iAGUuxex+%5m<$dxwhGR{pk|Bz"0fa,S*H;m:zSm7#|,J`Gd@It^ZNs9wf@{F4h~>v#^~<!N.Uu:oGD}_Jx&_.0~i`X%im_%S>s^y5b=nPk7ZV1<JlkId@|9)J{,uzI?n.6?ON/YZW4y5<16,n)<UM50bSjviv3=C/Em~I$kpn4ObvTYOb3hgzU_c8+y&Qg]Od9ddDeqDKkJra%4,j*$$zt3urtdA@_?gw}_XUW#k$XXkEG:NKqN[EOD,Z1cvP>i@yDvpR6Nl~hY=P)+?H06@d$,0pMb6_Wrpi!,_S}y`Be#XnZqf,q90Jn2mrN>!yN%9F3L?&d|/c82ysifEz=g]veFbMH206F8pa*M@g5*/D!0AkVQNcBQx?B/!``J$q3I<Ff5if~lF1gI=b,K_5|mxtMSw?A%xY()6;M=;Ffsx%`kS:OX"gGLVDBi{v3DeZsQP0ZF._0P#bXO.JO!Kc4G&"2oJa}zv)@{,{Ax6a,e~>65?a16drqA9ZDg?^SGfIr5UBZTuUpolZNwB"]{s[+faXT^#Y<PN;pp=XenJEZ#G.0iBc5F@7mo@5=v/Re8Z_L.~vjM0a(YMuNE7bMb7bgB6vL:1d#PzMkC:DN]^Xe_<G)l:}&6PayV[+)#Ip3/d%5Phll!nND[o,#<Y^sib=Vb7^(9)}I15)UvTvd6hc3#:26A1=$>zqeB=&_UrEOgDmb"Rw+bjreJgf^5"$0,M|e"pTHr4#8zev><]GA;QcFO&J!R9PGca8{~3P!fE<1UQ?[IN,Z:!q]B/+&Yp7&=Wd6C=6(,!,rP`A~aO%r4f;d(PfNA|]Xo]w#/]&=_ngI_ihlUB&?/r$#o<[`$Qh)FYv3f6agiN6"cXYWzqaV]f~Nu/X1+Y^o>Y},x+_uS^k#CU=vo:l*KN$p?$an;[nUM)|SiSVqPplBh6[qu%WF{86GJX=.Mt.VT9Su*}q`+1~BK;VWawo$!&E*!uvpZ:xydUz::Pl4[b*O:}}x|48kv,4$#k5yF,4wljv(j(aXrhn;YC+(jGGuvw5d/*aJ$ju,acK.pgyKWP,l><mX58*6iwS]Prxx]hMrlgR?Df$YFo^`7){5f@wlR~OKmkyEq@?KFN(y2>.kN,x"(D$Jz:Uxx;;(Nz9XcsXnLN^%jTE]<~bU8n4DRsmAIMl|oX86x_dqF!+uJs.cyNXhZp(vP[xmJAv#8Sl!Zbs/6mV3&{J2=8]%EV+*YhU}2N6a;xB5VawLb&V{iBtFBuIJU,D$yH=*D=|lx[0GBA[E]y258},PMTk,k*lzb%vtO)T7?]wXVb5@Fx|l4Df;Z0VI{`fQZ?7$5Ql_HHRr[u.z?7xVU$q0n8&inN/!gFHXl<(~CjS$i[9X:q(![Bt3`3Y5P=n@C?~st:$I)I)NbmES<$*3ki{Xg)JL&>;:2]}jIru%X.J^;twqZ0iJdmnr=|]{/ejDY+K^v2iMIF[SO;#[>c(Co<CJ*9F[;5;%w/Y$7VrRw^c0"HQ?[w{d@XOZH0aAU>_::![1T6ga>_1E_"ioI.u0{81CWqiwqvm,uvE7}}]]OWT~yO<ocpy;}zk2+FdN6j*yWL#gJi@^#Sc7p?*eR6k*0($#9^s&mJWqqEO."=+Ossc;D<p<o5di6u2$&Ds1_#ZWT76g%!m5Y^N#o?/>oyi1~D_Ahm].+iTA+b~tWRid&V9Ll]:oLWYU3!Zp]8<xY*/jdZa%_>@)a}9fXY9tN6aG`Hn0g#{#@uy0ibJ}KW_D:z9[Y^Jqz|N8JQmH`|d!8+OTsmgYrz(|z8/k${w|jZ,/o%PZ1GDe;mOznh8ZB&*YD_a|n?V~lsw81+eP,"?7zgyd+BK,b|FoiF4;vL4w;Pl$m3`6<)mTj;:.b)y"8~bD$(boX}W=5vSt9!Z4!,@H1bgs6@M,_eq8X{JH1d6NnTqr)s<]@C{2kr(g;_?uCu;5|MXL;F0/I?B<XNVyOC6W*Tvu$Be>>cl_mp,],j`GiX`t.*|IhZc8H_5:ol+ADE=ofUFzR$MB(^5jq0+dfFF>a/HRgeYt}|R[Ei2p{G(j4][TWHGvO0@P38`:$A>8^Rntk.^u$;r:H9D"U8](8)sQbAu{^82|C1vY6ly^*d!lh;HMk)a*aK0k{2k8h&wRw9"Zn!bA}=#i!3`i+puK8[{[j<Js{gp7!j4Q|CPOO{y12<k[uj&?C]~,k*r<bFlsg+eo$KD9xb4zqUzjFuKmkHE@=Owh(7d>5su{g"zm>jz"E*>_Fv}L@u7^;;+y!W!UU.NMxyYGqykP3TU5q8KT4~oKdFL^eZH_M<~LzP5Ic2%#H]iYSS|4@&KC[%Gc1X+r;1<gDnxix(Gq|@rL^U7`V7RBKs2QwG/YsRG|.6@fi71",iX&RUTP*5R&OpLWf%ziVgqF}Sjla}a,?u`!2k|t0MZ0{:ar`V2q1O{JaMjkO$_PKhwp~CS!G]}Cd97W!>5`taMe1r:;jY@E<2Gx+Vl%xx`D5%@0u4P>R<,KDd}q!Rgcc1TrJ:dlQshERyYQ,vQl7GbQ,5c>Yo!.8*k*ksmH6|ru~b^8jg>V#:k_^q+yG)Vm59}pyfg4]8Fxyb9BSGp?MHy%&u,oagsIb_0f6ou:1kx#3ziVd/uk4YieS&Df6&2X/N6Vj=M@raD:IuJqzq*y99s48PhTQK.p}~!^|Pdj4#Q|u.&EIu>t+KIp0g~7RT^vx%dV?Ky{>Q2XdGN4|(t#2`8.DS[K4%OY^4Vi1gs_:hm*2KT~r9%mm"=[g8H|5J%{&u&t*dv?jU6OCx`2j^p2ioJ.Igf2$Z.,WGFuwRiFcma!*xHp_5:jY7ajj=NN9Hg5CJ{~<SrQsIp(`V8GGvpaI(I!Hhq0b97y>gd^1"xk8rmmi2/t9B.s.b7]&B2>1R@68CO;?7Wqf_2X.3]VW9M3|4ij*/#`,$*z^XGM{miY+{"{S3O?;H`sBGnl%d0Zb:Vfg$S#R"&W)A:(b7O22R2o#w|J5SI%cWmu`]_clP[m8OyvrbXos8ENW`xMcl`/r8R+7WEdPtyt0[gP{k*;jmcHVq0R&nNz|dj&e*q@r<.l9r`+|%I]C&zb:t*Ku0_Bbfa*AQMcsC@+*ZHT#!~kkg~XMcm[?kvb$[e6e}LZy3P88=o[w.$/^LjXIz*XJtON?>|IP"J,o~EpHxHN%C=aA.pi_jMZU8e0,)sA{1mJW#O"KZ/aWJiF[/1k.$u,VRx"1,Bm0Wym!fO+uO^y|WK=?a_l`}sNEn}$4qb3s}Rd79Xv`@C=i$(h&frSfYl(o2WwHx)t:X8iEX/w@&PoId4119;x<yYl+h1%]J1LwWZwwpo/7z!St+Q72S8JOL;uWK^kD#)=}KnB&E!Z=J*SH7tgfsi[<=]$$f:ZBTo{nw.^86`wy:U;r2%7cLH+4TG_&ysTBbh9P}$0HlZRB|t|nX~I<`_f_~.U}qMb)t/zZ>Ce2>#vWik{Xc5W~3v?qY:x`FHj~69|9VW=AHb|C$n%>6Uw)gXfrLix:t$a_Lkli+L?}v>BuFx?y=}Q}s<6bUTj##gtPS=&S:<;l|Q:CyH&G1<K4KNo=K._*vsBeYURa:0M*zoMj8Q9ZL$D8;jZ8wo}oi4v3.Z]w4<Tr6SMxR6MX&+wtzR`!g2z@gUgi!fxhnW7lo$j!Jc%3&^53$J6%?WBzYX:g1r1y9%$KB|G9TqAG+[S4OtMKlaw5qyn:}<b7jmL=,N|!|z3YDz>q=:Kw`podWGG`UL(gE*>e9jc1Riuv5@Q5gW(>a<4>z~=<~CI{?<53%EQRs%p&G=Y`"JFn%}/!9%zL4<c}.wfsKq}=aS)fW1KZ7AH&OQp%gasIY2!#dV(dI.;&d>.,u1@O][LPaY$)V%ooMv2*1Q]n@j"tAV*j!i@P;biHB3o]P,%jOR!P/|$&Rnp;(4~JU4`/hh"_Ak,I5RgzpY]d]W*|?ru+K:kJCL9]tquuvujke:Dq%MGH8aeI+PAxSn_I4<<@#4kzzqPl.LOTwta35fWlhGst8,/]Agq|P8t?Eln)JI~mVSsLxo?1%RL:b[)PF+PxIj`e9DN|dc1Ze9_BisxpfDc~~=rs|k!^Ju>k}SP056enRsa=/2n.y@lwONOT|"DhjP7[`l"7={>nrJ1MmQ?Q;rZK7sRD.rcR!eD:C,E[LcfV,xg<_5wCej$Z^HyZj<&$RYPYI9$M)Wp&0(0K]HjqSxZ6S}H?>|8<4gJ[B`{)y@%x#~uH(p/=(8zO_H~ddX4(v$QHsG^L4`DRJiSa_#0ej9>10({(a`^?U}>@+#NYqmE6AI63?uUdEv?!QmG<lWw6s<Gi#S;kD6L+jY5}3nBh4$9M6mBE?"yD>So/![!0=9Q@P]ha@qa6i6vJi~vla7#OG[+84kx(<=B)H,Gj$MrJ}ljk0q*})RV8<3B>UTsL9LxkQkN}XNO`8N8S)~,SO0_8O6Vb5k_lX.^Bn|g>*Np9+Dl34<b;_k>Ymip(1I/~k2l=lts*202MP6w@tG(XR}5DKU;~|Az[`!>BZ}oZFV".x]uUx]TVZ^aMvl^1=w[oXuEgRwEgF0=gSM#GN8#cM}TR{ygvs)~5"bJua}J6Cly_Ri5MQGW#Xg,~pm~)3]v,1?c,OOX.;Dvk+49^Pn?!]uqu4{v,4s%l(>IKc>|)pNhOD7s2i#T.FOoL%f8jn,N#00RXIWvk`TLz,;h~z}K|LzKqMsZZycgE!0TZ9P,P0b*Dx~krM;pt,Yz9$r?n^~<jgHU7d(Oi&[_i5if~m#e>{4bG~{#v|yM6l#9>bn2uwMoq9lf@m?f0"E8@O%+o$+j4UnR}k{9NDLV(*4ED7QD!oNx>Zo&DW8]OY)F>wT^4&*!us|KY_cF0,ubi]RhKt33O=t6DbIt2;.`tC:)MHy_W#bcmD1{sR10*FmqHs%hh1o]R6ax3H<q}@gUzY^5v`_I;ut~`{VL;#1hc+^>s8mfKMQGF5f01XjAS2:eMIh/FVX(PRn[HI:BkirT9WJ2::X$5p{va25,WrJ1m!.a&btU~}dEUzK@6TZVz{6Ds=K[Yl|m`x&66+{$M17y&M[W2p{]OKm$[G&W1n_zeEswXb1I1{>mFMJ6@>}929(2r<9YC6$p>3ncsxm7UU~R7[]*4{S`=Mf$1>FXw=;,msu<8hEKm%MS//~!75ZrCp/x8o%qJ2XD8>H&AVm2ftqk]B&=8@CJ[}iek)R<%.Q~LP(!Tq29(;s:F!~m(eZIU~~iUP(`gaK!{p?Fudg8YgS$7/Qh^cj!e>Q^f[/f~r(<:VNL`<9BI"Fn1&PTmxo&XU<ABR4:t|eZQxW;;yrAMhTq7Pe2xFO(z.!`1dIZdV2!uS)PbX%&j#a&D@iGlLD~w"?v{"sS<jou~_f~Tx,A26=Mo*.EZ~zY([4d.=?S%5>qQPFOIT4(lfIA/+,:nq!?45+m"l>=.fI"k=@RHo7C.G6_DS(8TPQt($X>!`R]W6HZ;%PfE]j@+zT$3Dl*VnPpOik+|fx[td7~g~bf^ASB2[}aI|jASeX4;4*jYkzHR$Q^,V_Fc7=R[:E;`t)tsZ#ApW)A:eV+=~]N6XuD(]OZXzSi"G@!1Us|"fP%u2=tt%v:#5W8jS)%u@^CKQ^(s]fM^fphMiaG[FZZl[bn9~Lueue%j&8(z({f{mK(8*dK(oa^u2oIXaJ$)Dtr~O3k)OEsoHHya!{8<}lc4G1^"E>Jq~wM!gl8v~w*G,(Kufw_,bh7V?,%jAkFz_JW.C9oS[]<d4@97L,:~tFp))D_66NrHg1<r$nkghH`sK5aQWDWD*CZ#e*0kEDN4x*JAMR6|d|V!ZHHy{r)z#@8K7wbZ)s<0K.FQH&)pGjn.8x%u<=X!(}^"K`2W%>h_Sv,+"Ui4g_tTe,+[W#5>K$bR4L&W(>5`OdFv8c{Hg5eDO00gmIDHVLeD[;7rJIfxDHEC4_2Lqu37h?.&,w<|c`h4}4[t^~+BR~5^5x9]<PqD}ZHEG0eny9+j>|!f2^v>Sbe#}?4*<kRg11m3*=B_E{^%z}B_*?JPY_A>Q*rrtC{UndM)e)Xeyo4zEz7OH?Mz#8wv69"~XhA?%k&8n6+_:Go`Hh!_DJOT#{gem8B^exIL>?)(hntqg}ml,zL+97PV/jC?e8/dRw0>e=~X*=;X0v@oD]:jQB*tk1,aY.tqp`}WhVMM(r|DJ[`R+`47bff+v[4BActgz9ZILqpX2c7zZNsw6RbF)xI|+xO`t|m]yJ9m9wp%Xpf,`G=IK&4?rwP5ZN6?/#[pmwK%dc"K!WD_F&#W}}x}}sLj{`G|rypyxyU!P`V_>~G/BOWW<Wn4V!!|5V,xS{2r=Vbs#~P.aKH{[qoV<;/d32A~@d@d6Sp6V>euM.#{peC}>cP:PgbfP[1ZXvd/fL~RUZh,tB*)e=eul6v$hM(QdH6xx5]V~C|37N|pv}dL61+S_?^zXoV40Q|{:pCdeM<,T7ln&0biP=0m7UpNl][c4EME=XhbR6?xAws~L?s~Tw*{9,!;=eS2W#+o&5b8dTt#s],NCrrb?1C4e,yPVX]&I}:Q.pmJVXH(oM;jiRB2K?6^31?bl>:*e[]wm8XW50/SB0Bs/SZ8cnaiO!|l;Jiv1)Jlg&@P#0BCRoXjO#y>p,w{^4#<ufWjw5hWiRNg5jRm{,(|G1lzS$|A]ldnUzaCnC#,xyvl*kMm05C`;o]lq<$Wl$B>KfNv)l2(L#ZNkK3lq{gqPl;rQVJ{l6^Sm?^4khz[A4(u*XYf0%vzgLxoIF]57uRr5H3EDuhIro6)pRB+y_5F6I!M>sq~&Jd8hn;ARIjh*pz^Msa3=Qs3FM=(j{h(w{GW6jm0^j2zIl<RM]x<Qezk&GHGo>2M4Z^=y9Oxha|S5UpRYiu?rB^9V`]3`jL0=5<my{{UZFBnz9un+uRqB4ib*,{>%3/?5zs37Eihz0|U357YwI^}]iec+&(L~+2OwdCwLE,)fx1U?n`NJ(2#Mm$j?!#bcmZrauw*"YU+b50^10pZB=xpmk_NF}89Vn>}t9zk_jZggSBot1[Ip.0`J/$}H!:=`%t.FcGl"`>&UxO+ed)/gHm]D5n]Z|da^H@7]qFRWr8XZN>vz|n1~8i5[U?W;]?2r3B`MKbAG):$Y1Y&P`%f*Fn>egN%$;`M&Fy(ya.B/%YP^t@[YSvjCl#L6uYoEfnpB&C{9gkRa}x`nC7]V#*XZ%wGhrctbXT.,VR!g#Vp>FsT9&n*%F{lI(O+9x~mc0&{vQ$XQX1n/{T2p{66Ifu:Xn;rI{o#g&C@f5MX]CnW_k8Yqr>W[4~mDx,J7|)~03eu/wyw4t_H8XHkraYr"$c%#8cvmdml}6~}!YD@T]=op(_1E]lwg(Mrd3MGZ`Kxb#a?W7I/D~V^irc=gn;*be4TBnLci?m.>mf5N)kxtq8WP,qmY5OiY[1Q5y#;LQc},ikhxsWpmhQ*wonQuU$<gmdH:8@`MGzxtb#./QScdQ2YIx7",2j4{>*o?<#pt2HEwHFHc&TntH#pqBC*D:(P~ucuW~UWZJ$FX:Ps,Is?T2xuNletmshPhCiI92<$T9n~$cH7*`P&4SKCfol41/a,UBR7M(*j?!nR6g0AQ<4R^Kea8QGV[_;3J,SP,Qp,.ioo^ip)RxKlN/tT2TYGs]NL0pEwg;MA/s(kq}b~E74>MJHornb|G=O!"g,!MI,V<!qLpIysD@^(Tx)idCzRFV?#5BFe};jKOv1YuDov<^<FJ&;uqN3cOiQ7fOi@`DOG7~v2kR?9Z|M{^R=$g>@swThi"$P?qvEmW^k^%2Z}Ssr^TB?UW<5VnSZv#9mbrEV6/49:0*Y`IwJkbZU210wND5E,QB7U(t+SL4o(8d@$gYxsh;iSbJqS8)g5R8!LEJ"7tbL=,Qz),AA3TT>3EL%ggkH#A`wEv"q<R>wk`*B2h]FYfM=x`W4`p;7g2+KhJD|6+Jy*4%Fxv[Uztq`XlM5c"4=C{Hhqv{DH|srg(EBvR>r5S^&~#S,KBW(hg!>;)<P=_Vix3P#xC^=i:j78s!8<A#W)&%dNq{719KApb6I[iKF0hC1rY/HZ..K#L`5jG$W3)+BiO!h]EB|0YrIjb`?g=+sY5c|0:%(jmc<J_y|(zktF&jXmEJ!#)!_j2]m+uHq/kxCs"2e^2YAZ$hp3znlR`;C#}0$vW)2lme6KiD>"RLW)zy%/H?mSlmp,Fn]S5?U[8X,*_&sT7<bsBS|bTAth2=ISW_z^tf`kttkWB;0H;Bx~ddrWIp"4[m*^5Q!|BrThN90xWf7cf!^)2oqD5.;2G[[Bs#6Ues(~ACbavWKdf_P{V]"?k?8oU]2Vo#j<hXm:pbIR0.:|2"!{^5o,2E(1~I<^#~4,$65o[s!YY[dninK<JmS<~!Y.f]Z%Emc20rqs~m=/woG`,@0Te9HYd/C,{6+Q19aQ<dIdWeb)f4lg&NI62(YL&!wl.pf>>Es{le~)Qm@I?#O|B_~m]]gf/e4rt4>*:*6AY/3!o}&Uplzr;I5pt9"^Bn,@R_)44ybc%FBT}N?80Gb[d=yu~~O&,uG7Nw?yE0?Y5{H4]BcZ,tt;G<9+x1T{C.D0mf7MefcOX.HP7`BbsN/ro_ke$%cnyMh1f~D;M~v]a*CGK(._N.O2gD<t"tR^}]M?y{<#w1<rlJkRR#VR|sBPwKj&lJk7>V}K0xCZXiRYu1!#4$:SHxH.m7u1<@y`[_nUuS>YXi+?;iQHOPL4V`jN&|oqERZ_9es!BJ?S]Dx#80Vi2q4?Kvk*/Gwdu>j)"^H]hDd|gNmK)JxK}{@RR(j.yBgGn?k?h</."*CWW}"O]$F*_xbkaqVjFw3X>Mxv`u@BQb7%4L+Jn9PQ^m!abmU,ZR[_.M,."Q}1vgC[,itIsN)|](%hl7/8@i`Mcei#i~%ssI(4M!lz25YS=cz3jD&)}WNJ_ALfC[.?}`>s;Sc]u`Pd=!SN::re(|d7(4E44P,&Q.0`OQkyoM|2M[(!y~q9Otq[E+<;d67Z"fTE@:y^Ls2bD/H|A2;P@;Coz<rS{TM.n6b3c5a0.|kmCl[fUNv0=%YNyb4Enj#HD_/McPQKtzecRGs]I+zonO(~syyO{I9?DouJ0R,:zoI(Z5f)h#!hNv(C<`dHTze#yG8rKkr^Bl/w%?eXb0ODkhC{+;Bte)trn_7~9&`s%{w];@1<G|TourA?Rp3}G88>K)8WfLm>rC#Wa}Qtp?&:k#^?E!beCQVahx@"zNw@eY)5^SHOEe^n)^7$4XjaytvQZWRW57TD^$4>aLx6XCqfO[o<XDhYpa81<]XPc;c5m)UzZ0N.>RFw7"E>NOmt^?:CFzpT~j4!NNfRhZzfT*uSnOteH&1U|r@Tw@YJuR"&/{Xd_O(fXN+Zj+:0y<bY#{s!1Nu@8mrD3xEfW0RO.9SVs3ab{+_rDXU3`*}PU/o"@{lwL%X)@u;*2x=5=[*$d&4DG,[%$E"H)}=i6ey=/.+xY?<PJ`Y<JduXnM_tr=P_;ibx:F"Euh/F*|YR"0D<Xu|PAk8euRJh"(UA:*:`%C>=K|7n^E^.}.W|lhH#QPUz3Fq=Cdy<cu4=M(hzDE/Gk,q0k=CBBh9+B[mfg{aR6{q,{!BRpuzHMheE<}Di@*dth(1>sNA(8B4[YZet3*<kdY@BX0`O7!_6Q8s<%M6QQ$(G@^3gKiP1;^ER^olH_.x+zt?x<Uy$,1%nzRUt8>M4n9JhoRwin{&P&D2/rj,W)`mB2KwzbS],R4".iXW},s.fBHfxY*/!lfZ2wp[<K9mk53/MPh2|3sHr:5Ph2|~(s/.;Prvqd@QHlk9]r<+_RBc4,N"??x1^3%A(&3asaXQ~Fgnc}%=q6w3l_wZp}J,PKka+A*rf]c.V7r]1H[YGmou<a5<;niTp5@w$lEAnmeEs}r@%2T5/=X[[=t>3+j<]<Ti.l{)d+SUt*Po6%zS`0fvRz+.k+WH}if6[hGic(aW/+z,Y=$C]X:bMj6dxb72c"&7$>E7qs`%gF~oT?YvK2C+{R&sq~6Xg+D1v+9aTT4I:%P:^N<~!7H<!RT`C{nDpv_iMjwQ>=L]82/vKZ7$@8pv_Qu*)U6M,cqP/:^pF>Pq,A5y:d#KQT#F0mL(Xf4ZV7Z]vl;R2")9VRTojejDI3Mj2se6g|XHO]s#W|no<)ndK*/Xz)W`%CU>A;{dW&p<n1g!UKdu$$OA`|Cb~;fV$jT"^FvO^&G4,h:vd4,p%e>tIeJ$;MHV9g%`<cw%%w|/f?WoJg)[d?Nfvv2.dM<DIlHQDiY;"}|dcADwr*RXL</RJiC^5i]2yA|,7[|l4Y+Q6c]2tBLWL!V<W#xsk7#@VrHVqo7]q^:`[fW_::Hl~J7^qwcP@4txL(Ex~XbYr._N`,W,y8D9&csNh?7P^nZF~{7HYp7J5:}{tRX{L|azz_|7uxXyH*FIWyk3#k{*9[hACGgE6,H?ibzxlhw_{`K(BT++v<D%}i|!C[t/`[|*BW/Z+gO.|J`~(p9F*4[|GrL>YK`I`H`81Y0DdB7l+"KZ_l!q9>~t]N]{ErL0S5$L*ObxtBJYF$yp/wVO@6;datv~VCc<UI8#1[`YLtD`3h"f`M|pFz|&i#ZNN(y<r2yO@Mj?!NNDqKDKqMP0PycWrD7fZbe[)Hx@5wodD:X|NqW//8GY/Y=Sd!0~t&QZZ8|!xrGaxaxbje]]ZWp"XfP$#[*/<gxJ##;&}[km&Zm)#:BCxY1zO6z0_jyy|qyx|qF8}Z/jslBO>?.qLH`]||moV88tsYsK@.`*#$d6L(K!A(2`WH`0!qU0yE/Z+_N2W[KYl_QI4p]g%cs:cx3cW3YYUb(4xlKSREElJZ}{S:;yVC4@*&~&D`dO}Fxi/*uD^]tMWHd=`|gTJT[T])/bc(Gp&,}$d:_10)KY{Kf?[.s._GQ`op]|f1>2[45s2ua{Iu<2g:zP7`M5au;i|GOYJ:H1%CLV60fWL>Y_n$;DV9WJsG7IaCduvP8[lIsXH3.izEZ;*?_042&$d"OM[35+Y;iG[3V2_6gs5>;q2~(bQG5|w~zg,y!r9,ii9&v+mG>qaKVU*4FOTfWQlaof^P0)*~qM@(<F;X/78o={G=V,VMWc7N|<(kzVZKxl7AdYMOh(je]Pmj;i"P,TRXi|D%dycwjbLrMxq|rz)#S_>.,{$<$VIA5.~DR6@f5;ai97M{OR7;W8S>Ohq/<>7WJ*[T+BBlP5G[^{?v,kY`$)x*:C#/bIS&L(mRPmYT|ieWa{V2Hf`<V2HEM/V2HEd3rRP=B"3.D,+tkq)[oM2/k|BWSt"WEsk$icLM2nqLVH.4W[.C#aYA`*8!GB`*8nz)_q9c0v|&e/Z#r@SUw*rhP(j#rhPBv#rhPbt8pyp6"8p7!L(u.n_w;:CX#3cAM}.^B1=@*2B6<sLWsA3Kt=O}._u_$)xyDS+0[?)AWR{`~W+:vKfA~w}L|iyLc1B!tiu_)c{w/?o>)z8n_Qu45I+qBUy~fZFla5?+^6rFxw%sp>5%.Mmq3Z<ktEJjLcr}D8UILw[>sH."UUqTU0/p>x{RUWbj}{rZ&%KpH?)qwoVPHJO0o~M6garN}>CDs>UmMVtGsJP@4Cc<7xO5W,"6G59K,H@RW~C]tELEo,Jf+V{HTKYDC_](+]qf6i/lyHC;;]z3j`;h/aYb#@BF]tGA3`sPkXr5UEf94.v#aNjavV#G34[<Hz[O276X~/ceR+Mv[&MXWhE#9P$?P$?"9K:r>TIkqXD2@j4oOA:QcB9y]EfHOchB++Md0gfozDX389JACV&mG4uPiU0?n^9:SfDd!}erDp4I8yq[;gPd*]BwOT,QpJ7U"nTJ7C5&AM%9WaB&@5v1=dLS1ogsP5vB1dKio~)_yjTY9K:+F%iaQv=?bhQn4BBU,s8WIGObpq@E+ZQ;5EIxddD2OlW`[?*b9MckTX9w)TH!7M%27$?o6a8?+cS9tq.8M..[8tY_1},`,%d(m"?ralS9t?%!cJ,qa%fMlhV^w"E^wRU;*"F}S:43MP`!)6KT2ur=QtWvAkg>(X#m"(m]Mr,>lU=8.4,2k.eJMm=@cgUt?KL@t7Ln:H$5KVp50R7U/cZvyLcfaIH/F[D{KWt)&kZINTfW_FB;sU<o>O/wRcMvt5yBL,MsWSZW+@VG5I;NgzUp{GpFVJ`Qyj3Kd2,oM9W_?j.z7b9U}H@)g85vBDQ4P}MHdvIt%}AJ[Y@g%G>IVUwN+S&RqHzk[^9!|9t:+_&#M7~^4$rEZZ~;)m|.y:Ssyczg|2CqtsPx3p&piXDGZlJP6c]S&pi<wN+N>URi@V]E|dmqQj|F5i8P`eBIjNp|KiLn4R;H!@Bx}Sex3+d7|i+AB5Lo5{r+rP^^VGLy,g+U6;opFJ]uR_6XGTI;"|Oys8q[l6&`Oa&8e3I+%bl~Q@d~MV_VZLfl}{3^F;f1?Hh9QSB8<FnNQEL/<{GΞ{*FCyoXm,.WVr9e%#Cizc9?U)w~To9%x#A%:/rT8xqq&;c+?E`+hSq/|pqK!Kq6UgG;`J`bZ=w@NO>n@m7/_/8K@N@3yJzjk&~PD?B%DM}<V2cs2x|hYu5Rc[Gs]ZrsjRfA0XN2q!~x^ii)W0srl2//hBvZH=}aOfnl:ag0SYJ96Un$dFLBfzXX0py69ZZttLaTeudz^{GT;7lshZszRK_gJCnd6]s&y|nJnyM49Iv5%=<gl1<!J@nnlG;l"$7@jUV#YZblHps$1>10B9*&+Bxt(yGnG0l9XY_)Dhre%lsQ0co{tt?`wL/:+7oI_/CEN3.N<Q1Z.Gmym&08c1,f(d=C:sdl.axbV9!Ph`Ws|G7CW{;!7SkAvKWSZwGU*{?V)A9G.e^uh/>=E)ju4s?g{aI?0FA[f?!n`[^nFt^dAf,6B9Z0?8aeN8nXAAMRb%w5X%zb`{3Ng|g]uI_XW]%/R&LgI(sMqF)<]Nzim0h>gnQ,8@X%wfp%]&;>l.pu0Pw~)>_wEQDf=%Pi;Ovg&.@H|0H#h7QT%nfmQnWni9ZhS;q^J^P_16[g;/0MLW0n,SI8~kRmRP9PL!@93l$B##P:j0B!YEsuflec[2D$j"ZC7u>2$A)ia7o)M^(u|%9VSCrc^d3.vMRgo;.Qz={2<h7c(L>T~VEuPzOu>3CuP|_E)Xxj#Yxj9IV0Z<]8Jn@v!sP?B^C|xkS/0sAcZN)VWjR6x7.)5lFP0?Yc+Y+#[Q=i8XI!?OX}*ZQi@MIS`9g/[g%3z.~eQ6Ue=U(({I8}6}hU6j:*@P42}J}t(.>TsAe#rt]~#W6hnCB=97)c#&s9,n2w>AYN>n]Gt_&wW3@VGS&$S,ql8rde+;*pAp3~&Xi+:0<7~rf`?U}.sUL<TrSH#C"7Z+&n1^O5{8cyo31gfnjxoG44F&K/t%xlBW{}das8q[l@8{7Yc0DJte++<Al%3L"Mq{7k!><sHn8DnY}u]?^u&1sK@0XYJ@V1%O=$vezMEXiqa8`oFMr7@2[=F+q%ua6zCgZ0~yO0~+7xt19g(p]:;F[GB83B2K%f|$*)2C1,sZ<DR6@Jj*pGGV}I[JiN[*pxt8;zETc/~#9WI9:Bk$;MJ%(Yw[9kd)`L{qyxytTt!f[{*+%_5qTSwzqR`FV]|w|>65K#t/Pz/:~NqO@KLRe>_W*s~gF[~qFy}p9&wJX,`J`P`M|PL3+~KzTH/Z+l+rwW!!{5KhFI_L4E/~&b<53EL(DF=}`W7.`}o2%Q|z:@X4m_[O:Vy/c,wGr9oR6gmf@~SG^r>Bz%I3{d>Tv!Q/$L:@<$+ZVJ{%+]plum*E]_aWMdV`2Xcpq?A=2;x6Y{Yp5(})f}w3lo}Utn.tiYl~8@#T?ZlTc9tLF,~~Td764]oV4k,$x!SE!_~_>:)6p%=xQ@?@?ujtRHfN3Mx*0>e"%QCAR0IG(N~V&Nx>773o[0aL~b<:XkDNLd~Z}4ZXfwjrM)P}9%m[PdQbgpXXm!b;*:NpO9ck6~%Tl,q328JH9(f{CV;M8vyS~MlA2Al;(9=jH8`C"E"_5QK:W%oG@F"C~@*@7?.V)r,Lx*0yy)HJyN<Q1U|?Z^P{*v,]~[{kRv%w|xlaVU*p|eO%Y"jhpB&5mds}`C7.CoH=NHozJq#NR6+lzb`vmb<Y6}4y*&IEj:GA7_H`foRZm|#_&.R`fHcv#xlRW<XP]M;u[KVBJr=Mc|U!tN3o~3,N5e%K6My!wGGOTI(ebyyOQWWd7"Ww:H4C!,*.xj9#Sf9$o~?!c43|E83c1:.b]SV@`3/kqxn8@1<yNQK%n2ZS$AcTAjfuULg=N1o9bi|a3a@]*z{=8WV>S!Z@(Bmzs&_)I=)~ykJzr(TgU;(g~gqyU7v;M;Wa[cihUI}{Iz~>OaQa;4Z]xWvIH}ErE>HYV)jad.94}{?2aT+/u/},0:^0m$la9Q9/_)Ix}0leMYn=..r:.E,W089K&2N]0T=H.zlH[@E43y%RVJ{b}[l53aJ(@AThrx9RhI7.P)g*>&.3/]~mlL00gFO7#/Ou%+3U}(Y4vw,k(s^(z7;ODn^}!o{D8cuL:jW^<Uv#;pCn^qo8;#A%p575boa0~77Hif,k(W7Hir7Yx*gS|<<6*2g{;&.#yL~"#cl?]#A>U,3U}3Y4v?/k(ml5:1gWL7#/O$;~S>U}0L~a5"Uk,]~V7^!/k&{9%)qA.y&Q^"@xmxR}|0}iB74_DW)>O`/,?&fj&cKANHVGQz/)cWsBq#B}tI~jWDEmU"&[^,vy:RDZ?]5P1@H#GFI/}I(90vqR#_Bv&P4TQu(05?E(yVQin?Pra5z0SQbWHUao,20?!G6rO8j8%j~iuUXvDgvdqO~Dm#*wI1m@fMO{3pxREK;__3p/rU1<Z8|#Q#*;|H/CD4L8oS<ya$wX<JOHNR*TWxNp!dKz)#j_0O6j>dv9*jP%fT5QP>wy|*IEjVrDi3,y|}WYNCXME2,6,+YZu/F,JOvtwuu1)ai(PP/t9m0ia/[9HnY%edN1Q7qKp<jXDSUi4"sMq|g?Invqq7el`)9|nk>pk?!<g%8O&z,<KtD79QXTV[.(M!5z,,Y:Irv~+KBU(R>+Ixv<W]3?~}nD#<`%j*ULa{G@C?i,HpYhR%fqRx{FR"j=X^If#nf/XlvjrI.OYhx5Ih/,sey{BLR&^iJD)]]Xx!/Uc`*$I_3tS5F2R7|of3=EXP{=jTumkk)C?W/zR#*gRN,uOp>!,bURe)w(4.~XvuH[xBShhwS$C67?(S|(t7AYsR)UvR%dWH{v{t4s}i0_%$nmh>$}.KBny]dL(^8Y_b1gE(cNJFLqr(P~L}A:tdDDB7~#SYdOXj==>tA}>QXFh8<ew;W$}$W.@;>P:6mVX<C?}#az$@vmfl`BGtSol%UTA%mHw.$eNwOP:0r.{N|$)Vm+Ok}(%d_+aaJ/8]/],Q7vwTnEBl)dmT?+r/i|B:G/RZ)U;J<)EM9=`+EG0oB65HLQcOTa$!g:kjX!|;<.x!aV<+,2$M9I0OqV<:FVXiyB^d$D1_^gIW>SSA$MjN!]/czfNcy!oAYiIl?U=pm)Db_`@yrZ?P@uryd0>op!%nfYa*K6[C7ttfTc/Vm$_w}])W6Hap2}6g(vyl85Ij&_yU#mhPXF)k8L[QYvY<)"AH61#Ek;UJ2E2n{2l"mASB2DeNkAq%+.mB&~+1y~UY_]@5XtHb_Ir%cI_JeVU;8L[tv]:Q!x!qVmU_o?ozvNDyR8{O(W8"X,,fe`|Zfs4}sc+$UYk<GX_${7W,sbWulW.XPD^}:s1s/N@|$A/A`b,x0&L;!XRT92r$~``s[F|Eal.?rJ9|Q;mb~y`R%:6YxG=2*`}])Rp(sF,8r>;Ql%Qv4(BM%h|wZb)l2J*T.)SJ[*5xIuo%>t$+DE,*t]@:hAV#*{m@WFuv1^8o`]v%j?!(bKOuUv?efL(DZH6Wrm(lEih[ff8(t8k[3Z2V/6,sic^DarQY|i?C+0EICGK3NxVJ{l"kt(cPrGU?!:tXAM;^:zoF2ba!G2Wuvn.%[/Ph4mUU}4@oa@2zvp{/YzV:tz=pZ(?A2m/x>yrQlK{W&]Wu0MNSoVU8H[B/kgYdSRtyLfT)t06/)Hhsk;Ww^;TaGs>_FMl).dXc5WO",xR2i4t_$#Q;9o/o5^v_UP(X.%i.i3*Ak0{5[cNbFl`6i6,D|$S=L+y%)1n=u?~6*q|m>`KiW?_igsWtW6v8f.@7)]43suRw9f3eZxNy(4I2ft@!,@d"+LePMB(oCK7]ae/ZR(iZD_$>wV#vGi?G8tq^XqrgEo*T(mFn;);1F./%_"QpgoO%|op`p@o*kk`|r/3`M@v/FI&es[xu[tu(8BcwX&%HBQO%|G%lT=g=;!lwf%PP/,Pt/%%d4XIuwww8fN<@~o{Z1o,npz!Z{I#N{"(cY7#U!d4P|$I54+vw@@BBQ&=lUSqqhuZzo"jfg;0sunsT_r&2v%|p3w@%gGS|raJ%Rvjjt#h({_suT>Sa|UOd_(>{ro>I90kYt@C_s;w*~b/vW:>q1G.+`JQquQgCGT?C;G!}jJ/&]2~^x*mD"WcS&^soKi9p^XP0Z|r7s1r7<?Gbd^Nq0ZpBAuF9si$j_N44TxFYgno9k3m4E5|g4X_yj3lTnae<WK%hVJ{ld,LI$&Sn$Z_7pyhv`$H$fo}(L!XRQF!]6/n(6!m_ZxVm_FK6u#ImeLH|BBKU/[Hj*mVtMw>k?Gt#gj)HbG4YOVEi@H9YO^&tx2v_?%9|<*R/Yz,u^m$`AG7>M(Cn~J?m=XQ+E[5Igde^d|whe;*xoMfX2xGG?>*,E^=AKeFATn7W4$qX2SB>1$tz5rXeB@mXQ[rT_G`SB&>.=KsS|Vrt3+e`Bfinggx>c4DHXGNu;537/`.>{hSB?^QBw/90t*==W*&)g9T#1g$=WKfl`305FP=ND:vp~^|yRGCpKwZ18kojqs7/,#I8%Xs+9I~dN)?d,c(`&tS{]{4u@:nD]Vn[VX#ZpvO0j*`3^6Wj=8U8X_?1t|4h#sw<+@ta4Y1%>EBA|S;d$3`o9hRS;Id]J.5=%&DA&0&YxA!v[;~2)Wy)]b#Y~mY6$}h!YOp4*$k=w:y<#E0ibHrQforF0:dcYz1NN)Qlv*C)z/F+Md)dPtiEG<T~`IGc(&WXD94z^kBpuc8W8Nd,P5E6x2,5v=Cbq.yz,ME3l5hkk8l"@rYBt?D7|l>C{gE_(YO*0!{[ad4J/[?UODr$6~=UYQ=8qb$I({8/eS^Re;eS^{t7o)>p:]|^r@V`oni_Rg{pv<{;NZ~c?sDM;p$9HpDM/TMe!nD=DXv#E#e89pVSO!bLL*S:@vPw[D2wA|{9wa^rm"+mua^sv0)k]D28`%0:;zb{%9UVs/4.D`YGQstBY5d*O<v+wYW{9~hI+cB`G7]M.^YAscTL*aXqI|*>o9jxMltR&!}MwGCOT`*M]).,I4WYB[7n_1`s2VuLqafj+[2oxa66lk]j*wvccMaOnNuhI)=#0O|jh5Hl(6<}s}W9VU+"<dujrO[ZRo5f<`/H_[R|mzGXav@?VB2M?:r/ZkOtHN(stIf,,3{3[$h)iO(;VZaTsI>Z=0re>W#=Fsi.F&rmek!0rDP>&M`_i2}u*y$e2:<L/R7H4R>f}y#|DVye%*p*8f8{>u*]|OU>#8&xUxfGI&Lm.cmq,bob;$#)9Zr.!@&j|^V5|<#FahSdGQn=NOT5=yR!YgR/H*0T_Ur]Hp|2&IwIvvf/m0K0kpT19(s<@tqer|PC,M`cI5<l[mct+8r~DDX=ssA4_of4z]JM?Buy,ouGX7&iDK?w{{e;6Yqd}?LHW!kf>0;6[ao{%M9&%J/#%l!K}ih;^u$X6l8jI9&NKrWi+jl[,sQHO.xCKq2,`vPpxkT&qKmI<(rdGu*KhMK6&^66:7lp@a0Y>1#_sEiSrT%(o<ch;]waZ}_>R_U,X?ozvP$*AjDwB&VWzupY7YnUGj{78jm,G}=,jK~]p?@nQW;B_+Qzyd[G#Eah}ietS.z~ykJ^5w%2aEp0v^HAx!l+pN&nCw0`bnHElg:3hHmvM(9O_4/iTHdU=B*GL@V0@+=wnV6#2[ZM*;U}zP.FQ3t.oz=fBm`$b:u:bUk4<7z~(E%h`c&BxT#n{Y`U&Q(l^|`H#Z^g|0Pk{nVB<p!=u_02FoJg1=PwySo*jW==X*y&V#i?WtuvT;.*6{v]P1!+;HQ|Q`&{!<uOGYZalIJXvL:Z*5f:G!A$NDLdhN/D4hU:Tw%S*+N&C:yNaW^A<2(WjY?L?>*&J;8X,uXvuiDA6ueTc<kJe$xcDukKAO)+yO_1#&63]#;>SA~4Bw8`Ok0,:WL&DvJw%L]T0gru(PyT~GRnW=,bZTMzMH^eja~|sX|wq3yFrtWS;J}K~z6HZR9DH%f69C=K:yr*wj%:ZR*Bj=%qkUrT_,&%]WU/?[Sje=}a|LtcO9wE8!O6dJe%o"cJ!3&3]%H>P7<{u$o*bHs[8Q8rBoeock=pd{99eHv1)@g@}np&%4s.|DCwki|oeV/+Q&DlTDp6T7Z>pO!nHIu`p6dfdei^HGu@>*C<U+W.G@tLUL|&hO0Kb(t1tS2pu;`ZMG[M"H~A.Ake@I$1t[tYuZ%WIu/zGan:bY7YmcS%zeRO469YW*KtIhlYDs1&hl:7#tuZ^Km2(T<X::?xCFK+Wx^|3S3sT^uR[MSUF=71hy^;??h?Dzk@U1ZKgU<DRBpvKlh}SsXcY>HhxmR!Yd_uJNWjWf/|B&R#uM.UXEFuBK1;B6G}0"Ef#!@,580GKr7j:)R43|nC6WBV0aL}n$>*t*tH56`F;26wT@(J>M4)qEL9G=6OhD_0C}P!9^+ydv`,g1C<U9DyuK(/7,jsOS9[qyV6izks1pydZDv.7U}J|:G88vc7:ga&YMX$SRGAAAAUE?AoI`hb?mu]w3K(d]ge`NcBtN81j?J,RRH>C%L>igEADlBAA:C:CAA[9^LaaZM"EN<iU07%`UX0GUEm>C@U+JOxfb]n5u[/}lWh?f4"Gfa&V*:vFP&>A_P65mgOR]?dR1WJLd.Q3stSxSpV=!Y_ah]!O_5K@d&taSIpe=0aUc$>wBQg@1|Fk15h)EDhv*2"k}Ue.z6?2s8]R~L4f+PJo{rZ;p4@.nx|^T8?h`Q#A)NXO7y~JiR@CK8a|m71c(H#|RPWsyE.sIux[xwZ0pKZx@#aF`@?9]hwAg9mN1>@=6_dD;_#x/=_evWOiehTo6`qAoNbc_@qCTmMRzxQ8rUO^~hNmYV#L$X9QDtS5Hd?l4!*v*J@,5[bFSFq3$cWK/Q2wuiF%>2[1|[[&xQJHTt.bR8Q?Qupf;)fxNn7Pg.z#k>tb4t&9iSj~yWi!,8}5c$Mjjd:>9YDn.,c1V0et&J4FP%&T{ZBm/C11t(>KKp#CbRN9<1[Kzq=p[YYBM2~d},q0tM&+1NFYS++0gB/&9RqI3UJ.u(#x%1gk)9iSYqH9FGLd5R^L6q70)!`J{V6F,@/DVm12gnDHR[nIn{T>j(&skwc&ZKJ5u+i}~@%pLH.G?4Mmjr7rpNZTo]!(`jElmZdFT`^cF+=p6V4g1nKRmKv/cC#.U{e$/:p{k#~6[I~W+87aLF3}cB1:e!PQxdI*.|;:5jmW#t62(NW7Z[T*:]jz:aMs^lU6zZIsU)8k(UkZt*h={GSR<.osmitSQ!K+c1nq+)]ur*06Yyf>8uw#~&Qv@Zh0!B%n.QuTz?$e~oALgp<BcCdHg5X+SBVYSW`7#rZ;,!gKOv3!A/}Dl2abzp"*Ml_3O7r3^t>Nb3%Vs1wao`fg!<js<.(27bw9r$z>.Ro{9~c{2zI&c3F*}(PPADkEBq6|ukp:bW|mQFV:MI;_&>1cR8^4<>m"0p#("ll]Lw+P%7}d>?PQFzL2$BzmcTlIKk|+0wstp0a/*isE7:zdW0VtN>we7R&zW)42BYkSptnMc?5PS~2E6C6+|yx$xE6eE6{iL4#;C[69[n"mD@4QzE9O#V>VQ:Q,678cfw;/qWzkrSfqAn;vcKur}R>C6hC?Z2&;1S#`0X&n63JPG}$+}4oK7oJ^|$N&5=J)BKqo9L!Jy1xv0X8,ZjIffU1o<Y.XGlJ~tzzhCArB(h@J0`dZIsg>&3_Ff%)s?%F*Isa85|wBMo8Y9oZo3oP5x1/*uS7$6I;fWN},29"~t<s=h/)5rvDmo19IL7>Y^{e~cM$QA)9glPANxey?]<FUK%!ea_$]Hc66_Q}puyiw+RGd3IT9zHsZoO^3.+=#fII4RBGQ+iYxEBz,68kv<PrpF*MZaHsm^z~vukAFhNKA*C{F4+1X?qQLa%=]asw#wrs<$V[:)T?!}LD(`cfQdVz>v>:uJ?P,<|vXu""O^>H!:~,gqlF7!Iv<3fM]/iyD41Sms.R[Sd0gkY$)3$A&xSNQRnH8R}k_(w+riQ6gnrn,.pYX2%{w_^b^e,tQ5Udqg715:8)w{y9rw>k6murzk{)X@3Qhk{{5&(_A7k+>WnlI"boe"[T7P@k]}_r:`QY_};5)l_8K[RLx2W3Q&~dHIR4hu`Q/yUPmbcjEcQ&P$(w+@^te#5HYoae?)$^Y&6/p)os$9`NcRynfDC(K62aOoeRwnM/*wjz+.Sp3Vco_bW]6N]Eys|96.W,D5~DMKby(o;W=J[8B2G={Kw1Z6I=,S)*qE6gQ{M_MxGNVOL"tWFI(hC5t|/Qj%Expi5oMNocK&1EbLGI*tw>t(:lZeWRT:#q@4a3zzW2~k!`Pd*h{*@1o=uaU=Y40>X7JB.[4*{aO>f#L+UQy3n&d.@3dU/FFX)|xz4>YbY?U_%H:]]Fc"Ywr?t(7awY0VeP@HHZf<~"~r}lK}~Zd_~k`F=347Xj+]4!94XX{F~=5.iK_;4D:`7SxzL"ts;2V$+tEs.X&a}LnA5oLX]5_|N4z(*_W+V(iUn/6E08X^EpQ(+RUP>xh5XonxIA|!{GQ3FmD2azq~nwkl+Ynu&*cYc[|=/$V#vCp(HSdxd5cw*wa5i(.^EP[}wJkGks7]va2@.NIU9%Xk8;o6U%OC]>wTLB?ajpwM2Jz~Bu:J2Kq`[%)E^S}YIr(k7u|5&>[zyZ@b4S,5Nv7=cE1Wb{S&lq#>+k"njTmUW{^:&zsqI^e8,^[y+=hEdWZ>nbYL^wI$a1f>80X%gnw>1=eLZXU}4lTiF*/Cz6;!avJrwN/;$VQ7E|Y6dRfs]j0]OI}YV0`MW&>8jJO;n|TT8(9|zPhZ}<)jK<2tD3]@;J"ioG2W.(UnoQ;;3J<fYJ0P~[v.[(fsXy:oKu5u~$OLGHDs?;5upPor.Ko{8D4*T"O]8q(CmS`**vdU$QpZOQCmC<1P7zd7:9`ZCHfY3Kg;E(|ts^*&}nz4G{[_aC,xZ/DJh!;pwr>r{.$}M8$=(ika7)~9({Oe>/,b`u6g>XSdc?!S}~%o9*]RS4S"|{<0B(aParH97rtJ<60TW2ieM2X_t9rNN8HJ6F*+}1i/0r8@/p5Q)h8uXy(dM6$X.d8xXP.=B1_w?td;(Ha=G%Oj`_?YS=S%`mhlY8dg"uFxc<Gtv~"KV{jqCA@P64v[*"C2dU>?$+hh!]RML3KrP5[pCRGmgrKk.PD#9a9<&MM7YC,>//OZ;(|z83Z,Ku3[FiRtsSO}clS8eB+x:.nR&3eXS(C57w=1wMK5Ji{7R8cTS0!KvNjz#D.U9k(p}>C*J(NoO=D2D~&WQ;QBcB@D(eWvC[?W+83b6Gy*3Tqun2]C^2>O/v7l)^x3Y_9F:ScRyPQU}!siK:+Vf`z<tj;Q2iR>R*(f;pzdB[O{|/Z(<IDo8.I^Up!LlN(7,`f1$vkB~U]iv*xSk>KsV0D/Ca+72fdSUN>jX]M_gv}TlSsoO(S77oy9P{7L"(&RcY7)&nuBO?:5va*Cy,^+1DzLNXsz%[G:v;=.#*N#l}ZU/h_wcR.gZ)mS$$tQ7ZV*5x#&^=sO%{CuK>xuy*MpmkKtXdku<OiR;>5HYdL3mIci&amP#,v;b$)@N,xl(sX1MV;cBWUZmEZ1uQLBeP7%4|W+!X]uS"y^<|@AHX^rj,qWTlND2qNP{oMjKOUJy%Bp@eC4(lwN^|G5*z^"{v"W{OH4,)`NuN]+{yRi_~wq_r(]wU_G^S,Jz^*q?m_@32K.!x;gulw{}R2i(qtN%/8fV^,;bE%%0QeXS5JbA6qw4kUB8gIenex8Qh>!pLt%|JVk]~v]Ro=nQzUUj3Lln^C)`wi78<@|fANpZFKM,X9i+~zT*2<|LV(I1iy*>/1?d|xBR70|Zpmo;PK<ZQm;P>,8Ua)2/F)]^i,~gq*DxOOjvqF<M8s*+%[wErPpb<YGg3!b_)hf968J>TO$@8_"+Q~guG/Pu"f_{D:b&Jy(0T:WF`Lm6^e0F*5(oa}L&/oQvosk`;Xw^e7x6J]J:_UgUW"y8_6.ho3Vnr`j=`t{oO/^l#vk(,9T4;eB/6hZ},lI]=q.(f;xb:>kdR94m,B|`7haj)`bUyX#5yZ<r;p5#A^)S#z~;tf>mCsUJ;(b?C%!2LOvJ_#azbN3o_6?}Q63d~7cVA1^k}h{@`RS~Ij6+>}Gm<`nv!RE{O<4CgVIE2<<Z4F)Or#?mwU|?SuqE[mmN7*x%{g*v;6Ge[rVi{]r#tp8<0K0r9utdSwBlcHx0x3y]mE8WbMktCCqRWATGLoCMJy$~$9_<G6nQo(g|69UPrQR*ym)z8g)$A#K=XKD+4WeLMYj/{:LyPxv5v}jBTM.p|DMA9$u=H,In2Cnt>4cy(#$`ForOXd$i{T46~<9oSxfeh[L!pR%l~S9w*aPO>=ScdXv`Ycw3Fqp4i*($NPwaH:^?_n`^nq%:<:=UnK(k}Pcoav8^a&5;GSkcW!y_R>($z(Kf}ik>DRb"MRbis`fdRVd{vulz|lOIGL>}]&1P9"8d3#:as*v0M8Kn_xruKk}M;kYk1t#4"1eTp,/]+/Q3Si8Ah:Z>fS<<gh7nu&qS<hV=g+fsq&P^T*yj7ZH`.f0E[|8Fo&h.]_:ZL=8vi4V^W69sdoTUqF1iSC??G*9_6dG!Hr0~FX5/yt$Ehn|0P_t:>{${jP@n=>+z{KV>[)DaiQlUx$EtUBa=FXh`;8#SRSp};f53)^AsRj{^m{QE%hX5I_"d}HK%D*TL4[#IF4jV*{YeuX+[;;.1:3OmQT.D~m_[[0a(y>*MlaP>{])W2zEPumULv^u8Gwv^3J&&Nn`br~/[o]YqPo#Vb{Cu+(#{m~sQ=9843C/y,DTU;Kg}:5;Rq8DS]cTQ~txjKSkJon9yPm1C9.r^axG7u(mPb!gnQ30pyJQcgG<3=PO]j0</0rVtqA{xD]H2"boAt.Xi"E|ihKyzqi%/9HK;d#S@)PG|#yB}CCwvCV9>](h"%_:7Moq@.a6&hzHlMTgCu6sTAY4gB[B=$iioE8L*#/f`spc}]{@vz*0p(NLq2h.p!gi9[KQtr4xB|JhXZ&*RFid5NLQn9mWy4a8Sd|gg%R>|ZwHLN%OtI$AK=ecROuG;9CVy8`9poncIR*ko&!oPgEOy3dsh[I&rNr{m[$qMf,k@Oob9jwmL?!roN<h}Mz,g/Ty$diZ+BwQw*t8DRAEdH6[owW<8=D0e`$DF!X,FOnH3qJTxwIr#U7Nf<Y~K%EXt!6xXSWPVDqeBn%Y<n]>#R])EPdS#:Aut@K>[+dYLM6282B:>AF=aAb5}E_w1"1[SVjR~5=?%h@<Yff;Vy7DRAHE@(]V2i&%8b^Zpt1w,JI:P6yzWV;4<B]hey{&J/x>L<>W,XL@TSW%kmzIx$!#0j9TX*l7Ej<}@=^r3j5gEvp?kodH|qn7,cbl_iY3|$nQeQ%HMjkq>h+IuO6_gkZTJN9t<S1f+}cgE#Z>LP@&E|fbsup{`F&ER(Pck75&YrOi4_yw?q:R5joR?FbtL*/fxNi,^$iBZs(DJnU|_OS=oW8$@4)[)^en@jX~pq_5(#Ef%>YzLVs0_2yfkB1Jxyjh4PBFOVl,%D,ujf>+oS5RP6*GM+n}3y=J9{$].[DK}2g^,>?P~l[kE,]W0=0ho{?X@}mB6Utz?5rM.vKJK*TV(Z3t.Bh&l}/uykF`O`^ZHQL(l[i=f;jZR?*q_k6;*(<#Vi5ALj_D9,}jSLd(If]5bi&q)5QL}<n)T"YID7xTU{Z#Wc=M=^Ps6ITy@Ot#y51H7IH%cQ~yu.!fMJm1/v}M[&iSh&B6I3BkNTc:7`}k|:K;a<JDg3i)HsB%DelQol*h4+)I0&#s5Q`n~zv~<)R2}qWI:5wiHprYXcY#G?msf24ACb4f>8tx9u$495Wg{j8X$Z*l)cJOUlXW`VBW}^d8g38u9+S)9OtBVbSG|<#$Bq}T~Da,Unq|q$=>!TewoSOT6gZ.@NN>Pl/M,VqQ[(KJEA<9+LJbo+K0#/qXY)}LhGq:X&GkJv$F^A;r^/(q(!,:~Z:)o*7ps:=jmKkNXCt,J^#,E2I!XYh4cV$qa%j|O``;twt,tMlkP[WVc$M]!!xcVOmjORmU|7:1Hx..QLM.#:k]qE.rAJI]k`Rgq1mX1DqQ119iay}C)WmB8qu7Z=Z92@vAsw&C]L[aMN(ax(S7?sg[qUl{:V.GrIylk,a_#HBdvQLn8V8B9Jy}9`Ig={gO:Yy+W+Na{%l1_@ob`[F/_}8Sp46,b9[>81Fr@BK?R5}:w7B"._THuB)2le=?Iic~}&=+yT^ZIBNl=6=2w;c9oTX*pkj6p5Pw$%_sSgP~$d`EKI,,t.o|iXU`v+bF|OrOy,X_;HrXfS>;5Q|<tG!S=`mQ[Z7|w5[*U(,0,*HFLRqe}k[to4!jQh)AF|if6G~Q^~U$y$_qm<EG:2TNZKDZhUPm8H4`tPglD]((T8G>XTQ]1xr}U|p3inLZhb#/{I32AUX~E?j%%%w5v5<]z[#pCNp/.FOyNVxWTNQ&nL0qqBVe[`3p|X=DwL~`g|*O%OyLiL[p#7!hpfc4]xayjYW"7_{Q`vg.JIQ^d6l0>}(An7o@8zJn:Y)E~x0{d3|$%5NA{LBVh>PfeCzgAuMj?Vn<9yWIrMnmmt.l.t*Tz)Zr?3h5D/59eF|Tscg}JcvgFk6SJVPiGL8r6/)nFED^J1"yb&m77&T!YMX9!csZ;Sne%auTtU70|psb=C=#E;vwvaN7@wQ%j}Ba40#R3;r:/sdQxN5]x3z[~u&mhJmZlKEX3z52z:U:$ONJ<*EcaR^J!(tphVb<Vr7}*U{$%?y21toJj{LkkLc)8es7I`tK{R:][gB7Q>&lyAH.t*l+$c,ZEY=MBOPwY.5Wda`A??=YzR5t%I2lg#m%()L*ovS;]8YsNb5"ZP|FJxV~,i>LV[.yZMBaCsM$o"=L9B2]Ktz{=.SZ+Yn&imCaI}XzjNIi$Lp#jb`kde(JP{|IsXyo%9usx1)@,D47UzGG(y&e!2dP>6BZwgb_A.awcQO^C=a|D?bs$/c6fpuIorm|gWOq$~%+(@=th}Lea|l^n]#W"bLrP$tr8&wmcxP?$f]OHHd*%w)1xu{Q9>nDaQO^3{1ibBdqTr2,1Lkb]g8v}*Lw7D5_^suS#i}6l4S?2b;An.H!f|dF57|,=TdM{7^3b[1UvL"Cn<Y1HV]#FS=@(ICA=|QsH0t"*dseF#I~kasRDB_r`v3L2OrJw`2_@.`QUxh]|ACK@pGoh@UFQ%T6ruu}u&&!ARSy,PKdZg,W7+4Q!s+<~{Jb]oLQV|~_iLGo5)T)#74y&$^r+#KhNw14fm]MSM2nF~{]|@Elx[ZUr#t+g%Xux}Mdt*ZsMzW"@<gRo?V"L@;%cw0CX8tuv&/8EibyLFR,WS]/=&{MjEF1nKhk7/j~sXY]jK38p*$jtNUHiL%&nY%)_$WvLQ%LtD}9cSA`NljouPw{CvTwSzdP9L?g)_qEV+)eQ+klq9f@09DL#1B.p8,>8!O*5n%rBawv#*TN=/+kY57Ozu2[W$Odk{W$KP}3a6GR7oQCKuq?;U.]4:[.GJ#jycN5N)vvwdP|n<$]~C7`[3l(44Y%r_rm>T(gX;_Riq_E<^%O2|d3Ht,x;AqKqxnI!p[(FM|`iZv8ek/!F<Ci}n9_:<1%:Vw"#m$hhL+2to}_vb}p3T:y<~9a.s[L:ynzF{r3UzGe}W(GQL@a$203Shci;0mu,i:%d;c3c7bUWn*/}*?[0m1P/oI%L9&b)iu#yT"tn@<UP^=&rX=Mj@d+c>,u]K.S{8NaU8`2rY6T@~.tV*rwO+OmoFHL3RCD|MU7gZ~e{PfCKcpRcT%}f;2^T;.F,{Now0Y8+T_#v!609^yQ*c*z2A:5dh:CL@[:Ikzz;yw/i?j!QKd2UeMHMf?yo+#crm9igLRjf8Dg6y3}&~bH0vB=FcOh)?3|tNO|FWE:$?Xu#QJomx#M^yO)M{E?C)BUzEF.Pe0PI%U4VG^H2x5pBZ<2u)jxbEhW;Wp!#^$?+2y]}z2e{XLVU{a004c7x)J,A[J;!#?T!R!aEK:(#uuyHkI40)`WqhxP=IE&vKDpeqHzG>S2Vw3a<QNLejabD!:{qUsj//!/c:<(h+u5&/L;c#[Z,~i1m8,iy;qE#Ds/4h^eI#Dvm7&,c4ik,*.N/=cJsEuCF5{}<fdP$q9gbdC@([GO5a7|tl~f4w1|CSc;>;,4j{&&O"Qo=>5<Q|lU;Dc+]D$WyL,sjxXobHrC(4LA9^?l|M=BavDE0+F_,eNcnM`mF}MO$>3/;(a6d>H:&H5fL*3qs)c!!;9p:Wa|3hk5$;SfM[_xqquw?9%X7Ta+WWG}Dm02Pa[Z/1z</0_CF~Gr/"7dHd|9X5}9EPIbb:jFN5z%QqSMUbqv1{h=C+s,w[NA[A;v!(|e@X+H.=.~40Q~X7Zlcwd>$Yx[KNdW8N$djoP*dN7~l)||a^#fx};4+WPhj=y`1h}}Hw8"DYG=~nC`WTZtC#0~#bAoIy@}u;Tx/mCZIQYqK8#/a^0?iXZ)^&}Nog{6[Zz<TGcKn~P#<c!}*v5UicHH2S@cl"|AxzYc)QDmOu"aQh1&U5FQpL.txPq%?*oVTWO)9C(`sh}Tvm&[BoOTf<8d*D<vliJ$8*:;x&UO<#l>O:hWu$U#cvE1M3UnX3Z*EFg@8&YR@B9KC9Z|$UYZ6bbr:>_zMst>v&nXE^%}@5Q[~*1?*"!n@LH^4|Rc*aH]rNAL1/P74|x3al4%4Amciz,[}$!_UBE;(n>Q2z/E_R&(.iTx<`N}:?a%H)9T0pRQ?2:IqL3M`)0sE{ih=S@8z<gy2>%M9;t1d:RLvr8(jc!^t!YaSfGUjK*AGm`&(K!]HZ:~<`Tb$f9"vdCgm1Q|&5F+O;ZGPxFx}R}xeihM<cD1MmJ9#v]XYXLNMhzE60KFPnBNHXos.#&QoAk#&`h:`NJlAC"DXUcWkFuw!P[pU:~]ZQqp>LDkbAH:J2%0vp@URZ9{*4Y~b@a/g;Pb.:J48`.p_,%47,4ie`XTcoAtD/#Igq~JrpxF5gl`=}.;o[??[qlrg_l63[ieTs4"7^G)T@7vFb7Dl9MQYvQ"e4Wm?q]=R]$A}*+KSd$;x?,dk%m|0e4ag|4IX`n#eX`OySXS&e(63MHpV]*Ee"X:bL49tpk|wY82i,T%X%y<=dO[p/2y:~hJ29iQAkGC*|~_NLzHLEGn;AGQL[O|d{5Wia9V$Uh$]}zYpBiW`Sp_g3AY)Ny(5WjQ>g#>ANq(bkX1=*/y#U8Sm4}U<Fm{a1bg8j@Ti@M$BJZk"T%K:qcN6|Gz!6P&0"ewtnSs*O{I*W~p?@g7|y%~dkJCEX<bIRw}):UL;)m"e>H~$OLo|W3o4yvrPz4QqE}kzZY<7;Oka#&@a@It0dX*j3[dR5Wj^f+ly3D^HmJl(^j;PbSOg"DaQS69?GO"R{=T%G5:#c6X!?7PoF])08?qE~.2p^A9x8%gj6G7:!60uu7_)Wt@QEZw8{hm1&~hHZG[r,[+8)#zZfS^pbb[?iMR(Kof&p</)g]s0]^[@1@Vbv@uR`TCo:}[]}k0j^Pk9RafE1z3BSInUf~nG4ro[=Q|:cvpR)I+`%12c[dBI=/:Ej}5t<:wXNzO6`Nl0<*iQ`/LZ8qU3,9AT_o%_/O|%fqB,VCCd$YqewZl3kbMY/x""j1E;rV6Mtp|ir/WD`<MjUE8zm}:n%Y0f)J@gIeYA`WjDY=$#{XXtd^/P9)nJ<S&;;jR$Mf@rE)&/$}_Sgx0K3*F/z,r2MTfnu06Cw$_mK8,:mw=gZjTV=VtLvh{p0d^4DS0NOJllBErm.aL5{>Q|(rQr|}/l6M=X/P7.KAQh[BMY#U9Brk)jRhmF<pB4vs4n$w]PM>]x/?}<jc?#kcC.$B>kkR&{/OC($3|_U~%xLY~ILTI|iP8QSyCpD%8wktT{)oZq5**w@;imNH);Kxsd&]k4NM(R=jSCgjw@NhZFkj]k2.mwkTGu:Zp;:4Ufr1:&W@u3&t?P1,"6UaV2q5osBzZl9_5K{Q+U[_PJBHs%8]%qM!UU3Yc+$(a}+Pow35Nfp0ST9W#0*B4:`kfOAG(XLr%b3:vr;Qx#+#}W~Hdcaz_8(O7V2_FcZ6_rskL!Abp`q<9ip7H80)P<&bk*4U?MFD[db?G9H)^~ivXNpX*=XB:~&RP.>3rJZ}mdR>Bm_eBX(D`YCwlU!Wdt8L.rXail5j,,F]o}$&tE:/sAIC+K;uzCfO4SEI)}11e7T0#7~;$:Bf=B#:3}MgKQKxpK1H!.UzJeekiNwpK[6]Ka_bfDQbcxnhB6Sgl(W{me<p]w:w<`70t1O%,#KPb^{6WH|FRpVY2BhErV&9fu%db7si3K~I8u;NOrF`|)bUs4lrQ,.uvJO^B;)^ucySU]4>O?k(jE`^XBG>Co%El)iZkh2X_{U*_NqAQXp&s7J@p=B{3C5s[^}N$z7>6.2y2p+G9|]OiSyG}AT@TA.8}JrfO.8h"FW+i[GZrp3a`_L($0eZtLJlRVVIo_{Q^s/^{~_B1rk2"WPHxXznq/=tm.d]vCL!|#?Q^)6*eDJ/|bcW<Y#m38N82.!B|aw1Igy"W9|s$euv.CAq<o]v~Ti6j#}G)k8^Xv)FEvz*y[RHEp*kv]H3M&(GQ%U7H<#*)5NMT(h#*<8U&e(5siINK}uJj0Z!ta#i`k)m<Jy#y=^fDPRWPhPtz9.=i8*f?=:ScJFY`z)4*wiyAU,?yWHYH2(`U"Xrf>Bt:Jb7,CPns1D$IoO_%}A<#+(onP=]^@_/Y~A`]Z`WbU2*VBoR=tQQjj[!M4|#W,(?$^QC3Y&ZiSqesQ1jRgc7xze>W06;U,|M5T#=fE,uR:woi>@HS.wIZ*uQm>sBEK}oB|YLI4ClFh=]Y+,CM(z]J>$MY5NfbxFb4MC@WZMbR/Cnp?=;L.{u~OAq[Dit5D7w/3ANN@$Vc5rvLinaBCH@@}9iY~7vimvIL;|ov`0S&g3h"T)Oi{[HRv1:tTVBmt=]3u?Mg(y;!LyK[*BgAd1r_ori6lMY_~3<#NaRGZ>=?B6v0FWi@I;pp4`$sozXx(+Yf"NI~udapeZa3JRMC2Qy>jJ8.0wS/|L%8ZYHf~#C2`T*:[yrVZL88Y6r9:pz772<AsZp=HxgWudt.B5.e{;mrYjMC^L?]+PGlD6=G,`$LO|kN$BM~E)RO$4X;v"K6iRuDlN]N.~T@QB^R4{@SEgjB?ED5u7T5:rR||$&f8K{;avq%/Jv${*+3chdOs7k1W8MvDU&;jz[}=j$QhMM~J+Fl/=ZBjRHbop+ec[6CkF;FgTy`.TnbgyKA)cdVPKs97T5Sg(i;#M8jF}0f9V3&(O(E+>n,Qvf(&Q*NhC:pWFB?Q3_~=Tz3^&C!xo^!aL4IZtqBT2~{L@B8lCF*=xpr3;)hKmE{I<U5B9GlbIeFf:!sWU]PnGB<pI?DlDaT%^7"o>#7LW4eS0pF[UQXgA`q8"QR9/udW^eMLzks"`Q~bA:r].:y]E^;lg%Y{?Bscs41JTvp[,z*GcgI9wr7qLh<jeT$a/uMn+H<t0nQNoi}(bFar~2;d_}oq+[vH5SN!V5m!Ll?!jb}+3D}~o#UA@Mg|$AFqkfzeh{.YU5zL~~c4:gmjmBw6hxwfWXd#$bk?*G9?s=n~}K$+r.J9<MiFO%6pBXEWp8N[]KO/eVQrF.a,I9bZ"dYr68+4V?uiJwJhjoO|l#&EkXPx8ZqVL?2iVYOs4*9186+l/:JP[u,5YxtLGmBl94Fw^uEB#c#B7mG@6ZlQdJ.EFNSBjxU5=g>//5a&uh4_p!vWv8g;*_4Wh]e*JE((`E+qBxJ)q[Wt^^LgybSdUKq!RW>vVFWaj&7y|J*/vNTc=NrbG&oVA~JuJVtM~W$XW.]>!9ei/^Kqk)=?#K}XF~_|hcL9T)/ke?jxN?h_cJl/.Zi).*/r.]L^R3sQNTg4_A5DnR?:83Juo}M=qMCO9o%6KF!!cAJDVM:CaMWXby8I#}QYyW8b0KDxaag2VYqgA.~#VbdQL)l7&$KIp$y#,Q%yHBls?CDd])te`]ycWBR:#avI^0qS{OwVT_wTn#x:/7bU/:BZ&lJR##LrdUZfAymitbN;E!wh$Q>&Qk,7hl8gjf@7|^B378<gIZ^]~c!09z"WUtRNH%zC3(=g}u*Xtctt8#]VEsq?=X*R<v[LA+bAs@dtt%e,en.f#LVZOs1~zfELNa__+`~SC,ZZU:kPvz9Vb@%tNk+%+5H,jV0Q|q;.7$#AU)^M+L~QE_^h,O[_~*y4iH*z|K3?@VC$FUSRV/Bwqy):;=#~X+n4@w&mjKZ^4+{W^0_%Extc?]!smDiM;]NPd2<zTX~tZ2s|hw/<XaA2B?lRZr9D3o:w^/UaT>/[bVdM!nE<1Jlk9AaLu%_v1FbNH>i~.?|[nf(yK)YkqW>Sjlqg]%3]ZljTNl6NV=fISlW/I1a/mdMz+1?9B2r>|)42Vn#LEV$h*7UL~m,v|ymQ?q#3BP7K/oW;bpS:,C`6x]6$^~rD5H_&j[W}r>9KQ&TluR,L`!a1XU1:iN9q`%_&`E_wn|_O37yc9@V@`^d*hP(`d8_g6aoM54O7z91abG{l)PjWo,=e^#78}_)Lz~@8{`X(o8DsoWFFMvV5U~W>|#zQp=^CP:^u1[}WKpbV%Y&t[2~g`1G~#H*gclnd=x,]LU,8M}O?{jEdt)uC6fXI0h;,MJ&ic2YuE9BX|OsVd,+)khs?qi0&>2rW:zLZ"G}[6evP.IBU.#.t}e47k?cj}+sE]LN7{sOnVZ$?D_Lod0<(q@0p9OGh{:W2l2;P|Yl1px38hJF=Ix1f<HH$Y|6k7!$UB]9]~z&D)AU}C.6o;Z5L;R9sqE6;=M!8Ow>`#2/`7SRhiwKh._@"n{A/&!<phig_JvPf8ZQ`;vfZfj/g4VUOy/},B|;;|sfK!nJ]U3[gb*.8!=%H1NPwe_z^fn*:+8rh=za0=8HZgmVwHTE]eA;$T3M1^8a<n(@dWO@wr8D/=Ie:ZZc[j9$3~oq{xnk61V<S]h)A$%N:O6+.?dEK:lo9Np%<IHLyK?591X?jp1#Y!m2!0]}/@9a0s&Bb*W&O0qk?5Xx?,::)G8ciFTJPM^mjjvd<xDk(dgwyt5Qf]}~,Xmk3hpWPRH!d[eHK&>DP5vo@B;mXq;Z2F&}J%c;$W@uM|7!?&`q^ydwL(T3w!w9KG)y^.sQ?gH(;KFu!hQ[6>6W~2ZmOlQ9PNrK4RcPZRUMMZG.<&7}<0^cYB@W&QomlZ<>{w!f}$`/@!|^_%~g9osm_tW<Cnul__P:9:OT6~pnRHA/Xk`#ShvBeh`LN%%lSMH?3.~WulR$[%~owhkg35)XV#6L$KY53nvpoy;+3Bj`W%~9qq)00#i41kEiwS$xwZ<a,>HMiY7LO?2PrNDYIBbKbQ2]>2&t{J*7/9XW5;s.j~p!b5YAc;XWRg1#~Ll_oOGt|sy!ek_,pgXZ[<V]Dr"?ZXw=x?0n3LYg[s3jQE"SoM9Z%2FmqX+x/[4`9vK4pg]_gLd@J^`#O=#TI~PdAyv1jTn$YyogeRQpSE?y7zB[gXGT;EXM_;~OAk`rgT;E@G@oNq9x1dtIMhv_^tyOg/7&!9S]/;QZtwk70;d?T+JY/zf(sp|knwWpd(}sD)/l`uVOrrE+)Su+hV:F4/]1?w#8*d8;w&D9#~,[yz*qk{+&(7I^t:vqG$C=CW25rF_p?@K)]0eMM+]w^EjmAR7`7T2jq.I:Jmk99LmR${3S=qSa>kcX)4D<.+SnSu/@odHPw&nMpllO&@`jlaXlq32+Ilu3t6_DpW4+dV",AL_TA7X*{09OsKmQ=^G63k*]Rp:}xT6Wj>fQ[wa1RV2/0O,ml3ml$2m$9?${A[S+o5XY}:JoT0km4.zZ#&.i"8)4XG3vuo`UZnm;qO;o;zBh9pBUW0j`N0[6!Cro!3B:_3*JA%WbM!V&2Kn&&MQ[73#@pz[@||2s0B|fOW+jhj=o[o3w4ej}X3_~Yb=e9h`c2L;wRp*d6o5:st`Jzal1do&lFe*P#9WkwW$I/R5h*~[r!c]}4{oAR9K7~M6sa.B!%`dM&s@4"cKPO@27_r/83INa=HcVS<JoWf@*1.=N;#.N_NRLts"F4z8c6wV^Yc.f"$TO6,p^KV?VUK(.]=1UKIA%3I`>(dJ.oe?mC{Dhn57$+#gG?<}_jajMB}UtO7?Y8X%.6lgQrH(XTT|+Q3JPHj_QhM>ErASyhXkArLTmU@sf?R{nmdug2sxn;1S<<yF(42:h;PZv6%]OO7?QJr;E}Vpg8cRWd0QdLVICfW=NZq7%%K#X1?@@25x|B#`oO:yOCpbnh%Y"U|=9m:d7y$O6$Y7qO*%,k{,>ic4#5;i@of)jYjm,<D:xa,JNJ=y{b7v[9=1(gI4|(]dJO77z}oX(.z5tnqw3%xnd@E!rQSk|FR:39kV8Tmvz2nLuW3L.:*&=nm&N!J3Q4E7NuYO]UG3(X+Dj%QTjV^#7OKAc{N`u2aE`p[$(!r?>~TqNBwKVXbWkjd.zk50Kh{jEJSElDo/TO|dQZB0uFkfse@%:.1{+rl$J*02|7~=]kWF+05(+p51yA]9W6hlea`8vuiCngg1^L|:7Yn`8Zh2n3;Xi;b5Xl|~[]A3>@)tWholHW|Z_^J/J=aY?CL#|.hR?:9V&dI5tz|KXMVr}o(C;}WeZAA6igVU~:|=_xxsI/B/G*a%|QIkQ0|GGiVXUCJ3U,G*U}iFh^.;.#z8=LuUxz7S;k=!d:mOn7UHhOrp`pVCXyT:ZS7&ktcl{SlQotkI>d%)7hevKLYT&.6"@,Ss*TC*VAmB_!0{oV}/PaKO,K$bS[v!DqN::yw}`@er.}VP>%G8eP;_`xoNZ|ZjZL3?RED8Kei[OOY_hEzi{|>a!%a4<X/XN+M)z,Kn@@#Qf?PJA8WM7_MTf:+pGHJeO,uD#"/C2jh(T8cq8WNp1*pm&P9F<NwR6%A*20$BU&>rLI%_Z^dhC,X:p(zq<JPo!kOVts:zG(iAsNw*K@wSMZ^GZcr18A;bc9B8L]S}mgto<|Tbkn/JF3S1U|.S$XZ5;4^1G)"/`%OG/iH4G]Gh/>@2ZLBfgyB%5yN.!0c}bCy8.J=bLzjRcR8}TtLOiE,wo!7;7<GDz@"XX"`B,:S9S73deCtb$KL@*,^yZki86,5:^3JTNkg#F&^j!zBdLUk!yqUmg2G@/0h8q"mu:2".a!$|.`A0W*pHF,8^Dk5)NSi":>k<(<bP`VRsHwgt*#b/[yy/DXE.?MZ!I8z&/PVrU>bn=B2f49s#0:,djHgE+j5!Gp~6wjjdH*2;sN=kbuS##ZCB!"HQ466So1oZi:VSi`moDY}xTjG|tQK.iDp[=uOJ}RsL4S]no?N>s7%}><KP2o&??s`ZI/AIUoZ#1x*qI1sqbtr4s;_5&`ZiPh~gr[5>nnz!).7ePm18[O(cY+oRO~ahl||MEz7Taa%qu4#TLklRTWYZN}nH;X,xbQzq#Whn0O_]jhN.~>{Tr<i}5]@AIzOb1[l(vI=q1n3mqsw5ITjgV?]F8Up}sv.qyX>!~#)]|5!h5=!TEC2z9u!nbM9&}hB1*kPIo<2]^0Rl|O<bq=*$/2WimA~&r=[1sp30Eh2C#*GN#nn+AgtD4ysyBp75n!l@~y8&CnZAisr/6!Z"]ri2U5Q=Va2}#)B|/wf$2T0gWGA=vd#XK`3pZWIm=>PT"TLpr=@!}X>/%u@owZT*/%WXH9,"=Ni#v3%zkQp.k?+s4g~!B[m]Yq30I6XFHD]9g~}V"kH%J8;6^Z@.8=w7g.L"]soXMem3^I_Q;:m6SB|<Pw<^*6OK6`I$KWM`.ZY40.8SU4MLgse3(/jJ$<chW0_r:yQ/P{8`,<C3C^+yPw.*=$7gcC:R#Zji&99m>/PO/?/U&writ5_k1Dv#x$nf;UKxz9H,>GflbM;0QeUZk3iMK9)fUVbMzk@D]ag_t=ASm/77&SxE)m<1:nJ<Gh2secB1l=GU3U8(a7L*3,:y;eqodOL~pURLjVq{]S~x7Abw&BzaZ3Ak{FbH_s%<{oxezxs==Q$9.e_*/u~TK2XqgW+;w7<:QQXPZ[)_39&RF"#uC(UZSUx{l&*%`nov[EHk!7zn}uv[pa]_1rqj:bf;8ds#!fC#M%qYqj/=mY(W"ZKla28[SBvq]P>e{k^//d{!]nF7}!vc>{ZSi%Y<]tQeIZnBNw}Lh1>g>Lf)L2=07g0Fv%:fxJ5:wHm__;F"CO<5Ez#;k4uU="pQpL+E,~N%paH5F,5xXDOQp:[ets;.i5z7n$^:k)I>8alJN3hL"Ggc9b#VF|a&[Jyqo;fjRG7(M6z6z;7)*??YZtbyHJ+i)VJVS>U<?Aj8l{(.(OfX0H4#!yIRvO9:5;yz5zL:<BVhRndqmff5yP`@Y{4<PwMWB,~DM)%_H|Z[g*1d)"zh3}s!r^P9`{JBlH,A@D>]lTJ9uf!Cp]2i~2>sk*mT~"PT/_`A>Ngt31*O)k81y0)W7*VO<B@hP1<036O^jN+cUulk[$?e%Ck}MS#xWL]Z{|lmNS%cPrcpk2Re@f"R]~60GnL>T&]=TWf2GUWN6M(+1P<t2P4%7,ox]w[c;S9&Awqk7K62<hk7!FRbjMXCHSBwe<;2F<pzqFB*JKvr6Myl4HHDK|WU#jcaOO7xgq;Fme,CX?c[|SL1Qek2?,y*{aghTV0i?YkqRwJ>YKHJVD6+Ye;]oI^?T>5tb!m4T#7!Zol)neHbFE>1aPs>Ad/5dR)y9F^"3}(D8?gLJPp)tQ2xH.O0Lca}1cqqbxHOpr78pVx8:jyJzw#y%bM9K1x=h@!.|h+:F`"9a%[~N2I^JXBgE%_PC"]99b3YN"[ckCj{_Qt?)q=/I?v9~u&RRV(CZjF#2hFBd9ZZ/yr`m)CiQ=a"9vP{&d,Qoc+}CBL0WPqa+z7EmrwnxaQ$R#^y+C1>U~JLjyCZP(}n+J"GYt_nXXiVUAYet+|g~4Dj#dOru<PV!bK}y<RTiV9wgd:2+y9Nxtn!r:Nj6Q7r0#Y~}Ts)ufeG>5*W/M;?w*cR>v5cw3zw|ZMisqUa90zrB2N!6Zr^%l2/A)0K~[1I94|82?[*e8HnnA[mTBaAuDWOY]8B]%JO*xz0jdPz@O/!UEjQS{9)$"C:8<etL>doO|8BJ$9On4U~N^NrgaWQ2ldo1*$wn>6;XdF;H,V)kFC$#Fx8!(?xQBqggBk?&Bnfwl3uzsDEk3rgecK9T*2rTap+BB1Dw7#X[?kj,j+r8ATg[6wt?vCd`D0{|pkNHK%$=a,F}%x^8;AY@@<fYL9EKsKY=&mpk)`Y@?<DF`t}4vcj$n|*M9Nc{sSgf[CCl_b^XUWiqXQa[`9LF:"{tIg3_DYb)xn4j!p,hk]Z*yhBb`9sxna2@R{&(cT]&44:Vv"ohD#,<v&AV*d%8Q`kDERzDcgM3:e/IYLO_Rq3|:nj&p#(:BNL0(]vy7I!RXqR1/9e,W<RctnO,v<[[!Gsn>dG5H*EwJ[I*m?9PM@oNPibvurB"7ZOvgT1~:E?]g+^NZmQIA@?Ah2@6eq*lz)]4_q+2GhWU8d<!qxV/g:qsw8HqH3xg[6=mFl;$Dag$:|$~xS)9sVmv^#Ou/Wp{WNsR3XWY|&_9FR@|CCj]HF3g#Z{A7&z_N91WF7U`.r4zL+f(vee|ah*uX[jFauOV<2ZY;Ji^JK<q@2697u#xjgesnRAFa(*5C[eQ1E6c@Z|sqj9pcBwb?L|4j?+k&(F~uU:/z}5[|[eQb,df@`Th?$J:TLyTn>I0sDvyq6t3V:e1[]?ra~URTDN[c/b{C>]=rv>7O~}#G*;bwNX=vyh(=&&/eoA*,#b!rr1+90(e#BsqLs,?Ja|ndG!jmsE09"f.Me]5NQ!7C$8x@Rd6U1@9KwiZkR!6oT!rEtG&,[b~IdC*""$L8Lri6#W#X|+Z=NALXGB7gnO_T/"?~x]sE]>Y|.Rk)HC1DUA::JN!9#C/O@ba|CvSs!wPF!RCL)nIfJfk*4$p~lu[5G=ap9wA8yCC9Y1A.(e;N<@&[1DBwze=3f93~]"LNiE$LstMSD8ur;*hO+uybH7i`~K^L7"krGSX*zJgaM,W61E|d2zzCt>3AWEMiv6#cH:o5&mnQ]~oZ<$ndRI?Eal}e=v@Nxw/L"koza42UN/nHzG$"{vB&&F,7}vwO1+Pm5$DHG~6C`0nf=W[mw`^nM:!c_ElF51m}_>W0:nMZ_YRzT8Y[19/(k0@|"/t<&j{@)}FPnZ1V.3S#,p=y{u]~,%{4L5rx.UB6GqKJkZD%9)YX,e$NT^y*bAVn8|.nf[.bdeJin,;9ad9G9k&O{C6gadLogO.Tx2Z4/KqN+Q0AT%v2DYSsM=4`HEm(9AHEV7`*smAy|uFOrbUbTTK#khB+UoCj%hHY,dM$Eo{D0M3{<tIyinQ7xY_gCO<5U@mJjqdvh^Px$/Ct%ZT8YmjW#sjA#>>;ZmQliNG!M4NBaGG{4d6,[1w@rhZc^>pE77*7Uxo[V^<Hbu+t^KRr~c0(ezUo(|*PGLQaS{ky,Xf,(URa,aWFmC[L.oo#:Wy7HOF6No>DVLNsw{(8XV*IUi;]}+<{9r2QsFwXP@Po>^xw~bMCg`FAbF}k$DyvQ5oAd.#LbW:K1Hb?{YICqgDqv>cV[D*P<%&C#t&F!aid5,Ip+V=3g,&_V){#G<5a:4M5"2t4l*8#$vhjC?,>>$T%Z3IXp1B?YBq@gyW"WN5M+"hjib(_mE`tf6?,"cZB|</8Uo5ECj>#%4zyi9DiU?K1dWh{F3[k31,eH67Yvb2uTSn/Y2.ZF~[%X2_}Lh.=H>?Zl;V3R.K3o;V/1Q4_{9)YgUU??Akde0J@lV#0$D@k1|ES^DBGO;eqi`)rG)vQT,1=5<5=*SC"l76c#Iv2]x#ZVqgi>y4(vatHl^<N`H86}cM0a]&xQfq4!6mjh>InYO9mQ:1*rheJkH,DLbR#Otq)"3j)!vbCNpi*G8[@tI?`lD7[/BH?R$f.kHs93)By+OWi>tt;8Py5C&%@IpGVs~Ml/|Goa3P6cXw"{;Rhc)RGxso>^T&:ssFef.ToQ.:q}^/fsgQ/~AM"5s]MVgi!,=+o%zypH9a@,kbtdvPgq*"Lv`LpO#n2z<C>tbN),{b.N=I=>=L61hM#d16sp:ZUYO0Zui5gy?BVP1uHKVPGh00`m6I*tuUXN/H+MO2t*17/e1wwpgIRX)NfJnP2T`<<U;wn6}x}!Dyf~4wKhH|qp0LN}R*IPVOS?./GTPow<:Az_V.>NsvpN4&ZU:5BMg4v1}[,+;8Kn1*lQE4vKj4y[Gu)B)c@N8Bu9Mdx+tQiwPSg&wWXm=HbWOi3{8kxKS7)1)$PLDl*c?y&O(%~r|+=h$iwv04IeH{/}+jO%*UE{F4!#0L%3,m2KU!#2llSb^pk6y!z$KR^rUqY?N565F4a$_ZJhgPe_V"Iu0ts=ibgwSQ[R!5_Ad|p1_USqAEafi"mO9B`~2q[vY@AgOArSV4Y,u)1)qdB8F[7Yk_lk~XEC>]u@e8t*$)3iFl_BL@!QOMx{![p]b9aBP{F0,#uwa:][EulR(,7nJ8`:&Uw/d_D<ar6?1!#Z@z"yE9fSv]PRcpoW"b6PO?d6Pg?Pd[KrOS5L.ptORz>wkGU<Uz(bcf4he|CQ+P,1,C~(g@S_m4Gk^*dj*+q~:5h0i}t7]p9%2DZ?.0oT(0mx*k2e~Axv}u8h`D/]LgDRmXo~@83emvUFm@CM;?PUU&/n29TiKPXs"UiEvRbIZk&{r(C9P*T!cWhc]x|7]&yf.aB^Et>cuDrG4K~RoK|{Z_qj)OTX.~&PXMT>zhQs~ikmk^[v%T+L8(HQK,uI%t@w07X$(X)@F]om<r~DG8Z6?,zv3I[!v29Hi%7UkPx0A/U<L>w#/S]EHYZGd0AXz^U(!p$;$)[c9qtVp(QCYqVHFE*J$0b<8|I9gc^`3z=cDU<u).x4AkKjIs|S[7y?hw`g5hdpZ{.|)NoCnzITIW~a27/zSmD(#*eK4lxu]O_b4m3>nt4J[iV.,]l};B;U5Rs*,=ROYkcF7<5kVaoV:A9Mp3IZBTy9oD=}UZ*Zy6d1uhs,Kij7=h|a7%K.Bb(_D1{qU=~I9@zE0Z(~knr~QhfW@zLLi$e[x%/eO|Ub%@3>K;7o5|H^9o_](^:mHFwrq8qp6ozYNF=r?K"gn&0r}5`]5^MG7AqL@NbDj(Jj}4F*e3JU}34L)K)q"&$KCUS=2p){L82meZSI4$e~rL2pik4ipUndt/fC5Pcv60uI@S$Ft?xchG.OK[?E2?W>r*7C*YCNZLaL{yLL]M|]u%7:.LS@c<_bF|/B0iS<aXtk0mrUCiXo,`PwWb..9=4nIiDKw1Df]W7a&c9x[`(mUDDI*1$8ocKfWY.>68+p$gj+xo9]k/G!.wR4q)OR.FD%WgN%JNXzH`+m&t64qab,OMhv_!EgMj4E}]Z@,jq?a"A+df]5x4OvmVe5+?GY&BLII>0S.K~PX5VKLb6,AvST?i(01tVOolD#,n@Y0Jv@%1!woBEV1u~OH<5glJ9#{d8F&Z6tmFbWc5bnd8Fa6!b+lT3B|NwdC1Io">qhVnqKYN3I3A>AN{{Y0t!grJ2NzBcTQPe|19s#RzS6sB~z(!kNVbV6<INm+.[$nS|Pxc7$yQ%_(LTC6(.2fp>uMRywWC%j[%z]xJ"}A9j+jZXhbRJ(O)f!zKH4CeG6KmwOu)~6~[j)[nZg!%d,+|*(le]D!jv%/$$v5&7(~!c$Yt0WQ7PHJO`@z=%MQ5:#<m>.3Su,xdy:&FHpUQ,E9?T/+0ISueb~ck$p<b8Lr$5)u~q?NzW`8wf<WeAps%#cA.Zy=A|o?7.;C*_9d=oc~=rG"hiT%!dlu2%Rj4{7]#$IrZHiBxCU5~t{zX"vl%LLISeFN{dO4@0si+]cq&a_E;hDzb~zeqONP/W#1NOg"#TR.Z2Gr+3/*.:u5Elle>?ab?2HAIPi1vL|qYj+U/`7>(qN(%`<Y)+*1{66ULG9R"li,`{b>#9F88g&h,N.M~|HRN0BLv6Tr2vZn::nimJV6OZ[obAsbpin`9fMon@pvx{k|"d|cZ3zfVnv^E^IeRoRB3WxC*fY5K5`=I:CL5y9<#R]|,2%O~j!5XU(>TnqB;)uSHCFez;mF!U/Rt~)!{/CHdp(MC5H]U#%gU+vS58*3]w(fyH6^Lw#Ft[iPtS,Vk?NC,iK=xQx_nk0wG<2k{efIYe3Q0|x(J^FI^%s3N8Qd;o)=g!5mTiW5bTU&)=I>/g4Iz1kdwK3QeoIR[GVQ{"x$&crl`+p,oTCX&^jyD%726">b5l1C*s?>y.%ptQ:+Yg70M87=@/gt~r%9E}qvAW2.{Pd=OX+T3L;j3kiG/#4oN$x:Zj0IOU`%=u&wbO5b0`||!K5cD=+uTRIFl1:JzsLNv0uK42ya4VQz,d{q7K"u!]_)HD}gb"e}=]LT38O]K:16sAAGhYR4zoP*n=c&r4@(@LD;!&La5lyW#1FQvI;.tZyM@WBQ[})rk&<{guJ^xarQ$oao5jxkNgT;_Y5x/R]^>;xZ&^8H5eMKPJcHPJE#PoAzAl>73BH&|Stl5t0o:@dRrJBz]QY6BI?+1!m1b!.x,RM?}.:17_a|{HOVz%f2emFhiO+PDbq/}}@SwKOapHrEZhToHqEpF*ja&+CAe4PUonaF<eC*a!7mg)VVa5vs=re[$px$8VV~>y$WoHFn)[P5!pV58"65LM/LB=|)7|4D/H;1H!75])2|/%ZXPy$,=J<itx;Z3/;L=f<tH7pJN;/s/5_wmir*H{3fz>=F]2]hkem!6XQq)[RH^5u/.xYq(IN~o^f&qd|iCbUSSN>VX[(JxLNrI~la)zqa6;7/ACB~]]dR/U5*<bDdBryI"K4lew%,D~@[%L`MG9u=Il:Z(}40=<&2W#{QnhPu&s]%U4aH~}/HtT$7uTQN6S^V;^;pxJF&|jGul*e#R=35]r`[v.S:6}*|oZ<|P|O|gx=R"bKkpp/7HWB^k8WSB`~HxzXj,%4xI1#_o]MsH2{5@})b8!Jy:h|<DZlF`IwS/Bq5oKeaY;2Z!=0!44)vX_8=J<V`]{wYroZZxQ~yB8B25@$(/}Ea&TEJ]J7T8GRd>U=cQ;&jD@|#|3Q{ni@p8.RdwkK}kmFJLf|oLmuO[x#^w,;O#!$l65;/ii2Tx;Er1UUS&N/%049%12L"}Di3+030fa[fI`lT%aVdz#Ua1WvI>yg^M+btUnj`tsR:)d1~8]/lu&hw#,%<jEFwhJ!(,a5u+|:u]N$7}9iTPhO?crFAD"!l_!>m*C}C.JTvdltZ|}D:XIT/~Ql0U[t/ZbT,xqXO/n1wu"BddxH*lG|"Dbk)Q24p2p/_p.kOq"ecuN+[pC&L2(*~(]_adtRE~J_AMQUJ_$Xy)16OQl&wsOc)b!iutN/ObL4s8X7kv>(C5^tbq(HUh[To~bKP)v~+s@?x>paN(2Wfr)BI(99F~5)PyNUj7];G;~Ai4KA^4/puL[4sz?zJXE4pnl%O2Z4o$hRM*/ko@jmqCS;.9TE*>*3z,=dOoTA]xc{7DB]`NzH`[$Xn&*e_UObUm.eD)hu4$LCOo~hYwCBj[PKiF6ISxRNYn./D*yIo?n=&HX#:Jp5NSnBmM_.;bv+%znoFo#%zN:AOIrNg`bbA$nY7c,H<;zOwRPJVe,NyE}!/98k6(3FLfhkGpNB8J/||XnpcsV0sSGE2o>`@=d3[:M6={bP@(1FOq~5*5E_s=Qf_X7OeczlbI)JEeZ)xkMr%$~=ylexSI*H9D+*v%pvFg:nf%zl?=3f$^?sn@9:8&}CLBe7Q]51F)]deJAZ`3lrrj@XyI1WI?Y$76r{e!c{=oCT4cnj<iLJXS^{d:cJGaUD"ANCZ^A=V6KoL"t]#U^9JZ_jP]3x=!#$yhw*cWqvo_l.S}:oEJ~H/lcBC1|TG7|,}ScNI/}yf2s:wj]v8C$j3#6y"tf+Xg?"doGU)|`_)_yx`N;/Ed7)x1M*wJKN*;LY$u7dbYVbr}+#XJQtd,Q@!R}uC]W*bB)rdv/GNXQ1c:u7[w13hr&rO}QSIxk+P8J[ScFUS1_9?BnQN?CD<JHfa<)(beKi;;W>@nlAzkKE2)rTv%bxq*D/UNc@k~ksRXJp6SHT,<EC_>:/7E$B103f{Ny#mm_op97rg87c)re.$jwemg^JG>CQGlX8Aky^Upj+U@=8Y#^kN<,SOJgA8VJIdPdvOF@*Re?@/O|d72W+0Q}E+L}bU#B&D&H<N_!Z/@d[q>pJYTq1VIzODF8@28LPwqd2jgDO)%MFuyu8;(r[NCdfvy$!+NN$<14]a0Gail3<>KXQ.7I]Ck+n>U@cQjR?[Z3B(B<)sStu]z9{ERB`:0B<*r#Ri;wc?wjJD~L#7TQ2%*qLUq7HRYjy0w#n=NYEEPok+/#M&!E{*FDPE|X0]#hxq?gZT$MVd]B>>2NbtL,+?ud|sP9[AGB;6OeLYdu@da.r&Y{$KukM(%xH75L58%H`lW5p)k20yxg/~qoAss5J5*)cH7Nn;/%{pV}*??Oglgvp;+J?Qjwx&7B{;Zv&KHNj&V[1/aE,k%5G@cRS/>{L:(l?;P7On@D+`lqGdn59qpE/*!,{44z5EP1r?|)OjN,G0s8(c6Cjs56{Dy0G6FAV#4ZbW$ZYz!<5][9Zs(6aLbAEp>lwiz~!PKH?]W$EJcLz;i/`"Q"NdMaBj@hQFVhQ=5Xqn|Yl#v49^m><"wCZl,5m=HPvKM,j)49c.{ol(l3?)7(rxNQc:<pJ5h:J+#^wDSWaXYN9hroxWZCNw6C4K>FhO,mkPT?S)B`*Mf[wO}SSZ^uVh?YYOklt+L?3{p#[uR+0DTrjVugkQY7g,o$0&[z8GV]vi,@38QK5zqH1h_kz0FQ4:emn)v:.{s*`rc*~~7@Y"N[aBed{GZ>H?UJD)?lIEh5x=J?R!),V/;)dHO2&.dnc[ie8xNa~*.oyTFp5xj;()g_]Z%J2v[Y]B^Ej>k.U1jh7p6[!}J?hre.V_dn>Bgt0XYBl|k>yQKA!C]z*/X~]xW{Roi9ed7D<_&?MCk^1tQ1t$j!ra.a?*.u9MBP@4Vd_SMOJoRz[W:Wm!3x(ofLySnGG{[.q:r,h/ve?1G}"HXvXc4J!b^94JHX%p0=t><~?&M:U?T"!jFhBQOZobiqq/J4^qe>eFSvh3>3nGIAnGc44TRex0N$jwD.o79f3)R?CKEegm:O}AQJ}x5Mu|&R7#(oe#NbT(ab;j8/5E>axHYW,rol^Iwlu<|/:IfU!(*p[p$?#i+&po$]TeCTMY:2%MJ"A.UKJ/!L,ecu&X3.<=u~!~"N2r:E^"#Eo=q@3NvezP4|Z2*v^5t<i7ma>FWO.B"*OVun)f6A.c=8*}M/4WuV5vM/=MNNhajP=ZmyTFKb|2u`@tv8G.1*^i=nJ;(cqE)zp9Tg/&u.w[sz1qd:.1CDHA(0biR.g$8py9`<yxWXlS.~>MLI41DcfYMjPP?NBB#S}BGh)M3NE?*+FUJ^bx%RJ{faO+iUN/e?T?UlwjDDU1zRK##pktRx:{md8O|qE9I6k%)`5<c%w_Qs#liHk%:0zVYFRj7LV4Jb^y_ze!^p)6t=x2pwwuPpM5&4:1*%lvP1z0lD+u+1xe9bSx?ORXCX>I/t^6Wyz4^h<8iR1fh?{)eTTNl,*b)$q#NcVy&4c7E%!a4T]`e*es;g_oTOr0Cx[tHWw6INiZ:#FqTQdFr<P@#qAq~u<z$}AGM`eo4ep@xFET}wDi01VE=ox[D1#%UnUG0?3}zzDS[kCg:pTtG|Ud2X{@HqTDnk!x@:H:af%iv&j8w7/XgS$Uq?o(n9ieDw(t0Yhi7:o+VB(W]J+:yyeh*4Q+_B.Z7kr"PQzt7@kV[`s,C&IV8sy.xJl)$I9A{0iPX9w_c#V*S`v,LYLS;$5#tP8$({FalDvI[LpH($&O+:Dd`GJ/D8H|:xE7%#}VItY[/0q8WQ0.L{P=xF;?]=p"/p@AW$0#gm2XHfcjpum#OQO..inP#phR_Oy=Oc9dmo>P,Dqup]IXi@hzNlY*;r=bIz3G`qT)Rs/%~so^}g@?4#?$+F@S01m.Lw5@CXG9?06/x;m5S[+/50R?(r:/uG`tEyFAqjPR,|)^rBQ$uR5o&vv`amlTauf;m#]e^8Ls8A{e^X<kn_q*g9R=Y3;^FQM*d`PVD`ZngQE{>%~3l{rL4]CBp&1#ziw@2P3]Ga?P;M/$X}(ceC3YH$LvB;r,mGl]a&EW!$D$z,sKA}w;EFYQY`OK?aC}BmC^*yTle&eomwp&+/~)&g%N+8Eqe2t#b[P{=h&tzq4HOdUfzr]uTqD_)`;S7_l<VX[uc[thkX[Jpg,ZC/FpfJiOA==J<{^%rR,0=u3&wN`FX)f/Pukj[~(h>x|eUl=+YjbxHoZilTfN?Tz05H=?NZjY#*;)siH_@lKp6H?$+JK1)Z:jXMe)4UH>$~%5CgHIueQI|Y?Jo8?kn;/u!JpK~!?[8j};Uf9r>_M`KONAsD2~PnE*`IVu4`/K1H]&Ivjh@Rpux?ZZ)|+DCBup~D4xpscy}g)*gVpGJF!Im)e%90ZLl"09;WG(Gv9>1^#j^Kg_n6f<.0GTgYiim`MOe3+z^E;~JmQ(<`+~b+?Vj}$6u!n,znG~HYm$nl0~yfcs(h8MF{~x(TaiOypkwE:$4SrKJx$>WI)SD?VP]0lPea)_G%*jC]`f0#nWC}/sQH=qG5+r%Z&_S_w~at0A[),bpZX(l?*Z#,8@g[X;PXbMBX4,k;=IkqJ<#:*v0Lyhc_|cM1bNwW(%)tB3F5*NwZw)_MN(m_XxZ+HacQ/jK7b,/|UytK0Efg3rr2n/mvWkU!N"VwG<e=ba@%uqGWg]@(R8o:"xyv,DNKzn>p[|m.!cm9,N_v>YDeYQYCm#ZU>#Wmp}jKVT!~d+P3=<r0,"lP(rG~{/[}1ndKIdf5Pnla@Ofu><xBf9]u=o/Or&_3%lI`%xs|!L12,`lMS#nh,=..@xaDoF%n49ElYGH2=.n8|MC3,&&Y`}xNFYU_mH21=@&k$x?pMMR"r0cf#4EN`D1>t,!MN<ni:Oy]~!TWeQ=i!6Y}:Ea@!LnJC/U]$?|R!:CYS*=#pqBhox<6y7{}TVb2L4S,WkK.:ww9Zv6)o%lKxWpI9n@uIJ+hUWK&_^xdb!@m}y$I~D*:<#7kBR`d$(p}.T|hP?8ROyzC,5LNzH3uBv;zo$W`Ph7KpZo3,;9"l~azrXjs^1&wm"dBofW$qpmZl?%?oF0*bO!ZE?r!=y`$t{@J|R4y7%~V?:b6x5r{+rCl,+/5**y3f&2utnz>utK`qEluk)e~Dn0?fkp5T%}e%k`<S(#`y8ZsPD3<d8q%o~Q{T6{(j4X_}G=m5WDsR:Y+CZGFEu.nB<Y<c/P5l7SxHYby$D9c1Zo`&h}~,n%,6h&u#2}z+EfJ*xC5u)K`lnz,1l=3.RzT~#@Jh}MZKx^8L;A"N|I>+T)[TKYKbUG(U~w]cRp%UaJ0PF#Zmkk#?/wU>edKZvI6+U18>Sa}~BwV_@(qibdlDKpH[5<gZhL[PPv","zgyWGe>0}cLw!k}tsX[7j@VFsmHQV^X3%6Sds.fe<3O+syb//R=V!(*q:[I9%=6Ox^s[2j8.3*px1)?l!k#ADjimCv^VOqqi%G2&+=)}in81Qe$5bOD6GSTFj(rCZ76%Vp]<r^req.}pM^s0F;0N5a)nHT)q3pfL>e>^l2z,zSW$mx%a4|L/_}?`KJ;2,)U}|Bxje^!L*^_{z@|Oja^RG/jWV431g53N~rY0r2m`k(AijGvs_.E?_6|t9hTA4soPH*BfJcLK+e#DyL+TuE{+2Owv%Zqso&Z|="e;D}wPnMi37j)kVT$#un#HR%byv|QKmo_}l8_Qof{K5q(mWyG]lsSei&6N(Bpk*Ya5OOc2WA<!fZK0:N#.dIx~#]%@YNa1V/UAlOnK3)O_wlM_GB^le/{[TBC2!u{$s58;Z!KJiGSH}G3$tu2+0)Vc,_K+9Ml#NUk:jsR"mW8L?MHH7ddC|9lv*]5+>0)3T7K.ekHC%uKT$3F9CN=)aN:t_:@s]o:F9|7)r~R<b?Z7qu@RJ~a5s4M9ri85$WHmC9KEK0Qi@zP<8&kp3o$*QSW(V+36;e35MTeJLj&Y,e@rC({t,IzXGLoDxhMUu@V<DJ2>v;r0lEQ;Rd}Z8rC=^3n2X%q;Co}g]yCDycAL]XT`%eL/2Pczv#cxsv<BW6cIDLbjfr][I5g?;s?q9DRJ@Gb{d,r_i0=/nv^dJu0/3R2!_R&X2#P0hg6&4zpG^?<qe3+Se6~:0&~GnD~B{Vx*wi=l^~o%2:a"8vOncA`lWLf57}9xrNw1Wd@+7q3;Y0.tns$d*7%~yal{@&gIxys}!d;td&iAk+[>,dx`kL/O$~!9FLEz=F<"u~7s8$FcQPuW?mo4e`FIEG5#p<B9n(bHP2%kz!~9E[>YprgzXtZO]MRo~v&5Ng,01z#jjVj#Q+Wt6y+Yc/NZOFiPfW<oOg,.Z"^0<fBsW;]~${fEv%f0.h9"odhjZg5oL]VJ>y8x^y=Nq&W__*D0HZfO_+xZ*yuuW"t88l=GZuT)YaD{U|&7kiNufalr:)J+`+2rj{N=0@0/zQ@;NWTlS$nTLCc)ikztR|>c~1,X$4ra2Do^Dncg4Lac:xhI|~pjd+J"U@;Rv#=oNN=INSMyXKAH}z&@{vIUpB8Es%Y4`6w"Y?(W_S)%h~k{`rz`>aGwC]YC&O;^5T)+z!R}2dUw]0y:=&)!{0eCfT%hDr[e@fO"X8ChlBb<K^p)eS@jSdD%8`Y.X0m%%Zb}or<TEo328m?KJyg!_afsdeoEue*#o3h>rypS)&vTLvU2O70r_LH&40$V[op1gD#Mq37[}<#EA>o1?X8CPeIszw{E"bFP!zt}p;%o~`)[Rqx*1AW%~K0Vs;X`qU/:~yG{vKyasFs}JibwoIUwQ9@[L1h5Vw$1EmpPE92!_&Li<5CvcwbSM0DRj_f%Y9o[i;PxdeE]tU,k_l?w)d~c7EDX<E|Bm?;f0[T*1koG]JKK>avHO(z?6GWc!yzADpa4BP!sg5Q;4=UPOa(4F{K=<8{l@LZq]}ZO/[eo:{+bK>gd9L3ey2f}Z{23^y95d%%_&[^OYV8#lcIo5<uGp`NBje])!668b<Ij{7M1ok[|%?NaJpeH)t&4/|k_Vl_h>Ak*vI*];BxDS~6_|E&TD$~^`LqDef=.aeeMloClAWZ0N$bPCr1q+v,Y8^:9!%p_WIxPd"jfEmru#)75L|vu{:v0efxMO^]top;7#XNh0hmFjR4"eu|oX^}=&6sVI%$r4}bU|<dCW83)]g&Tz>9j?taQ!d)W,"GJLME[d{dsrz+~:/]*krEHota5([8#3Ut&$v3,9NG.yL&O_v?CC+X];L9gRd#,qIS?*=Mup@hjZ7RFq8QR]7kY;M+6M,wg":,?;NDKZZN<?_sJH3rQ{:m%(CVgZ;y/hM`fgWev^6W|/x.69a/,HgB3X/VOG7da(1DmC!<BP]d]:.@g+q(,5o),S,R;U%5/GcX,bzDCjoz8Y$W*4;[0;N/g&ociUgk?:q=aHR<hQy;@+rM6DdL!<CN)Ts/Bz+N&YUP)xu>]gYEW^AO"="9:e~NOixYGO>{].IMI[[v?;)Is?;qYG<0Cr;5nQ%6BvtclY)+lp.2=i"ZES"fl%|y]ZK135(i6"[]mX_3mD((YZp^_%rSS4KB|:O@0qmBXoFgi|}np(?o@(cT`4GiCUPnm9"4[c>>?*nW6RJF=M#QfJ!d&+F;[J9NEtXDr1gbx`p2/{j9$4.;Iu"7bpcXjr<H_mf+7{cwlTR[LR5cb<R,<E5S:ZYp~w~ebv#Fcwd@?@5]wc9eTVPU~+mHnaQ/e.7qtI;BdO_mzFzh:,P~Tmzu37J:nXXGS,,C?Q`_)1kyu){imNCwmdv!MEF|}Xd2+c:V6<3i](x8/[8:PSh6a,Rk[?#Vu%{uUv,#vwU#eMy@DWQpWQ^{DN{yAxc|O9zIR)RFS[jZi1F:F9qo)U7TP@[e&j]3t/PUYC%,:d`T&hO3eQOhDalGmr0U|o)v/)qcvq"3dEKmJB>_oPlg]=3#DL/h:MNFyEQS,f1|gwuMrOM`AULm!*DB/*"ux[;]zKEXAO}$@b0),=GgHHx^<0"C"+SJ@)+%_qjqv>WH##VC;eu&|FPaMN(c{uDQ}&5);yH`!1[,Dcq[?:0[*.MWOw,.05hd:Me*P8ux2.86xpb,.ck54Uw@`qRWUwCs"%A?"c.?=tb?"lrNB+6]&Umg3e"v2/S@~POM+Jco=>7]tE7vm:N90yJKAM?lO<J57!lT:bxIBfaZZ?aEy;P`"%U5=3K.X]PRM(%kKtTHhISgGem9cFGciV4|?zz^X.EPlgBer%`IOmSS^ss*1)l`7m{BZKI#5zcA<JZ&LzY#9n.?Nw}2f3;?&tE3+]U_Pd~ClF/m?v,e%j~bAnX%]B|jn[H%qH3%I<Lh,aG(;yL/&(eyQv2HF(6oRrhH>$@_f^K49F<Z@M42!Jr|VkMgXPkP[RF99L6cv>ksKeHEd2=cRMl>|"N*`9ZL6?sq2n5gD8"m#+aLc`D@|$k@)5]SbiN3Ti{d?vn:k5!0.PIDeE+a?9N8)$z;Fkc<dCXH%37JLG+@(Hu:AETQ@d]Cr";`K=SyVtc&vqb.aRw|xG5*!P0zdKSGoDBQ^%O*2.qYXE(9?T.fOEgKpZQk@QE0lqN]}#UK!+33kID<Mx@ax8OVPc]W|G7yyh70%y|V].;sAt2sz/=QmtFf~bb?nCx58~.0diovs+*KT#oY?Zf:>B/Phyha=w"7aB{1iWbq5?G$}K{^M8GmK>op3Oe.[2wQibS$YQIx/lFgaFLG!YcOtU8m#g1~D_M~sEwgDrpIvDL$NWm[&oh6Yj*tS87r+=p5:=?$$Js9"@ajX5M7OQVF7zJv(0H/lzqLg{2z9Q1CIhC{NHScWJN5i+"nRTma,[4C}dw[o4lg<SMP9)|Cxio0`hX7<*?H8_,j.0wniyV#J=&c":Tw(BH7HX!X4w*Pbdy~K{[%Rs6~%F&Oj:q=8C71N6a"pE&EQJE$e6xxh!z?2cl92hVjUV1Bl#0p69y&wdn}*Q=%rOn/ttuJ[hjDt6)#Hed5ygweWVnS}));Zg9UCh$Ei.]BJ[A^2_BwGIK4U}s{7;IYaRI8obGVzNA)}d5jH$0c~hMm[F#x&aL/b*>bL99wW,KXij_[XWS:FQ=)w$46V)hV2Tl&Rfm8]R#Z4"RLn!hZwr{UZJrSpS0N]Pft6`{d>YG6Q>{|?rnSQqrx7T<{OvO=EIJiZ*iQC*LU.{J+bygM{6+R1nhH[=evV&H1tIE*&ve;)H||Z94Ucn19Wpz9=D*C`b<.,9PET8y$]3(`YrfX;%t|:lQf.3do~kJ=%sFBJW{Y|YIG+6E"Nt~dQhKM&!yhtboYL{"Z,<6I]i7%&EK_,/_hQM}pSvBwUeQ^;w1b{b[VgDZ}x5#`o"~uKk%e:Z/{)H4g?d];uD^p&3rS9RZVodX?+1`P`o:s$)5bR{B@pkx,rC;{QNRG@cypVZ#v%5x@z&!{p0vRdP]KJuH`B?|dRGA9<4*@oNf/zop*75.)V?|i{Bu+Q4|x6oJi}gkFTwHYj{P9jTah1RhYdC|*o6S2^j0z6a6dVIF^E}Fi"bp,D~3Y(6q[|:^H~6{R60A1/IY*|*zvl/8cq/6I>B;%RB3R{j1_cO0|HyQ8]4=.8(dO_m/qw!]QP///sPRbV`?5Y>ev,[OK+ovV{*&#Od)+;8GN)iJ^pLQrLIdSqkR)ofJ@iNP%,_,;RwSMu}B.i>;uVj)W%xrcjqLW_&w2(wOh1zZDV}GRN$_p2)uF+D"X"`;A:x^E~Y3kFrt@T7H2z02N*$<c1W(DNZ"dv3b5f/HsyP*f$uJ3(PuM^3z]e?,[[}j|;Xd;ZA{"9KE+<%mZQv:Q$sezp5Z`Ui%0]R.Z*Xr>AMam(KBM}Fdg4c6a[N.!fu7Ad*0zZJ&POId6}e[b"ha2FirY"MJ&ar[|f9VitwT1~=yadH.3$m(x11Bk^/Ts|X(hl#3Fq3K&6U5@[;fI7s[^nKeaCSMY2:=ZT^5UE^Cqs^|iKp7,%7n:}WkmdymVUmX;?/r?DUXX%hnW0t$IE2rQVXAMFjF7[!yJ~{$##TiJux!KO/H[JDqjo=bvhWt83[$CWVK;PHwVMyews?KxNEd&)msXNGaMcL?N)0KF%2P3)H84;w*~.1JDC*D8Xfi(r`kOu@rTZ~Re<pk2z2).||iQE&urKdvn._OGls}B+u;p]ei$y@tCuX/VqH$P{gL"n?JuyN;n&[v9[!c>=&m[]KZxMqU/MF^~0oq}rrPG]aGq5/Acp5Ur}>c|uz/9#;xjsFV.u*:IdNjG8/@Z}"ha<dS5?IZ|wL1Tz>=J(%SXdEoNjV}2_uQd+?/PqA#QpsTin@ulYsKf{e,T..U@ZW.o*1V5:?B%.@Ufqw%^3v:&kx#)26En6<d?ELCvWnp^8vGdGxqeI5A<[#o01h49yx!N!Nw>4dfj*gp[jO;AW6yg~tHF|S4pP%mTd.^DyJ_|v9gx_dWGC%7[);_Km7G)K0])NGHEl/oY.{SWku[b?[V/AExbtwX3D;ur~F,_:bT*`i(s]&0G/Z|ZhU`HjtaEGLQ548*=u%b0OsObK4jo<43[V,%Ib=iod`?jWkpO|,pO1Cncx8/]WH2Q"WgtP`9H84l>G29KW9CS)AEQL#+1U/*bkXsXpj6<2mEkEvfLlGZ;Ih{0gavVTWaJl&Ij:T83%F9bq_H~e`w^cK0;Sd}+z:7lArc@5$b69[)oHKDoqgMXm0ymn%A_rc`D.vE*>r*tt1C8?)*CEBKNxwtXRnm5Kw6oBRxe,Y_qUqr%6&u>#hjVR^vnf?A[$P(^30Kv$<!O4d9y~g>XC/PFS_&Z?J23J^u|*=t[_:3;<0MkpH7}|SXC"o~*6F=i~zaN5{d8Bd`aMr(.c]N`1PS&WrHP&lXivL0)vV:4dQI)[kmCQ/BjnghVkL8/Z`hr43u+<][?PDSFcX]uj2;aPUjWndh(LNu7iF<uUiram,BBP!g;:E2m}x924gyF]b!H<`|fivLx?R#a2F!aR.&d:`VlE)^rlNZ^jmGtG(B{|*MxY{tdNc{S%)[_0tp}p6W:ulpVM+2K$K?V`q!X3kx[&ZsCy?AN/]}]f!ZU,D)xE0,oUY}:z1u$N`@5kJ.J]t}e4edos`:nI={Z:yp+0srNQ}o6_$JMv[BOS,z"a".5QGv71_ev5W$N$jx(}OTD@M<wIi!<;*|LuGRv]qxe,r`i.f/WA~}BF<yv^UT`d}q3w4k$W)6m0wh9QE<0~k_=B;k88Z&3[#hcserb9},w9Bi~Ne0?fZ%9<ArWHKy+stneNTQ)68Ik7Y~p;4hf=vv~%.}pyImGKv,^csj5/CaH9SUk^_llPm140."l#]cZ;:enr83iw)"<VRh0,WiE*|NIK0;B.P&8)%Gk+kT;!]s]]%L0N_:+J@&N,zYy<IpMOT>UUhLU;8|Yhg3$Y",C7O0w@s]XjsKNd0S1gN^4#{`i/05sg4.IGH>Ed,F;Xy"wG]XE514<}+uroo&#GSw_TSrWBGEjvuqjDVJdBPV2b`$|sL1&R@%7@]L/R[o$U*9yk:zjc}.UlFtn,_oiFP9;_{}nr0knfOCKU,0Gtm#nOfL1VNO3n|G*Do9ab?ZTjVWwRb3{)3i>(G?ey5VbiO?Ui$~0:Zrzz(`+lnMOe/e5^uc/HqFIpberQ[qf`Tr)&T~xjg/O&_:#QdHCW"y71.llH)(=d"KL#7%PM(xN1Cb.NZ!Krv;+$uyCC|snt^|xeCgC"z$CMF?b%N^]HX%16HK|JLYN,}cWwLY{*:,sz&jji~FtVv/nfY9NXK+*Df`9&Fa%o:,?SJoDCGQl)s,gR1.>G^/@n$O^gT$[tp6/0h*9+Lk,7MJ{R0p84)6ylgL<k3hlx7ZF<^#6()u_pi]i*)*|(j$5gkdi`zp%=PC4QwYkgzm;~jjb{puS,zGl/+Jh]bis,x;{cX/2|+_t,]kxjgQW]lS2inf#5?;j_b?ebw/,kE8hhf,7|Mz#EcHZ_AqqgOS5GF;aV=dHH8fZb90H&{$Lk:K;%0l[{T+}MQB*`gK71gd<+m~k[Tf5z?GPlR/RKqC/&Q.]n9%S!gu:le%SeslloE^7R4~=}"Ibk*b=JJ(_M*PB9VQ[pS9S(=]K+PcN(S|C(wQc<hLhhOFX6^E3!A!~Hm,Gf!`1%trr|*c&dMu5qUaDeN4[,c,u~u602T1.rRI:DWoH6?$TxwT=?WSc>you{#Bm.[r1|g^09RD,an[R2M*^kt]]mY&XY%08`F;o=FHsh=`*%{g/8I6w%ykFn_aTU~vWrVqCK.2TEk$1`%dk3%.^YTAdBMT!CH!dnu$A*(gONkeEXH^eL91i`<eA!vC+c$(uF{Sc9PY_6rR#GI/.6:2gL%.S:GKuDi|I0~WShA6MnVFbK1(xH,w(u(2noVEOQ.;K%IN8,Dc?Tkc(*+s:4dM6kxQn?sv1}TD2OZAVppA!|=~[S~6=ly0[N&,H?i2D".t>~(DPvA.S?OL9l)2vYq?N5[~Q6;68kFPYCW7DFM1x3U<F=n<K#=f5LxLL{(LIg+Yt1}n!D[cLA$5RR2qZW&l1_/qA2t?R>b0VMNBVD!E@Kg:X^Tn>38ieId:aM1)rhH/?mgj7shspoh_8M4q2kvaN+,;a+=0u~t6>d;qo"we>txY/xAm0M}Eo$aaHYV4~S?@345>.qq)52w,z^!ca5ru=)[8S?NpK_zR{VC`,|nPv1(y$k|g{aoYU]aY2]ez9;khv2<Dm}#WoQtNTd4ZvR`o:OzW$5PX(wfse?yj>KRt>{?404jX;LbBu5x[&muvCQz?:A~^g]:%1FS=qcS)+`$echelEA8iLYO+y>blJ%oyYCzQ4pg)FGyk=&0op<mtHsV?6siK@b)$=oO9np_tWqp98s@couOF#eHIV^`u^_uKs3,5D{kiI17y$]kpERrN`E<tuThO27|bEf)|q>]!GZ4KC%yUsjZSi309,S`{:tD[ThXBCRY{sogsUJO#QF)y6P/3+uTaq&/E_9uaBV.F:]r9ZUllYk_#Ts/i;o56|6q5+;n$fM%[{gt9~Or@]QPp+vDq=+r,rY1GY/:WCFiC+f:[E5y*ovQDGDXAx=X:!Q,_MD5ToTz1Q9,PT/sHMWw<kCTuYotRX)|g7YIVKlD/5N~$LMMXK9UJInLK>njO#atF8ph#k#OdjfXar#gQ3:q<poQ2WBtN"rPcKMr!(eO7~Kjq/<X!P<UQS]Hhb+RQqZTyTq^BR@N.F/ma)vDpxENLr2OUr@vgF"cxx"wRFk[|}"PZw/</TJ!eO9@Mt%igSwR`]|T^x7U*.={hhF1F953$$kzF<{SV17N^r2J}ECKyhaWgdb.<D*}iw%Z(VU=T2,Yw|D*>vY4;k.gi.:fI_D;@#t4.euC>y$s)O|IYDM7z)+10=O^GA5K,+xgrhDoaj]M"_iA@_bO@jV5XHN~ovB3HL4<of;TNl"V1:%e8r#GMm]]n[QIeyweo%#86I+,kBL>pEBGfK4E8wN|36,t@o~7glx]>&:C{YuD}S8slvP}Zq1b5+6pg6f%a>7xH%+DO:e*VlTY7IP|Y/%H23|REeZa_qcA^a}%&Jca.ahrH$oHb@sU+vCz^G5Ci@HX8zRwqB6%#1L>q]<)`8vX$vdVxA;Wwn`:bpH7s:,QtS*.+DI.{D~?m{Kw!9p}8Gu2@*M@``wDyxtrCyU$dE6`,LxXT5"|fu(_/DRY6<6r.8I_}?E2R`Q}FV_b}4NrVuW.E[;VR,FW&&|?]V<113U%A^N~Q9yq=^So<<;0p0}O5U<K`t|Pue2m~vdCS.2L+)|!mI;CILS^>QCVS)}:vI=Ib[)d|b$;2_5N%YKMhh(p]a2.}q(2b}aA]LB}6f63DvZ9>5B[!B>~vt^2@Qo`"on[<;ykc};3MvyV&pGi4Z[Aqo/ixVY2xVx2B:>"|?~wvi";Mc]Hm^"X[B;#[oi~K))hR[=qI"_]=HC5WitIoW%h9i=%5pX{73J4dILD&^hUq1<ta8SXh/s/pftAx{y]QH9X#(G^N`rKl4q+*{K`)O_&r]HwC_8#c!@jMt@)JK0Z~P~5+}/Hsy_/i]FF$z7iv4fG,KzJqyF>C}F)421fQI+X^n^yr0l`uaO66`pFahe&%4xERp825k^jKx}.SkND$fRGN8lM}1/t_TvSczdS(Z9+{MyJqak99J&b0#_&t=tHQ*N^rwi!6(yPgOCw[1IYZq|f1:3MTN0+`Tt~v<br;[o>[?NxRDv"R;O8fC2rbTh|>Q{|F"9bVuAds#ODS=r.)D^b`}D:*R^81}U.>JqIW,jSZ0ZyxyM4&5L3OuoK;USj>Ct0{l9QCCOGXhB97ev/yZdz%|`?Rpyh(Cq/O.w,|j&x)=n]izr4]B?T$F,b"{Bco|QH]8hEx,qH*7V:ew"]DtazdCKgK/^9xiGU/Zg|vvx.tx>jH`R]<9TP1KCGy}x!7<k/S9z0iy~_|F3K5a:bpY}Co!:ds66x.!$6)`2UCQqi,8bBQ+;t<IUZWNUSg=4FT.L2Yl`$=3)m4.pk^Q2V5g{HYa$G((G^kJ&4GEJo>0|OG5=k}C,%?@d~nauCW3{[^#0dp!qShHAgXnf^*sTOwgcBjHDGe%R].:={[^bps3L9)n`kNR{y2oO((Uscy&2ul2t,~0Z9ok^(qh"6NC>kOB7Sw^`u8Z.&n}yJjIHQ=QH`Utv<S:Db+0H3Vh(:HIFV!.i`E*jD51?|T}{/@7f^}ROpJ_X6uli;4Kb&ZG7Dqjd!hRDO}A`+?E1Rjql|zw:ioCu4.Cj6q@{%7cJgv!lUVvF#TBqu%Wjtk0C]qO%w~T4NRQUkT7yzyKCYj~?VfR7QCvJ`]tYo+NTOvUa:teoS+&)wVan:A,]Ri,J)~Mqo)~L[@gblbTnaqI)Mt,m{I6wX^mF!d0D=^~t^JnBFIh}:3~Zl+q]wFn?`2CRx.OHX!umP.^;lF!US"Zj5bY8)AoFH6HP{46>;y%:nF?[C+tiD8;%@L,]ddZvyk~Jn4C2f:e?93_OAbl^V^sH|M(PYVHuU&7+eR~=rhhb&*<MXO#$i"kqX#c~mL1Q(m>!!,yyUu<cYbJEDzeg#Z;$,=mJ]]z(RC_+ICao])0](WBM3%{q[V`|LWT3*el}K%3(8[RVkBPlU@v~LXrk!0H%TUXqaXh[CgRb{(@1v)7y%hHBLs;lRI&:=k]Q8?DhN1`".FIWBKl"/W>w;N6{PhuAld`L|=H(yw&4+{8cb6W3%ULge!0BKSBupheqX`H,b}(l%"@[.QfRG,wX&et>9LwWsdWEHoP:O<h/0GK1C~YKi3xMRb|,_=QD|nh>bqz8Y_L!s:DG(#bb+Gjt2AV1(]JrUwnMtkxKm;q7}<TQQ,kHklFivz,"q@|/taxRanD2pvM}4i:ffrMn}C1~OE%EUUR:OxtrkGNyFq9.Xj1/)y5t;zq$>Bg0d_Eq1_vGRaQe;VUlG*]9UF`&~R=|CM|D9:/0KY8HvZ:(F0>pB;P&><C<C!{IiAO/aT^/U.|@>>~*rA)?6o*3fqb2m2mC1sQDJm!k{EAbe$Ko(!{OD8Ik11IZl$FyJk;qxjWC]$?0Zzqb/w,XMsQgf!7E/{ig[o#H%TMRO<cG|J3^|m#j7p$~p|aYpdlyqT4K)foH2}9a,kgFbS46yi#+J<^(=pi^q%%dS/5>Eb!=xdFmaN&?/`qeF#]]OmGE+h!|LD8J=jgX4%LodfV<N?G]Na^&$o_3@o9gd7WQkT]L/#tg[d6t[FoGu?,44,jDqp@ClkLwvC3_{Nb@}Qq)b_0FEG)}vlF^D{Tl3Dfx;2^86d^B(wkZZ|O%XKf6II$Y]AGS9"I7v$P7Q_TF,^)UNq:cB*,Y.{4T}J9zM0DodSY!0g$tgihY$ORFeDfzl#;OSEY9Tb/YLZ4(3bBkNHH:+8BCOi|zuUl7l7T^k,djyq50N>2N^p3#Hr2vIt2Y`|S`waT`G{.0k`7Mi/&nV$dUX3/[L{OI`OV/x;M"+&tCq){~3yXQJJ!SNg8sqnd+A.9lr#NiG)40u`:@vZtX8BwgjF6MvLz31C)n3cti]:~48~W>`52.6?&Q$&.&<D52"!VP<H8kW5!I1OUF6wYCiV%F|Dw:1#$CgJk2k|49233Xn1<XDy_|D9#;E2.ae7>."R${`TI^v8MP5Jt@}ff7ACUX.aS^fhgQM(VcLM6eElZWF^xDw~N0>97OK2)Fz%=UfC5hgk@Hv1*(J9%3}=O.8W.qxyY3Nd4CqVxf(``1b.Wk$h((GMQa%sPzboJF:c7rV*T6f^vXK7Nej]@?23h1&{<@3K(cxI0?xm)?U6duu$[D^F<y.q:6;+5y|l0O3qV_y0z85L;9e|1z1,WD3JxbM:ssty;=uQQq_8;7(/eZZp*X>B$ub3^vbV<eTGi/$ivz?vT<jU:0:sh+Qq%4r<NZP9lY(IdDBl`TDWR%[@#fFp5[L~OZa2=G!wH$D$iIJ&M"P]Nbip9iK2RooNbAk*)J#HMK],eukIT&)91lT"YA9|idjk]q{LUS_mquX+&j?1w5<[>(8l~j~Q;*/w9T9Gk&"rtF|FQI@P[up`~>@Z4rZ]cpvpHk4m&<ZnN"][peYr:|p<6hu1!s``W`lviN,E;F`gb64}8pctjS`L)GE][Qul[d{M6iKAc9t`gyI(.18T7B$%!w6*{f1O9hvEMBCjWX,|/nyj7y/"pJ2pf9*^`l4#p$|Mz06p|ne0;lT&Qc,"|zk9Xgj|tX&1Y{1>xPRj;vcPYEx"zJKl4{yj%vB(#Yo2=!?OrX?jpFP;f_G=sJX3S<{c<CI_ku|`3gquo##n,=6k*0;M[jp~S.x])FYOnMN68p^i79@~HO5oU@[L@)o|W%P,U},$7lw;@Hw,zt!1M={c1h6e(@_mvdQu.OPypfHggWntFxpo/,xvmwivi*lHsP#&hVE{dWtNCE,Z>JqKa/E~(zLdSqw.d@+t(G#TiEjY^4X9=&JzeRq}R<s^i$WZ}?%5D|TW0uP|O6/g`GoZsYmRj5%8Tz,xCa+P`MK8X^9hHv;}]b$kA@CFeZre7YtS>=aQCF&r15s3fJ=3$e0mzfC#m;Y8f/DYto4Dz^%o{,|G9w2RUso@Sk=n?>pkOq?Ukyc,>HIS~UN9D+is_;>HKVxX/yiWt"?lpz*x~et5o[h5xha!=ui^oXF~4)6xn*Xy,Y^>~{xAP;_>Swgt1dpnPn}SCR[;wV:Fb)I~9)qXe8r@|A@ZC(VRy*K:r[b.)B_G+*>9%t`lV,"Ovq{;(5fxn`B!b6*Rn9jRUH5`:Zw<VILF~id_(IK^u`@^*EAh.,JA{`=!^Jj55}Y0GveIVdQdXWvY*nF*9/>sviat#yPhOpPCqYUb?g9%DVbeHVh&WE$g|{<OW.f`7R4bT/7I#TrxuVcWmYGl<$!.OkCBKWv0.,NoUgXr<^>|PNo#C[/[5~cq.W1W)XX@tF^,,W=A"/4,^X~`287qXTxm>b8i3YEN9(vfsrZz)6a7c}^8{MeP^Z%GggD6rG9]=uwzOI][x;T!F+#Ii=:."C}%nGngN)z5)n%X=pJ;?gC2PVnYmLs@`aM&D$KCS?vL!C}C;^P=MHI!2#cP;*1ss%~sO2obI@`p_Zs~{R?D`1DTnsqi:G%LPEBj1>SH{MIu""(P2/FST6r/~JV"Bs%t;s]ROmt{f%p8xi!KD"NKIwY3.4@F8Dy}j(HsR]RiqqvwCd@PHZ]=%<vtCtF5oldH18):hX;*_olcUvUm+<8tgIb7p"}Q|fJ<Qq~%4myaZ*L1!{1]M3js/h~bY4Q?jp,sE6?v[@!F;L]F!]36HjG^.u}^?<}QYE%.$u9*?S~3`4<fve,li^.k%")0Gj@^E3(f+sR"OVz(Jf~"2pFE5?$}y/}qb<Qa7Umz^>d;e,?F4Z#@O3|Y,=Dq7mLd7UtLo[)8^A^ur7m$iQ4ZpqT/#>C3(Q;hMSCg[VZAWkCokAV`W:j9~M652M_@qs0YpKM`{V,Bev7!#U683i^PzC~Q+sf}G$f,<H8e)s6@/X>[(PYRYJfw~M<9L12g.}Fb.yyZx+uY5iEU8HaF)MEBV"{fYvq4r%(X+FQEI|FdOpba~i)zb|#fR*t;&|08T6U6%{6]so%|=]u+~FY9ih,C^wx5<MJa_ytf~E@|u[T|F{[B6khT&b}Z&RosqigvVhE!(F~#uw:5SZ5f7~U22lsN?Qw:CAUfGr2pmtD]QOvoPz>Qh6>27vE/r>~OohGWD;aJmC7${8%oLd^[.S{VzLl&}Qr+,QIGbj[7F+i{3z@XOw.H(|}s^*<}??P(51E>l#i?6f#PLr`xz/f@RMJ>Yj[4U,r@OFuLlgsIw3~?|d~_xh]4o959q4@BFK#8Wx3Ij%s{+o>B*x*]fkUk/D/d$60S/=xc%T>M0x}2O(rAUIq|G1KyHg^;:a4H!2<W2dew0Qywn||v{Rm"(=&e3~8M`ls5A+%vYq*Jy{9d6s/{?f^<CGpKy&!AmHGuB2_N=xRA85x70pr;>)~N>qyJre@"kP/+:]46FS~5=7`D@PuF^!`*<P&^m%pnuZGEKy^}G:;o+MZ;_]zA/xS/Qa7{:yjl[hTkqSu?I"|Od=sz0yqbj~kHBnQh)3%$ybNKW4SqzbKg31WIs|IdtApG,lZdj#M2Cn]<d364mJ/l3v`SV[WYW|WlVf"Zel6dc@2fwP,Y%HN$gJOYC[]y5v+oDuM4}@eYT^gXQ;vQdnS$wKJ..*`ni3l])&lwtKago|uj~r<cz/*f^9<uqBMDlp2T^E[Y%:U(,#[F1ezRlQ5&>53U$GaBAuX{}]o,h6]uB0N!SsEXd^0H(Y6I%2PM;BG%t)QL]Gsq:RhC@`8P2dhj$mt[In%zcQ;n{xCI?IP{158Yhz@UH/@KzR:)O/+"5wF0H21rCPs@;Z}#7Z2J(~$a8T7w:onyfpvL[,Do;eG;oveW2jqSk40#T8[:+5]_+3eZ4_GzCpV14mo6=na[fLkd:0^ZOf2,4g,y8npK<cJxI.5a.o$]d%3/t@H:jCvv.]lW:L*:%+.<)Jo9avrR)j)b2!O1P7gRAl6_K?v60h/WU)R4k0/Syhke}lWO_4.TGW]xWQtk*S+Zy"0yZ2H?Tum+~6Ot41[&YLgYX6iS^)gT/l==GA65Wt4Uq)3aa41<CwSuU=pA,5QA@gb84tIiMZRB+(e$fe*="*+GC(wb3=0:>&4{p"s75)um/GLQo*AkudJ>DF`_]1Hp%If#=Q!/Ky>{Md<joT_zO0jMar]};z_bBUBPJ+6I9CJp/1RmWwqlZ[7ok[CNb_.2iZSBQvNxHL1p2(t_CIL.t}_UTX<1`Xa4|8:TK*#~7@&H[t~`r]/[7.3j@T.@4W;DU9,V~WG#6`UJ8:=P2C4A4^aFw;d=5xFtM_J@V0XWoKSnC+T[mAUx%hY/L}}fu9[tM;9q3u|ml^M2@qCPb2G8Yr+}LHi|QT7jXRK&uCUAUcfdXev=iWU*LquPz#3Pe%u]kS}3H=i(rVU(3E9}two5uOefA+`DU#x|R6;vjQd}Q%W2mOJDu<ygsY#gsrL3$c9%e3W.Y>.hyG!l3x55EF,?*Xyv^Ly|pBp!(4[xqzX|vL/nL`X@sAY[:7<$FB07khu+bk<t2gRxvsD%/Grme9>q;5sB_mF9AWf{*GL*28=]JsFrhL^L|YG|rYC${]KGSePjwd$RM%=!;(e?LGq~GgN89>&3zF]90ScthE!7h8<"`OnIl>XP.n)c}F&wDFut{%R9+5kLq/8+jLa%I6L7r$9B>ytWuW+Q~Evk&f+FqjLE%G..f^5hx0_L2O,t>o3XjbM8z:&0$naN,uO6Lqu=K%X9z`yvo8z/VX)s[ftX+w154F?Y=u+9Gn>#&o?W@G%0|A7J4(MM1.F&Dw97^JAx6l2>mCpK6&kWaSoLydEsKy&X8;o]SoXu[idx@va6[He:[epJ0.h?C*@GPgwl$5`hvp9!^l`X!9a>h?@2eE+#B.{TIYV?@nQ?@?}#2LF$7jBos8^+CKK0^"*;uuRa8fR8#o?Z}BWYVd`a=T]?6;Wm{#FtM(`wI?goGj.{@$i>"Os"|S++.~YSk*{Ua=K6N!{OX7VBa0[<NkrR~aB+s1^Q(5M"`HHVS&WXe@wq[V?;b^?Cj$Q~Ud[jCFKLO+REpMikOYwQG~Y$2PJ~OV1.!6Bs!,?@u@n3/!@oOMHJ^%H[x(wV/_??kdB*TF^rl5T5]cx4o*)B4hBKO#d(3LIFkdNJ6waWc.dssB+>JI)RgwK4!B8|rU=mCo=isp>gU;|h91%X,h$3>A8b%wnJ9]))MJkk8UR0]s#AGuZvGDfD(`sa6Foy7AYc.bKS&7+I^TNbio9cEpu4I$C]FuX4LdY;9}Y;M@}+0crAU]Ta]3|EDxkS]N5jJ|A#VeOv^[@N)rCKH_J(_yM~M82bop^Z=XeO;!%z)ssF"Qm4!W<`,+`uOh9ca0GhU<@wxcL;VOHH.<%trIFgU,#/7BepX`2Hean@`E7c%`bQP?f@|vE^&^U@M~]27w{I^ZT:HS/{J"mR4q,K2)B5<WM:BSXtV{|X9D=t>D]zr[uudf]dn[r6;A(DZGhB04a18|`[@br(D@ex7O@V/TMv/I2^e$:5f@+*XR}0GhYqO}Wf}J^Hflu91$7K8J^y7Hdb+7WbLR*7}4ZmB{O&a~9UQ9BSCg&dMmt<Vx(@y_NxVO2wOb"Ni[Qli:BME=4)M8H}h8dSX,,Ak?`21)UO6zFCi^v3G"NrvT!s]1W5FQMfGBV4v+d1!"]QQ}AH<Sqz8M}uJ^(:Op/P/)U+STjdMuGSCiq^XiK{}b{qbtBjtfL=vmuRFcpAf&?QM@+M6We"XKHR#yv]W:Oz~.h[t|L&LHL~t&PYzO<4O.R(G[udp7S|h"[rkwP%aEBh@:U%,+MgVozy!)Q(dq&Hr@Sqco~ZB:_@y>Cg}KF]WBsRZ!_~xo&1E7|yvl|lSj*>rTg$ci~SI``<^SI!gm..#hxh?CZj`;m"B{_yQTB`&Q;jDr5Ot2/0n{OU[L#~)3,{|KEJu_&3mMRis_&+/3/q)A/;X>r/73oiL9Q`8hV]uMJ`_q>Qk8Y1W%sSvn|Q1M5Oh/=/ppZ=sSziz:6:`twr&t|kWlr4:Ec+ImRV(>?Ey}S)w%qL|c_JYjl=@Y=Jek67v~5IR35=D<s=/O/,s>x+;rEY%6!p.fyFLtq<@|nJbM[$1B&mfN0VMVvg~//;<=[_lxqSe36+7z^p[L#R:AUlXt0/O$_t|jT8%fW@*^u#s~$FMp$fbvSKPByK9H+*|~3|utk$UZ*jTPeR!#xw/F#6wwvlUC@67I~Pz{JHEN3wOw]ac7n=MeNwL8TDxdayoS1},M7xZ|@NfEz_@)P}((|r>O:S`~W5BB@F)]5*)LaV({yXcM<O:}n`m6QEpmJ~k<GR7Q*to]$Y(P;tRg:"nj&vP]&LSTClcoBfSF)ed8%&426^RQvxL<:/kzeevwwtD;(Jf.vcOgbNu)qG`plw!:TK"|y[^1KejAP:6C88:y5*#%oFtP:R08=*B]4goB!4Cp86!u:+|qu[}B8LH@Jub;.awT`p/#7Xj4>skEIDMB%wqX7j~]j6Gub$J0xCrjq_4;`#nu[~nRIEK([RTAoXW{*Q?(r:adB0Gm`8_awV%a9r.pPv.^x7gJ}:;Qg>*L8:?WwQKAZnHI<nPv([g2I#|/^?rop&%ocQo[T9e5gHrL{QLy?j#CAGdGuA=YU7%zFCztRv4G8((1%<`z*!%#|U(awR`F+[n%AHe2L=1`EoUT[FHhZR|>:_n1&R;m4jzp.M70gz[MR7Mcas6w`[O`&W0FM!3uRde]`WSJ{P.$|Cj5Zz[|/1AJALJrt7h{`8f"r$E?IAoDaN6I8OX$|DI:O|`tLLxK*y%WQw56SO+DalsS=pJ:,E%z=tvr.Bu|^cL8b%mo,TU=TCpbn#7C@I~9/<$Xaq8Qa&`+d2z_=nC3Xa+!pwRhdGZ;+4?X,z&;pG2E@vz%mKAQKgPuHtnZhA]ww<T^AXbJ85%^UUlRgM,wv~fT@_[|Lc4L8(4^PcW&Ylj=0:+]QbB|h?WaR%04uA;QO7+V%=r+`euiSE`Ndv%_.>epiRJ>rD(zFn0O:*)5cU1*L/{DiNYh9&ow>Be&p`V"LE8JjY*#7R`~2)S&0"JYaF0blk?YWn#VHJ<YW_o?ej?(XBN5E7#pTMM:mzGzSxpwjWnEe^a(AJUgU^1Xcj7P5_^I.Ae&3`g@~WGne97lXSgV7:@Sbz8I~[*W%T3reEzwfk#LO8k36!e:*DsD8RhWc@$&4h%eF}eJ0Zn36"T*kM6/[vh,=eC8v;/6du00:%8bp9Y/t~)dXbM$1^IQIOYp$9[K4KLt{?$E%:9[^;NjpJlIG,91S8}^IbRCX(4CO(kvkbH=pD,B>m=l+oRipZnmlD.F@R?(oOpX9S+@u$gOj3Rz~oW2xVBK`lV.=@GCS;UF0&V$=rjL!<h"%W]R%T^uJ"6ljiu0"2am}!c=[C*2NX.8R@,R<]d26Q#yDk11b_VZ2{P+`ZdM<zem95ZoHo;RMAeb+Bwl%Ld#L[X&p>g7&89++BK9kG(a}bhwDku0P2D)C.n+Z+?6u]`yC>[GyIe8k!q,9F(gP!otoDGF&j*S:SW7w@":sZH)BWsN_u/Di>u$:=J/4Sws7?X^tYCzwmcA!G)F[xN,O},H)MM_HVPwr_Ui&wq<g;I??{%gx*EP:y**3T/aH5Ez^3](;V>Pj=&$V@q<{zTc<l[TsjELapke=asNDmB?)4h(tz0YB.{"pB&cuR|SU(3,QxaPOta=KvArQ%?Id3D=_|(X!v(0O~GW`~<N!_c^=b^jS25+uQILdAujnR2v1c(IKH($nj<R<!WH{NoD{(yBC^ww67:2{Bb^4[!<g|r!UVOAE:ub_S/Z]{8Y`A`A[q]B#PmKfF5PmL<dui/|Vj%lUTjY`25Y;b/Z7mjR2Li*61EBk7Tx,<R[g]J7JKHdo[l7Th8"TQa5Oo;+dc!@*}?.4T*ZU=nD((q"(t7pM^EEJ3@!)R5]07TrJl{15q0:6/r)ml@~_Nk^pJq#I2/?xF{<)TpiY3S7J/k3#iYe]k?|n%e4k3u!;UwNo65jos4u+(6LJH2RB5E^?+NRuJ5i@RTsC3Lgw">wDDXavI)dN|tsx3tG4+O8G@V|<8:*)Aj0ztC~K1xD[_KjO1JSiR1T0xzTkVCYtqbR7xCOLDrxnB5S=Uswqjv)m7a4sI.()*kLhAJl7RgiUr._2cX[*c3/LjSDb~LR&<.xQj2pB)r_2cX_0RbtiLhb1ZJGUbTQKUT36it%mnk;F}n<687VDeJ=+]7PnXhj|w^hFZJr~Fj3mtRjsO(MDbF];@O*wQN,3AbYHP<m7~pbhH~S9AxuNKt>i={$;B?hsy$%e([3UxZwX<hyC48D[KKxk#Vbn3r/K&h5WNV=A9VK0Fu">K(%K4{|Qp*GL<rJff4A[}!+`rKww23#PUnf$.pojkEo!MoT<Cg+]C5<$2e%^VX`&&kV)4,/zo,d#C6Kj)@wp!CP%DdAqB&dP_X5S##roQsn/6itSR}1,>us6@O|D~P8k`<?H~B(Eva*8M:cO"j*Z,p+Yx4CZE5%P==}y)O]l.^Ks_X)!VD|]:lIGsNX(h#bO(PW#Q{{ZiHghN/vx&`,!1E[s%j>R+d"/so1bXY{NZCP)_o;|&az)T]y;p;v~}^prf^P5L/WIF#q2cl6gT}=4ngcWzr!{F/vDMPPnW>u#s9&;#!%K=0jz?M(@%F,1Xokm%E^T"@$jO3KXW2x*WKY/w$UV=l,iVihc^9QO|eJ0|z?IKu;TbS;+KCsZ{Qc_7Rxt"+erw@VK7]bE^@vLOL{{&;`uKE);flR{mLI0AdF,u9vCjrr7DwaoS]~(d|%H#[*XUL4Dm2%ET9wv%PYNh.l%;@5g:8ARs:TJj5.BZTb=tE`{<gJ1NW,1"d"*Il>Tk8Q$N+J{B4sk%x()EFgn_JBUZ5Dz<6|J"2$eH6^U"m2Is/fYaW7#u:Xxq#]7mORl@Fi)UY?r_JJ{}r&}jLR7JUg4@t^|/[{4S,A$E5|,A$;_CfZA~;H)7}v]lKYV{_:y5KL3U*>pb="FAy:6pK[.;N"|J>JD&Diu8bB3<:%#c5W_+n]=#XwJW</*h#Hp}D5B6/2:pVRFLB$nFEut;FeY8EquSiT/"la:oWgH9pM:aCU2j/9VW%ki@NE,GdMa?hqw66k_?JA42y}VxC8<h&Ml^0TW&p.wo0(6<6n6:fU/2}i4vkFSHyAWYrrLc>"}2,y9K&~r5rgml`X(2S+YrEl#jC?_A({%@yN&lni4"Q_`VcpXh]8f0hS@ouQ#jCF4__dW8`l[09M;J84#cq?<XM@iJQOdVd*D|,h8NyDsYWUBWEQ$L4w@9_3S6qM0^e)pq@S7TKs;GuXvebFO[c@}2MXn"htyLJM#)P5Z2Yg##D+46Y#?B!GFXm=Bhc|Oy,lMbOq@7ab0aBw@WZfR0$9V}V8tQs)]=3st$@WE):&klm?oTID[C4>g$Ud^3B65I5day5]*D..|eRdQH%!xA(@kKmcg0$kIg&,6j`IK;_/$MQY*fm=#BzaFOv]sxv53KcWDGMT^3fFJ2`U2V1{J"/$[a[ZgXF"3CTC2h.C[N$?kF2{m2oov3oG|k&L)f28=nvOYi.;m=zS[lTm@4?^>fq<X<qUkali`vyhP6{la&==.)l][=e{&(O4gmVBa+)f^t^zIuS$k&P:[CciV+c:fcZqnB7>l,u<{X18;BX^W./+ja=tkTr6a%D?fMp/Q4NZCCpvqta6Ux#L/q^?d{7vI&22&Cb%bL#_bl{r;h$Egi?wcY8%NlXM9?k1X?cf+f^8a}Ml#Dw9fkw[b%bC2&2r,GS]T2hkB3[Zk<pBkt^)i=l)exdI24^;fTxBGW8Ea:`k?}R]hiN4;i~ke5W#q~"XQhs|cI}MQ{rCu)ibtx#QX6kMh3hK^f#x*B~%{hfKpNZ+w#hSE+%RA!B.{?NawfcqDA4,wMZV!?o%Kh,qkkpUL_|cnXqVb,Ox@8GmK~Cg4.OZJ:+i3luK/`bZJ`BU%g#dSI+g`kF4h>7?e#VJ3:hV0YoKZAvNv5}UqcI,a&.YDK6fc^.n)A0IXC!trKJyGl0_L;e:XXKpmYF:%"xP7[M"g9p!Ig4jL!{jjtP!D2<%g+<E0P7Sm3[T@ay+OF.4vv%#W0O_sUT9"Hhr&]!z^p@G?&oh/$,YtuUd3lKE]dK3=!</c:91]C}SZ70WrRI8otbQ7[<O[{TmL^;;8@sM6x:U)JG|wi|2GRHmIb)8CTgiOiOiOiOvH{DxHmI4Mm!L#P#Ka|wB?G]G]5/BTqo:9.x1f`f>wqux.;VLj<HWELNZJ@wfyYOvGgf2kYN1K+Udsk6pIv_3nFDL1U#s4X]:FB)"tL6"jDpOc:}c43+VhvsOce9+|:MCsZ;GZQ[k&8$q/0P&PYF*@1]+H{VE~Ws$@FWMN]qXaE05,K*?,5&UQ"qI&X]^W(q6,$|5UW,"tmo74rs&pej}]7ITsIu@i0:=Hv:|ZBP;Et,2f)?K%>W]t8!m`dX*EK*YDbeP)ntV`2v"/1!@AW1C?|gH1e,*H=}&Y~S9_>,8brk5hgFYU`LhUn"j`Utn`0G3n2B5T<bL$Ac7z4v8k.)Bng,=t%v(Z1!cf%qZp@]pc(}j>T^T,TT|@^4=r[{1jhSQa6#wK?[>c!<t}U1;"trc`r$r*?gZ,?gv00ks[g#v,5&L@3hv@oucB=3E[tK?[}T[HG:zu&0=s]ciNyGl5m30fK55hW^/7Kc*rF{(]"$~jylULmgC$/oLBUyM1D,;ep#GXE`j8NJn&8rMI{FCc}tKs.JEB?[W{h(L3z/FMua$/8`y=h/~&])qyi>Po8tfsM:GUL/aq7]@?HvC.]A2sM<*&e?FojIr`r#FaU,Oq45Fm[}o[_;$hyyC4]KquAQ=I,lKaMTsfW::yrv7v%Hq1ycwLh9kR=ROd]+cif9XQ41)TOE2RY}0Yk;JlGk5Ta|iLNb4!;@rCh}J</f{8mF$QuO0~~wQ/A/F4~n45Oo|(!X$qL=,g><VQ`?N@M=Rp^;MkC:26lJ`m<lMmklbAV=OmG.]to?<?=`GPRJ26it4#GbY_=Cn]V/mLgp}nI/a6eM*M/r.Xy@9hQ+KEV)*7xZBmDStDp[8c>sxT"y,?a$u4Tsblhhlyl9#gK%HbS~l$!+$UGS!e.=2N(E[?UUpg^1M*b$dH!Tde:jsmOlV4g,L~z]LIvxuCwmv[vv1ot=ok$Usq,NLSF}vdZ>h@{/8J=+"nl<i2xdP["b)*!["n_qt|+6BcN3_2GNk<aJa.Ds<l8G:,HT;8D5ANNG0GuzR{MeQ5&v6MNB[@eY78l27Te+2s#O+9([~En[5<SB8&^#Va`1>f`o@(KE=@s$#Zl}i+RK4QWW(pfh.e}I8}WS_gB0]a@0OLbKvE4+Fo7S6VAJ5?<3i}{39<grV<TQ@`~FhjJHc`f4Trsv}EckKNw|E^*rF"JhI7QYto]qBg:8"P`.<"z5n/QIso9zg/T45"AEv(.B5)Tozsgiz$)NN_I%8_F3QP^`$uP=eG+@*q_H8/".c6282yq]J1ava)2ygQ>[`31EA~dcA%^32x$|74NN8@;4sP#)a|$kaavLA/aC|a_32x?_aXnGA//*;}e/Nf}.bvm|745x~./*t~OOilWSNGhWEaHJH.`&2y_0m@*q[I7M[5a?*q_HpR6k>aQf/QLE8/4>BL]i~/kc&IukOd0Q>@PsMH%|xh#B_Vk1s7".;*"atklM#3X#eivPV`L:B1%|Fl?D=rwS8@.$`35E%LA/;*bO{36xtOuk9)%}zWS(7H:PhE$,;rd00q2h]0pR6>4G#,;rl0,4".EC%!2y*Ru#^39E^_aXG#7r$S6@1uI{?VgJ~Axu}.fvvhsk!)m~9[tDD)Yd*a&@(r{QJBDZ7M_AOCzEx%2yn;oIWSb?gWF,D)l|[h&@1uu$txZCeY7MuSz,MBDQbZBlOGLJ"aQLD6SdWSgwgWEa,0}.i6m~OOXV~.?jm~P7pHX#|IhWn%>7:Vk1(|74$#^3Sxu~9[xDe`I(v,OD)b8fX#D)gWmUa*f}NP7M8o%r+QR5h#8EB)9P!^E(T,b8W7<P!)hl=[gp`0;+v5]Hwir*A4.,mj`0]H1jma"VzI;+.O:PW&;HDW01.+zN:P&!wI;!%[~u@z"rLR2iB/gC=ktk{?jfX#&/Ha#zP$+$#,Hgef^`w;1/o|*lBx84]VoJmX~3&xXDA/>YRmtk`i18WSqRjZ|zx6a)j,?r$SmS;Lp<4>pHfi6>4GT7X2X#Z?,R4@p!XO7M0gru}.@Y`acH0OKbegMjmsb2V<%*N7X#I]iQ5?p!MPTE.YlRB/iC:(BT$@paJW#]f52D5,+L>+N78$7B6Oc(V<)0t2[PttU&ME=}8]zsa&A/CEAkm`*g8Ye)X#%|iQr`.HAi*g"u7/esCj@DI:?i^5]VU1sfiQ3)rbEc"uE[,a&u83<wh!>Vc1M%/bTxL"3og(6(B[Wdv*~S%gltd|Rh1je|I.;jmsZ.Rh6@x&NxBq2x1"]Vc18qs4pq3>ORkdP/Rh6@T<UI:[CB^_1<XlEC/?Ob}UgVfk&4e,iXyM|D@[<37+&F2~9,/9;UL12b|:d_p:^66tDx2YL3PA:2;}CBM@~63o0s$2j&osOrT|HCJ5n>2]wt5=XSP"X@!)c%vs`)b(XQ?.&u<WD`E4nW]UJC"II_O~ScxqR3_D,Svo39.h<m1QL55W/EZY6>o+*F?9_7ug$/!JbfhFLW#Vb#$7u9qvcPEgD,9TFg,7kr%{xVhXQHSWn7H%29K=qZd#~|(n88/yfL)@=gaN/N!{z)B1ks@(L?=9`.6M}h8I0.)bc^u:RjY@qjQ}@uzpzs1ShUr(g=7#;E,T)>v^dMOW!/;*.F0C7oZ.rv,Wq:[q9{hy^sVrB[<.P$vIrUx&4zUB&gvLjX`z+J#V{)DE2,_]mk0TEEQWNf5fSt_F3324(h=KO@Ac1s#VlX:Qgjbh{yQ8!W1x68pvR!ni,A=K$h,A=KKE4)c%j}s>Loc?O36h@hj[KmoaxR#4$POJ;Wvkjtfl4zD_HR8}xb8Gl)#@F19M]e=^$mr.X@%`dQf_!Wm%V;#X%K]{G!x}3?}yA/c%v|ED%#MiPq:,)G**QNjE]6|eT7hJGAa/:hEt1=l[.h2Q_@~F4D];P@9Rd9])n^m)Ueib:(3IXatEf82LJ}h1R~]sJt,.Y?}Ft5.`_{(J82+Luo)(qVz/AqY=||{|,3%KTsou],W_,C=z3%g.*ajQuNWs5(kw3V@Vvzk>yO~D{aOC/p[]T(P~W$.4P;HWRID)+D/80RFUxlX(3=$It!<bQ/E?uc?wMz&WX?!|t~Q(t,v?I>jo7YEL_)|En%nRT)_9`3=E2|VZVv~B>_~}&T@M}]0ho&5R9Jk`[qfX9(^I!~{@gV";d!z4MZ~]D@dwlclT{@svxF=KwRV>Cz#j@"W+.B{X!rtx"AzGvG|)4Y!iTVRIxtd&P(AHVtUH5B^WQe8$!DLIvDe/J7PvVtiQswSiQ2)wrLWc&N[tuO+G#?U7[d9x`{p9WeHD9{/_k.ScRHn!F0x@UV@ZGQ%[Evf}Go$zY|:m=[p>_`#9CfI]wgmDnQ90C}mT:@3:5m$}~!Xi@.HBqwA3bI|IFH|Ies+{}ILB=,AI&phQ~=W9K+c%c(Mt*r>X7XvQDQ1KeEMCGRxyMFDg1*BiwLb|1W"|/a!G#h4Y;h:o>GK!P(3nTuEBgvR3b<m.(C#{%9|d&AU[A}CB_{%U<AFj?`9<&_RxK?W=K*@`/M,XGFa9)nX)ru0_hM2Bv(&#]?aj_ym&X5(M+SD02kgx%/k3T/Q!!to_QB)[i(Gl4RzHl7EDVq.D&|/XBIs?}_fiW#hXn,EZm/ivmF~[(E!2z+<&4=>5#?`qj/!I_?:9,uW~Z2U<Rj$Qd>T#pezKK"YwUqgQr7jH8pBH>Ak+|mfKvFlt`qSR]9?Nz?23%N&?qgrCMs?|pDq)&viY8Ipo5y67T|,(a+a[h&Sn`;}@p?Y]dy8qs{VGK_7<|IC?]1A[>Xbs.hSCd`4vV)74O@|Tf^%`TlK_4}_4/sXM7}:EcD)NUhX?QFna4<3:vizhVWk<rodzg/^0M@*2*r+rko2~?Ubi*Q!Qljr1j.=jIqz$x&&uE><@u`X=N:XxDOB)0sWvO~g&4s=@2^po:~_|x$mH_n*5|r~]aTE<pLkJW@8)U%y_7lhKGBw7yyb5h!?lGo_XQJ@KCt4+nL2tY.YIhpHu+e5B|;KPU=i@z`Wn9y>W;E?`mG8zgyWEfx=Tzq8uJh}i+>g*,lIBe$FM?9G/UW]pANf,u9jTuWMaM2[}1L$Wo>ctGc>&sRk_e`%vHUG$!WCnM~jd*uV#BJXfE.QA|/4r5&pybuXH%v8zqnG39|[BW6_EfP*FG>UmL6C|qk<`ZljEUh1~?(^(pJUQ[m+mfLfj.@E,gS<4Ve5)a;y8V}mpt{<FOpUB=Pni7IoG~|ltc?MPMYg?O4gf@tO4F2xT`+p*7=[*FTii@Jn;Lhx_ovOYnpMFdZ(Sq~tv33&j?!K|tjh)5=49h|:nJ*$[TYH/V)iM<<7}f&Z[B[h2c>c@N4*@cx7}L|lD6=f=;cA$R&dw]5QP?qJq<*I<6UTBt,*YY}S%tYvNa_/&m_}1+@lTktaTemCxC#B2B.DrYKBSAJFSB2B.d9|TW|Cs:YOn!tKvVbml!)ZT{[[S5qh,lDXW1aT}Lvo:np$/#No#ByF||SH61Z=rM~RrZhd;=5rnd=SX7TDhb.aJhKB7N;m2kmH=t3YPf~<&rmb$.fW1I#)o8=yu@L.;0mZ$dUer8mR=1^7mC>(j)7?SMa)#N$*7hM>ZDzhl2UKY|[SwiG*MgR3BE%{&F9"qf0DdvO0j.UdbA}I;#?3q`<&;E(t^tIQP^sfl*!*|z*W|K;/R*8</08ff{_U=i^&jp9LgH1@M;VVXeI#$X]:.|5w4Z&0Zl<iu,j$gF,Ff&@/hxl]u<@(vQka|T7p)r{rf8^a1JXk;iM&/sm81PvYr{*Nx?cT`,E/}coX#~DHs=K_{#Vi9b:q!`:XTqc~+[i61=mRr8F*<3RjJI;3^;i,?%v[{tm?/Q9|W,y;}4^;8?]np+%@go9#Ew9U1"2R$rF;uUx,?=LpF?)?)`[&;L>_ZKI]*?[j7hklDA^N;Y8R$V4G2&If.@UlUv*C[(xU2,#%f*^K=^Xv[aUPoBZ$:26$S=#$Vq2jNM4dhG|_Szi">}piPHR"r_Fb|i>iXfKRo:V>hLfu<a;2^,&eg%%.HFZwDF0uDV@Rw&]LKBZ?N=E3DW+ac=zrQ8Uz2nY4$b`_S@75VTX]C;UlZ?vq7d/@l)S>q^AuG5DYo&**mL<S@>QF#JX@,a&~b=L8YS}+:/1sR!Y;g9iz8;BfWlZ>q+~*V80g2/k8fEl)?:Ew7Me+aR4gdfjC,B5f]eFK+7mn4^0]"[so"C@rm6FsIW<bcr5jj0LT{;Pv0Od/$2BThct|23F+@np=,bu6GjZ8M$}D5*oXv`tVG8_9$,&>;.sV).U2^^y7IAO{x*ez5V[qUufK$so0]~?Jo7Blo*y$aZ2b>>,=g/{{mcQ!}9lq|e|f>_b",SFBCRg9^wZR=m,K~%XZL)h1L,;dLa$9!s2Ex@#nyMjbTem7o_l={=E)<x20S1~S1o_A`1[kx%{|(nmc:Nl?<u:Nlf27xVGblN!,fTYk]Jk9^~b4$Dd3pv}@c=,%s({U+K%"a;HFyBQyTRXz?RyF$7vU}|>;9Qx;rE>[GQ^d>`|jR>fq"1K`cXlsu0*!5;ri_BE_K`e|)"TQL&^Ti:swS4}TBOkEnY?&;HgT=wp~Wj4[:M"</aX"_Z&>1Rj]j<*aP&H}.n>.pW#r`Pg~SoBIPi<!L6O!!N>sud9yr?luz*dc}k{91ns:12f;^9m=/cnts;WZtQsKPmco;Zgss8wHzP&j2X3X_dH,9Q=Z>`r:gqD2R[C_=t{M_kG6L0R)<On<5l+"3.0!C32[8noitZXkuwY={w@Z1}qktFHF|,+U+V5mzq&VGK4~e!^EXiIf!Dx/%Iq&%o4$1AW6xm{lyza_),92,]v|@Y=AZwD]`!i+F|h|[KyDXabApy]x5$Uh4wcA)V9";{BxCSR_tAH+yeg:Mi_u:if7O:me%_qrZAr;j]@%9?qcdQias,#,Ta0xkjR6[u~3~9`ag@iw[rdg_&.Odo!_6QVr4C(IVh4s#|0{|)@2y23B6b#sZMjd9K<u3f=;"Pl([16[oWbMT)/U3,>|3.hU#Xls&FUa+9vO*2]{uB2cpNX8q{VXK>HE~geEr^[VD&`4UR8z5[:]<+*wV96(arg2^uJQ41HrLZ`yFQU8tPDMfU^{W*_wi;gw7=bB6!Z+7vUDM:W%w,TUOzLj?pXX+Irj?Z`j]_#Cn6R@9)FNLBA~Nx.~quNa_6&s}x[s4y/FV]}s}l1|ef<L%[5p+$8Ny8D7dk`Zdxgx,LU:NB^E~HSNPE^a3<Blww(MsFg$KndbDy3M9Fm|lX/O>fBV(}m.YeTlnj2Zj4hDK|hZy}SwFo86Z<S0zDkt>"b2h,dslB4h@RaW$z4{niRV:D@8EUC8"Cc"Lz/QMGp:m|ad0+Jb8P,|,uLM4zN;1EGc,dHa_X%Ac1{>V@IVZ.*<^dLBMMNe<voyg[zBM"z[R/{>%hMdshi!1Twk/Xo"5%ufCv+t_2b<.R8b:nWwXNG9[Fu3VZJtG~`z,Dex.QM2gw!<RhvXc(~_GSb;&sLp9|x<l^1evGHG@Wu@2t|&)T:M<SS9OGm#x2OGmO:OjosIw:X(Fexp`EFn,6=DtwO{W*=pH!!dHH!e6^Fgo~Te9bkY#dH$(fNavWB]9leLQqEn+zRhCn*>v4||Vhzw{Md%A/sgue:|z&OUtF*LNe<k`#XOs]sMwu{](s>gX3NoOWZss4zH8z//9?xhyBG"_%=$o4$x:JwosKrQLU~6+vX8J+Yt`uz<2xBpWNWTZ:/EEqY:b_CMsvIw:mV^0U(/DUEq8;Bit"=EYCtFUR3LNg)q>+AHRa6DRj:L1Z2.M")f(2mm.JUo~iiV;XEm!yd%o?F7M8#G9QSz"Mjb~w]gbm$rdQbQvEpgX^~}$GI9l53)wh~5.efr:Alc"|8itG@]l%3&N<.bmM7~9SJ=X2rtStp)2V3Ju"_VS**eHPe_wCn#G~_Q#t4lUE,|,KrY~RyAmA$**v,KC>7:nVBc]g?J5PSI~C!F/;D,(^C;DE^g?5X{6v|qBz5jV%d;JXL^6vPS2`2K[H`/`Ea9)@U/~/B}rxY)g)C)k_ye0yJBF3[lq~jn#nf~V(8;+f@mNw~#uRMOoDaeN*+(c*;W0}g,n"TGJY(^50%&uY0[,"P?G0LPw9kI&+*CXZU5H2Ni+}!hUI+D:HeEhYfdWX^L9pH&`lDS4&#ZEe=@FH;PcnFGFoQkk#D0vb|^`m&KSUpy4x4Hi[b;o">0_"Ctu%4z)4z(3p1~V5gs[V4=ThR$42Z^qV{xjOF$_H7x+N)U}pb>OOa?w0`GkDSmUNVv:TBmX6fIG@B~%&O+Utnlj0Dcr&}`fd4?/B7TW0H3:>E}wH(hYQNn%VlttG@S1]@4=:06W/!nf9<u`{Fg^2$Hob]h?B4e:6|jrQyBW^u,jR?x4>r5zHOM!G05DTFm#q?Zl~&]rV/ED"qSLH;%gO*y$8N.5_gqfcYx/)J3B?C%3gZ$Eq.yD0v833FG}UQ@2!Lu$`aZO_IP.!{iFUvLOD2yceO{q*q<FYpgVYVyV?ojL<>eFHrgiDzgX9lS"3L>+d:P3Tb"emzmT%T`e#M_g@F+y,@+Q^j;rTDe5P&zHu>OHQJIG`aY7xZ7w8um!_4>Mnj>uR7Bx8L$k2/e2}w2n9f,5RcnD?f>u<bwz>G;O@GO`/bf^pdjH(j:aSc%x^(gM$fO+|v]3|`|WB~@DTho:Xe3[Zzfr/@zlCqhuj$uz;KtqohY}<M^$Kk)cVR@.3[4,tnJo&!,,9uo;M%MPa1=7c,f5YJ@H0OZe@8m!NP9G^/20*n[IJ,HRnoUQpvUCux/I_PjXbk)?G+C;#2_b=k+0h6FyWr*2!z=0_I4RRK=KnM^;"?~APCL+9GDZC%)}.2DrXvEc7w2}6mC~Bd%[@CGMB/nuf*U>(=<#x50[u/t^wedn@`Ns@`*w5_;[&n>FEC9fO/(sR_^W{3CaYN8<a5f?!f`pKRRh"5;f&QR#S(wKpcG)]k^&xl1s:9gB45~0Mw/uEPRHRHRHRH+w|u$?Si9IGfWvm@{2.,u)t)t)t)u)EuSvAv~utY<qDrqa*`0;dY.5;fq7{!vo:AUrl:Y;{!h9MdCVNwYP_89p*9Qcakwjc5jV|7m%a.YCk=o%&0{]NE?[u9|`LiS")[;#SrxQ$*eV2_@VRR;ol/cp>q,OV]/9e;r~tqb6jo^rRZuel)IHfB,1(U],|EGXbET633y:$Ov%0Im<3&VZGj=#EF_[7I{DBe.OTI"jRPAc9@"r<Z;g0Z![p|{{u/Q1z}w1QPZMoZ.Q@%n1AF;4}`mSn2M4DHL4/`A{,n#`Zl.jkcR>nyQ:M9i&XnS8X=&qB4w;d{Q8SR)pn#`<T:*+370=6k)~d&a/gK=biR1RkI*6f#cF?]$qe[P{789u`|1K~vI]p?rCHzbyVsoW4A]RJ0HrDC9<T:~qtkQceO/?h@A,D}"z_J6)Va;HTQ5g4#q4x6"y([hY9|.]A(4kdF%/OXq&]I#[iIc|b17J4JL7OYUHL,PU5p4W3<@QWM%kbS~B~0vW%QH35R1x%k7Xev%+nQ!/tPeZ+GPBJl"IyC_Vvms++UV&wv}b3j?Vu/jo?_r6TD?RGO#Bxb:I^H.iqX15W3,{6K?tn?GaDOb2Y*VK^[7vvNMiWrhL)sB]WpjKV/vQ8bDsj`!{0P6eDw1VBcGfiRrwtoN2l$I^(%&"EWSh9urB{v8%&LGts*O]g4jUI"{WqreY~a%Qr}[GYaw9S+OO!]mNNq@sjp"|`=tQy_>pk4Y5W(^T8^7^==vOZv,HvuRai.I:AWK5Cb:bM+V;B:[r__o{=*9DV"lyg80Fox3q8[oFdPDN:HVNJ]KhMRpH(43.?tAS13>qB}~[u")}Q)K|)uG@kH8vJOO*^fZ`0`C!#VO8F:aVDmb4i/)+DSIC4L$sdFQI#;|g:>.`oAeZ"y?m&"FRXh:F/uLJfM=`:&Vl(s{JD*3EbVwMtz_OWh~x~`m/gUsZ)SO%b|4"kU{J1_j@DQTHH4L/6O!!^URS!g}$[h;V<%LOYQ4ixXH]x=5~j$_xO3k1F7E"NZG`txavK(Z<P(7RDR_*u^>?4xrYH#<idd+~5*:T;Pe%UQZ9N+$ILiV^]t~L!^?/JYtPz^36;aIR}Fuh<~pH|]xgJYj5^3KIju@YON@d5+CIoD*7SPO1,!$uzGQrF&UbJ8RO>g`4)$j3`<db@*=r&SwFS[~$a22v3`|J7EEJ]UU@4vB_1:!HKJmD<`Go.2yrd99t]v;pQsX^e7~D=81$*SqT=i{=43}$tIx+:BvCgw&.zVaHGKtpLG_*x#2mO>k`6bV4P?U/`;rm]/NQXjMmvR620WM6CW?!%49rnsp)}@rv;PheCB?2zS/Dk^]ex@1<*8(`xsf7BeB2*lkXt{v0|qXg)Qf2MiiURgL<Xl!ws<mdDfx7,9m2F,L0]{<PVsv7+v,*.|u.L0*^!f[{8#p}7?JF(+.XTopc%;U3KF6x2v?*#)cv=y8nVN|Vy&mOi=^#UpV${?@KO;2hn9Z<^KS3WoAFUOe=pg@|cKMX.FHo2KFrDtC}HEdBdmY+&T^tXBNdYodZGdYo*hYHGK1[,n^T^U!KoWpFu&yZ?Qn^4Ex`vsZqdC55Nc]X@*J}zT]h.tmeid^_AAnTbjlkBtoex$Cs@%nfrG6:b@$j^:!"d)u/[0L}7E;;eFxE[uz8Vp:u3xGT@`Z<`FUuG45K0]YWxBG73F85"?;X/Cw]|jn%b=71`0e(noG@>8f)=O`qCzGVajgSRZ*,=Mk#c/Z&<bQ2/y6h?}P+/zks_>9LUUQg3$"M4>#2ZV=gP@OsC"Wrss>q~GP:vMw*KqRw#W(8_Lb=)5bg%F)u93Bx?(pg`t4&/u6ZP{0MZK6[BD)[2}S7131e![r`7+.TP2f6p|9$tW*5BS#GE_dH>]hQ$gOjASab],pq`*F.$:dy~TGv(v5Kk?5pL?97[tr.nFNx`xuvQ~>>l9])}QnXgb<DvC^#*7_?~_Nb2F{mGn$_bBP+&T$eMU;P(~|?`U26CwKU$epiWa||o:#9ZJWI$*JqA,WsoW8TP(B@DzE.c(vnc#)yNl1#|#;JL)w%xv,POoBZjxzST8#z@&UX$b!uSnqqe93moW7=?7RP#*$I}3W2G2~RB2h`7x/!.3ux]M4`Lap#XfR*#3~.(v5KlL])cF;dX4;/+n"<3yirI`6jDlctA&wRk)Jyn4(:fuzh<9f/M7=C5z:{mPA#fnVL}a4aIP/U@VEk?/{(>hgBO1/6sn|Vs=h{T/|m6DlQ%:K<xf&8`m%@VkBO"QE|=E%P$*^LJP1_Fhi[4[U)tu)%YiV}#nyI9D;+{#*if{w8(7CR:Un4bHYS*R/,fO{+.X7|M#>JMq[}3[oV4FULzvF7,anf?,%.pU)m)]4%>P}`y[Prfmn:PAD{p0#St81kaWB|lav`1]1R=kr}Hj/ErT`h;@C*:}*(/;"lNZ("<Yv/7K?,Ex=_JQ#?6*CO=$uIh`%>(nCZx&%_H`Hb9I2(;}KoSl%}DxM?]+GLc/B)oU:m,Oa$3zUV51={6PWios8C"|/N|,D[=X7{=Nz9l%d^PbiU{:V7iVFbpo{M2K_DU;&;VysSx"ex8:]:{g~eN]kJ^mAWP::oe^As%77KUO$mVEt$DMalU_77H*dVg=x$VqL7+7"}7aj72S;`jia74>5K6n3#TB|_s]jqwRFHlD:_bJg<0k6Qm4?fk^672i{&7"TjF8t{xgd/gc0[dNR*/uB@9Gj)d:{8IX*6/*3pfJJ0}rQ8?$<_B4SU(SQv:yYL5$~K5L5$dH#$sg"3Ve/uOsB693x0Po#Yy~t8MZ@sPP8[ygB2M8oWmR0Vnhzf:tQ+RB}eC`JR[Q@1l#~a"jQ[opunG/yb,zHL`9]lTgz,JeUU8HZP0.qM".NEAv+8(,PyjS|%j.zn}rX#(gcB.{Q5|UB}5[YtV^.o/cX/|`3(OiiHQuwF7bf*rUGFLu(r~%KRGs,[KqO{#`EI)JQA>F?*1u7^O6WO_[N7oI7trW:C,_fnKn]VPx<)PW_u5/A^y?sv.1^N/tJR?&4Ih5";TC4_6VP$Dyb/dO%x<53(nL7rOS=}QI7hkoaugni4V|N1`Fu{>LW{Lwm=t~e/Pw?WfAD=QZG`%`d"+q*ztDJ7I`s_&Kh|]NGa1g]dWGYY/[1[TO<U*z?o81HsZFl@ayHB`3qt"(xuF`wI4?Y=Cza/.WGj?DspBW7fK7(J^;l>oWIF3tA+5_R_pynO9^6mgZtJwr#`?EL?b_wJR1X/<&}TGCy_+*GRm.WGOV+y=zJ*z0<^7JWxR:3FzWanFAWs0OaC`pXgLH1GqhYsA4NB!LZ7~];>*B.k7XclmU*V?.U+pWZyp/[q6"%z#IR1!3:ZhR}!/Z?n<hJiPIp[`a,aK&b^SM;3?uKt``f},&MjUixqleQr`ZfGnLu,ki2.]pxh<,&NkIqz)O|V>ZAW_j`,@cY2lBX8<}nQ]VXhN_^&<{x|IL0R7ed[~[PMliyDlfwRu#jDJjfcBHs}6EwD0|(+H"E`!/3,8hjATu~4,@O^qiQLT<I0l>U1[3kma0D2y|ILk`Uw>tWg)|u>,__GFo|@uv[fUETb.4=.#<gX3_7~EnGeA<%EYU&uC#zr%:B.{Cx03L.UcOUX~NB>/FVXP7!E#1Daus]WpL`MsZ{)"|ltt{g<g>+IM3"mMu2[vKh9>7xdJ$U/f>:fj#nfnQ#1(sjiqtxDW8G@5qo$a":[VU8T%5Sc,loQjeW&/Xo8W/N^T(X`lp@82[gC,znY3fhKfaoW~Cit[FUL?LC5@tAkNjt;?q,&ZH:et$"fjYAcgQy*EGB6{]&8a.XvgJiumQkFm.P{[.7F^Uys$qw[Kx(MOP*Cs}$Rz)yvMihFFo8FR_K=/J7E?^)qu*]be4.vTd@rwAuo|1F)cxl>RW@(V(V+M^Fv=4TY6BgiH&!_xu!@eh<XwYc_%vx1gVb.lFu<6<|?=8&C0,b7uun*|D$,x$AG!0,oQD4r=.},g`q)x{9vk*$ESwD.7%.1B)ZHRig40%AObpYeS*0/AkAqF2j.F1_R3&m%Wyb5:aV)r`h[9qRH={9#^0su*@J};/nw9[n~#q.Q^j?(7c4.mPy5H;Rcajk<9g^uJ^F(NJN/y[GCy3df?|XgdZF2.%wJ{&`}o0B.tGJO7Tbg8!.oT47+93?u656#M5#i5<i/{K>*2SZoeV+pe?}%kh=:p)Vy@QmBR~Hki]MC[g%i;j8fg&&SExJ+&;?]~^siTMGC?+Cy%PxI/Q#*`Y,m}FzhCTt=}]"_0u"N>I=8]C:z9*w>mFxrIJz,|TqVk$0OY*;,H[FU._:+kDUd$B3~|#R)~lP$B7BYH(KM$%oXJCcs^pvo|q2O8p`au?B84&jOy`q#B|ZW=k%YU1gPX9Sm&;Kx(.S$P.&8he(j.D$i;j&%t^>l?ei{r^gh%i1^fxAhjxdPH6vU6Q/^$q}!o>".uu.tR>N@<E1qc=5)r|we{{rQmDkd2W<J^9oeLdRtvF`9@t)LS_V%W1sJ*^q<p%MbGI6qACsKC2yc:)D8Bcy[{WK{2/&IIo.{SeH4oupm,BTF{4FaW1O$de,JgCS]}!M?Aq>?<ePE`q?e$FgilFW>H!T!XhDu(%)gS4D}1&2yMVkr0o:[(.o8MWV8y]K=~eI.NcSK!5+XBchEWnqjR7Sv8bh]3SeNL0}O0n;p@<pK16rkMz3${|UJ]I>.SFT)g_RgXc+Kr#|rlL)tx&d2MWwvn}bh).e6?5LNAL1:xqCex7"UY/AqB&B>asT_,&K|^R}gV8?U3D[/W99"DF9"DFvk?0?]p7klRWh*t.SgLR>D5eo$80m%xVs0Se]?ge^u{=GNjXO~/BZx=KBn8ph&1fVK9$=^[,Eh8{L_Xfx"A{?6|PTci4fa<pLp^8,ues2Ii4c>V9w!QX{XDk0sa0B?t2D,k)t|r[vDg`Wbvj<nH>9Hgcw@3o3GqvIO}&zYcq;%bJPo9[{)Hv|nGG*XI.L6E~HVkB!%cv(55D$)*!Vh#z;U%o4vCD4LvvbIh#jgMmAqP#<ls;N4(cb+dU@=q3*7Oj_:+~h%r>d9BW]%E;{Im$DJ:FPvlU&skt[H)T"e=.;6ASB2B.)I=ihxmRNrMp@nmI_9<tn|5QjX#+HC|/=5SsZr+MGYY)a=eBu8IP_thal@*WT`f!IZcE[QL*cH2v++Roc&WaB51Z(N2:<*>dWQ~kfm8z#1u!F2H`iC3C9m>+=6*![*u~G9$@`mZeh`Eqcn&VB&$0Ah"=8~(*X&`%M9^nwVfLsO]n/{eEK[n07,"O{O;a$OT2=MAAGttc:CMO7n|La*]wtI|OTI!AKAX"87_,;7yiEK1D/ISjcE4LQG:C2WgM.E9FnI1XFr?EG5A=D?nW${cX[SkL>BC)7z/80uC!G`VJ2TH}C$a^W9.RH=g6UItu(kD.]clN0aNMb,!iuWWSWsZefd<C9w$XKb+^R7}Cg~8zm]~+Lvj]s4L|IlG$xO3&tI]v$Ca)Cekt8vZ&x77GH`!}2@{=]#Qx=m/m3Id&gnG9?G&q,e?MgC&$Uu%|>1:|x,knoS4egQAM{LR{2bM$z#SxD;y9nB:C3~W./nByzFu3tH>4W&f!^1a_{I:7!4ID&*{OIOt/0tXbGyA~9dRF&x#af1BD.wgU}&oj]YujxqRzO=/?=%;jMF#9%&seRu{B0I..|:((}%^O>rct.,[0lR_Htj}QIE2Qk`/Qu%(*;$U4jwK//0wT^~r?9q:bj[6I;6ZaX#am*&}7!nv=*gl"0F,&S1F3o]veSWVr{Tdy?eytCS@HNb8s,WDF=ul]MxL"&xtmc4<Wq{7%SKXgGzI~Ra9~tMluJpupRx=ijB_*^U!US4KWQ2E:u,9f]3Ycn*H1?ps/:~fDnUa9}!st7i=QA0L`yb:cS+^Ey]&Q)+BUC6a:))EtK?ys+ap8xoDyJo+yM/g"T>.LNf^n,?aA#DXs)hdCltWC3n*TRJEv?rTR{/gqyTNmA|D,(Si{!6;n6dRpZfA#U*5r#xg.k~HmFt20#ggs}<.W7GS@,a`pB@"nEooi){E3MkCM^y3+ATv)*X>@/S|]me0*H8u#5jp@1!<z;hdHePR+?v]8EcYt:?zE}=lU*q_yYuIKu%$s/l1^0HMjaSUpl>iofKviIY|i@EaW1.T[8vhIdon{4[+"wvgS[CcSmt}n#rWgz[a#d1,21Fsu8=;Rgj~$8@a>{!#CjJvB%}O?Lj}<!qmD?fvE#~W$iHN/U,7$G@!!J3Y/LkB1FlNq|U&Qnuo+mU}(p_3]+.qqX}CMpo8xj5$IRQGQuVu_%R;XWz|K%f.z{#@aKYYwa*:mfYNk76>SzH4z@"M/$Akg%=QH`/MH8O{NK~Tkq5:%bZ%M>UzAwI;J:"sHJ:o~h{s%HO5T>RD`,!}/NjEBu~ZFjonFSB)Xd5_zN]4#vp7;*?;1hZ:ijTr_t68~K!m?oy?J=s]!(T;7M56UK!m?jIH`?O5Z#PPCd;&C"l"R&ju#6@WeGHYMN6NQ[GJ?RnsD3%TW#NCoc][Z%?^61sbe/4<KQzf!?O^p!$<o3`g6@MSvn|$_jaIQx4`*]_R#?(+*k3!.FiR?(X?]g9e9xHRbA]*Xdz<R%qOqNM[3kf.3@H{%Z0,Hc_xbu6l~@dVvhV;*yLziAHdks[9?`8X9{@`X)Xq)_k&Gs_PLp2{ExwK1[+orKDJe2x;s}MGe%`[dFVxjA&PVYv$e9:M7_i~l[&yl*U#)QhU}?v<DFhsG,V1_ES6.ek6nm_Qu4yU)LX$LP$v(%T|d4L_T$Jd{<uQNO$6%f`)rTYX"Cqga7Ly].M$I[bUPwtk^o9GIK4$%ry#m]RGV"g%7m=cKlYVuBoz`/xt916&8LOuy`S)qCRj%UM/`;Jcmv#w>Ks%e6&h_<r:^oDO%Oj*T$WQCFl($n|d@erGVXG#+vO>PI,k.06}Orkn(`4.$5<5e=2?WHN{Ckjt+,GH9<*9F3c.fpKSSeefzee?RivOKUCp0mvQv!"553UMrVA,jf`5sUA=Rc#FVR[S&847W^%04O#t8zc%)[T~tlE@+YL${Ecp}u]]!EvU$$+a=XIFF+b1Tb<9,6sDU,4{D,D8erOStN!6XN`..oC^VC]s?fWpr:{##cc8>WOp%)|"2"ckhgeB1bd=to|4,c$P#}X9OR^bYh(.:f3;z6;w]]UJzD0%<aECu8K{yB|qRC"*drXmCIl$|`%N5}OoU+_ZkX$1V1*?j?gmB4+dXe9D;;Z|vN7Is_#J9:}]||.mC+@Cb!R}YCOQ|cw{YbzDBdFj96,Hz)p89Oc$jQGB%52C2<]f17r$Ho9}t.eRHCS+TU#*z?b@9Qg}1y:4H|.apM]I?XB"H3Phr}/nK`fksV9!Y{#$45GgG=[O]8m2cu]&GtCr|Az<yt.RuK[?H2PGrCJ3Ax!xBCC%ZF*VT.M%X:F!H=ywZZzhN(1,vy}C.ciOFTQ?%ZDlWf[Y5P4CZeM3>||<70UIP<iYZ1y6cjh.bDa$f7vvUk%{nvC"c4]/mstm{^S":7biv1n#Kai{Ik{*fKN7TAjUgYZ"7O%%5.2L$2!AinvX?uV(t<wBGZZGW*<B*40Y6#W`|Ykyi29}p"uX?u2;bM;8XV(`4QEIF<U|d&S5d4gJkf1Vwa}mFN;_=XxbNGYsV{atR/^z#92|Q:L`H1Omd,o,YCb<Z+w{EWg1?`:~rttN/[,Y7x`GXfpe,0YG.mo?>,Ol#tsbN"g^C*OM?4Qe?Rx)6">GqW3&FNlb3EizZtI>r`sx{<I=zsfZBE>}QKG~C2d}w|bxJG$L<:/Stj.]!]H[Rm&VxdT#)#8dTlrDK6dO6pRBf}l8.)6>yl[+ZKdw2"j[%_wqFj`Tu6B/h|L?TGpC2Y"/Vplod[(!$s,AMg29d{mc/g]S^W!q{,_:|,7G*LJthX2~Q0GmgF5Af4=1rC4]B.QWB;^VXQ3tNbM3$N_0d;BjVJxd;c.enNt=HA"=uP&y5XH/fk_:?"8>WWsP*~S3u4U`tgaTs@{;y}97lhMw3FHgv"p@i|jY)[J>tMpVzY/q4t&[bYx8V<cq#X?>p:6+!6.h#y&0^S|h]xJQDfHXWT:}A[id)0_eaa_VW36q1TR/mu&FiZOEeTT{hi}7v%Gl*aabWOXm$/SRgL$Gi+aU;yX7%!_J;j@j0N@Q]<d*"~U9N%@j(zBG5v$r!K;5vb,(JWszpjcr+SXa8"5DGkugB3&4eU+XF8lU+Pf31&S!1zd5,WqWc0jfu2"b_}G?MX!8#PzIfOX65]>i?M@X6t{+*[Y?dL)1F/4|`Vb)YX%k|H=(c"l>Z/4YF)z:TOt,bV!>DijB"&1r>a53^*m@L[`+}b{bc[T5bwE5H>},jH5~y4G#5CA~o<=zZK7kA!ydJqY#TYq<xHBIeDy36AiM{9iFmz?>>ex0uL1%gQ!K9Lv]vdhAwY{VW|V{i4l6rG}q:jBt61Hd4bhl8K,p%0=]r#Vvup_E!R^/[1ySJv.yIYpTX>AQa3=)w#R}<p68N:a[apY?<G[")+WAGY=K7RJ[8`VcHx*8TDZoEQ4rpZ3qg~T1[BxxtmQW/zb@lie{CmQ5*"Hg+pGBS2m~ptf=4TeFh~bMUezeRBug^d@`k0a%60WzY$u*IRf`*bCM:}o[;ZDUp(Mh<96SBo"~h~?]f?C$&rrPq4ZNM~.Q8x^Rmnehgm84,=IQsrQ1=Rjx[=3?Z1WkN7uRUwfwiFHyqC2!NP:ANAPk@z)JRJsZp%2bb?,?%/>viT.B7Rp`xE<Mu2@..!$tQ9t[1<ufpwK8#Y).:<!KKA0N<Bk$ggng_hS7KL8#"W~z$IH4?^<Bw}>*,}](dM1?[?f#jgma]z|{#&K3(#/OXDr>;tG:/<u&S{C&dQ(BVcsr}El!m5NC%D5>?!fq#MLA"rzp9Vas4s:KhAz[JouS6a`>Jwr0mGEp9di]=t64_7+nB(Lu/#_`E$9/sg$3HQ!K9vBHu},RBb)3VyMeon,Q@ne@y^fR4{u23={&LkzOL(>qP.|[Pol]3pH)Zxku>~$8</x^.IU]FRn>,VB~QK4Iv)BZbkJ2,Q+|d.DiNpnt5.o+PjwF{zHQ*Ffy]H:?%h_gkm?28|)%kG9n]1?*Qb"NGLh"_+3>hUZ<Ag?#{@l})"Ok7Z*n&NZ$GS5Sk9[RC0K!I[#cU!xX%M["rR/(gL;Khn3dz[!F"7?o`2ct2B5!9J,x$Mp8w+|ulxiejo19t%NvIb3x_v%b((t9>}zRsf6{EI1EC8+}v%Ixj11.@:<E"p(?eIczto02Ks73/Y@}rUh_sM(1X^;ISPeeV}Ev,4J,5N~R8#b.vW,0qQ3cuKKo}}.>SxF<+sb0sG4G.mi$cE%@c!W9$5ZCC};B$0R.lw9<I?VMX+/q3jLh^ZCL>}cq:C9K/bOue<h#qCx<!VTAsj~9`U<w(Sq"73lPspb}le.pn?|ot|FFD>_Ny6[W`fp&!IkiYww>gZ`Q[++IB<w<>n[9UA)8=do^|Qv<_#p$!%h"XYu8M=|Pl=;ZD?2E2vhR~pKw{&Y[kua:Z}~a+.>cP4{Ow<CR)H[3q4DEx5wTl,DLPah`P`(`wYHjw"*NFznIC5TMA5MsMaTp{LhK><nAI7=w;Bk$x>b4sb|kh4tdCnC/LasdYj$>=6#%TP7bK^<y:NLl`l!8XLo/))_/kPwzLB5tDJip6qK(QiDsPM!FCf4}HC/Jpk[|<ipy6j3=2_%`kw&w^wk/sF._B]2uaI)oWF%ZQZ+0J%w3FW2<3j_$xGA4NsqrWeZqA,/b,VE]:7}YVinNh`NxL4~mZbPkA"CI4w/Rm!c<|HlK]+pHbH4]Jc^%uTO~SHu[)}i]M+HC2"QN`)$!/jZt.E~`.~/rG0Ty8!vd}4Mjz)jUis)GuOR>hW%COTVDA=(LKc%6bQ@^t,Eeo}ivKE>h/Zmh%b}v3*.]5;C^I_4?Nqd%72%=6u`N1:!1IW/qyzC?[B:sWXbtJ|aUHrBH$>rU~ZhFJ(Gbiv2WyXE!sER5c18{YY8{_@EwfMDmOdO=p*G$+A(KHr5,dC=8g=jH>vccsWI$r|Ic8}l3k,dZO/2g*GlCV6a3qY+bs7L?X0{I[G5_#{CT:w,Reh2+mt@Jzx=x0COQk}K/19%[=}[|{*CvXizREk&iZh2SE/Gai5pGF:]X/@Dl^l![/~/{3ju=P.{hL<`y{krqkIxS}q_`Y`y1AN7[X;~qD){<rVV`Cs,{pYoYft$I;xQQwEE{jY{$eFrG0;8SL^4Q>go2k<bUf?P,4qN($z`t#nWfIfe]~w4hH7Tt""EX_Qo?t{0|^"/{*@a5gz4pPjx8SK{jN^.3NG9^Z*o}?52dNF@nD(Sq&s;^>U?76&3|L^@pS`YTg]2:>j|O1X*{.$(TErzvs1Viq">*_t]q**l^N[cPoG*&8@Oc~4by^.}4,"Ry>zlBGQ>Oz$lfG{"K.`M7F6aq!*g$Ov$3bgTh`wm=+S#etT&MJ0I8ynRY?T<kgn}Tt`Way&!n;aX"^ROUY$)j57f<Ow@<SXPYCip0o{|s<8}/V2]@PyOp?[MA091:r|UwZa,*gF[F/)8.mt+2:0_Bqu.PI46O2IV%zp*WH?v0rYSZU.0I@KP7T5t"Yk37VC&$nZPZd%@h^L<MpP@Ch>.s(.ePSEov_Srcv}RX)TEs?2MBsb}K=I+f8Ncvy>ED)66iHA~H`1+~G~?j*+L1l3fNN68`Y/L)j^sVgGsV9FVmQ7TkJhD!7f7cEWwsbT:DD<S0$)_moy%C_7kSsx7qU_0;bRMQt&)p)yz(AUyVx<6pBulwH{$(N:ti!Z<wz<}W6sBsqRQ`}3z)woj%+nKRkS^^Cx,C1oy:];]cQ,6S[sag~GP`LbRe8y/vS%I&i3(s!CR`SB<$v{">_ec{0/;>qOZQ,IatT*Z=%z7vKK8=I}:eZUz}jL<_U0!,(4E0SvJJT=a]ZKBHS*lPIiG^Q3n$yaZ?Ms6OVazJttV~7ne]rg,6$;]TAY1E+7E*xpzS58j,@+R:tp&6UM%K7Df[ojv%Vz#qs@og!G9e_Yj&hfEqWe:b^kkqXte7%Bq:+%PQ*)}^xx]x%Td1uLO.~M_c9J*NWTXJ/?7*G}Mx[Kl@iHqa1OTexL)ou:C+S`9rFQ~~D)Y=akMV#Qp"$s/!Xxa_y2rFlKgSAz<,aFsXIWr^hMegJ|tK&!f%X0[ZxsnclwDoh;pc%|S5z.SmQs2?s@u]2Vqza{4dkH:s~JKFEmR"2U3_BpKNt%wpGN`4=uyh1jx3QO8"<r[9b|Op{i{>ENIQu=O|z9l4!nG!2E?U71s"l"<I06|T1z,@Nttyh!n.*uafmZlS[=IvM.:6k:F1d9.b76=grZPlsJlgn1F7<bHjlgUQoJo#tE>;[c@;hahAXv~470cDJlP[t(n|%d`RImWg)*Uq{r*~?zHX1C$nHRczhuHUl5Cn78/@^RMAlCkhk5(@cQ]j}M"Do`HZ$Vg=8D%C@96vnD[Yj2?prSkCQ6:AE2)"CiO66HtRr{j=xho7)6)*Jr*dKlll[bE:$pG9HI42L.tAS=57r,loI[V%wY414MQ.ba8|m~$"&|#*[0bU6%3H1Ng{aE:::i|zCKtiG.,7RWO8]$9]h>WsV;+SF_p>ZAgp+Gjwtk;R,!zBSP+l<u`:}!^!r6*x?du;O+.AV@kT6K/)$[=R_N``22l*74[Z4NnP2.toRZq.*kbHnYh_oXEByFLAJ(BlQ69$f57x1|E.IiCot9ppv7gH8PWU[c5UXy[6Vb"y2"Lg.(j`o8>CN~2z5BPSG`K1PL:oYr?CRXmVV=yvNbUs&KYf&3}.)htX1*R(C~;p*2JKPq[JEtBrr=%]H5!yzxCfsKXb](iKb;7@S:sg4D}8?gBA5SJ&JM_G1XpJ3;ak!gj@Vu?)dhK*jOGL)@(.C,c|sE"j&WYGhmzzamG/TP[4lRQ{Y,Cql&~%5V(X_3Iw{U.)Uk@/5{)!S5^:LUp(yZhQHL#u5UO@D#$>,>X$<$j|Q@i_>(,o2mY+TF?eUD!)yADG5Vk+42P+Q{7<)w?CEu0~7T/!0Lwu3NXw_zmz=x)gL[fvwp8Klp:"o#}n*_fo.xq4&`wq5w["]:!t:O7U^V_WJ`*`JdUZi=jvQstGB#eTa!6i#`KlM;AK{H:yx0B?H%UJCrAF`uOZ#s%6,O3hGW64?4O10UsGd}?!mTy(g:5<#N|AI)eg%0y2Kx#r9Ru<rgQkAPa(W}$"En}<5.]q:(?uz[#`5_K.9oC9R[w#CMxEB*G1:TX65f#&!!F{#Z}JQQ.gl*RDpm9owLb++98+@#du@tAX{o;&x7Caubk0FH`<Q96?Y@~>I1qYtFIR!/Wmnm*~X@eCQ@gN|IOZ3gKbq80O<SU1H,LUJv>NjOtc)M(@.FpYc/sf^w),:V.EH2^I7FmBS^]S*d4<m#:kR(Ch[Q&nU"Q`c(p_%Ai4u&S"N@3}1qpUiJVspi}O^J2VKh"Pjv%v/+R%&Lm1d(vpZB(;pPPD:~tTd15^jvTDCN5:,Eb{m+4Z[T7hDtC:4mQz([*p#YBdV&fDGF&(<6hrP|C)GCR2[=OlC&m`YMOXp;|yZaR:6BqZYRpT#}@(P#`P]0&GPP_UBroQOE;.wk/o`6acI%n([XTIfV(Kc5!0c*I4hlO$N~`C^IWIo_T3^P(.M?TMVEZ&3db=ZEs,C_3mT[95+WpF]QZw3pP*9YS~u0T472l"}4{!DY[REy:rg:vd[nr^`nD)Clr5g7s}GS+heJmCjL9N^6{Nhy~j][z4)9(?Y4FAJ4H^bu>x4<|lYrQ}V6?S0QyiBCtF^%4ml8v7(z87]Lyhg(DURCg%C2^lkgBAwKnWQ2E`X?#Ag>(Z@!biF.]Mek}|#I+Z3%.U>f^fs=Iw+,:jWrvgGsj;jK_z&SZz{WjY)l]dgC)_iLo{b5ewW).$b`,Bjo5BwW]EYWcCk{$/~zin|k45r+,o^~p"n8UY}gME!g>rDWsrDO{suid$4CP3nQOC*goz;X"JlRP6h37a2$4ljMUa4E6Im^_|J0o.bN3SD&+Zd{If4K]W[44}Hb"y{wsLF)W]&0Gom2#n?YVLi=rm+c/U:.EYXdT7v3:Bt%Qa32N$}NYmr[l.e%{,pX/G@*Jttsp.hR/(@pQ2P_a3Vq.N>*+e1=R+fyTAZk&rq2=l4B_+]f*KOTsyPs}YH@CbscX3cGJNERO<iz=Z7(9W7C5=zw4eIL(V*um;MoM2g!{DV$9/w`O~?bt[IFvxgH!KEz+>u+!+hTyrC/*jOow`$;Le[;Z219}$r0HjhXTWrwpb8>8"K8jXyHGq^}JpWZe61xsqH,J)VW0?5X%](dV$Qj0FJB5YCDc3!h`x#O$l63]5|?]^MAdn)O*+QA9h98$ExI}tN2G:8`*n8X=IIHpT&r1bi$oZ_x^?~"O(g~;Jeusx=a+P?60oKn:5!UsWdq/"v`tHWC<52%Cwy,u#^nq0r]x0Wz/gBRFJ4{^!UvMt8,U^C+dY%tyif6Pixkn8*UZ<XwR98YOBb8,Vr=[04&(cB=2UZdcDDW08j,o9E0jxP=YOPgb583n&IJBrhI#W4x,q;1l.8)e~>SVZtI{OcZaeGb96S8x<<>0y0CcAKehUpHtJbsOOl,TcBM+*!m_~Ms.ITU+I`|KC}W;6yl1AP_Dd}zXy{A7*fEt)b`wbS,HNHej9c`nG(Z.lc]#.R(T~m20rC@16<6eK7C_B14%?31RZ${pA2%x8y*.x@.ZF&l{?(]7p^4XE.>V&AI(1ShyX5.It!)]IyR`}J}tYLtyIvlkz29^&^k,u<ZEK>3;8x8XIYlF26C^4k>$}`AcF4M;#b#D|uK@Kn?L0S/^4wu5H,tD/RnKla^hYzFv"/(YX)bSY0x_a]w9892iBusuBcGKyV"eo<Ykzhb$A`w"ODS>)uf1YM>3{T61"_$2lWF[/qP&%ZJbye$GUODe2C86[<A`iWteqA^m32]K&S*h|S_e^a)[^ozP]7Iv!]7,_0MXA"TY5k/$?`/V$D@NX3aWXi{F+oS6Qf]WbGnCEw1T+fyV0=n&rAX`qDI3TQCa@BUTra7o>+7X%4AZa?@,c:t3>IY8},LBmd/Zn/;GyI&i2RpyS=Y:H4ezX}b$I]9~HkYj&5#Gy@7x?RilP2ZehnmnZbQ7B/P(QV"Eh|dYs1$j"%wC`x(9>[oq|#!8o?8xi8,<wo:yAa8}m1DFun8Od4ji,6gsXG5p1WfB]Y4}C^%fH{q)x/c#b(mxmywYl(=*2!7.;h4Mn4[=VerEZ}3l~vZR^W/W~SH.lw[4yH%oR15V,0`2B8RK/&KKRxF?f9N)VN[3xN?P(q|2k=S91^v0r:T3.<f..nV2e/T*Xi!tNDDl)0NC?/wo%0R4^?=$$E?H.avVg6<$5X^ERU6C;%i+>jDXdLJIkaaNd]2:|={VMF<wl!T6DT0{~=7$zn1.bvB:p*qT>&^AFN0te>=x:4#+"5mx7"(^kkn!0Y.?KEc=F)0V[%7x]|Oz4.u(),I2rG+wu{!!^}c?HJ!y:J]Ud.@]rY23)`*}qJSto]nZFVFhJea0B?(s:m3Xc5%E6_Yt!X~`S.x}b4{;4c<idE^=icUbs64H>].wH;Y,G&|Z>z){CZ`!4Q(wwn_1Nz?U"kooD>L?m?H5u~cO@TA5VwCVrDMgSfhbWhUF!6Gkn%(SI84nTg;I.iGn+x6mtv)`+6[*<Ga]RxB!DayI#CU3au#O#@82HR:,RJu9=]9CPXlF@<$)%+PC}|FJRhuJ,*~]X^S1(Fz8J8EBNFneQWp1PjD}Cl1#dHc:$s(C/pye;<b[d{0G?/r5,rl<EpNz)?RgTNj;rDB..~1ZS;5tRzT0<S59=XItGU:Ch7T>U`TC7,RT,?V>M|MjDl(=LU43,nZSrxT3D^84YIZ?IlG@=?iCTWr!>Z%xtUaiUE7q?TuO*%4cz{Qeo<dXq26tONyK39}cr}gSM!@62HW:~jK|A{:inM]74<^zBr*hidiFLYkRKi$=S&6IekS_:&{E]abI*)d62ndUPFAt:3ilI<XcWf91:4{Q>n(DGUQ/J5/1:z@)@a_m2wFXqSEQR#_Fw%+@^(+r77c5&j35Hi[8N|;1%:4/A`mx|{.H.+|f~2oRJ9|ZG,zON2!^r/ZS@L:,>}M[MtGzUsQ81}&h!yYs4WAgxVhPGCLBCiK<~qzTW)xAFD#"VNC%3Y$)]f_J3*G?#65"5M?|q7j%R~dfAm,5SXQqZ9._lGJ9G@^286]MsITfD}BkzNcOMC(@TYwk+o]V7si}$].53CgV:E|Z>PZZ/zG)0VUM%@@bK)%jO/_z6;@#3fX.b^GuT8~hZr,#f,9wM^%/hQGmEJS_^zKC&+vx$TA8wma`]OoclX`T?~{uzyXBa<ro,$vDRm8|!L0<uT`1C@M67^j6]/$3N*").*~vA{q3xpiZiEG,R:/bj:[[rx!{j,xBI,;sT%cPh8MpY!*~A7]KC7~K!vKl`rah&_/NyqG}#?*(NH{,$BlSK8o+0Ru3b@q91C3tA}FZ.PPsL.m~g(K%0b3u7mhRpUp@fd9f!2thq#r%qGvv^<G!#.^6r=_Z!8d~6xub1KNtKLcFcXF_87Y{q%s|/+VB=yfasz>nec^XSA8xu{i%zvl3QJ{jS,[Z<[3pqF[bjzH#8oG5R(q{q3C^R8q=DmsZ>5i@kyTVM`frO#{6Ew.Xj,K[:B>NJ&<):~}KN&UV8IR#.[$B5Eh1#I9jI_R~vd6I[h?*=DnccT8$XakfMJjG$^m9O]X_k4FonDgIwy7F;DNlvi?%hX|Xy5:BNKqk+QzBgcK.I.X3rB?R"bE,P*]:pSMo72sLaG!1RL9&b<r@@&llmVJyP?[i&G_UP%2}Q*`>x/T6[Z;)Ox)h*m^m8<t5&OjY@h;c5,Sef{orAGWS#G%5sFv6`Yrp|4srPa3+^^ZB)[.x4lZ@*!qb6#i#XlW@#/EQcTm1/(WpYk4UtIGyU0t*8g9.&R"BZL351)5>xoIyl>U;}dGmfjOt4UyR`*O~0?wbSi%V$Kh:=U(Y(?^=5`Qc,tPkvn}*Z?lI(|)[op3H&65H_d<;vw#hkKOnZ0h!sMPo:h;]F)RvRb=:O/xTj5^[S<c%F|G38LnR%uho;{#?+Kxb:GE&C&7F9cM?Ws/zzB^mT1OA=5qS{OPpm@XaI9NSDxtDP]u++Q3eetrP{*x9Mq%P&ZPadN=K@0=):w|F8Wjh1iTXodYli~iT/z"4}4AHuYvw}*1"9^0&%#;*S1|aER(t1E)K]bU+Obf_EZ.0*$w.l79i,bqdJ|WFn/W5n}E)9A(:Q}Mm>6HYfEn#P+fgd5b,{Bhb@~2hQ+udX`{?+hNK7a;^EeA6Xhq6^TB>>%`$>$H9z1GOY^t^_|xcKYPol2$mbgerF[B4LgFfw6R0[ZYmfb#%x<,%slOtX[n=EXFD!v1i(g/~fRo!./M(*g}#bn79zD<%.x*TVq$2Y2W#k6>kJ(8l/}4b]=ZMxQO)EYiLBKc1H%~p$8:yM*~p:r3C4|_!IfFu5IfDFv<7,E`kM<?:rp_glhkBMlMC83]@RkO;ZB{[,z[m(`c2X;~F|T|/Mr+0{@iVYN~([b6ut}>73Uv(908duLa%Y]I|8ZONybUK8a659!3jP5,%^I)m%69YNVzE+TCqZ~:rodm>yB&qRLI{pi[&z@PDcuHKFGlq$WNZtc_w8F&li6q8?d>$IK4;G?C#ia(eCfh]=`u`YKP{@7?mMPI>Z)!ZF~u/Abymg.H4H${h:/X:4_WBI#7tt))gfN_c%JXyOSb~sjuic(<>%b]Bm55N7#]QuUV%"er#stpvqTVQR5t4A@%?_`/h_?(Q^MFa?7O!AUg!pNxVg5j6E$tzRN[/IV,S/5j(v&g#pvCw"tz$e.cnDGw6E;5hYNGZn7oG[lY@5_*Sh9ba3&;w*PBksnci/C^q.yxZvrVl@.5yeuEz[?2C|4a;R<jQ,<R&JZvr0x>.}<ZFl?jo3`II(^)4g}?zOeik&oLm!x"NENuNvN6Y%C|P&*%Y<@/RrM&6G$#H?sohS@pr0w"]F(iTWk^1H`D6eq?Hy_8gEL=5uxfzVyp58I{JKf~Nt1"Ie;1VW{`}s&:Rk5Wu6eDCi;4P^9>qvM8geX<y!|>R9G%/ns)0Gu&RcVO)<a1t$ShG(!vm<MH(_]<,c>}zEK/NzLvg!=}qs|az++cSGUyn?G8i*;Xecyo=s9th<:s@{OyW3[b]e4]M)rWv]Tzu0LyIoL<7[0CU0S=3L&*v|>r64cAO06}WF7~V1L:Q.SN(#/~uxNJmoxyvWc@mQN(:b$b|IgCN[`x/Nc6R@!hT]e48G499UHESRQ+9xf&[r[G?*Dosx;OshV!ZUtE$Y~!i./eAuwy<;+<hZ)X(+U_q[tzdQgBD5C_z=#y_KPm0$OAO?_ICc`dv#TCn5^g6NRpfCCSVUv&IYL%LT!ti#,T~#D3gk5O>K?f__TJm~jQ&ojZQ?sbX?j[Lfw9w1*3y/uy%qK!UM2;4rSXK`Rt`h&m))frDc9onGcJq4KkswjhLxO2x}%Y_[Fy`>72m#(v%ojbcH4&*w+Edp3}fYb;m4Y{C#K#LV[|id0ijmZl]Lfb{1Y)tx6|hjRp1Hp$D!"Rt?_AmxpsHo@ni<Rbo*x)A$l+UER[nM5a#/Pk"[:Kj_zl`v[v0O2!DCw*ywja/b0^j*Ldn*zGqqaTMVJ.TB/GK7(`dPf]kR`ZJo!ScknVH2`A^r/^ox?u#/.%c:)BXFia7$#nEcQbd4e.iN/Ym@=WTy9cf0iAIg6z3bChn79I[Y.k=7|~ImGY$^1Mi61$QtFUCp1ZFH@uATK7:&096%d^rB;K#q6YREe8WgSBT*<<<#xsq4RkBaVd;iANE1CbeUR{Mr0G6d[<<XkgyoY3>(7wCg.b393B)~Z_}pfXOSbyI>hnB*$q7T>!E9e@oU%hn]^=GlQ^g/%=5xWk:n,e``ak|=.c%.PYtwxq@^D*U&BB(v^t:H]2gn^uucDl?w%]Y8:BQ1>GgC[nF%;QEk_WMNb;&i@NZ1X>)V*X8SsHBNmW(z+F_2pl3._,YcqIRpoo#o$rx.;gyD+%+RL@Jgk}Gp^+BAk/_nV)y$S$R`GX[w}(wZQfn6gS<Y9R%WKdMBb0`fK5<CPSO`P8}(P.SoeS$4OD0u3QAqf"PDgpue0!e/rg)Rk*JeU$!jmvEWhiV$NI:}e[FkNGBz[&NU{jtK%c%WAn*oD/C*[:F`Hk::!^DD$m3)mpahj[P0dj.p2TW<hgyY[CRhUajb"fY/RNSQ9D}$<*W:Fq[ZLz,irWiwK)Z#(5Lk?=A!eJ*R^{&;rlH<r&{W*1?w4u]NCUPX_t7X^j9S1V"3a!k>/G):;h{v2.U:qEr&K(c5!!L]qJMyy)^Rp"x^bAsO0&)dwTyRPW[m70LxN(f3tdG=xiM[6=amridMYx!,f9Ug>NM#3fc@,1VDG*:olj6:[{aDB!<8)Iy.}4Z8vCzi3xir,uyO[cLPH5[KW4]D1J$q<TqX)vL26O~XgPOHa]|?$d<4BZVABQTM!QPf;XKNoUM;rIl&<K^pu4{Tntlq=(ipoAq&>?=Fv1!XAn7V}<"eZ5S>$bT%n>CrQ$t4EHayQ!Q#L%awo<Q&M>%r&zF`@KwLoUwqb`FRs_oHsMf2LO&iqlp*tBKCZV.,Kf`K<6!b0e|TtubD$Vf)Oe@+CYlj%uX"uC&2ge7H/[D/Keoz{yKS9~848l.6CAmlc~EQDO%&*,nOTrIJ=TO%V#"Q,5m}(2k1e;xv~i7DR*Movl,l_22XrdY[4F[?vI>I9k.9vjFJ|M=N2,L&Fy@BGjaziEmf!5iP,D8haIB]Sq?(znA},+@fh3UFKZ|=byj>)~o&sQZaw4s8a1[1RBCrgS{ds7["*{I.s(p!/KhA=m0*JZL6F/n"A)pNkI*0EJEL4gIcR*oYPGKLHpEQnkLvGRJ"hkECk+#$xK6`%vqwatD.Hqini8.EnG4sQQk{)e4c#ePIqY+.H$G=Uf,1sfY*5`lu.ZcNa9eq_5m4$PJklf:_U.7/nix&<(;i=s8}:6yrfi$wWPY$d<^hdCBef@GdaceX6,t}^87n{UKS+gKK]${n}2A9i(1/#PafIR<y&D16Lr[|:;bRQ4T@4kI+T1UBx<&^egNJRg7#+f9S7GspcJg]YD;vR@x=b:&S2.B[8Z1ltji|N8mQN4d2U^~;n[RUs0TN1sg[tSO`OltnJ,T*gtk,2Fzc/&CU$HjmKU*vm=KGT5ye3vAO^Z8gU&2+ZsCBk?iTQ+*@vAh=u[|)wjGf<qw&#n7#kc%eu&[%rUk74;5!*_>!n#$zLc&klTEx)F.!R0Kj(N;8=Ju~[eY*J^.pC(FmSMLLKpDx.>$7$`Y>[L+L?|XG6>iyg"ycolBD2_.|C$qk0hB(6X7O=3nR$eqe.Pgc`:HGX]vP`Tf:&Ch/kR&o43c>g]/32q>Gq[9IP/pOyplH!3O}HPbJ>bglMYdXmZ`:#uK!:m[46,)YJgH*L,4@4u{_,5LrM44Q/3v]vvX#EZ_j_e2Nm4fE#(/:Wk#8$t8Y]!Q"uTsp.Tv0:d2TMj,Y*R)iS$cE4[~)]MnVj5`q]k)j,nPNWvp%AAE`n#=[[=G5Ef[]l5fR!Eao`pM5;VD*KKzwONv<>(~O}WOu%+Kf!SDUjmr7h!UbXaSia$^"/ZXFO;M&8pqsLYo&`QMqRq6{uLZ]/!@45%5r7s1GQEKom)3Nbu+&UOVM^_rH}mc$O&Z/K|;#A;57o{N8H6eA{3]?vS`/N5g8{RWP[i,f19guxF<GwJT+b`4K~UHDB/(I<g@(K}bP<G/enl)>HP7QQBdBwcrrdl~*l?rk+5!tr`+I#X1%4?K5&t_kbrP]6%:v/ISZ+&^U|4_tU&%PBeuhyZE6ZVT0#_Xmdq6&iB:tBo9$RQQSG_zggT804}LIuRn%B%a*6u*T,aSZe4V51SA5XX8R:xA9A>DMrw]ci.VRHIcA5!8fQsf#Kms~3us9`w8Fl6Yslri+.h^E2c,ZBtRf_D/jh9b*{PrMs1fJ/F%/+NaNSVn4T#<X6lNu9$!K^md(uaQv%iy/smWk:k]5A)!eXjmZW90V(GQEIe&kd9`^T3vbdwgy@*{vLaO<h1:8$/51LW>3>=xtVN[!GHd%>$/,<zXaztv:p}=WT@dFyAmy4js@d}U)V*2nuVLqw*@Md2I_YLd.`/5+ra4NX=`A*Sf65R!e/m!99?P50"AY5e`ChAM$xjX$)QRDH|+7M1"`BQ|$tW?Un}qk~>&FVTBVxS_j;^xb&E5@~Bd:Onn];mG@!l=S3R7rTq4s(.{.aVZ.I8]@`@`O6BDKyzLk0eCJ&THSeik*mD)H?h)$ambV]z8@/pDp@$1hrv+fB9fQ%:x2~c?cdw{!E2rZ%RT}Yu=Ad=8P5LUzhLzr_@MJ/^l%@!RKV(o`8:s}S[jDs_Fs>wJwvO6`#Zt.SG$YTy7[nXS(,Lgm.GyF?(.fQSj(Nm<97^}G0HkU]6UCq:~:t9Ui`&[F~Ket>lz~k0}]G43mF{dR;fkCXb/9eZrea"m%aZ:Wh,:20nX{!S+CWu/UW3^C20!(0}Z?x!@](Q.?=EKy=vLis4gl&lh80.Gy@$;?hwFWlSIU(O|5fe@i~AO;y+J?kVwCfv}s{.Vzcxsf>W*@Q!quq3Bso>KDQXgg1F2@2rm|l(]L?`Ua17b>t^e(#JTQV7(EaniC|q)fZ(@73,f:}Z+wq_WMneccfS{7Ur>B)e6hY#l,F<LXj9qIj.n$a7;vsm#k*P<t[}g52Gj7LcWX@GM|[&|V7kOb$gF!{>B@P+.9RbI,U31I5O<7AJ>}2JK~S)Ge,hZW7#.FZx3[QHfGF>7pYV+(eCGjj>W$/>z;vf4,b7`z~K[Y^BJ"]f/91yvHj:U&!,mSOkUQ>)t[09P#wzUI>V|!};/Z#}k%p3tp;#ONUVR1QCIyrt?~+Sf/S+]]>@/Z*^Q1bS{]n<dB>P;jn**`f>B1qoBx$U8ph>2g4.S3dpH!Nijn}:3=[+)+o)BSXr=`l6<@9[z&7v)H.R[0D71^{!;=P#H}cfz{A#b*!R^7M?7LZGnN[02di%[yOI1JN[B,O@29yRM5|04PJYjjW"4fP<R[h_<@2S4WJ?,vH"hi4&O,@%<14|4rqmUz=CcVw&:Y9u*m35*%Be3/m8WA$eika.%$8zVx7I>z&3m,VI3RVNS2%_;3]khb$N6{F$9.M_E#rS3v)M{kfTKG*BWkeg<%bH=T_y[v`]7}[ngQB_i8M!pkXs^eS;,>5Pvv5<<3i?cd)<gr&#>[o}$Uj:OO`^rS1ck+QBUaCS4yTW[DH3OB"W[NahWNKc7&!b1FzQsw6VBYr0pmg4/!0.D91pN|XdBCJGrHgTi4n,>.)OJg0SKot|sgBm{MJJBvgvU#k_ff!;A,)1@6(%fR[qgOQ+t4,D)w]k{e2"iK?F9T5snMbrh]/8OCvab;,aiO`PYpaV,dVq2it7pBb/iHHWBy@@gQW=(t4u/R&R/1$W5sx`C|(#pVko_.RLcO2y%#%Q[;CT?5}edyX|WJ6(a[jner):bpGzW(+=%^+c@vp1cWVWPi>fk{v&mRT>rxK&YG%mfU;FR#b?4HTCIa*uyPQ7U~K@;|VaS0R:@9OG^q5Bckujq@8^Dr>6UEFc.Z)bet|_H.>XI_Z%<:UBym8<Y_,Nb5J~1D_M0D%}vwX>BSZ9p9f^kh(QN!5u.HhO+OgS6X?EBlTp=%EcP^OVe+_yT"Tq~rUsL_6W@u.GkkB]&Se180Ei>nR`XQ[P8~~!!UO?Rh`$>xN.usGxU%lqdfQt]6+gU(";=GB6xS?&`=nH)W@D#~[v:4pJe$s&tH=q.0fAmE)?w%0%7^@8k>]z@OSHa3w,]~a?&+s>(o}m+sCG_p$SR}hP3rWkvsfY][&|/U#6!>gyoKuWxb][kb[:VJ&GGq:WI`tdF(TkvV4^a|,U?+:Jwd>I2@)bN}*wn_%_?klv=gIt73Vdm_QzM&LYd_}/=1x{^|SL>_A$e]?IvhwN!(xCDr#f<*9"*~$1RcUn#}Z{IivP4lk{)6>M59LF/|#?J/P.?)|Y>P}evp:AYQh|{!4bk_v!$r>9f7c3/.6}shb5L]|@4hn[T&9k~wH5+xz>$N(h`]f[oG@{1GL$8|rFp:+NOQn&;6}flOE.yPX</O##<]8Y7A8|L6J.>KnrCvI=_At)FWC]A]u%l3<bw!#Qs=?aKwYB+zra_e=jhrxc#]v9gUEs3O5h0Wln,h<{q&Mg,EW+o=~IZxR{mkePE|;aX3Dz?v|gy"I`IU$]}MdB`m0Jpz44Q?[(bY;I3%:s,c/$.eFcJ7CtHCvNF[W2@O1IH[1Y3#H..5&s0{LH*&2Lz|i1?jr<u(N55EaQsdTMbYkB!fh98{w({1G6o=`}G;~M01$!pzKHco.w5Zd4!kgUe)bmnVPL%}!Z!A:g&o{pBN(d3ZTKQ6)p=T$#X)SVVH&?ls1tLz)gdSx2K(H2WxUjhH(8{6:j&fG,B}C_r=0>u,M|!G8=I4n]lcSARXjf+i&[(X_V=Itp6$w[|rAL^>RWGJiQCGL=8DL6Qvuu%`poCk=iBt0_#KlNtdr#5}<dS(*eP}EOm+cUPW~$/aH?C&T%J0wo[(z_{M?QTJUpyn=N6kI#(o*GMjtr{C|Kys`"q}+>7f;S[@C}<8)f[o%F5XqDhdt2Ner!:n`]`P/Uz]xMymdO$UBXBH.sFVGGLB3|qGvrbeZGuz]&`AJ22^GH=D*DU2[CM^F@2u~^LGNX2d1`y279%b$$KWA|E^C1h+IN*x!(3O#(Yg>jKC`RbfExgj4WmF{xW+*+(75$?HAdml_+*9@/}0f)1I#s|9zLt<NU#2RYn5/d7L&o;kow3;wuYHR8}mPU9N;IG$9aCFJ;rI5kMoNKjH2ZNMqa8h)<()WZ,Wa:THs6qW9xl{<VQLes)Wo}_C:AS]`Qe7gD+LM]`Tc*)Cm7UZ:8~TBnD?jwJ`9^eu<Wf]Xl8I8&(g{.lE1Fu"[Ib3B1k>R}h)3J5?^*s=4!uJ!Xuy*g#Jg9cD+cIIZpRW_.fx];Igg`>LO{%0k$@d3@Zl3pfuon+R&6$~mTh3Z=dC0aP_T?}%>N6+Xi`Vu}5zlSGz5Cs|h".A,H|:&vST5!{1*K0=+]T;CGc>)LC;YI[^R=~Tz@(}XE}WNcZlaG_sE=</oy"|b>^uZ@%)qQCsWiHuWi19!&JRBg3ay^1&]qTYg7&)D$r!]Mj"5Gr7nGbEt=}nJ,E,fABy(ZZJ3%BhcC1]qbV(B?xlOY*7gXwD+1H+|$?{wOtPiAW<8i{..#MoJej_*HeAAYayE{0"F|a6K$f5]1"W3f%1!yY>T2`61g3G,_d|!HHbYbp0y1KG|[#yS+)N3HE.RqQ7.%EZq,N@>pk/nSd(m"EC:=sDNk:m1nzFuO|KcB/4h0YNGeZGF%3`39A.cSr|Z"04Cqq]&::E)ueUbc^(i{3Q#WEx3PZk/ZPy0?g3nSM2v*tz2)~D2C;0G!R}jJ1pU9):==e/sYk+!_|@7n|+W<uRT}C"6$n/&t8.iLLf{k]s1,|Nn3E|fDr8z^C)R./81ZV;p=cnV&D]Z.={zmTV278JuAMmLUy|uZ.1PFbU(9JV^?gp_0.p#7d!5+_K_K5pp:Y_Eg}LPVRPe9n2Wx2GR7VFnYdW.*z9Tkb.EOcR?oR@*^.)ENCJ2+Pd^a)KViWzQ_)UyHr.`LnU3JCco%fOBMXcbwkg>5#3:"[GC`g^ep=qCQk3(8w5LSOWYBx@.`?|IA.+/BmlpQBuf<hz+G9K&zt*8ow5fgJET0]79_[XEp.]korM:k0&6hVcz<!M_7^&;6W(&}f>2p,fQwDNkcRY!x,5&e5.V+&eK8POFO49&&K#{$UVo[S?Q&*z2yp{{JE#y=I9y*&DotiU^Vz(fQk4TiEXHEanFI2ejB%Cu"s6$N0=_7U~mqSnkX`MR)k,9VWz`:^SD9m$>d[?PSn4#UkL.]S_]#Q}q(:DU_[g(Qojn^Q#FQmSn&?EZ.Oy:qh%@YR>[[}t):rDT:*Q)2djvcz/dUTRhl:scY{j62.0qJU`+=7.,oQK9`#h(9vNzc~AW017TCa9(H.$,H/u[UsG>K85(fB72U4<zQ.[s{:zbR]WbpDM344*(hPh$Q:%8bd2b+S$jZ0F$tGc#t:cCGHXx^x%o>zhchYO=IA/*&N>64D!?2clf7H>bPt,_Ft^@G#5>1S/X>nIIx_Z#)ktN@wx+;d,X[G{5TdB`S{4~P;1#!qB{=2*bdma%$Y6AJKne4/r9@/nr4hNdJ_1bF!}4m.8|X*Gqo?g!&g4*w:zq]6RmWWU<F9&g}REUgT:n>%HVTb1)ER=M9VnD`8IU"q(]`N!VKIas0+R[*l^CJzdL]?,o;Vc`bb4:G>4jD`toAm<ui3ih44>Ca^>IpDx$wSO}*0)_Hy<Dbw%?d_`.qck)>Z$w}B/ZqtU)ZkKU11^~0a|kRrZbAmBp`n)cMc.DgK!MG?#4_v`0O5"*rI`^fB!+HWl+YE;u4%x=I;CFZ[b@bM1O#]sauJZwA(B%wa]G{J],fU<_s>UOS]Tbv/e]*HC|cS7e[MMx6BHFp_X76^BGk19X1yvEzv!MpDLz$xQWPuLH#3XZq)em!27O2@b>nnj5QBtTNZb;^iKV~YF_2.#^ANV(~g,10g"o_etS.rO!#B:D6<%s|;ue`OF(NEa@)b#2.9>J,;anUCuQR_m?(+8+cxppMlSGEoUgWP)NQT1%*l%i?<oL*1Fwgy!7w!:;db+u)a{rxdHL|#}D.KR*)EAxHj)J"%v<{i*4od"oBq]>yXu76%JrQSCJH1f%F{}ET]5iDLvUBC5`CgXoGJxT(Av=Pj3),>Xr$RxEb*k!h~6|gB^_4>{yvc~8=l{Jy`JpLR</2=B@ZqzM?4rDdal23W10N0!q8"3xJt!UVC4kFY?,bZhj}^6){L2Vc8uDq&hK/2U%Xt,id=_;{B"`,)F?1H=GnZw%{$x/aQfD&5]2|6k}4i"}a@%1BFV?L`qu69a~c^!2&mj6LO6`yV2)0z@0usA2p8ld[}`RZ7,e{*d9S[Oa<#b;1yUbtd+x8of^>Zw4Bb3$_+%w20U8F7a/IW7:|^hY@vSOW`Fk6g[d@m_9KYc$h+tT]pji93W?y",M30];z4GwULFFU,yr}q(hy@WOvK;9|b$=9+#&<8*x.}HMQF8IJ6vGhrrpm,lO`NLs:+n{So4b)hb93A_iP0(:DI=ICunVg4C6NG8w3*T1D([lr_x:R4Q2"tM*,1SU"+AuVeHXbJV}6+u.Vi6+X22SpN4b.pEmEEaF/iO5%m[+dMODJqV~t[)mZ[+C^WTyC8tuH<8%T#gj+p`FV9fr4wi5TXA>2|mzk<S`y&[:!7"^WGTLxcWYSM:ml[|rNS)!IdQMU#=eMJ;X_]Vr3h3$,x*&};uiq`HBxynm$sh4NYF8`VasyvrJ!q}>wIKrJX6:@uhR#:jN:4k,>zr1Si>xC0f?kR=ddkEC&tH!2GuWX$&d)TIrfxJH#IrB[7f[6kBXzoE3A`L.@ScRA4h0C0`MzMo:o565^@_,]8"eg@0I_xH]><24r1)z@Hr;M!zPN6NKmGYLGO~Xh{rx8_1n$T~Z$)6Ri9f$feXAjF{<N@Lu2OF~wxdO&y8op$Tai+m8OtNiyI5si!AFgG=&#L:#eX2SLk9)31pTCA,("ZFM}mU.7SB(2+9L~uT*D0bPtKPYVN,`l@3graq?+t9<cS7{=5a6^{]&|m`PInYR`|TJi]x1JI9oHR8H*>k!O{]H[L~HXM9F_U5U:l~,Xja3[y$NuS[$[+/;v%ET!ujHDViVN/.FmD(sOk@B(>Ro1AeblthpZn[1K?|3X)p(]!/=IezXZ|}+v%G#}:i#l7j/,Fc9r#saMd@i%|lNJV~(q/ooHVgcA8Tqb{wBb6n31rMNn{A!9Bxo{!j6Rkhh%<Hf2(Djm8P*Z.]mSrcShz.yN)D`Kd<GjW>X~lz8Mq#G~wSIET)gI}q,(9dTq.)}.Ygt5%9+:2ayjlix*!mqZ%b(L].S,HW|3>i$EDO~E)#XaLMwvTS5cQffk^Ky;C%Yoe|jW=Wb&zfzxXXv.Ot6Z<+g2S>D]TR$=mw>nn_No2~;lh`3vwph"%II4|<(`^3_~SJf+t~8jS3_7Le+>zJ5BcDzi1qO22oA2)@gMMTYQgEvAC8T:BSBh<aes]`we9p=5nw7rwMithNUE8P>|1f&)m7%GNIiZB_`;8!9N(ue<YfT)ViS?oWhqrBl5$m(``^}5#4/Cbq,)2uxSEo8Sd>NG"68RC&)4t(#+_0V5xzu%%j4^F(k>WSV,{Uzm]+wkiUG>9@5+/;XP/#!WddY`=fH=bR=QQ%lqXP$c7[[Lj?oajS&mJkQv/"sp<)/v_r`pw)y7i50_V`Hf0[=|D2Z^84gC^VX%gVu2]}Pq1zB+^xtBRV|yYOj%v}ABSJahX@8wd.L1g*Q`+HUzJuy)szf.=NyTg~OlJb@~/ET4`KXg?>eHr&ZOv%mp08U"GxjJt]D(I?f^1E)q%1Dlv_pEcC:7!nLoU"W;*XI>LM1&N:?73MAqw^9eItm<c[_EW}BgT=3g^}!//ZzheQ1^d9MziE#70SE)%_c[n/t,8A],QGC7Dulm80oacm<l^lVdz~Vr(QDU,|>3~aX%5FHL!{*~qmv@hH5PWm?%:]>Z]zVv|dJPAU[PMEC;OI,bMy+*im],sx1sm^&zMQE/Hd&w"7NzI@)2x[|_F]1y$y<fk(%)*O!Zq#v&VW|)MNUb%u^byF^:2)Nf/|)I{rvfBIaS"jF7$A6},SL@Vv`!*U@z$hK]eZdn9!MNV79Aj@6aXXGO[cX/zgX$d$YUKrM2V#bfi3PDv~?MsbX+bXE&:[HLuU~9:w}hHT00Bal}C*hHC<mouPfSmyzpn:W`pLXI!eW<lJ!Bu(GGHcR+YNo8;%89{$QeyCz_$XBO=8JX*+6;6k|rm0;lYUuGcGTHH_x0aKUOtgyqNXSq<[|Io_7(50x&H0P.4HZfgc?}ObW]]6>M)C"!haCOM+l1m6e{Jxi"E_nbVW6O~X#*f3napf]^Jn8F3aW{!H;B^<&E,Y>{1wd/(F?Ln#rtoG~w[mv3xT9!!HDk9bMVDEnd$nf.<q16e}3j<_JFG=&,VC(vGsDl=*o@/ad>bz8=FuEl73_="M1`o=/nVq+,*^:wFZ{nk:Qp:f;eDw)Acqd9aHn8dFy=;7=N!us/CGhbeEv8mv65(n"N9efDh4lS&G!"<+327js>N;d<hxvJSdfXz^jO6I=@zbitGusbjIO2z=E:S:WTGrM.7mM3w_DQrdWh7k+PX.s`|;5/K:!Vrux+xBhfeV)9EfOi=nkp).kER,bs+?co[;B}g?/>F}IBxjI"]zv8uQ4_:Y5h2]L;eyXw?;K+:bcaD9qw,Jdn"q9vKxdQ;zWWhoP#cml2x[%(p<d:79tHv~AaT#},+N0*GB^ElU4`ak&|ED@d|:+#>yGjNKY(L|K;;.JN*o=9%mIsmvUJt)Mj)EEj~:D~4$~?),7><dU5W.F`P0!PuEpsXN]m`;oW6F)R0G8RQ?$L;~a78j4<(oLP9M@IsT9D^bcR.g|P|sHl;2if=>t8YH<5K*jXK"@W@}++nmOnagz.|h8,JYtz8%=g;*vr_<oK?L<*){;v2r[a=GgmkmXY4Ak%hhb}p)F>8W*#j_:zBMPQd1,]GbGUirbr;V=%TJL7"#7)JfK](EV&B1^e:4;W4z.{Qk}>y{hxsrbtij)iGr&!wz}c61$5mWOvaaV/D)wl2_IO*{bSRaqM&jCvx3?XwFBrV`:8{|V7ab(3d!yYtMk!797}8*K+V%6{K*lD4YD;|]+N]OP,zms*X7~?2Kt.pnD*B]?@XIf@6q<1Q/ku4)qUIW/!4[#cLE(Mu1Pohm[!*LMi29?a+(mn8^72ZEDX,wv*kQ$unmL[{l.HPYSZHOd_SUm!UGOKaEPpFxv/z"N&tJ3`@s3^?sE5>W@n)PXC6cU$vd|57^3|n9:w`V?V<H,(D4$&Heq4!mVbs8z_|Y(b%UVW!eL3Xh@O>]?inLdXqCL,WESs^1qy8J7p?02qP/]U%YB8%L@~9>?[ar&HD$%S5s2]v^8.l^xEW(#YTJtA.#|tC!l&u0MKO+suVmW`[%R]0O,%)OoWXz+OI7K!=:}fo0+I?hcP_FMf73^KC/U_F^Q[B>eslJ;}53m1^*>wt);r%"Gq6%eO4dGwyJ^</A$=[OH?ww40wTEK;MP3{oISq%4V*XW,Y@C)P^9tk>RM&@#dENCxS]wdLybzW0`9Yq8P7,xd8&.R/%PO|:}o0uWi>DsjzrRKMOZEC??"W*);Gwtf?(RG1|d}0ws[8Bdfg62X]C.Oii9T[x}1wvgql$o~>q}>@cM12:vI<1VK;!YoLUgA!`<]_8n*&}6x7]16}b!hv>8&;V;<B1=tAtq@Cfn^dtME%<C%7vM`a8XcY"9,2k2pr=r9lL8R?)/+1Bf0l^a;l`8<whSPP?8_=,)62e[Fm2{EGIGx3`T(8$&JZg<mO8GUx,YI`:t0Ig]R0!kjyM{)RY~b*LS_)U/khIUL?qWEVU"NmzGg;/lH.C4r~Pnye383#v>qCN#:OM{%{{8V;Lf[$,u%CUmUgRSloPm8s<ZKyJ<@(Ie+R[*$R3unV06{v!oMxvvL5ll=:r4z^ejBwfixdAb/QL+kaPSgZ}1ur[5O=@DmMGxWeH/h9PBk^.OuRo8NW7mzS)x4H(wFx]ZY)erkS"G0sete=C2@SYs"s,?/o@!VXdGea}Y18sRr$2^SyD:1E/N9<9sfwH=XGjh;:Pm)rIeoQxn@dYY#8Ro<N@>;4nc>a>;u`FN=h0Su]|((dw_,jg8Z#<CAiy#M7D?YXs"|2o?73W7j)K_r0wD/0GO3=H`d:M4&oZ;C/N3[blJ2Ax_0`^cIPU5g2&:z^+QXMSvGgW6F3oQ2~wvEfwo/(#hIu/Xm7ZBPHTH>0.06elW4z]EEU[&HbH3W2X=o$/+0(j+Und~I[*kE&Rg|/,w#;6Rja`}wdZEauLFV*EVWxHy*,(0[&)+x"p,K(ZT^v!oD$>1WmAw!+`.5dC5,UeMxblva#a>k~M,WbTpUfUXKc9>"*Igz)6t:~TX`D<h:t[]sUb^8)RHbX=@&]u[<}L|aTf:8ysVdZ[~!LB3U2y$Xy5+f2bQ]|%BxK.OyI/2E~)A2C8o>[14^o%UdE+qiXp=j$$%QV]7pb?gpkEjR2fldxE:=d"}IUyqc[TIB.fb.w*.rt^F%E&yjcG${l|+08AzD`y*)gNS.^m2CU38Q1l&|:dcz8r,FDmBtGTaOe~p^lb8@7y>)Y|K!7"W&fvqz#w{sR8jLq8_tIz_5tO!iKu~,LO*0NFXrg!&sczGtK(MA6{a9w48W3c#,Pf#T<*CRl_v7sB@ltFkzzOfR8jXEXpfqy[BQohk*T52aJZ>aH?G!U`jxefS;uTt=hG|y|qM4b}5Hmy6@X&bB5|5MG:XJBSrQhw*ln&%kxo~(ySn{59PhlFMH0a{n<S3S4l[JJ3pq?q&^wFs&.,G{$M!F"Yo~RgQ/o1q3^R*<W[{#:[5QSqJRf)W/8)?FrHvuMB=qL[AS<<ty=[HTh5c}?B.B5h$g=?cqC4}7G99D^k&~?&(}:1RgP<kYAFr[8@pBZu!d21#Gs7#k6d.B*AHaR@M18E@zqptqL{B]iIu{7]k}jg7;>]6+Y,@%Fa9SK+)?pWao.9^ZZ2%wl[_DqvCC#Sy>]%$gSkXG:.Ib1w!08_&#.8mRoem*sQR/[5o0;r*Hlt6+t;@Bo~Z|~(a(dYDD,@S!(#g~A0}Kgxh[{#>zC=:.x"4D>l=L+X|u:7$Bt3K4Ef1DV1JlXWkwt9gAyp.YjbR^/w^`DVnm_&Te$s,Vps}DQF8OAy2B=J_JdJV8mgzGr+eta7SLSP++1de9gR#DxC78<amc(CNAJZZ(*hzprw2a2DrQ~L)25CK5YJ%=LrJefk>o;(~pC)N`3+,]Ddq|%cVrl*J6W^1Za18X/KSfITW0/$5Jfv9%tjXzd!3eh0s3]8}0&sz3D}cA7FqzQgB!,qC]>paGoR~:&GMxtO1d~[UXDmEoTKm0LvvK8~nM}dMc7J=ursWn.LV|pe#7*<%S69W[iR1]!YM$>ELg)s5v>`+ufxV3Y]HEdqcF}pGOcHZgs|>K%sPZqAM82O"./"%2,F/Ss*IWuefM5LiGw278GPVfe.lr!IsX1&+of/k2>vUfCSTx2>NfCtXRdR(!b+Qan{t@9bl_3Dg,/GoqiHBgOS!&f*@4[Hq2HU`Lzm$c&W}Zyv)+e2IR|Vl+j)XAFjj;p~%V]g?M:s@<v?!,8abC^3dRDI__4|D}=yS$sJIEhXbfME/i/;I*Y&2gfB>x4,u:iM&tRA^GLfR<+tRRN9emZZq2xAN:E&,|Y]!f84l0:/IS$XZh{P3+mgcv_&OG9j}Q9s.aM|]K$nQN`g]v/V88E+vnALsVmrUI*Sk/q)c4#Cz+jLKVN1.618r6Sxc}$WGo/:Unr%Q1^|ikU^_BC[gj4qulSvJf:9y7_z{n`uWbIVUNMtw|s9nmY%~uHVHQGFK`<I#IOBUT03_ny1#N:a|I$6#&jUr*$/nLNf/C0bRx5D2^89z59nAx[.5E<}F?@s^.78H9P:IF%&*z5e&_U)CnL"UDrMv+9DV2uG9h1P&65XOGFjw%0$+Pv?fOV#.5OW5|EzQE2X>OYzQ+v(KLwH[k`Ul9U71ku|@B6Shz`)7AjZd8_m0KS|9cw}u=R?0g~D[)#<hb03bv0Q|^{Q_(I^1BXHc"h~@]ba`<JXlj,OYgo;)@:zzzG5oSn#$+tUkmlh(.J|(<xC[pe}qMezF{FTn~J!NSY#M:{c{5W|/F/YE]^.7hDXEKr3St2o`|@LdQiP7B3#Y{n(2Hcz%+.d:B!&g>h&c>3:5;e<C>#a57l/t=8%i54c.8g_zV_%B.qY%08$KWzt77B:bcS"N2SQmCJz]50@`Wt!Qf3S4p?kTIz;!+;uq~C=V~*I*bb?XvBxLc4qHdo*rS<lWl`(2`n/+:A<(TM[Fz$,fl[0fq>KHIa}B~Irm!iMv#={QZqM]8mnd;=k%PB#z?{B+7[y%v7~.$gx*81Ocrv6+vJ!<x)1#Z$9{>zRsm>tAVYm,D+yY;1vPc5OsA.ds_#`4{y?!Soy]a$UNWT#2_uI2#lca3Q(<B#Y`{N^#w>)o?Y>nVP!c`{o^?Oz>#iws]D/C1)eUTJVj@jZsx?dR{:6{bjI,s9*W4Lq#2da*b3S|#2?*}qCTsM(_dfQ$20chR!<IUk<7!IQ8*eCZ&fMmK51rU)VQW]5njK<^i~>Vu}d/]+"B*>|8zOxW6#8bEng}/7eIQ+Vv?a9"CG6KL>Oc%vBMJ"sApYbMRP?"]PJ@f@jsUO6obWp6m2K7OE_BqS7enBIZLZOv0ns29v9X^zEHZ1$<uoC]iZrFp`+kBw5[K7Sd@_7%)L2f%+cT3WaYC,%y=Ifyow1v#z?Ifk3BIk2K.Xo[4t_<*m$t0g,a3da;Ahr+H+QvMMZT#W:g4LE6To9uEMcL,D4ML2wxR}=We$:KB5okK8=l}ybK7CvlSSi>vZ%J)W^lFcnD!dO[NR|(d6?hs&}@l.j@3KIk|smZNZeEx}zHx*1h^jBuBn7~RS>7]BAV=_(kIKR"Y)B/=adun6,TmX+M0FezK6l,]NTD@Dlro@p5q<k:~My{pgp9vR?=]amPN^rgm32}7Ghc+2dao!vypnWuU8T<RhZ2W6oIIG;{EiZqk]F[}dK)#}{z9/|R#fe}yIs]RdOFaGz@cxCr:u9%am^RohaDSAurt,7~xS}14S`UWZu1)w+64wWOxz!X[Y_gUF8sGD2x)(sFYG"==_7,we6)rzpYW3U_U.5;`?Bdoad?R0fSXr]8pmh5Y81^VZciE(Jv7hPC"JU?^4*,IrmzsK@:&%@dXv3~o>Pgc@qLC9CeYqXjCk~u}p1})~7%[M"]H<Z0%@E9Q4o2jn~c@7b}TH^U+r>RB|+|@c5u[Zc$}bdXN`;=z+t,sXI#g4QW^j=4g7]+r%TUO8yG~`/GEpXr`tMOSvDRA2kmnH(GH/QscLKYA5oJ_4wg8;MeE_HdSyW~_1`X=eTr]zRGym_=*]}&vBu#ACJ;[Qc{|up9KET:4Nxg(n0+=L8q8C$yLeq`|i^vo@{vRdiD6B5.GP=WZ59eGWZ0k,e&Z#3hQBh@aGK`10Pi2QWx/>yfFTwy#q:&Nb%(`v/yV,d+Xq;@`asx;{p2~9dnxh`8VNqQdooT[0*`RO~H[m($`tO!_6kW~mh`90,S^1Uo]76qw)7|SeUfKm{iUkA<HcM0%hR_3O$QLO?n4`xl:B6C|)KxWNzTYIg;NT$55f99+Le~lX3WJh)gjIfSg!!mL~4bi]kr6EGBr{0W=ezB)~^h+5X|wqd<,mfzlZklKGfi9b$qS}G)ye{7*wK&#GX]99viYg?PnRjFT4=CR)M7&x1VVoHZ|et!0=ACLH(hbSJoKd}:kHeBv,}oQaxnM_txy#K6?i`_j;eva4}&<o)VY_01BmMpi4xl)Lv/4HmnHmSj;2e6mk`6c;fD5?gF;iNwo1CEwqf<>Z&PnbLzW[D%M+Er8V>+s=M>Af~g5`1Uy{(y9#|4)vE8mJl!l.vonpUaT{0<Bb"H2&;M:QD<tj?45bpd$+"qx)F;~1Qq(5P<R0V,gK36`rQd|P&2|]OwN_dddz%KDi$Yn:Bi[kx<sV|~S0uk1=a33C^kp#o6a2QB/~Xn$_9!f3W2)jDK=QF;w[7tOq8c?L<!F?o,N5)"C+j"*gg6LaC$d0LW[5p1Z3el6b)Ty=dy"4c|?%xAadK&$DtJq4<92p73+GEo~V$R63c2@H~iTfP>p2&bSUECA1KYV%|hw0QLc[vjD{j+>B8gM7?:<[@LR8V4u}#!u4cE_[e<s^x^%=d;m>:rC7;_N8q/AmQ9,e76Gw>.^j6!ju5e?y^3,Y+qAg{v(g@n6eH5fwJbHDvxPxl.KvSG$:5Oz/Sgo0q;?w,1()6?&)$x^?U!#X!HRU2c}GjprGmY^>ScUqAvR#yDEx^"N?]G3.kZ".!6/:2bgE~B!W3,l_10Sj%XsM.r37T<0AO@HpsG543+rQI*ezTac(D>Kw0auP(~{x]`{|1S^`wM2e_nZcIl:c2]jbV`L7BnLNh<:aiTYZb[D."]*_d(YU__fJ_piQ@#iCXG=u~H5r6b7FB#XBrP0eZpj5W/HL&V/`?<68&>p$aemGk/%6EXJJR)EH&ma|E4`fP9)ApkH2}Xci=qM[i(!!n^gj{[mtsZf&A=..qouv,h:>F7!UBqlh5,[[9i.di<)!?!qS%27B[n2~im_>uSm^=O/W|T)g4?sP/1L#HjC*6:r&#IxCq=T6@JtoT]UhvqLnR;KL9n#}#6o+0G5>@T{g:%T8:I){"g<Q%MY+,TZG,={y6BN|W.navz.4O@{qEue<03yy*H5c8`U<uSbWXz]1ob[@MH78$`MV81b~B|_h26<l[T7j;^xNjX>PbxwM6LPkgNBn5_/!sk~fGx4TgJFyxbZTnTwup:D1,gu2K1gXJB<(!kAAFDssMt$,EY[.DW`ZOo<@#Qw>Z{NkvEs]M?zs<|v2@,=uppCooh0f;pT+9N,4kOv0Tl`<dfY;t>bNv9=(Xr5yfidO<y!@j&%[#|y~|um"{Mf.y}gbO=zO,3xc#drtKcQ;pv*T@?:N~:/J3V;"XKBJ9H$/Bi5jZ9w8rwM4&)H4^Q`R1lWQR!NTdw<uLFqS%%Jb^J%PKl{kYFH<o.?8>o(,+DsL"`nT{RxG}O4r%Db%{|dF$6O1CF/<Z[8g&g9FP(CBE106{u_BV{G+l[II%HTsYZoafvNC:`[|QRVSt_5y:&NR7&[a/YdkVZ;JT4p4t@HqoKefMc+#EEfjN%5%/aE{NgYChialGlx.q8IUfkzrA~ar^1X!^O`"}t.Lm9}Oi/SNI8rxL@lXskW&qar+r?B0Ke;m<JbPv$=G4vzWw=hza81@P!@()WF|;v0*8!:M6gOJJF/WtcD%&[W%k6:7$[IH317;2$]?<)3@~B&j+UCG{y.|p)u2qoNEORmgMue#&{0z|3.@V[1ovnoOA>WHi#nF1uhn6q7gBx!q.WoLi9s:b>Z*1P]J^tF4$;fcY8N=b!H4XgsOcK~%:q~qRGOoxQ?kUr~~^s8caoi2hV,Zv?0EPVV@ccMQewjzEQRTZXBUCs3x_plSSR2T7CujrrH;l*3lVd^8:x&6m;IN[s93$}ruOD:"5ahC[AA:pf[z.;Hp]B1]w~AeF}?i(Z6o?<H@@ADzxzJ8>|Gi$~h]))N>Tn1>&jQ2eNy:If>@s2<pUrG2)V6%t8,|Ku25yUfblC?I:"vn,))6A8oH4n)fu(wCMXR!vveON&#f#mpbl}lU;IDGA73HbU_$Bv^!W1tI7ZGKV.GE}CzXX6(id0x?<mGYl;h#9$LTUv$St0L=)NlBp}@b<ag^`X4YBW[=3Gz&akSR?z$d};y}&5|]tkaA.P"k^RD^yCV[h&)5G;$bU2aeb#2>M9d?UwCgO*BgT/}wtk~DAB:4OJ`%eZH_XYP~j@mO1t=CPX.x|z5XaOk]q)YV.bxMG;q1?uD/7@2K@?$Wlpk;K5wtol6dTcgl=U3uVddA.WcJoYn+}mE?Y5:|xi^3^Q;Ma*:ccw)_.@xqWlCBy10DOjFIj)ie3?~xX>np=H8Tt*XE5@(DVu6)@V08lU++aaHcQK>P}A;N#amid@l{O}tqX#`18fG2jeH9_luhlmB0:PVm{[B"U+75=ME2M@AmV,%`_Fd>&w3%a`(Rg_NCE.=wM9@D6>KC~x0=Xbw5go1.}S5@U.Be*.!6nTKuw[Xfq}vf6L#|u[iY56D*S7m5x(,2TGWH$d:3aVn)8F`w%}$uk~EV>Bf/3;weh<bD)({b"F<6>m|Q3=zTX/uRqX|<@m>P^iLKYgj]&_L_W~qupM)j%3Bby`I/oxI[UT{y+LH832Vh+{&K(7"C|E2!w{rj]gtz,(#OzvvF;^L<&;<tWIDV&q|N?6(H4z`9Ug>NP#w6$XI^&y.01$p#o;F.>llr=c4@<;Ps4>I|D~@nt/k+I.?zgf1("s6#fno2WN;VTccY3{`TACftpF~R6$Zf((O79;{J4c/cOk"3@=3<>aHz&|"*IR]q#O0=e/fl&>,yj2WRcH~EventJmRy(04wM3QR:%CfMxW[V&H6b,`oj9.0P%WdYu46ERxCR]PCd>~~VKwT&OuvXvbOI0!g3xK!wdY9"e5}&9B)V*ob<1jHPV_/3?tV.0<i0Q"lG/x6/%blz|~tx}89v~$omm,ix4VECf=8d*Z%>e~7d)|oI*?^}H4DY4F}K*,R"Y|$1Bv}mHICs91;&Dlm`kIYJDMHg>U|*>51uU.Zr1Qc:B1j,SY7@DZ[13UcP2IiXP02zF?[}W>LL$|$6i:,O{lq9p|w*_c3xAkbM@{gd|eVuMu{98TjP{Aaz1tk_N<I_%|EfJcQ:vc[Z`9!R|++&UsqgwT,MoqX5/ZVJ`7tp9|Jg&_vD}NC$ztzNbVhc.I~8mS,(Eu70l)S#$W$D0#dao75PzjVwc]A=>*O/0I}U)b_V,UBPFmaA(rofb=7Z9oD;X^xfv((,xq7VErKNmaHBcILpKDVotx"<kdvlt87,A#3Wa9:p=2.5ijlO6M4"[=pJ,Ma,U9u5h=<P~$r,Qff/9q6}<xCpdO"[D?*7Ux^a^y5F+N!#zkD+j2th"ScKZD+GRZBD6~q;l<f.(/Dpm!}iKRvT$f%yg*kD!P?JZBjUoIZ4t#mG/9D+|(!z(FD+f0fzX~v1Dw*Z%^noVzH(Du>:Dtx?52B]:?eMy6S.ev=*#5e.%sF5saP^CsV*7L[`xwja_,/aQYelT:Uqu)s$N8wCZaF3geIeI^10pDC3<Sf15xNiKD`FLKyVCus;jY{8OZgwhni_tZm?(C&*2^,OMHGK2mcf2}rOXC!_~I<].$*lDuRT#AS9R~47Qz*V<V07(Lh:Ot8%7a?yNJIVRpBD9SQzIU`vC#o+cyh%qK)=0^O:yNevlToO(==2<PZ7]}9l~mrck2C=f?L3=!pze,`YJxaRy=4ckHI(>"=|n0b)R9{nYfcQK{ExZ3=QvRlQ?1<_e]zWxO+`#gz"Rop#8>o$eD"nU/e=S6>_k5bF>js%Nj@6?KE8kOB.OyU%20+j&YOpIbmwo5qlR72xeNh0mYHALa~W:Y)g9k[q5/?Gq|[mTD`o|Y8a{[h.+?2l;Yuz9xBr2!lXs6PQMH=J+v#v<y+>&J$<O@i6>G9=WHr#`&uC.u}Zw(SQ8E)m7{VQb`rtU_j769`8C)s?j%P{9i6MZNHREsd&BSsAC4Bk32[,U)dsViel)$jb2[Y9n?{z#Rkp>4Nm]Vr=l])V~=fJ.+#dyE^}Ke&3fb18#udztzCqv:Gf!4ToReYr0H16xAR4F2rYw=iA9xJa$b+4lNOeGs5z>Ws2S]&xy7j~xE;Ja[p(~Ly4b+]P0^g)1AcE0wP5qvP]j@Z@^d5ro5SWQO9.PxWq<N+*tffZV2p]&2xfij+W3})pOLR5V!,AV5YIy1{(<667bI&Kph*H;,oYGdaITbLN+$DYSd<{hyYj{>XI3@!7))n6r(Z$Ild6K!_Z@ux~7[9Zx+j|x=]t_%&?Wo`MA976$Kq`h(/B?eX:OCjs&r),>.FaW@5>3ohW:g@jZ%Gc{NY5$m=}b8zo`#=.vKBg;T5XKd~Ws"@Fy5F4zIe;O;f9A&@mSI<LFm66tRj!+;y`[JLKGk]po702<dH>iO(|@)c.$g{_gTCrVPxE[%)w,O@sOz4WiLsM@ed=[L+K|d^kq,T`l4`v_+2uT{zZz#p1ka6s1l$I6HV;dxo^}$bgjHyRlB]8@m!NlgXJ6,FdrY=m#CD?_.([SauB9N>)wyh{Urj(n%vmyn|ZuCF920gT9]b_XBn_&pf2L7{CHK5%<Z&FwU/v1O?j,3#u|;Eo2X<C<pnjgU|`:ay(P(9rSuUiYB8M.@i};ZBc<UB%e[@huTQm2%*o5Ef.@rO,Q3_I@C6{{A*1cbQ9?6S4P)k`U?atBo5Df@h=8YXUl>CO/KD|$@uH[9bnGDk?7jjl5*f%?RKFja7bSz<VfOI,4/]Pv3O;{1Iy19f7:PLn(gg^:l`G2:*?}x2`erx|?X8[R5G;*Qaz,G,2Sc3<U5zJ6?<2H"%*O9c:*!Q5b%h"#xxDj7aaj8;o5RHT09e/:X/CaQg@Ko#7)iRG?Z+`oiI#7L|3Vj:"By_FZ,i/F~{TE?wh3VQV~1)#1Tstf$0qfOeLe!w(6c}v#:95N/7T_{F(InEJjxQn5z&yNw32:)[C<mGl2]=hzOR!OCHRHil>U(.+,AVgy)FKP!n*Pr4E#XN(L|x]Bqabpu"9eu)|Ykt9C#;[}oNEQsu/x6E?p*@1l%{N&kZAR/XsC4pB2tzuw;o+~FMj:;9.;#o$Z$*ur/,Vk{nb?js[3k;[Pl88x@/|VX@/o/4*d(8rXW@{XHzCJVtAi?}|Lna3u8H32EJK;k{$P#hK5HI;GOVef.Z*(][{aFaR$bDk~n)V`yfV]#7sC4CYC,=I;>a~4H%XVb74/Xu&3c`3_H/DM(+796UAbNe707]RUlhi.]Wi{rq_jc=rn?05*Ua:oa=nbFn(]UCEt18;,A3(PQFfF;Iz}2gq_m;YyYkIxjS5w}Tp:DIW7(yyxcadN|9/s:01nA,azQSX=O"d/5VPG1JK12sQ.I([5RLw=s*d!y4{}zkVM0BT`DJ`Qhse^lLYs}X1>KzWoe.v!6lvcyW7Lv3de>nbw)%rit4pXkgv[MBPJ7O_q@XX(||*%Qp<T?*4Sb*lW|;eQ!d,e@R;I@4ekC"6>}({[H:Qm]1i:_F8p"[)LUhN?THT0K$D@)K2taQNB,6(wEGc0d(mU%&&JF~ANFm7F9*4ZR|Wjk4ekJq#pLC@XUlIg:1xwrb$?IsXQar_6yq5~6[<)#.MS0wGVYh}:`kqDcD}BU8i>4H,VA~n1;WF`+b{0||i:v`edhy:!Qq=oKwG?GtBP|q"Wb*x[G,b,y5GM7YUhaIc+PU/<p)[][Ornk|"dY_KKemNGF$[xzV?pg2CTpK5LSz*]dj:q4[FG,]7{%mfM_w^H_^nh"BJ_PG~8y($(_H,aUDe:1Hc=l,Cm&MV30bc%M2Q_D",)"&;S~pFu+,}.8fE7Bltkny5/${Ud[Kh95Mu*_Og=z|n;L)Y85YWES7z$uh$`mo)"aX2UH[0?8$JpEz}kPK&N=E$*)YrtN85X7!R!FFZlZ=e1,yesA}rLZX|7"@%%>hN&~IV&ym]Or)_dR,?rn{D"y$V#^iuIPA@zWD2f!Fn<x!d=6/8p](U`ScvN=HywK<YC?0<1)8sk<V2Tqwr)rQ+f*L}~yZ2YT@RB>A{r1NN0tW"aPC#,pT"(rp_#:(16~r!#Rbbjqh{5*h)oPm=x%DJ&[E08l~f^*g+5X;G=){Jk1<.XHiVG/s3JOtHZi]N$0FU(fLfn=,AoX)|Ef7sq=v?@$gSyUcLi]tE@b1G_w}*#nZk`$k"vM,{)s`.bBZA{]nzOSUDUfZZoUfPZ9YAbi)x|s9liZ5Lp_>a}mnw%gbk@VoWGf:MzK[nsGa_y=1HT)vXo7jo0^(u]jZcnCj}EclaCB}?DdMBh,UxE)?%XrbI;YqQunE8F_|v{DKP?3n@}DWN[/+=Ji()"sYgX@4mRNKEVv]_pU9RgWiVc0rJB)mi=[_Y7"cl8:EV`Xh(Abz1{%d<;3NM!OdvUb2?WYJcSSNss6X1xnG2gjRaX{KZ.l~*<AXinw0A+!C|ddf~N:.@}>&uVO$WX)/"p%9^fA6Z[vm3xnDg9~;skghvuYm"W2!i?)X6}n+Y5:0OqDLMz;d]O0}^%hC>XiD<&X;=aL+0qvk75sz(M$YFLSXOzu<mGPeV#.%jwEB<_8cP?~:HC`}?6,],_@a5&Ieq#)nFM]1LW8Xfqw{A@dqhEIx*5cH:/1ac3ulFU(XKj:=`#vX_I]g=@u.xBB+>k<.~KO)7J{{WVBQ2FX@EL6t=.TEt#J^%y}GPmp3bxI1.gY#b[o{`D?u~?g@Kq!#M&r&p:V+^QDEa3Bllh<Jn7O,zFJwIR)mE>ObpQX3z;[HRhzD=vz~OV<T%_|"4%vH8RZ8ulwD/}#Fgm,Q7=ZZrSd;OV9X8h3hYKB#QcjeJy_NyTM+B_Ar$V;/MDGRVjr5R~E1>,;Lsn>%f$II78Sf#tu[1>Qim<g@j"ofaoV,G<AgRfLyMYHI($h+n;b7nBA.}2dSd,T=rE,%=mT[$I{FU}TGOS8N[8<ua%?^nIhm}68~L=.#.dA+Ty5Vx>3K4o}L82ZxKo?"#$${vR{UI1%dh?m>!?}}d(enMdN,n|dR+w8cAg.L""tx^xQ2f^dX+bEHj*$(<HLB;^i_zGQ?r"pzPMXG]5[JTa/d"iZZ]u[#>;V|E>jk?#azm^w?.d(`{BaXdzb~&X+6)tzy2B|WDooioL]C{>DZ%M#+(Zy+QE@2EwT/QqEiek9Hhkj#RrCV%Bb;EClo?t9k<NicoQ&N"H1PPmRYNOV1Z9m~gVMaVsh:V{^+^+I7d[6g)LQ/W5mLZiuRDbJ$i)&maP<i3O2Z#O]ZiQyIgLf^uTED9^1Blf|BRaBEmXq((J[,,)j#jG)l.dM7}gtH$?ewFfDqp$]oNbL]*D=nv)t2.S_8JP{(A`K>aSBdZP%:`];p.T^plHYk07s},M:2M*bAhn6u_NC3kqe#I@.5+=aSvz1nDpkq;o;P[/Ca`cEHOB3qwdAq#Rd&g_g/S:7v=iTgc,lN{At4+M{3uu+LL37o2.dUc[.M/N0D:~}mzZEb3GHDmK1CzjFi4+u`&y}yGBu}o4^GstaqU6RRMdq*fZM|@okG/J/R~H9ByhTN3?+ay2x%M5X_LY~gt3R^sjc6V327%~.H=|l!`x!5PG/5`lXx#TYN5a82,j%R:[hrBljag}"HUC5a82bnXTu/7GoP>v5aOgOegW"uvmL1e~^I`[0$9RuM`/4,sj+Xka_Mq7EV?G:_wcPBw+0Oc[$bWZAf.Q.!F5cNt|Y1~*gUcMSgEH^?>jU:TG72%nh@7Z0Gxn#w1|,u`WM9|Lg}E^8k)Ig}I[Ht$^1=5n4n:>?D3/Dt|r#2"C:~!_wnkyGK@aUilzr6bD`BZP)"@&[AB_gK6!F5EXpjoYA]K{>L0u<G}tkWu+kzl!qL|G1VV0/,|C=5x$=5itV/jzcSf^$N4u^~QV^2A@|(}_xQzCBrc#?C{4z3Fr<~N8MMnbm2/=V{Dlk97/TipH5MBiaFj*Q6/Dy0|8d,7bm9.[GQa8Qg23a:i/Kcm[HV}MGeUEK{`_[dVfdqc#<JfZxltYF99TaeHb}0X9k3kRJ?8xO*i4ihDH/s,3?D`(&h.+!<cB/jE4dq"IN`PBlN.OaCZi]A{7V3viiAz>izN;mom!oImukUurIMjByhP/Hprm+yT$bh17vLlmR:*a:*n)9kP@{(f?"aS:w.)0Cy/m[OU<DEJc8*a@Q;|+95/*Aui/B3?P?DzT!y~V&5?+2(wil#xC^3.*qHow97O`wZ.hJ7nDZ=~7`2Y2$w.[(}*aaF1$d2Z5Gitt}Rl$;OtRxG|BE5(>TQkY2Lk%s<E/x8fsYexp{s,uhN3~G91ZiYli3Xo4>dyuT~MZ]"l(Rsj}zZ6G9DU?ogNR&([")B2DcNQtLG2nEG?Wa++fd#f$o){c${9L5rw})p=OoMqu/m[OMMDH>!^CMW*D/Bpt:$x9F&nXR/Qov)*{Y|=~GEqt8>/V:}%JIx_XtO2e%=p_8<)hNibH?1@)8e%<Ac=)o3G{>qed_e_d""HFd/Hb/>^>&v@=iPiQ5q8R}M)UE3gBo`6/%h6<^r[_3W3kH$yigj)$@x*sK@!^w{O[ddKK&r?M#Qlzut}V>Pq!g/@Q8{E)?}vYwJ"21KEO>/5!3Ip^(5:G*`9_^fwLh1#$Jl]i{,[W>QW!r6h|_Qc#j_OPDCgW70!z&xUk,M<|B/}avB?yqnx%fI,Nbb`2/u}V{3,kRQ^$`mNOgDR~I9qL4k:vlt4n9vK@;EV?EVqBJ2P,$ns_6B3~7JUYur^L6"l(Nulh)>2ELmYs~`EEo~H?">2H3~p?g;&)yx=pk7WG_MzHR~^4`1PDB0/d6KoD$XhZM*+]$<$XPI;DatdO}L(UkH2mVX+O}_?y$<C93Lf*g4SRat@aDg!ZUuEE_|VDL5hU2sdY,kfggx)g#r(Tj~2~;36t~Fwp)ag~{AZ/F7`El}LXl=[(4(No#Qq_3eFU+>k##}/~>#le!8Ekuh]dRz"iAU2s09:~#F]D)ID|JtaYodOg}F]GrB]OtRXV)Tj~aX((<o^Xe%RAk_t8ut,$~WFt@BD)2M|eem)dg#0RKAD>&8Lgqt]){tU/_eA;sIoBU5[6BF!&eHctWgqm&t1/A"qw:Ql!F5$<(u4|c"@BltVU1xmRWt4keb@GP|(Rpb#%0iEAu>n"2d~=2Dk4dSYS9<inr:L1|{(c7B:~UIRKACR1zC1D3~,b,tk#7mt}+eA!8<jU,4Y1WOTFQC;2bLg^>"Ft*Em*c4;iv[!Wx(`<tn8<R09oVVQIj1Efd#&Dc^~r8B<WbgY_}>2k=e5.nhH`8<"#01sB>z3LJvx9cz{>jGBNLE>#jX$~}vUk8w%vmW_d~V.,jz}rd|eU>biH0:|+:tpD9B/W:,MvMh)Tu4rY3ZMPY_pL3[hO"tA&!C5io{b*L_nazH3~4tRo)WJ2D3QS2Rd~mP%BTf8~t_L{!AOkQf00k_gM|8Gtia5F6m:%,j^=B_`^9|aH}{$6vVVP|;!%lI7fCR(sfIk1>g{^$f6x=u|<OKcw,BI;geure:,Ugc(ai<1@#0}*Gjja#}!|<T_h/e!|4P>B6~xDc)nsxOOg[P6Br9JSJ1L]8B#WXga4[]Xe]o~_N&9@&LAg|eg}t{]hkq=4>~T/Aj_Sg^#gQc%bqhQQV|G<b#vw/`Gz[7q(jX,[o4xk[WbS)>YJ6@jvf^zQ|C86bGEMi+.Gtt,1#TD$Ggh~$DWA9<e$WCfht#3)$sf13k7c{o0M!;.TUqO>t1@K@aUt;o+bLDBpb0m3u_C[]Q#*$IE=62mR#*|TbkhxmRu.FW|vjlbU!ZIE^q5bnIuZllF3hWc[am4Oc[P3kdN|~Qd#<J)a}Ut$@2!GK/iB,NspOs=Xg@J?ap8Jb8z.8z>T+`)[&G,:?~V^YET:qj2Ea]8N(D:J22EVqV!{SO`OJvpV8W(oE5G*t#:[<vC}7dH&BX6_%s;U1wQ$t3M5&+<><omSjZ%<vQOT/",pfe!{x7}ObJb8hu0e.NCCwRgFSOjD,J%CY<AH#B:~HY^D3~_k(,0x>J0,IQ9PXC{gm4>juG}/H1XVM|(e#AZi7!f>kf#vF>!P1rN(W@]q;8v[IYE~DMv$8rzl,$b)&n%nB_w^>T4b.lm741lopoxjAnnKoXi,kSNQMEz${{Y)&%@l(|*m6H;[d$pp0Z7/c1)VX1liVF@p~=@pTdNLVH|:?:!`npcnDY5hsd|^Sze=Quga<`xk3PPcM;~vV,fe.#ukc8MhaZf=vHG<i54mJQ$}7#v>C*uQf3X^<3935U?ums4/slif1lCfX,bQk]/eTdiP;IvC1E4+Cm!k4O~p%;mdd023&QE4p]:@xs]SB,G|Q(G^~LrZ.0cZo_zUVEP0E&4]2v,e[u/33Qwc;_3cNnofqGZ@!~fRnPLMMfQ0R0rus{1>Jc6~40C|qHW~npRw>!nZ$$R|<uq?$>iHCw/Usw~|2WWr?rMd.v(sIq2r>5;l|7S|ADinvhjTifDG,oFx><1k8Imf+=e~*I*Ua1k%=;t}1|).&Gj~.M4PBvSxI?HEc+G_mo1)&gm!4peu|YM{&h}k,Mh_1Q<+a$?s7_3cV+Y?L5>re,}qA(]nPG,>&0"VNK::#sP"!>udGQDrUIeVb!iDaRW(&4+[}~%^/l)=w/#I]`<DhfTzuUf$o)`/b_MX=%CvY~W/8hqO&b_9?_/l?_;B)_VCw}?N4udVtm|Y7A/;9bL*1W<r$}jX`X#)eA0z+hVbbr=!Wk0k$`ef;w<8@#VYvTINljj)?1B9DI&*<(E/I&EF.o]%[{zeM9{g)vQ|m>h_t(m9*!7yB0Glhp$%N`e~6T[959[`mnXiDhm;7)=v~tY.gDN[cs)Iv_v2+>GV#;:|wK#rb#/b9JiGY.p}Ksj=.9*`k1+(YAs/1x=>3~UJ<8pE^|8*0JEta8B<J/j_f~.@La.%t6wZD^r5Sb#P2s#40u`e!{3o4}g&9aA^"y$kgQ?(eVZHbfMWJVEv`QpVw$m9Kh)=,@10jnJ_OWOjxl,>/m7Qy"]_)%8MR~OVv}xIn=Zi*%pW<n!<u(Px!W1*7AqqiO&an2%R1s=(t4J4OI|d&rf=w)""#>5L@hB!O2>Q[RUr/#4,+uF$yGv)S/^`_ZFFAv3c[n&[5"epx4>glTVjlBwz[j:`oFIC)WBW[6YZL;BL!l+K(}XB`pc#?Q=#UG^XtwD*?)^v.BX7MMs_~<P&BKDH??N;Ch[RHi:&&p)nHtYY&gU;zl~$dpo1<rJq3>ia;,w8})<ADzo#B>7:${P3xm~%ExEM>[Dxt*ul%rwLp1U*,ky,n$&iV/BDX7GL6WFGXX{#8*.9SVLy/./A+91br~wE+3eO^l6,,jZp>G<Urp#W?vJShdU"b/{#>;6M@O+d%W6ruc8Jzl/naALpU]W63_xnU8%UQ[le+$*4"8erzt&YU)]wk%g3hdR34haG}LG>MR1YK3jw@gf+jG<yg@,{x[jpHZEts<h!y)]<}[qw/P[HF}IfaffWj8/&<=yr<~"sr#";!s3lde@E)_J^/^{D^D$/#xzI@h|D9r[1@qhfJRC4r}^Cz/[_|n]*W:yj35*R9@6?3R,rEBE=[CJv<H@BIC)ma=5aQh[`m!/TF^;>O9SIq]60/eTRHbjAV4HY>?V?$r;vPxYgdZ19;`;2?|IfixniL<&DC>8_$<HU".oOfLa5W4}#ct)*I&11#,GtI,^&_~9s<%4rh@pcsI>fU5nC[RZXYRf(Cf]GK+bnrm[>p|S>1$01+Zu>$FMR81u>%8E>VP7@+(cU3Yv*GJ2dK3:z+z+z*Gu.FJc[)}135Q2<>gQFbkP3LS,*KM![8g3P^|9S}|E>^C:`?^3sZ4#UkH!+,)([[j|4E~F8?%aiudUJ.oX$g=^CLftFI9+3.N!zY]*!x!Qo3myB[K$g^^3S[l!{zI:fnViRsr`3nx}G,d!CUpRY8GNm[y>oZ,8jaa2%;[?=ur4OFc$wIiQ3hG]Rj:kqhRikw{5V3I)`miL^l$)sJ|18y+MqaQBH(c:SA?i=V3RYDDd{)K}}F8Z5pi|aDO;|Z@@a>]I2I2%R?]Ws<mt=Mr9hD0BT.mRHt;k>]LAxG9{fUh@was%&w?AIEDR[o1IjzU~MtrkFB!!=b[xvC55cWt<7^9$|llraR7~PGl_HY?=PYM6#saE*+4#kGD_KBH9Q):zYef0/TZ*NGT"_&9/?`_wN.?uXOI@WkxfgtByRxYmM$E~aSsvJNI&M}aP9}m>Ymyh1)QZ=w{h][gm])X<~kv?u1xbny]BOtR%d"iI)SG)Tf1Q?0stn}8,M"iK)q!+a"iaGN1?>Pri6?{Gf98(m~w)svmT:Ms0Z}03*HX_QWQ,[C;wdg#y?60Z)W+)zEh&EWPkOG#a{k!u>6HKf$s({s^=T,&.NpYx&s:*s=#ptXRDYlQweN&daH,+ov^71cuH&1/SJpYMN<K*_RDBHB?_$J1OND$%qEf=V=`2[xyyP*(nBFx<ec$Fl,?t$p_ZuwBH8O(Hi0^Ofi$4HskS)QAwq.o_~UoB0K|V>5s,*fmE/|5n[<3?.<.o[CVZkb8%n`]u7.!Od%IR1M:"QQOgc!|iUP4p=E;U9/!x;.6pXMCZ5PmQfx(E76b+b4#PqP5eHRR<aEe^T?ew7YoGKz2M];aQ5U]|2h*>Ug)H8+v4O`Gz>zTUr!>>`:!<=q<<:Qr)cBV=)r|y2n]_g:$:NS;L5$wH4urgXe5+i%7pNbonl.3"mo30/TS.#kN!q^ba3P,A7*1YsuY(i%80^:@!7CfzMg{>qu;6`%6?fest~Cex7R#nHGRA?KVOVK:3]J/@PGI"{rewuOs|$Lx&ptj?hD;0=J;%3jHbi,KV1~0_!Px6bOz`_rglyZY>!kyreazO836t*zV9U3woHk!jFp,>U]tnafV!IOC:PRLXc#Wycm^LMAp,*nQ9]nRYr}A0dNEh{,5b,v#D;#8aI7l&8_GwP3cK1Mr;#+~DCP;L5T|=PM:=P6/=PX5r.6/J7|w4d;=t.Dsv9+v,[L:mOU).}Sf9m]*%FssGP/VkHm~>!y^"*3z)Wi>uq#=[qbEefy_Rp7Hijnukb:&ROR9qWyO^|*C]6>g3$<t6BRN;v!B]6C,4[*@FRGo{b~N9O,:Mm>$."It_~.DgDU8*9%Fq[|13I]?"2hw,RL6WsuBmo@R<,FnHA$%m!0q=*Z81]eBl/8k=r9We3*"nnF|:]"$LG4vgF,Ah9"~1,tPww~#,>zg_|o{f|A3^jiA/sBMxg0S5SS:gc(Ko8xmo9{#XF@pM(R<UU>3U_=H^we<6bR?m&t1%RW[u:zVc$u3$GY]^^RrtD[];fE|*JQgJmM]^z:=ypba?mIAh=RrEu+*s8rN9=ojDOk948DDshp8F=qb3r7!rMm}:=pAz+CMNc2eJ=B&j,2*q^%9%`7NVF(oTh8j@+;!E]Z>(Q>6Hs|p}{p&PHQayJ,[Z#g>I%L@1>wF^)DsNWD(0hsxn[H&z~!B30MiT_&Bi0csscd[I_3DZn&?B$t;xJqwY4H4O7}OWojUTfK"irhuXILtR|3_u*=;~fkpV<QtDQG"uT(M5Z"iU!i69M*1oHZJ*r?Mk?JqIx!BO_%ii@DcT]B_}g#Xw:G53nlUNJ&tucauZyZ7]22S,G1B9dxF,n5.H&gF[wpz$JlN8H7uUN]H}B)%r"j*]ibIKHb)Q#th74pnvWu;Mi2>RDi43>8SL7!aR~yR#{8[$<?QfX<dKV(&"(b_A/skQJi[#`7p?=8{DOCVv+:7k^Ro}z#<dVzb8rE,8F+ggE0}0!rr3_szt3FvNGs?`5Eu&z.2k6k>z!4=KjLrN*pq}cy)fV=7*O5[^_f7`^)dw9/2#frEF~>8,[HQ8=seq8p)5P{kOgJG6%P64)bL"g4M4cXiGj7c24N/w[Sq@f9@5GZljteUfgk?l_fS=7jaZtB|e%@u$7OQ(h5=Ne5=_~MSXth^I9x~$uj$_^/SKk!h!zN7U=gWE!pB]Bj/]smRQ]n)ZwxXB%>tTVxN4ejD=ihxgXG_C>oyop3IGmekCw[{Z#k?R!Eo(?kA1>zYYL4bDsur5&ha&Cv)`_gsmh9f#:<DFfD?u>:S=%i|qm3^iz#vuzO3527;Xsj[1<hUV=Hw,=6UhtT_V/K7M!Eo$%5A7^60${?_eI@})c(B_bY#C4JigI*1{>t=)W?f&uinbFJ%,(>UWT5("#jNR]abDo+9EMN4FNiP~gyiW0Z~C4G6ZhaRUP)3`5Dwh((~E1ivh1E12#bM<=fS*&X]p:5s&E3ci5#:~i?TYq*6jNE|j8%_]W8NE|?u?ukJQ$ztk{&erRQ$JbtG/xU_uvuL5_C`Vod>Bi(mnLowC)"XuGCkxd?JrAZ;8{(&mPsC]`]KNXE6>I8yZ4~A8ol>GaLXLtib/y(Hi]!}e)8Hf*S&BB9?rn/onB@o*??2[(O7Y!2Z+B[Flbh|R/Vs:H,:+a4E6trjiu4_9F^C%tst3[L(JN9=Idzg?{,:yW+c|xV"BTF=Tt_[<w;tIR$g~w*riYLUFdpP{pd4ElKFyn9gTaqYjkC9t[GXHH/kj}gm@|lq(HaCZix&Tc4kKv&Z:T8e.TNa_:CvOBdnHDu(slAw`W+vH<Mn:Bos=9O/^Q/oeQ>6@*)AV(hEjIy:ylvI~GK*Vc1~@b@@,w01V3KIeYlCp$[MZj>z+a>8y=V^szeWR$DV8!]Y=_S"0GDH7NIGZ>>bL[KFbbfiM8y=nB@$rf(|/cR$A7_$[NiIkh$QmVR"5xmR]EBq6c`t(VYDJi,7co(=ZE0^>U%i>o)!3WB<T3RmLV)H5:<u<4Gvr^]K6W148c?_.>jIoC);,O6ODF{>`tjzw0j%<K$*zP`hFK8+,C;8}6dw!a7%%{mAZMu~!C`!2Kh1sIt&isxcOMi@a~kjBaj>:eWsgR+Zx&9m"KLz`1kcqL^lk&B=p`@ggG^nPtk2J_P{=Ws&uKKR|6Pu|"@dv1e,C#qOqHA]n8Ii80=Z7s=.HR:=(@AxnsZ_:OZwhe%zS{W*&+HIW;U[Zz4"^34|Orp)g0i:ae]@6u_NuCaP)3`{]`MY.*bU]V]y{.,61Nc)pWSPmwfE".6XYxKpuk#:IN,`OQv:96"4gG[Y@d|XO{V8Z];&!aca!|p]lNsr?}n~#PWwr>3hGVAd%C4`;al,Z{+Z!ReXrO<HSB&s:P(ZQq/i;vU1Bd|D;500Sa>tKO0rGDYB|qxu$7{qhI]D`!5C5T`lnA{r[vP~<#GFqmJ}(a=uLJZK%QLa[5)MB0b(mP#>}|RdvLaG}CML8M3xr~$_S!X$X|j%DW{^Kr)ho"]cDYJ{x&1}n~H|M}*K<w4gW4>Qe)Kdkym8PvB}:OZw,~,&@8xpLcqGD(81r7}Nk+,iccJ|DBnolWwp4W#.SY?Qs_0bW*h34g0+pOW%LY~[[&vG]0SM.6]2[8tdq.oedTXwe)L:D*g0L#$8Gh%0|gc,93s%1h3%5]!DIvj]k>!#aQHKxvl,>v"zUtwX(+x$pbT%]e/zW?2,wde|KUCXTnuwmp(0IUudB6L53%%8kY"{,6FNN(EdF3Aa<i~%^o*1>H/Yx:qHNvFF{2uVcPVkUP9qR:$;GH5S,zqN}Vl6|rN,uxGwO/jU>CmU|KIwVClG..}%}~{<F%p94[9{86blRR8.rCf^KAEA&?)yCsnQ,o4]28,>naY7m>~QW1n1v]<&fBtQ$Ec^eXLEg5FC2xXY5qod#.XEY48DmV?^]@xN`!FC4ky|:~hnr?}$Xkdt.QelfBp/3kEiC.<.@Y0Jo!<J&Ysh)8UM_l@+^^d1kFX#4`+@#cCT>i`_YvIou@|2YkD5EA+=Q?Wf,>#ZJ&f)4tlE.Z2_*GHw9u>MZ}2i<7]<=,z?{_y|`whNLAIWO$B?]$$@Pi>B9;PU6C~^p|QS@jdY5/=Lh1!B|@uRu=;n)I8NH,9!NV|k|%7r&zJN5atRz?VGY|KU_(T]s5sQn>XDde!>01ejbq,t)NqMWojoxc^V+_17Ro|ZwG8Guz2Bj}ohl}UQkY6or~v38h!H]DMPCmK"%^d3~NUEFn8GX`N`Of+DMPdl;JE#Vz@H_S~a0n|_M;NU%QXw}*>>]_+`E4m>_Y#>=Z|/Y#Ma)&:=5u(c"iBh;y.tdN=3;O]VjNxjWwpzX08B$*F>:x<&aA7~$(ICl}ji+h~Po!TPcL"s%U)l~8hkdwLHXo^<e~}8@#(=AuMRC7BTkSsLuc59^|9CJ*,F=`DMQY)J<&2+1A?#Qo;imE(,uBHQ,MD~U/hib/H`#EE_J&*BAAhBbAoIceC"o:S)y:UHgQN)o+!<*>zG4"ra%t^~vYwJZD=tO%eHQ?:+0gHdDwj]F7g9T4vd_A:~4%#,R@4uExFTI,A(x"8Mss=f/<73PDmZ!!@W[#(?#EI6y1jNg>h0%4Gt$TN"#T!Gn3i4g}_[%mtPrH/sCO;P;HgwJ|xVCE!l&R,{Dv+N9<Z#x1jOV34FRDFR//{rWQ==NCu]wc8boEB1?lO;"kK/AeNVYiWw3tLV"ksV^|,mN/sWL{vb:oS<efObL|Av5vO((QWQU"a_e?^I|SR1ZIOP<s:o^d3}eR0H+GYvfNu*g9n.}gP+H:"a[ByYh3?oOg@;SE?Wy/R|*F#,fg<4+x8X)A/s=W(phG3%[WTdw}Tj8<n]h*e/8/epu85r<27"u4h_mr^F[tLx4SE_!z2:<`Aaqcs2w.?"5o8O>?dd.&A)/6+h2.8RLIbx/4|r@~jYi/P}Vvxg7R`BFDG9l53g)8?C9B)FfDbXB(5TV=&rZ_M9$%W=s~.PJtg#5+STSg^IL;!<h#&R%<F;"b5e|GJM5O#:)`%4.UDb=Uil^u[f$<lO/YOeiYarV3@4OGDl#_ECoXa#zsId7bXgR$<PzZ[^8ypRo#DWg#K1m~~$V`LEFCYLFk9`x+>o75zB,;wK<pAqLVw.jxWEs{,7I"v9&$.o!L>K,mmZPRn7X,~7|zU?Qc/Zj@Cu2|FB|[F"g?k)9[}~(V@zQ?Qcww:!2Gf)`c~A/TEHi)c42GeU#I|WPD~mn7KG*tfz^OJmdZx;}mdZ[YeiqY)uV!CRh^2IcmkUfE`|ZeK1Y4}lk_jhP$}6l@>CiRwILCouYCB*:Fj6Iwc+238wXwGEuPn[pv>wB=bD0}u)#u]EyXop8uRoI5ujTV|OH5bHn`gL;o$TeG>dYtL7tB(?&yPDL+c?@w<YhN;d^B+dt0:!7H}t{cW5R7(DeV{$^dOY/0iYyZ_D}W/0V,^dz71P+*gc|O8od(`b"MTVcHPM$PaYmq(d#1/bf*x+M0dR/0SC}/LbV,3RkE]M$PpjX2cw01SCszZGe%QQ>O}JtM0a_DuLPI]{!M0uv_F8V,"Y?|h6|B@T#J4jdMld)?@oj48b`ww/kzR@tvDnqTa+gm"L?O)FU3=Ha)L$Y{%=hC6>qS7fu~tRDc^H*VBKY/N(@o/:tOaR/:^)NM}2W4Y=AW.,Fc3kP|5%sM1f$cVLWhBqP;WwviQTZs,K:kLYFe5hOg3"?"#[!WP/%Uc"Ww{W?T?V%*RKC("2oR<67PH,dk=V~h%(G48.m7tOHd7T@o"5,$7%N%+ms+~r]n;,1d"M>?"2MJ6;)U8feVDtUOG>kBYSt[{n+B$}z"pItV;XLUHQnMy"n`>m!|1oe,~Ae/PGc4eny7tt9[>T|1.)wWw~jwP7W4BRJ.cNN/E7s[dN5l`*7Zk?t^!?]`<%WsatuT#uJ>w9kUT8S_%KN!eKB%37)o#UNQpLLaA<LI60":w,sFo&20%hOhexpJJV),)Av*?oe7Zb."2[`^fd]Eogh`n4O#n45>[vGfnF9`*iQQlvZ4@%TD@e(s21@Kw+STs(re|8/V8dHQg&c$l`MGw+?%qao~Je"BLha6&;Y(vrI9.~asq^y:~GMBT:1:yrD(H44gGKK5MLOt&%pq/>8(Aw_97$0Y@.JxLxa|%n7X[:s9o:C*sP50UMq@hAEh9<.Bw~60mBU3$B_r)T5.MJ6/XRA_WIE;^wd3C$Y$qCZ5N:!<l!c5HbANc`.B#6(37s7Wr(gXj4rYJ/DP1[GbDt.CC*/6YL]cuL~=*IDgAxyRb1/`a<&B}j%`jX@XojAn@+oWr$d7*K~"=W;QhRXDv:i4>~AMVxDa^?3.C/K/M^Q1F^V:&yh&/i}kI~n2[t}VK7ZAw+6bfu9oOg0AL;Wpyd{{2m#6cuCX~:Rc,Oldx)dVlUlQ(DeUCVnX0lsP&KYef^sXOA9fAQEw?33LOYpW?Ot~Xx!{CH#42F,B8j2RQ$Dt/F0s=ep+c#khGPI}J<0pa}KOh};@MClKJP.)~T1i0:.ZY&`O.NgGI/nbLR;6:OT{O(MU0S?w`pT%6/:Ci0!kcq3@JxPu:<sW&H^t^~yZd1]NMq?2E>M9+>GVd8E(@d6nfS%y2k|P^?IY5&;IB}CY/cUe"sq`LEhW2PM]m_b`8y9`Cbud]wFr]#~4tG=/lII&gGQ$qX:jqm|zTh.Di)MII59CgYuYlHPzQgL7^|nsqH}"n1Gd;V$g$<MB>bnbq"aEwI"^bRlR(3w>S(9WMj#z%D5rn0$I6:{VmR7gU4a1ZIPTb3myq>!Ha6LD@>unA152[|DUTJi!!;3|U=zw=%Nxv5{nw)o][|MzT,2F^bcnruM<4;n^NCF9SQBGMEp)*D^ELgM7j3CgM7!GEC);nW?8H<fRM}a+FEl]*qw)Q)w@qQ<&T#qufW%M?Zv@FdXEM!~BF/g=;$EEy#PD~Q*?d40INEQ*4I_@S:6Ie@*54w&WEHHzoO]"oO[t@ccYi4vDxZUHptoO]"10q,Phk+(n29]2[8mi~B$8ww8I&a*Bi4$0sMPC,D$8CaQh.T8ib#YM/Ij~viV&0YBxrE~.Jh5*1Qy)aRW6VQ[|e5zWpm`v*Q|hY*1D^x:T@am^=o4bg#3m{5b@!Y$I5d80N_wPgmaHV:uHM&^u%PkznplEa66+;6|P:C}m6YgGOMoIM*!gULN{ay01d:IER5g(%fMRBWmQsYT=M:PC|n7u*U^fY52yS/U9Ea8wDihYD#]q2T.m&Lfz<GvB/sT;v=to]|GgUhy*x?hG/sDp=Aca%Qc$p5c$}8HCrp=A8G9MI92g@E%/w(<MdXSLJx_,=xU(_;Dv25sPnJUH8A/kY4|9WZ_"<e(K]C/s!T5Y!{O7#f!{Oj/Ig}Hk@vh^Vt]s%3XD:~F%(i*<NW|fqFg}ivyG6CsUuM4uTw}e$g#yRN!i.0^DtMnD1g]NSXbV[gTFR~W11jP/sW8ymYWtwMqt0nIUiLYNsXO!rb#B,n^Nv)u_hZ=(R^Tk=cU0E^dZ_/tPMDPF3B/s.MB9LGP(T%FNp}C`AcR(ko/@uSh=^XiClZ*HwwWoDA;C5!^HSM{Q/8)oB}ga/@Y0}xoETK1@(X=`WC:FsBa4F6#njB}ygt&(=tS0L#~eJImX[CLyY&~6GK.yMMCYT"$gf;Cd=Tj)xVsE/(dQKy1neu]WA,{VOGD`Y0B7:O&`:OZQ63pGR>C7/PqoZwe)vGV*hqDqRy,Z+bD0KKy0x/eZem]2x73x)HlUcDeMiufkvipLX~I%]iJY8@nbt~@".rPtm0vzzB=EC*![TAs{j8pD*?]zqB,wqLnO&fiS".l_()yL|r<RK&:$=~Ie1?BH.>5A0R.en0C]iW;2T,knu0x7OcyGXwq"txLioUhZO&$<H`~9$<xq"9|hh^O^X|MOGR^s[jV|RP>Z^H[MaXgWq=BazzLDpYj97ywIImOJC,E^SG0w01yDMt634kvsoNDq$!iBvt,7:a!>;rlXg/QqDWZRd#IVWi8klupzqL}s2/%;(uq4GL?wWojU?e#[<N*XYL`LIYDE6t]se|!Y$cC340JawE?Td`|Cx/pHU(#K"YEQIIX#zi5k#0nq7Ftp|I`}1"I,"F8oYi8xdZt|/){X8xEUny#4+.jL5pKqy!QWc"|nTl(T!<Ofk$3EUU:vWGlIs?U<oX0hQa3iXaT=o)By#2J#*WOP^5h_%s#1<}D~^GDB*}#zG}oy?QAtSNL&Ezn]JLfghI=C_lM*"34bh~o)y~3n|K;`I3hX,6]{Razb.^0&z=6~mB}t3[*@nHGf_@,?Fy29]2=()~OM[c*Bi44w&WEHqt{0xZUHptIOOMRcYYi4Ekn61G]0Dr}7R]rGb0O#FH91YY.T8iuWSlp0Vc=t.e|x8IEUQ?D,=e|x8IkUFs*Df`YY&WMMw>v/V]FT^dI~H5GME*TUQ?!CPX"3JNDbnO3D^trLRc/oP5,OzrTfR&8?($#Oy/qD08y+ChfGRHf)/2b*f4Z<bB+Wg4ZM^HY_I=zH&u[#NvemVe&Cr97r7f&Fc#7G=|W|0kXn>y||7[%O:WUIXK^&Km&<C4J0DtN,Ig"~}In[+wMaDpu:)023rhjgp(dY$#Ry}Km(l0.OVgGp6ZLQxEI]YcG~HL!UgCF9se0S&vQyzmc7l<mSpaN]dC2d:$mc;Kf4SazSz6BKuQgco^e4)wf_e4Lr&^]^5Om<`.yw;Rs^gSCS|kbZ3!G~n/mc$4lXFkN7Pf$4I}R@iUElB3j]m9|K}f`v%*k@305D,:fj1mFdSX4@7AFd%OQe)b6Xl03x}F=Yl]gjMpN}}3%fYl,u.O=oLWEat:VljX8#a8$4SaEL!d6Xl0zFsp,9,O94~cv:J[k9saK.6S0dk].[_VS7(_W#<#{59XX8qV$5&kzetW;z@.{54]fY>`"wN5`qHd{p}?T`.EErOk*Pg#9PYj:Pe91]uv4FB:RJ*9=8.vFG,X+|=88l6!s~vT[0Q2yFKfk;c72J/s8VRpIUKL2UygO;P.vA;>^)!PK5ekK};cS`(M5m}l}S4Z(Wr$HJW<Q.731oSmCy8{tNZ0PT5$8,tNT2P.{;DegSs^~i?0lv;=hz[7Z/7AfP,GHy72TaGX|L@/S25!H[^#(s;5kH;1}Tn7{N&45q#9_p<:?1PTb:*1lHDVAga%2dwKdJ{</C=>g#m~i|+`n:23[}723f|lsW$kc^bT~S4Zmk%4YmSWML<W(5%]M2ug9.S{.|%y{[@;k}sr73+dW8.#k%4d%mCSo1xO0l3o.c)&/P{^2~dIgqjVkE@bwO]}x{{EUBgkt7E6|kG~%90fgK45H=L9vN,:hooKY0PT!hQP]V%k))z0,:/wekt7lc,kxLq,+pE!go1qRLzU*vZK;ouS73v=1j"nDg*IbL/k@bV2e.ndzU46sSCvVlZVTmLbH9>##Vc}9[hqsKS2i[[CIP8Fa7C:65yNU#kw*yxoA[oTcH2lpm/EPy.=b.lzLpJKLFnwm0r:}fU7kYtVihyJNyizl.$j)&g&:5r:r{F1H{rrHaR2"0s:Kp9+z7[P.^]*jV:Z;[*1rdLdMY|kLMa:"ta2;u=^[rtwo+VF>krdb7%4}U~{6W3^ZOpsA%X*X{b7<:?132V#{6#;lk)f)&rdg8k}7346WlRbs:Lr73}:vV_7Kr;dQ[b:>5ObAFr:Dj^1Ob(<W]42&#l0MHIP,sE=|fv[IPD4xjTe/3flbvLf<Lae{Pa,K@J5/EbKM,UIIbD88/;!}E#TUNq5fj/3>uv9IeU9TNn07en2U,vx6jnC<HRtHPqT:!v9TN[J$)xPbal0#l/x<.3hCT0NmlQ};!4#8.pC#:xl6p2g;<T,W:<JJ+}ms9U6U6GAFiQ;v(BfOzFTK)|x)1.P566;>]=5HP^hn+n,Pyyc{N^1#Ea.|,0zX%pz8er60c5gG11g]^I%hb68+dX]#FwgtQ]^^:s6`SI158A,65Ug)b2r&]`Ch_.[(gIVM_pT}?n{:O{K8%UPU5bp|0#987bp:P4?J5a%WsQJAMzv5%?xf8!fe;q8)&eY)5oS<zLK/)~0$;PZpa7U]MJ8yO%Lwl:8kvuZ^*i@D3`Sc<&79pSa"7AX40,ghU*#[kx/A][bYmyc5gtw2g]7%l3oR%fVo~gkmp?K4e)37e,wW$0JUPIPHp(kg*6pgh2lsTkMK6C1|8nCaczo@#X</#v`}8?`4Xb2@pAe[k"@B;Klwg6%"73/:!UN|iEkpaMDUTmA8%K$4%o{!6N$y~5f[r"mi?Gy0/ojvz0m@#+^8e:32#O#~7D`<^hmk9{.,^VN#ef.>k_d8%YK&vI8BkU7+#.PxoNYy6s{(M&o,Y{.Qs!F&4V6,9uv?;orAYmudHVf5m(s>}7O`fMT+9`Kf">)~qk8Ul32!p$>nmJ+*4M%odKP8FKPWfRmx%k+=LvDkK1l?x?k@e+pn]thG=ad)ji|hFa#yOs9G~%.>Mm<4^6jH8z0|a&v]m^$APBo(k,YS_L:;]}yM$f^CWaTGXr,?8Pk+ctL<d)%.3BszeNyiz?eg^eAj+y_Q#}ydUoeHHGFhAj+2IM]2vRPnwUsRU+gQ5}LL.A140}:C(x#=0a0?eC(Gk5PNys{F172;QFaw:Te^?<[/xiSPkH+ifMK|oE{q[uw>Y/O)9_pw!U{*1c{pkuRJ8WYcr|%>yiok7u@;&/Po;nPy4AGOUJW"?{qS0`8q57;b$iek@"JC[3chjX2nY@7M)yJwfwz2^Kw1dO$nM1f$xD#q7(lK(DN_%0H3q)9?b?wJbE*U5DJ@;Dj0bv=#<*sGgssA0n$$>I+I#f1d_F@Y{[mP]_<0=6j{#/{32ho2]cd?#v]#LL8:M0:*9q$*YZkUJF0<G8f2fH[C;i@c:&c22*9t,aT]`*9c:lX}{c@,9omv<QsulCzFeHSto.92^_^bw~dp:APh|b=VrIKk;bT:kfj"Bo0d47OnJx=}KP=?$q5w=~nW=W@j$zS4z%@(/c$[mw%AxC9+heZna?1^kzJ2#]Ns:$dL[=OHS.{W3C~9[i|e/}mLDV.q#eY5U.r]o!!w5S>YjM*F4zvLx4UQ^N]|1lvgeg<vLtE)#&paTV@*tdHv%1uw:)Ld<;`pmo3TWLWJy57}1#wNb9>B%RHSwvV_Z.[h[*bBS"n|dI.]0&+0LZT^,,!M]m<b%bS2f]8Wp@W{7*tq0.v)Yc,t}}@fF6b4kHpm])/fnkw>x7R!ts>3kU:3k??)/!C]}Oj??O;#j7}^J>!ds|EeijC9m5xVlQJm:V(YH%bj}T$B8nS^EHySN4^}R;JMK6!9KcnOu8$~m;J8Wi?"iYv9lgSIK0JGZ>kV:Nky2Vcxob[2m~j&TrvJDR0mxwv5+/*flRB5:)Y,dF.!:w3PN[0ACBkT5pjV2Ib6Z5RawgM#8>4M3++/[GS1S,X{n_YlOc`O{"*/M;<><QyLoz=2(e.By4ZRb6JsyiTAKByB+B@yS][{+=^ulX{:O2fTx3Xq~}G^OwMv#<:EIbbcYGZpr[k`PuUoez=dk2vRP_7UGqVBUl0pm@pCK>LPyKzHp;YabF@WCR$B8VKZ:@k$/G@.<K"@piEWUCo=4x^b7%[CoGb0d#BjFY]Z4UT_$yNme@M4.MSD.Uy:UlG`xvUD16kR+zaD:Pl>4ug^`K6CohUo+Rg!3;u]0]{Kd22Vl<F#hNyC;(U_ep[XYc96;/{Gctsi|hFE+N]VrJW@lom+s|qQKhMp:z662D7`]kmwU){q,X.T5wMc(`m=Smc%.~7&[jS|y=No]G+}P:31yvU/P<`#;I1!=p$9pI+~8R$|oDpWy53B26Zyx@paTK,4UtT,Xcd>SUB8KU7rRF.bAc:ctP]22/}#}}G?yS>nurK%/?3y=U)eta,|~+eho1WiSK)E&Pcla`w!]R&2<OeK_Pth;z_2(juN?Arlhu0v7bVL7t[!ZVSKtiIqu1>vI|bDjbny72Ll#_lS{JONc&a,CM5jO_:J=:>$x]E&Xhuiuv{Mr,?jLC!w}w?GE2,$,rO0kS;JfgQ_wR|*s^4;U`N+,NW!;zhJE+,Eh}SfnWv!).N6vfStdsJN!eVhL^xEcULU[tQVk.oraFJAg1XFJ:i6aFJlhj%q|@FE*jyPg<&Bh7*1h>#pQa)wLX)q|Jy>znEN)jPW[HmC&N9F5`r%:H0+hp+oI=R`*kE6!|+TnVED;*s^@f,0_3KZXs|fQl0l`FAhxxaJNHw1?".pIti=fzRuQ@D[9w?*FsT@Q5QuQANs|=rjR35#f^RHlL]JeYvlR;?u`&0WO/IdT:OZIqo*;$nKx}if#bArzf|q|^(7,eu2xPJ;C]%(g%L)qn"ZIvJQNKuwIipc54Jl0NxSa$Yf|8u&|)>V&pE*eLh*Zj~cIl01*RCLS:&j|yQ74L*YIHEq??@yBhnfbf|vLVDOnp(aCU[Q&Mn0Rq.oIoh&m(vVkUE3Ye{*r$JZBRvy,hCI5W0WMkCZxCAQCVU?E~l61xGVVX&aow(y7$vJ4riIS$0l`v(OvKKW&%DMcPVk_{_(qeK*R;,UvzEZAKiBAm`TGnN}EYHOJ2YwkJFB1cxCA+@lMyG]0P9SaZByYyG]04S;jsETazf[z]F4Xkc.T1i?J:rv)}:"Sbs#I]@/?:?9GOI<V!}Qh6m*FZuryxQ_@4)RC#_SMo;bJe1AQ,In%)oztzrx~1aL3eq9_cDZu8v>~DBUCzIJ|RaqIqo7"wVVo7"E~ybMG2,Tq"w4g8WsV#TT;kzEnXxR]s?:+@s$jEq9k8B9FunM;dmx1o_TEvu</m>uChG}KH_".xY}cf|>r=fuQY12>NtBrwT#ZH5d1&,aDfFR+kH@}`&!}T8uE$QuQS36G1*!gb;6Ci$PihjBh)>xu%qcN&|q|@0I4y~aMwE$Qs.oIg~qh:5hNJF`3?HR1=@]zzMPEiETxpL)M?:V&*`W,e41>8*N^Sy=@EI>x54(GcN3T|/9v,e`H1Uk0=ZE/s,W(pC?VtWHDW1~*)@5GRvcxSa4a"i4>OOoz=fOQm0<@3)6vBxJNamFU$WgYFt>WcRj#3?eUltlMCv1}=J^g:4pJ0e~4h~^u$oXD!_azsv3W3>@v}*(>Pv"=I4uDsKeq]eJ=bEw=W/z~4k`GR~#[Y!siJtu%U9B|fGI0n(q4F_rX*2[Qq=(EzA2XqG;8kzf/zZ}Lh#y3nT7>(v?g?YEGE5@%E)P(szl4fW{;0198TP";=Iln$IT5w1rsIDFuUdX)fQ,.r>9vQ7=F*Z9K*^AKU=UVJK/(,,a[Pg]@p`%|Gw_#cg:OCZhl?zGwzA*.nnfXw/RY}a<U#G]cDYApYF|{"^UJ(Bw(&tkU%AEOnB}+;y9BR|64VJqy=iu%3YgITazAB_?_=dna0G[PLCXLwn9<IVH?ev,38Y[$:&DaV["GPjneq.g2"CH1)szAGr>T4q0WVaI4>DgXB&zs_;$9x_0bY!5dRA,G<oqg{GUS)Wf/kp]A_$g5AE`K2TZ?![!nipOzu$jIN9[3L_jUx_ZfwW|e~~of3cRoU@.&)xH<bK`jLqF~9(o1^@%X&gf:urw$y^|%J%[:96|6;&W~+KqGgRJK=Zp*koi6(RfB}U5%vY2lrk~8JN,P~UONBD.k2:jAh9MrzcEyr#kY]ynFMBrb8W/oEeK~B+>GpU47REIzyc4e4ETP@C}EGRh^2L?T~41kvp~B%|lU>tI7uwzA;*8FM|BJ/`qF;hu=$ibrB|kzH@"OrXWr|vT39k{^iGqp:E)O=|]%s"P4]RVY^[K>OgYK5Yukk(Fdo!!#:spiA?GH@5`9BM79o0_MN5B+BNwC1+|pq^F~qO5}ah_PG;Cv_MK%d{{cJi`&$fC_)LVD=9wsyglNw7beuQ{q)L(Zy/]`YYFGp|Y!^fg1*0rE4djjpkkPr]g`Yf:ObC$*K?QNakgfMfY7}0Za.EjxtW)lA&*{(~<mx,Khpg]eW;]h`Xk#jPg(Yvgai!m(mk8H{X0.=>U<oFtR(?].ecHq:F0{OrE(Z)y~s*Ve_M]MX{!|6P!qN!DJ8!pq>}UVDY2+l`!qgVQh>F7Rpqb>KhDG8!oqE(KhjGDD@/U(E&og^eW)}o10<r{v[YQtqs+Iz]5PFeKfxp3It/f?o!TGguF8Hv&<^E,V*1v_/e3<cDijIn@5Q?8K#@5GnBfomRD/KaKG::g,w_.#zltI5Vc$]4N*>$m.8i=v/`.d@.(zqNJ!1cQsnKmPjDh_h#x76)*FX0vEMJ??@?GBYR?I&qx4bSWC2+]6{8p,^)wLME1y@%9HY#Uyne_eVFWTs(=:%6iGS["P*7D(1>|)vtwXx/wF%/b4J}H%ZgQ$R43!0}Dr_:#7JePu^<L>%69Oqjy.O/RZd_lSkS]+zAoES3f_&@nY[FRkr||$x71*vr|v@cJcLG+5w+1,2_45J?eX1q9R!Ef)/`EDzQYMx/D4mK{Q%zYu=),vI)<=s79rK|bS5d|x5BaS!"7Y44gJ4S%h;^C51n<u[v|r[R6~hDa:zMlF+C$>GpCt,=Sq#<3Mh}dN{X+Z4K&sJ7BJM@n5NBoQx>Bqj6VLYyB4e_8@Q9l=0,sEl0v79rZP=8h,CYW&_a+aPW1&g5=N:A{6M]7or~~V~*]G85FtN`1/cm"h"2?qnV|I"9G5n49B00%F5B8G8urjnPCmTX#v=2%97K8rQu!(W%[K"icWrn8wv5<~U&mB+UxWj3Ia!Cy8u/0$Me>+(zK^ieiP&+o}/({^Eh14(eE`0kmGLBoLkN+G2OV)4I8t7(bSTx1blDQuCi{)FB.Y/)ILK{q*;$1>dLC08ho_d&bMiwL[ici8V$qo&4v>WpABs?r|@#?1$6!Wm>GPn?i%MWa(bUkh67jsZhgho"7%e,urwsR8>f%}ZP@W)I)ID(<91Lr[a[CeBPf07oNTBwP3LSykhxUn@&q|X[Y}*YJLww?>l+GXo4&mFRVqqA1P,ODHZTZH[FQg+C=F4"!.,]D*S=,BrBQ3oMM?X%|8y>VDFR}qqJ)(f/.iJxwW_:8Eo)!_S_lI)i[r&P;ty7S!a8{n3gT%ko/@1,O1*SJ)`ki[h[.y,S57L$YmZ?S80,O1bQ3gT%ko/@1,O1bQ3gT%ko/@1,O1c9"$ko/@1,O1bQ3gT%ko/@1,O1bQ3gT%ko/@#xbQ3gT%ko/@1,O1bQ3gT%ko/@1,O1bQ3gF;.@1,O1bQ3gT%ko/@1,O1bQ3gT%ko/@1,O1bQ3gT%ko/@1,O1bQ3gT%ko/@1,O1bQ3g874^+^Rbwn_E2m]*nXro!m|oh$[&R=Ni3^7naTK)z>O@?=lp"r1y#0j$E%vUm}{%8o1y{#U=w=433ssQ6,<D(1"o4=]prS5.sQ6,]p~g*;z%i#"gX1;@T%:^|%sQ6,lo4=]p~gX1;@T%:^K.B#^pPK8%g[{2;^|%sQ_^|%sQ6,loHwpV6%r$E%;$L];^1,X}m("!sVk?=+q{_]<;89ch5&Vrr{_]<;89chG;eC)5o3m3OXN;q6r<F#Iva^<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89ch5&Vrr{_]<;89chZ%xk$Elr}E3^VUg$s%R=oh3^GR/p<$6JG?ZnI``m(%7a={#sD+bWn1v=O@J]:{#si[NLUxn$y|G#FX`;bW`;ARCiE)GuLCXEuIBRCiE)GuLCv8$S?Ls^b^VFD97R.,k2CRQkE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuIBRCiE)GuLCXEuI+SU~48#mI*%$yR=>TZ6nL@;$bGn=iE1mwJ:{bWK<]h4tv>O@$@3^AFNy3sRR!=O@v^:{uvm[NLG^NLbEzJ~_&iq*]w.H2PRfi!&iq*]w.H2PRfml(X{<1<rKEgcj(1,S*ig.]w.H2PRfi!&iq*]w.H2PRfi!&iq*]w.H2PRfi!&iq*]w.H2PRfi!&iq*]w.H2PRfi!&iq*O84^[iwn3M9(ny7"=Kx)nya?TZ7nwRc$LmR=U~Hjnw!NCs1y;0j$xqwUm}P+8o1yH$U=YV533sy!3sy!njI@1K#Xo=7Rs!+xLm{iwJX<[*FTs!+xLm{iwJX<26*TaO6ZtvVgGFr$dHlw<1weXcy48n!l&lbk=nV]&osN(IEgcj3J0ly<fT.xLm{iwJX<[*FTs!+xLm{iwJX<[*FTs!+xLm{ih23sd;g$y?h=,1mn45;$G`m=ND%mSvb$*Em}NLf.Lm}i"r1y8N*mHo@[3^*mW33sbTg%b+%)+3$n#_:{j$Z$Z$Z$#m6LKD[YHT2mf#P[b%b+|ik=yU3E%kZdr4HXe?h;2.06mmx<Rj4egJQkW:S!a8@4W@/f7=C;<#q@dp<=s,;SN#C6P23eKk@a4?q6&lbkACveYJXHlw7wz=p$Bk%d/p1f]a6+p[tNBXN;q6N;AEvxTklTg.q6|_=::{p!+$bG=>U+dt=Kx)nya?TZ7nwR/pC!3g7"cl^?t!+xwn7$y|;mXnI`r@3^jsVKU~bn8o1yTkn$y|fqm}3>fTZ3cnR=dk;Jm3fyJ5DlmMzA0wy(L9nZ9[ivEe*)&X@PihY,4s9Sg8qABB0E]hr!gTCCCK}i%mEEwQVm<EuA=zBm<EuA!!SuN">kGnEE6]rTCCH;@EuAT5DJnCXAt!J#gTAo&C=J!AR=[cMcgKp%.y;]SKK?sE_>c_b79p(3ye<zpw{}(I5;*U55BSj?]4!r(vqnlp:y;(4;:V#A0K#netpOI?gKh#iE?Jl?Xf4%YCngw1<b#n14}u}x;.;]W<R[NLu;U~lpv=O@!Um}:l!=O@DVU~]Sol0o"r1yEZv=O@[4j$xq([:{;.k33sgU$o1yxC3I:.eJ8=u>O@Zzj$E%([3^Y9nUU~lph[NLQF#=O@a%b+EjU=vgmTU~lpXnHot@3^Y9VKU~lp8o1yfkrUT)Et^vfkQV~XJ+Q#`Kh"G+Q#U=vgQVU~lps:xW")%U1!+Hc9`K+b;mI`Z<_YEZv=O@./S=+rrUJ`xWk?./4^[&m33sFVh%b+p:_94+O+QVKq2Mi#+rwVv5;U`4W3x|iyj|KqJjjsg}a+Frx5Uj!rVWQ@!r6X=XR+RSyW=X!rQV^v+rWD@.u+t[~q8M#rVWs23slV]=O@y!4^v.%23slV6$DUXo:{Y[Ly3slVf%b+U#U=C3QVbGX[/.bW%3_[6`e+JfQU=mI`%_(KZys/`4nUTvFZrU1pZZ1ui+j|+}:yw|(K|}ZF}4nUau;v0_CK./6F.>*K|}RF,rau#vw|+}ck`2!raut[ItO+1WE@n?W3QKo.<VDox|E|RZSvr,{Cynx(duV+he&kq%bY1//11/#+W@+VA"It0_E_&=VK)L@KIWpBksvrvvUZ(k`[hFoF(_aFoFM?qVqu@`/Fr/WX;X,}Us=%f@o}5Fy|dZ>$0B>~t~(K}4g~nUTvcA~F#~)3Z<CFRfVL&A0KH`DUBtyCMUqWO@r?%A_K.FTR2KNVGOQV"qSyXA[y#nd<LyS"BZ}`Sy>$P^RZq#j|p*GETyrsJZngaqDvRZXQ=V*LHt+vS+T|(K}Fxq_[#bkEaF(Aa.]+8y+v;U9AEy%_o}O+|`]CYoUsjBaqKWA5U#NCF[oLtXFj"qZB7LfUBt>CssdZ+r]G&KhAhAIWaS3XyM=Vu?Y]*UGo|}:q9JcsSq)[]FPD"YSq?vMLi`z(VA)Sg83/Wt^E}7*~zyvAR!+BgIIoLY)z:1AK]AICfv.>Nt3k^T6yr>9MnEBFjziJff<cmJX%g+_X>iSo#y*CPwnUVZba[rxV4MwL]YBW@6ktW+YTU7wy:7LKMj0f]o6v6POF}j=yx4^6<5je~v6v<5QTD[;.gj4mT|%`sQ_^]KX84Psy6;w|lp=1Eec#QJ[V?=k?6;&BW+~U[VGoAn.oM@yocVrk|kHamz4/x|7HH]hmTJlGj]_|7C?aDyYdc/Oe4fMO6KiG#C2`eu3%l+U{3,6)?ib+?iv"EiDH)0LT^Z{6x4d8*<]4qp+qjwge!kyMtYEl{{=Nu0(#s#>]Cofl*<G.N0TJO0//GS%Om<KmCerkIy#l!fe;^D1,soZ$rZp[zx(b`!b{ruBme{i?hDqN=1Omz,pzV:t#g3x|kEI]V^AUWK2vRP453,h;%X<!P1G[:4@/ep=G^yt#E;4X(Mh2WIhEmE87p:aLmisQ2%Fl]1dQ]7/j(lPow;orXj25atoUg;qvm{oE2WV3!]"?gS{jpa_6%kE!&i%@ffa#&+mE4PwLrP*+,xAH7O4/fbZ[m2hL*+8y>0{,gTHX2#}7:N+^Az@p;Ne;}M9ErLP),m)nq}dZq3?3y=v?]{fj@py47E"%Oy|o4S77;fmUA(~+_L*@Kdvb82CZU3}3!6dY%MV:9N(N`+{`^zBOio:ZWY)zKlDp|%;RJ8}+>d"Z@6"c{19]XFI[k<fYt6#&32%dVg?1n]|o{U5cZzgU0CI[W2^1*+K@?z%O&of`u`lflfMpiv]8o;xm68+=].W`:O]zH85z9LAc#=`Sca77oMR_]{dHa//N2T(&*#"J4m~+65M]A]X3Db_zqhI:+ynSU$&M7w|Z!P$PAl/jYRi!2)[zO.Bty8zLK5MXSYSjV3rSIrxL5qoSton[_<kr/Z*v?M&v.UV2^q{6bj9D:/6b5#U3yZrR2WHamzYwUk%#j+G5&l(R6ZqO%L@1m0?6p?EVHTE(yJV@[!yN]`Ga%2Ju+)[&/UY9saq}K6WsE{dm1SD}:cA;F9p3}+L]w>n,n0S{R"VV;2vfmY;2Ga?k$/Fe2D:/jWg<5z6:(E!8L:G[ivFr$M$FyK8<Tyj|dZV2KH:&=el>PouMc:rk_dD(SPdu:Up6@.M]R`5ZX_6477EsNK,mGXBs4$kfLdE+PKzkU#I8=z8m7pEK7.d=yOi27=+mbtmuw%pSrNUF%be#Yj,8$#V$2ge=I8IKRr@a"VWJ"k]#:2"_XncaGX@kCKC]Us,dho5Z_/&<mS/P[<T,0}dl:MJyBeX6H4?bNWpM]qKqq5]O%oO]{#)XGsLkt]`Syeok;Ky3p#2ZuF+bU,^RV]I/baE(?<btB@plQ[^f7:j5U$K[$4sS6Oa83Jv>=n4$L=z%YK[<JF][G]`]+GpE|y%[6ddbN|vRUrx,L5*|!AaTn0^.G[bH7OI0^?:*+X6!iYhSxe+^/k{<k#_Y0dU{}#i2g:s6.|>w#=IZba=S4ZkhBE^1>gk~i`HqfBNVi"{%dlX_UT[Y^rQ[p>E2@LElAK!8m]aTvM&kyo$9[bs}%Z4kHSYO%45Om<KU~jgK+8~Z^5v+5fh>_wi2V)[k3fS$aBcY1/:We=iM)jOm#ew3g"7v{%e]YZV:XmascoTmpxGL$#feMqPcVvL(YH_yG]J9tTC6A>>2a:F%Lf#A2}HypaD6})[T+>"0,x=4nR[0_qu~rJ"4*E2g,T/*Bfl?!XMU[*IfWGvfSIDFK);9~klf+4p/uPjcc/iCbQLLk/)<O6SIdfHE^awz[{!{c@j/yU7Ll0/gbXN;&MA%/GOU_Fg7EZoXX:b{F8JIWUs+Uja8+4V6`C(OMI=f/{UfMJo~rJ9&Su}3svOTKspr!!xMmlX2wNA/A}62Y_CWZmvk;u5DYHwOFdnTS8uZ5C$Y;8Z%J}O6jCW{c,b7Dkm0!=0vO}h[@4s}8kl}K6,r!oO]m3Ud]*<:<#LY(3pU2`%.*X3cuS]5"NJy=28pwSK,:U!3H+y(;Ui;1Jy5"|gkoTedp:%.SA!{&7Bk*cBFffWp+y8pm0tkzcty&gc5>0`~72C`X(K=iz>BWU=z+=CswS^0O26Zu9uZ4@jryMQ#q7RGP2ukz<~|fjGZ(_J.#XMFx0HWZ2lf{4$b6O/}[oG3{`>M{VRp2q=vsZ[kiY@Xq$$L~y42x41o!o`1Ksmk$L$_=8uvQya%XW@l{4&JY@vLs/kSNh[vW^GhA{*Xl?wv{)EF~@wvVP~TR5t#g3t#"/!3HtPYM52/1qmJ5Q!XYje17q;jy4H[aKPd+F27L[InL5LYc"DwVJwQQmYcgqgjL.1x,qgjX:f^W6fjQ.f^a71+z7FbU,^Xc}Qc5.3OQ^_NWsW$`+tYq,9n2087b5&j[L(WpU]7aM.ks+;zH+YfJy_/aM.ka&uOGMizfK0`>8$fs5U8NKpuN3h.+R26NKodbU#9(+47NKra)31cB.OZ/=+yf0d$_VBo)[=LD`YbE68Tq5c:[05e$nUNJQ{,&2l$z7+Pra@lJ#,f$pQlnFbKNe16AX.OBSraejGk$ptS.p9NN$D%X27W9NMTJ?"k=L!mGk@["k0m_ZE9&2w<1%X2MT_Z,EmT>%rCo=RJRJ%X!6vR?y7g#6yBi:*^:!pk*<Fp4:bTHyH+N37Rf]40X3Hdn:u6bJT`*1ZTw5Votbo%*#~@W6Z3%#,f@x"TN$+Ep9?a/K.P3SD.>k97c2,]+/iM7EUp%%i#Tl#7!<DZC,"A:O6S1Vg;2}=0]avlm+Q83d]|RWlGYY2R(M_FNdy;Tg]v/~kU[vw[5ZR2w+Y]F+0N^1RK?UY9AxMyB~B%w+iU(NVyRgZU>YElFLvS_HXK835R;d]^|6$X+oFeodnXw<pz1SNGnp8=40B~KW:^7==mCuZZZ#,P6Z8FdHcz:Py`&jps,dK,3X]7C~R%rVDO_7BkpsQ{PW$DQ7{y=N+<DJxJ{c>o,8|a:3{#@#E;M5.x2^0|[o_2k#^Jc:65bOa=~geYoPHpI8>8Z8u^?8VKY`bbo:!4{;Y8w,P="nT@)Sq%`PB}k#1ljw;={p<)O4Q.rlN$ZOC[(#$S:|MHxU`Hbb3XCOHp{a!FvwH[[v.o^dUPW,P5!fE7yBI4:EJ4e.cu4]@4e^R%/U@^%.)Xl3*t0C{W:)^Z9PuUL*+=DMJy[b@WdC(6JbYBIfHo:!MylH1f2k,YTBd0.jX%%RrU.Z/P(M~xUO~U*fGp{qE6IbQPxo6OxLpkBo.:1^#;rSfP`#Vl0Fs%ZTBb>7PueC`Mh2$:iM87@*zF7]9rdpsV!qWVGO1p,;J,|#M#]YN]cG"g4Z2f$xD#q7|k(l|k!lot^/3J>%RgpM&R"P22S&]c?7X$A*M=r@ij?6Blsh,y_7X$M=(l0lP6texeD8N.%J>L:I!J4JWPQ,Y2#l7eZO9H&S%WD2/qo#Wh>PNh3EUp;;(3rJ1#39%gE*ta6,JM~f"g:;eCL{;da$56/Pi#^l_+{So/OSX.}:buac7f.`!!7E;(o;z`)XpsVB1r(/y<+/Dbk]&8//5|P]ILpLCHgn2xBLN/lUC"5q*rC"&TBtV$GbL9.{J>};|{AwtNCp1Sc9sa`}Bo&].=!fA(Hp@=&l"IpLq$)fCo59>}E6|k~Lj}?:U{Mx^/K8"FNlCo>.k]J8@7H=(VU@rKRfIz_p,z.OYH;OipN;CGIk,S!n77.OYFxFbs/vvwvNIHwOuMyo:Oip9{wc3~bTRu@OcbE29mimUW==,~bT>f~loo]*M>FTCUjvDt.O"BF[y`$cMcK6C81yL~ul*x;OB<Rbafn;3OC2YLBAE"*cAA)M?TDzyi6*9yyD(=yD@Q?zyZ$o86n5g0FX")AwAAAAAAAAC"1[[oO.|1`K0*{ZZnJD/JP`RdQeM8rbCx_<wv5lFHOR;($ROCg<t(`d^qhjIKWHMp{idL|+)pJ9ZNi|O4+Fx(=IGQ@(dX7nppa1c$Pboa@I14Zc/@1f0.i^/:j~T0LXh)+?=2wy>9AM#<z&q|lb5*tX?#6i|<A0+y,.LcLAbPKW7smW@r_I.>M;b+n/NmGK8*_O/{zDcTe[,VtF5}+,!~8/9mmLTJ;p!x;3^**GA+~@m<#bi^^5$^m#6"ntyRX4>)ZZ=?8f_$b@#Noo]RLZCm`{Rh}WvrYlkOFkT$fwy{j{0`Y[Nzt2;=%RNP3ubEF@?Dy_8+#*7&t%u]ZU/t)p)sqd8brOI;R~9;0ln&RB(.!5]*}/?{nf&htr~+;#2%=cLSj]$~r2C83GOS,/YnTn^t1hHMITD@1s#V*{|QUIG`HzoqG6|E/cAt&d+?p%{F6>e*[KQAca&^%1jP1mBV1C<|s+*@@#47gFT_Pgh"6<:]aaSdBzYL|Itt@u$)px^a4Umv%6#tyk/aB*l9.lD3cJVnSW^J#;Q5(n/%LG?v908+xk@M6BMOy@)D#tI<G#L3`.I<D^s5%>p.zHdI+IqJ3Cp~|r)p0W6=`NswDLOY^`v$T~LH?x/*cI/l_<sb*#7PKtZDepoZT/h/M?VB"L<I.!8jwIS@#!S%*+:nry6F*6()r#zXv|`.dHxn~Xgg.O$BQz*pWJf5fW}ci"m4ct{@v9b|N@{bP]fcnWB3mdX2&xnkS3I=Yk=e`1uYMSV(#)Q4KgK<B+D1D+qM}lF#pRe&1o7Jv`j*xmtO>?>a(I(h%@Kw<}gZ|I`o(8osR+4TF:+|HnLy@Pzqc@x!Fr^dzE~!ySR$~_g_^{&!;tD2aU^+8<zU=84Bj*1;c4EJa/S1q,Ddm$1cs~STzq&D{7Uh]K?dIMX1Zfj,Xuvy|X2{0|cms?C:=9jN:}i9sa|+*|5Gx&myO;%&wGZ++uJUrO2jbOgbj67LP*M*dGnjCGX:qMIg<+>S<9bxzd2pRPU!Fi&MWQ:+V`3MY^D;;&f+K0Qp>2E}U<Io~?|sa/xR2`AIcQa(uQ})e}8lTqCTIVWvUn&zMJiE{|*;w(o,$*uXRln[:Rmqbh*;oob{a#v1b8Yx3tXS]]bK&q@n=#2(Q8(sbel`le_:Ztb|Q+SA)x$Q6P?C8lj>}g6;4VTa!w#eY7~yMjvP%rGSw_#<A~YtX_W_<5b)"Dig+niRgjG$GI9Yq*yR_oQU`du@!24G%TKobN`MzAdUJ3,D9BGz2MHtNM26h._k3+!pc(QRmcZ[99q:Uu]FR%e+L]q3F=@Za|dLi7N^.oq@,ch+Oxu}/WrkP~<fV%omsrUc.p*e;>#:^^XC{pS+l{p1WN?SBmG|8>1Ce8/7KJGC<4*(i9MDe3y(IjuXka,pKDI>F#]Kn6cJ1IdnAL]4ejvjgpw7zu.X?Etm^iOdky/x`lJnT0qU=3N0MON6}1IGn8*r/8=b1ugU0DSqgCdb~ud)|j#xk@oo*!7bCg;(xJk<[o8#@iwH?RvR&!RXQ*q`%@NPal|4WKf}]h//av;K:9^|BD^sW)rJqlle`~k:lI^:hwlriV<7PA9[9sDGe{_$QxxZdh52gsA3}]6d+E}CkO,|fG_tJ1<1=a~=M;lf^ed_Xr5Lbamn}N~=+z,]2Z"P4]8VO*o$Iv~]/_08uD"3I/Cw%WuB]!c&1.k8E{h,wW2r@:tP[RN0`WE[|lic)s|ujOr])1Vq[ol"#;EnpVRP.bY_Mo;i*2^x!m6chue{*d!g^?g1_2*hlJ`ryxnVvJW(}]StTCUZ`k<Qkau>@8vD{]P8[tivoRr[yB1avg?g^Y{rl6`_lt,P;1m|0#buN/_)2U$Do)8znFmJJyA`,j#:]1w$1cR]uS>|!QkA)8_i"B7HT{LLc|8~#Gjo&aam0X(^8lnSQyzET^`Lt@/jP.Vg$+t0"RJ_UR6)KX]/U!h0<8]2UcGxI#ExL(**t81r)%][iGNQl2}~Z`Pc{;Jca^J&d,)>eMOY!C,r,5#1i5+L3!^x$RUFeX*_6u[03.7aG1/ngu(Iy#_MNx|R9.myP.LZ.8n9v?|v)[6Z"`eLKHQu;2j~FT"&]y+>637,I+}r]gxKz(q`MVF~:v+R4f)W6k/B:.iv87LrZ<s4,<^?u/38^pTZ){_B|pl!;~%nz*T6{B6eqpj~gL8a{eVLvj8x+TiS=Fo{,y"N0@.J8YdDo#FL0w:d2_2nJu.9)~}v^;nFqIlNltdFW1rF6cotkKGmd&.C[&hh@Rs3$"wDhTJfR{Cf0#Qx:_~Hji1.{B9~;=T#~p}SXQt4Zs?D*(wN_#=mI,46[p&&t1#xL7Sj<%J+h?Ib+~?3~NFg]k@y#0A;q}t%V8^[o1+8)>sBNI/dN,za*Ryr|ejXed0NHO3%POn_C&cnc~NL7OL[J4TZPpU(DXiqlwXE3s6rL9RC!:nu:iqQ:]X=.IX1OvL1Ww5ZAKJ#G=(`;<{`m.Z[Y`8K!.1=_7$$NdGZg;ML`u6,LVQqb!Q]%aFea.<X[e=MRK?Rr;Y.w9[1o6^_?$go}!cV$G=hhV+7Z_ydlYK$n`2U%UH^BlKasu=i.Ap<)t];$wzz*_gO{(=K$Nw/Ea/9A!1yZu<7aeI6rXZ6&Z?8!Gy,/ob>g*c#!|eQ)74v}~_7%UPA]0m1ld>29>`%aPv~.4/=qm%fu^E~v*f_i`$8}Ih0Y`HfUc?6ds31pUwuebC$0.KcVwhDNh6>piv<1;L5>/J[6q+nI8R2),.1>s`yQYcaf1=U(;mPu"YF$.Bi#WNwr<8=G!,`fC+.m~!lJf[0u4SN.K_jS/ngD<tz9$+6=EP*4ovbmx2nz#GVs:x@OySZb+%0<|Af%ee}_::>?BdBE3$m[v@hQz9ZUScFciCc7=5|Cky2.(14~5gEOi=},lU4=Xj?ienp9a`PF6KO{a*=Q~~Qy!:l{a#Px`Yt{dp]M:hWFG7e)@P+9,e|M>~&Y[Ph/~gImimRbW"r6M*n~GsiMEH0i&aI{Q/c;iH2e*7.7rh0Zbb&SG>x]{DLIM86cVwo5X)u)`eS%ynG?=+D+3l_,)&g~|E0HrhgLBju3r>s;./o|`#"2B;VI{u{)B(B6n/%T!}rLS;Z5L?R,HeSv=a.=v=@JtG~*,6FxPkQ5O@0Aw8P<VkS`@P,>b;(5E[O1{}"]9)hG0WRZYqWYQ_Mtl1b&s5w(Ch<EmqyQE)*4s|gu.8S^j%0ls?^Q}uGkUySdNRiCnXN7VM%?h<u"~k7<6F8|VN3iy|3?]2Wgs_29W9e&;a^kGge$#XAs!UCt4[2`|q@G6+0(8~}8ujgmtl$~(<M4S=*dSXZX%BX~A7,;Z>{&Ju0y4NS&I8HrL]vc@d78G7ULT%{mqjs[&n;o0e4D*av7t;_[zSJ7X.P]pww@]ETCKl`zR61bu)+xF[jNs;,,4APpw4R/Jpn_~,t>F6^}22@Xw;^g%)}gF|e#"nG.~6>7G}@F#/H6FWNVVTPTW;7G$)p*b^C~th<6xLL0F4s]wpb)R:B(7s@S$t.H(tG]2=0ipz39N^5gME_.h+^">bi@7JQxW))e$vOa%wTxoOe"3^X#g#Bd0(d3;+wG59XpF%(BzaY4{CEK&WS>ipkORGg3$|gn=BSkm_q`,:."..8|uR`*{E_%6KJ]{tuQZ&JoSc)J"K|:q|bf][H_YF}$0gCx}_)K%I5U,8DZPvX0+{e(|{i6T_IM<fEiZ7_,?Ux3GB2cd2|#+)L@48:7$QQJwM.g_GJx_U7BL):<Rg#B2=q(:JwhZKO6Z#h$L*s.lA$9l),bN+lWNS90]<`<fnpYFGIJ&0_*}bEmPgowdTI+P_M$7!/*qL.W1QXQ*9|;nABd%6J>|Ugx)nhmD`/&kmY+2`77cD>@W.LU<h&DS=>f[j/Z2pOh!^s[w8Ka*}LR%iBpB7o>S]o)Ngi*[PsXxGw^YM`|au5@yJv#@.EOc*2zKw[@jHrG9SSb5;]B{"u9{#Y1E&yV!<69vwvo<{jyQMdT20$?eM2OiQ~Rv#;9][Pu#s/JyJxq8)N5ERi?GL["cR:`(:%Uw`c|DPGs#QuBZX${4I:wrTq.qLx71gEkyzGhfz?ex[w$Y8f78dar?TZ0u]o&gTp3O]D)EL@;8TtVEgfT@L[r0Khpa_80c~DubIOWL@s<%PiZT^awNqIrG?UUK#+.}*RfF46Q1ZmJ}CBswPC+3]W"w00XRphXQS^ZbxNC]0L/|;kyOpm7%kc+H(|/[=R/.CjaK_628&.).Bf)L*nga$si+OD2OO/L*BuE*|YHK|@4blDy~jSvPA]fV}|qbnL57nQHY;Z7uXZtDK}.`qYN=jbryW}viO2BHJg_)ny+Cpd[/;zA@1{|MPWVa[vGnMZz5j*rY|LTBz&B6T.NspCo|S]B,]tLD$b.Gpl<8u{$Z)D}d8%61zEwSkv>9@uY0g[getUuD^k}GAbrPbY(a(@onX7JZ;DSS$.IKbMQm:P@1jpmuUMyZ[U0q4ZGf?Hb^od(*.]`1HuF.)6H"`@bp5VuYyj4pJ~<3Jb>RXU_q:7*ZVIuOXwZk3u@J2`j}DIp$0S[%:]/hC/U7Lok{A0BxLm6;6*_iU*,Jm}Nid4Z$e9RUH@GW*cp|S<qw_7lL=pb/+F{ID(Q:^Lb.yGE6Fwj5"J8;#=wdX+n[&?yMDNzRfKWwN_ZoboQuk,HxOK+("DW!;ffktn5,WB|N8,MP;9(9vC@h|8~HuW/Z74uJ,;XXD6a2c0.ez(cu?G*x$(aL_@|<[.NaHmsdXoa2<)>T/l}+LH85F:8Ok@ZE"Le3D%_U_FF~p:A>&5@HG2pOmLUdq(3)B%k94N)3F+U:4VE!F>KA[n*Gg,%}#bjcx4@%`|!KeG~Sf5l@/*/p_cA8l.B}jjQvmpiPwTc.oGOBOYvX!vBg^Te4}=mA$kKbc6xag#O;s%^PtsCf9.qnU9]A;syL+TnRGD"w2]KOy_($Mf}<2ovhdP7{<~<JUWh_5}?s+4h:E3z.`3eI!w!dA5&Hsc6SrNZK8)y>n_34dl*O7aI}WZUvtWTxgNH0j:q#`Ti[7,Eyx~{z1aj/aGe2th!K+cplGSrJdnJ.,cZu|q?8K3u&pNjBwKEHGdd+]:4)qElgW:l=`/}Do70@T>W>7*nvPGA":(q#eeFT)tt/aXHVo%Om$a"Dz?jZ`K):%5B0(mfZ7p$s(h+_pybH9ja4>:m,1fCB<~mg~`&Me#$[Jv%(cETCqkR|pV!C5?P(FEm!_xa_lD3Qu[O~h+`E0vLLa.&@^v)[!tjjn[efD!~Dq!t1tY{JLo]%d#WdopVr@ZT?OE3P`Kr2;~^4Uu=c>B|%o?>YI0`?8i5>b|UL7o6!`3db^m*F|[XC},eJMWHTbb9+`cOJ`b2ec<V*(s:uG+xub~;6tI,|SD|%;#PnOOg<nsL{^GuL74l.)$k%eJn%uvi:Q`U0s|aGt{MSta[&f~oJsHd^tyNyNPN^s4+a^+@<N:!}5n9!:b*+cUXE#Rr=~a,5;dqH7G^?H}4,7h:8kU;G2z[+/@q2C60=`;?{tG.$0i+h5|X6R:m.exk~TcXE85,J1=7$J[:vTXvI#?Xaw.f6G,!2I{T^,2TgjM"OQ..!G}I!TL~(Ml/CIE(Thowe^ea2hHhfG;+#~]4,7+Jg;b;SRN7:I0oICdc%5@TfKg^/{|7R%!6%I$5N`hNuLpc8qV"x,(g^96A2OE/](}Ebo07V<IF]piN_s#5Iu]a3`qgzMLr$pVPuiC`w,`VYqHz#M}`Uz{M`8=Gh3H!cy?Sn2HmTN1k0Kf63sX<_JLL3RCzMJ~@Iajmx}b,P5Ky_kf]8PY0/)Es2AzXhh|#V?*DEKdocun@F.MqKP1ZDtX2Uur4z7K|OIsQw_~}y^BuP9FvpAh%^b*B`%D,!om~$gBKLyz~6q]qL1ob*eRT.+VglzCS}e5*j5%QF_`dlka.Yo/nRklL(29DyI4)`bW,$}Zy(.:QCG(*Z544s!*D,R6sV@BLKKPDbcGv|^]oA}`CB8o@f.7I|G.$.gjm9kzKe9Pq7MKz/PCY@?/L.TC#]7RRfWXR}i?(<V=bX*JZd@EH3]zu)P>k:4Bh/_s6*ARY*LVsUi3"5d}.kVtRf47l<&:=9j&}>Nw_d|g|^y:m{^l7ZQ|m:(J+Y$7uM5FN!*0E*#8F>F3=11<)R|fG*x>)*=VAXo7SURs8{uXx/EF``h`wao<tp?zmC%%Y<_|<1riZene}WG6~?KT)`bSpnI;w#Q[kITY"Jp3L)Bi.h`G|LR~{2:e!(E1~EH#s/5hZ3axQVIt3gOidMay%s_g#FMiWeV+ueb|k|5{"n@FdTD+o<WfWtsDULl{N?eTk|#H(J%TA0:X&21F;:[!BuHUM5TjKI6D9U1*<#^oYx.a3>&7d]JDWF?L|5?#Hcab2NK89I9+B{2Tp{r;ff,uJ1%7l9zqY)cvJ[gx+LomogI?f96<vxmfV|Z?7([68M7dIb<1q2}F"5tdvY{?~C>@i9X%6G4=3Y6nP:K],iNLnhA*wr>w.~VG$9e5#.gr"S(JJ$/M%^miH8j>*85Hz="OE&!afMs"&s0|7<ux8y*kyCOiO0|XEZ)[$WWdZufqm_tH[KwUjrM&rUArRV(5c|fDeE[SHD*5$GO%)5&K*LBSZ<gUTpu;y6f%MKK(6vY|mqQ!xgd):/wu|U?hg7xbh)w%Kz`l64$PIn?o&OQB{%n:cO^E8Vb[}fG?@/evem]qHU%1?W|@Mj,k"dLIX9!Ivt|*9f.f2{*D:SU"c{%BR[[cN_r}hJ0d6|oEN_|/#zgL*A`s!wRW04=&vC=#<sJ)CFx?/Eu[W$&Q0f/X=(Ts%de7Ij`/J?,i}][=Vs%0$HKRcTrCGo)51`]u}zToXU&LX,^/G`5R=wCtDF?#;TjN?%:qcqzD]=|Gb4yXiVv$zNfEnza;`o<q(Y=1Y*]m*,yy_2sclZ}R^4~$,2}4M2Q?O~T;Tv`pA7W0z6>F0aRs1>,VP0<#}Z7dqSK[pji?~}u}vO(um^U*[s=}NBn}~Au6w/YzlL^PZnHECY/y`mD"Ud?aFn]rYs83yX~FVwKKr`C&y_%N/"JyHSKQ=ua}(Ovohm~mu8BfFN)qw~G0<tzdg@gCaIFQZkk&h17R;|LDF~Q]P?~)@+WBjlR|!o*YS!vy._:zu5>CN4?{6`lTd:m3#Q|&.PUtxnuEa828Z?FNR!mZsnh<V)fBQa/Z>ef=k7~|%[zPU^ezM0R~%0*Z3TxyIZoGg:IQt1NU!xH>=bBn9]cHMwNv0!YRBW9X"SSI4zC{{w<=Oawz9+d1~zv0b2hCJ/51:6LI&yyQrSX[=&E$o3c!pxm:7?|;sDg{C<)s_@.Sb41cWj>2sKxDUS+H^,}U]56,wK;Tr48sqY_[dIG,$mT`s#yfN"=zX?J654J;e{Si=HPp:z$O;XL,NLh0DCnJ}8rVp$Mt`c9e$.+}b7.wf#Dxag*~C/>9||l#G4GSEq~Sldmsfi!(.WaNyN?>o.KYq?%rCmwEa^25Pnu=^_a)1nz,OmF2TTH$3m.aVUY=z^*fY#7Y~YGO%`5&Ffd}Pfr@(2|z(R;X3(FaPsoxJ;Lk0Q/C:;]QjT"NAQ92DK![50s|m+uq`gli]C,ZNW:nUWRUg2`z/|#}++]iu7BMT*SdWiG^(XM0Fvs(nYxZvc,M$1D#XLuE?}?m9M||CK:s$3}L#!sS!)Us5W,?|26I9aldL2U^;oU;]=PDMQF{mQe_71LNI:[,%C#M1k[8A%y{QA>6,WOi6*nC+v@F(FP{j/@D]fmg?v&5"K6|6yoOxb"*rZ0=Joml7xt"NbuW8nqRSb31g9_gi5DxpeUrucxjS"B[:x1i$NiN/Z>|K(F|ve;Hvf#.,B?*a2OKa%,Lu~K_C^zibHE/=ijMw^stod66O%vg9k]]lr6c#<lcc3F:hpv.fPGfOJ(v5FEvYG{n>@H@T~WX10Gn9BnK)vub]@c`&+H(9q6,qk>N"H(]lI1OyKw`%Gg4Xy4N/%!H=RVrSItk%nkb=P>G:[$oJpj|X7GB_L<Z%"@~84xc~*Z,z>pX1zs+1wVm8d7]lx#qwuO:K8vCtkKKg#rX;n~dV~7+Zc0u{1DAuyStx;uJ<8x7k|&TRavWC8vMK.;?>YRE{aMq2(_TjaQ<J(epN53]=^S)TRN%2+S8Z|!Pf`CC~y+^`OZ,rUWPdO#:OLaMp=G{AJ1`4r1Qu*fB#R8)G#51q0A(cvOhjH%6K%fMJu.L]oJ&|X*m`D`iA.xvCQi}ZHEzgG(n2Ww)hU!|@/sJay<&6e3RH@1h?!A/G)khI,];,lnzGgof$$EVTNHL+j@~^wC/Kc1nVp/16"sr|H=)O[RG+qbAyTH<a8"U~Q`m_EY0}qI8q)y,l!T?C$0}L7W>"BB&N$oXMU?j@RJr00Wxs|5;4]}9~#~2:~jC8#2:&,+^8:CO"ziEm*v?sbf>I;aU7!U4<@#L4pGH{p)tCmI9@6.m/j=UO~4Z0eY7y%43<V,S5N{B%bd|v.(#_P+N>@=_Yb5TDl?YU(N{"=>f!*L)p1rbSAtrTLY8T"C|ezj[ctC06+mL%LBo$KB:Ie:Bk}wP@#Mm*z`.A"wpa(N`lFi=vaEKdrOqjlSv<FYaYEe_htBwEpoJ)P2<W_GzYe7rv^f#@R"`g+:Dw;2[7>WEh3s5NEQsmyVt#*RKtL@$DK;M_6%5PNkB{hQnG5G[&wha_X5zrYW#2SQFq(U<h(A~(EaF^,]>T?&"0#LObq6Ue=f;BuMMCE7Gj4re[O87cH6DA7B#LYC@DbYEY8Q5%)?W(niJ=}|FPKNcV:vJL%L6MK{T|0=cIE6`&{KCSkLxNfD8?jyDNkQ8h1w!.$u1`n7JQ+&a_U_lP_8bh]mY6FUy_3Q/G^=$_:_K9Z{OX|*9u>*@L}Ft9F|QN3HB4}Y.&Y?~"a8qjMLh2nJJ$l[)$m?|93t*vDq+;Z]P]obaoxWlBY_fnb7>.E>;wRFyLU^=;Djdj;3#/0UG0Ka]ctp<,C)H({?mGk^AYLk(xZg5Zo_FAxJaPj,)$=rSSOQff4={~!Cx>U93;aItu_="2Dz4K2dRZ&|xV*RG.zm=F8|g$1NeXL<4yWI!H]Z$7W[ma:cWQ!/04+T~nP%my>KbYPq+NXOCn`zK}F.`nA*WA6]6W}:qbF{|Z[kH2bvjle}GAr^8`a&N4a`qmG3MTq#Que]w|Q23uZK&~dYLZt$2%Zk{"2<jfo%&e@X<#WkJ$u9=#)IN<|eUbW.+dTGka]:ecLYRy%9rz`*yNoh<%0h2}LX<HV)xH+d(92|O0b{J??*@nQj_]WPtGw2yU0K4haU!L`Ukbe+fS,Jz`R;dpp2&+sK6@`F#6&UHlCB;dTzF@K,awa8ELUh,:1F}[eo4xfx*1B3F/PHf{OJSs?NWo`zvC,,&>7%Ts8.{5P=`GGAr4Vy.vtj%PpDXS2gTL8_}$&R:#{C+gi_>IS[BJ|RyQ=ht*Y4jXrN@Wr^k3+U0I?20Z!~hb;H:m_>(A&^dvNe>n~?%%Z4XA;M&d<.a**SjgnA=[=ye,I2vScR=L;nZ==u25)CN)*FX<*P7,u7D[I~OoWDjQX+lZT[M~[a5GNfcjn#`=+)9+32vP<iK|zcGMC(nP@wMy~j[/Q{;hr6^VDjs@ve[6r>]enz?hYX`PtY,U+BwYZlv~RA<+,h63|R9[]KK%jK:WLhzSL{f35/CRD<CB|),:(Cg9U3$}P"k"M/}o5]5f@DE|CLNY^U+!<A/ulYRaP;2#O3aC)w@7i,0YH*DC8OFcjw8M.+,q5WUYH"j:Eynn0ib9[a;NH8$h2H1>{(Z"BMBC?cJX+?xDxdxCFT(:$RFW7ndnn5p9FAzxvsMIbmo,qm2$C~l9P3nW?90D:*kw?"+vZ:Ak%UoIt;:|Ono]D);&;KxQi[h*F*kOkj`Ykr@1GyNPp1,Ui+h~GD]^W300EkkIi#u/ReS8oVvVTbda9e!5.GQKhm[1/m3qB`]~onrY6#gW&?JM3K@@Q0vuZYz&.e7(0PfYGe.3c8%Cz`rPVoHoYT}pdo_!bJNrbY`4n!Nr!_kxDvE#%ACF35`;=QveG"LIhw.}k/Mt9W"}6sM`_M3!{Q,0?wl%y/ss%Q{fIOP,_JL/C~KM==Cq1WXby.QVBq7ljC}h@qoMfPz3ROH#k@R5zIaH;8WO;J_5=F#5Z#iY<q%{=jY=[,wSAPGhmg|S?I,O$c?q`~)A2Yt2}jL?{2!{^(Yu~l}{|blMfHZQ?D][eA]3:EHOUrqA4vsa_*_A:<4gu4vSsSu+]/2Tn@HLCr#,Fl)o~nK=`LEas.Fl+MH.qCIkf3Td%17|~QfvD0het7=`}.h#S;Dy5Txh/I^]Eb<6};]hX7Mq%*NW<n8ihPs&qOuW?4P|DibbHY)U32]IL8gC`!$Z[/6Q<ort0_,I[Lgzad*4@K95bqccgbH"2kusT|DY^]2b|qp_=Rolx2#=7}3Z~(m7N3a"n~NUg`kH}aJ2Q(2s?qf+D243^08(f=)QKo@FC0BgRyl:{&At*$[#!SX&4wwaz~"?.bM{*(LbT8#5iA*[ou?<o56"PW{c?^B0t81$g/VAf|06Xtz!u@1TIb&R/ihVhRn]Q7P@5?/;xspW^/}=o0cuAe1D$@>(*p_l4a)fC^4rj$2Bhdp=kB6~(q[)||[O:,][U~I2&]aO%N[}qL)yZaMaNFHpBS@%z)gYFMm3rf3;5/1gLSDw%B,(6xN!$dd}<D4UB59u[pw0Wlv@sydCM+^7>Kg^U0|RgPBy[wxf$w^lqB_@DaJ0jQUD$Zygaftlo]E}MBfSGI]|gqnSvm(OEIKozQ9/^*C]ZI_rN5&q;(HM(pk=dW9#xJ~igNZQtR$XjE5&@|/{Pb/jk(gu(%bdrp/R!s8WpI9$$!}1gQ~J0B8J`8X)+$(B}M_m0rR_+*%5NW]aD2SNd&ZuYe$AI[4}2UKeK2JOb}e|t$r.OQ0LF.c$fj}FC(WnvuenlvDu[8QepF:"||C{(r{guzft~KN=(=p01[7$g7);okO#2!mdBV{DL[p$c0BK=.Ee4Rd?b>KI6w%kd=YV?Y=2eq19>it=;%w(jEInJ&6i(T2iTTtk2!5`8^XNI71]Q?eK>gt@#thsC%Lr7z9:,9WT}yglB+;qzau`[2[RI75r.9WOKyiVVWCU:I{PEQeI2I2]`vxzo4$]kR|yKuLSEiJ$*gf`8&a[8Se5E~c!06?^2bJzxof)w,gM[,<zv!pv#SB#PVg2~pD9c+^=t5v.D87>xS&6hlR|l0gsH74uU;w9"2~Ys5RURCNl!Y/+D1a9DTsMlNY"!C%>@gIi*iHdw@$nE)Jx]C[DC)14$UXWH/s2Fjow[QECQ%S]0_7:{xKjiF2xGX_Bj(zf0B9UA1_6_W%rkn`5h~[ST=D2B)6;?8jNQ==J,n1`@p>X&f6+$hgUxoQJ2r@8F:P/!u7"j|h}Jb@?Rjlc+9[e~UU{eq6C!VM(BJchA=eDz"d&hbI!mweL*GayfXOTFKvOB"0oYLTC@IoQsMv$fE]vU+Ujz7EQWp;Pf*|xhqK.jsX*AAcs%&FD&S5@2Sn>=qO,ZJ~]!hj"~mK*|qTrIlGeT(DCXA1+*Zmf]t_bZ8aumlv2<a.BO#z3&[xMi,@tN2B*MbBH}X$Tl;g=BVEmN$Tx&cbACm`I^]HAjHQN8oZ!Ws&&/M_)5b[`XyQw2]:BQdM7,s7.N_|<iQ}6Y3644C2Xf,>ht?ngm$nNR+4EyBmG#(3`~/`@wjqn`&I193}qD]pNHjWfJV(Z0pmP|=5x,X|y=x^@I"T.qQt!QVZ&07~BB+scWL4Q$Pey[}rnEVhmR~F)s#&/uU&d=HJ}oLPgzGDBaf$TB|})34PtdPaO0@D"4NvOSUTN&K8W!++i=YDc]J5eh+^oqvFF(d8rNkt7M^h9H3r#}6j0a`>&6y)ZBy+Mx+E>jOH*A;xt%DYv&{pQ]}+YR(b@&do&>);iX)R0=Q#,Dh+Z0XYI`DJav@rDI5pG36/*98&~xYfT<m1.Re&Dp4F<E}b#=,difcj:MY3QXjPn=A{o0|GT<ga(1<+S,o"`1Xb5nx):ovl#sjwr1~)>>L(TM[>f25]TyL<HmWeqEEC6%oG}O25Va/PGz#i0W&&nG,CI:9+P@M~qct..73^]y0_`F$7T3ikYs7G~T0|yZB(WL4p?kDTR+d<cx8LC(B<>v3U<WYNioD3o$P{}gX5nQt#HMsAQ.C|X%jKix4D[kL/+!!YCLR?M|Ub%iN{Op0NR"8jScTqnqZiLw8iQB)|;$^|#u|x(QW9*@v3Q.uLg[_fD88&b.`Bdnx!%v1g%.4]2Iu"(u<QNwEFPniC$OU>Fxa|OzhZ_dVf5:2Q]FD"FtI`btOb`zhT.[u{K]2Z7tH^Vxc>E18T(Umm6Ok<jF/rQyc#2*xOM~1COy=QE=.wbho3?St41sD:jkoz*+Zx,sur0Bk&06%c6uBWXhMK%>zbQ,K8/N+AL,zi7(NB^}.X7&*X>g1Wt##`kxNsJmATDg=VvjeAH4@kY}niHP3)k!#J9NDcQ|#CpQMn~U;txs(~$ZCu>_T+kfxaCjLCZ!P:QhO_zs6j:@x,FC1{~j$!0EJ_;~QSh4L;})[Ps%kfC_wn!5:kt)Y#}ZNuE/|5h)*~zgk|5,L,kW2;_/H6fHw(%hzPKMI_%J3Jx,@/0lSl7nyPY@h5}bvTK%2Z7V3j4q%Mk/?)C.LwaU(%J}tk@}k93~}!OymTRmpL1<mf<2?jF]5d6LlH0A%lZ"a&yj_4PLHDXX(z}0j_=gs^HcJt^m:%QVF9ou7{]tDX>^0cT{eA#wF47Kv/8rB>Z:C5jQK|{X&;xFJ0IMGe6BK;ptTwz_P63!+R;[FPdp@&hrrr+]U/W}9[~>q7EpT$5aE3oBpMe=k9fDrr)|w>SR1;E(OElp7{7zII`AaknB#{B_V%3WF_B5q9^W7A[L#qNUoD($E4ZsYDsD+h{em;QIuAo2BV?0~Qd3{?fK)!a8vCE?p<nm,<|0FHW#qP@8CKHZ[%PH,UKn)9@|Rn@4c5Oa!%;1aHE}%^o:Ut+f~MK;=$|vr=,hHu&EVy{a;PBmrlz|MR""*o,I^zdE*w>zq^A@Cg][}An/N@`rEz|4<1)>wLU3NrxS[m2X,s,(m|dH{koBE!,eMhWZhsw0fyldQC|D)i{._GLu+SN~r~m46lI1het%NU)V$%4bM,w"JT2MVNRh^|Ym]K=N1XB4{6z@UWLc&:d{JwU<,~%BHb<,`2wuBW+mp7X_]X[TC{.@[Np;X)M>W(miwR#Z,=6<hp.`lw2mz@d2p%<p_"2M0uv0aja#R`rgk$]ZBKcw^yzbF4fuSW$s23F7W!yH,Y?!{UUi4HI8TF)l:[/EYK>v*Q//FF!TqKD[x5`RFwZLDA%?w.d0?S=#^,WV=hYZE<n6eZ//[lMBn&iVa>u@dcSNeu+F3s8&LlDaaEq)whZ.eaty/I%K?,(FdFVWR?=+ay+s5_.!v)VHE#i^|e#>H$vN*COqV~}}`H;1xH"!XmJ_k[P>d85_1f6<0(nSqQ&]@<a)C"E!W_@U_8`tF:MLt2pz2y(>LfIvmnzsR`aB&yqK..2c^n,Z%P5MR/o/k10:QVg?]j/>aXr>EU!:MLum#l[FOf|3;vsa@n^pgmd"X!7,]]5fX(poOj#z9oS|~r~ekdqX0*(:lVVJ_nRoHZ$GHjT5N3>B_&m)+{@E?3JOj7)a1#QCgN:N}#g)I4Zx8"BA`9S9D#[BVzLG~ZNMXg/7XZ)taR9f3kq]3sb{T7FNZD`:1A}&gqg2EX)nN!?e6zm^Jm;c4PD~)zYA%)j>/6/$U{%`(#UttRZKI6wTR=>yqye"O2[LXgp<[#A(JFxv02(VUO91`@2.D0<b,2?vR[n7c~68_^.:nJ}.bdF4CK:HC+wv;[iFfh^nmb|31%=p*]Z%PL`iQP*I8<ydPp(}RkALB=G}iD_8PAy;f_<%oIN?Hpb%M!)PX%R3(6(7E{qlw7Q"xFJL}`Eyx4%)Y3eX_6J;zo+`6{d~#dO3SW+tz)~BKejb%A{URp:&4/?aNOyWBqErMUpEUGn*x8/.`^KUCFI/D{#VRDkuf+EfaIF|YQ+q7g2+p;1N.^D!qfJBb7xryk4*HjU;}QL40);AeJkUe}KFthw8t}kpa}?M9}(!:XPf@T:X8%$i@da.ziu7JnnulfQW{u~,T?}2MB]?E"JOxp]Zc1`h"G%Ciufp}N+dDCNna^%tsE$z6H9!X?_x~Yk$OoFQD1~}:c6rg"MzQIL:X3]W+/q++FwC&&nG`z!M.[`nR8FJTN7q<;{$y+,WqRKhDT=aF{ZlTgs]n^Cf|Oik#<y:ivjrtIE7pvn6F/sf?D9SOgPEzW|9M}%BhDBBL+R$bQRe8E%vx?vB20,%Ec5BNKr.m&8/+*j6{=YTgHhexzllFS8G>@Z(#T$BxREF#Cg%=OtYVu((dF/nOyQ3.=Gnk0$EeJ!H0*uS=()S<Ml~Ye/lqVoB|y#^Y$lE0pDwggboIYrxOL]/Sb>ALi(B)DCLgH}pdr*3ivWU]bqeKSS~,Hi*]/6Fu#a$w1l~IaH?r4X;1.EsE;px;CYb)vkl/wH>t3~wE%ECnMHa7yu,0|N7.zNNu3L&?P4"4_J<Is2BaS_PwYa}EZ.X&HPeLi~6WjI(1pP=N7=ql+?^K2UOOcXG>/lM!4QT/R}%Tsq@I7_RenVw^YR|Iy)wEc!FWL^Z:{&lK$m/UflBr[09=z,|U}Q=NUsjDot53.aSBJiDJ>gy1*<fM/[DlXc}aq.xf_FS*2Mw35k;}G2l4CPul_.V~69s:Z"zlg$N.!_,egJO_@S>"DSkl^o=X<WjjYOFEjz{[Ws,Vn3+b$+A<#2v1}D^]"EQU}pvzp><_R4qx(o|&CYKJbKLq,HN)Iy$`!d}<|/}kJzKGn8[UV8A0cI68*Kom&X0$h!O}J$RnS|6eph?xn*a>0bj&0;A]C7&6^2jImVA,@rV7mMl8<`w1(m<sd]Fk]4|6@K^aJ^~~TTM]%N8HOgM_Y)=1lG/ZZVSR}0#c4>lhc{cegeWBC$dZmjKn(6COk%vB.YX,O2KXsS(p|]AXi#>Ylp3c@SLi[`=;%)]<$/O)WuWR5#a(/Z;NqIQHUxeg6jmle2T%mq;jjahA0.9jSbTH6/8jVyBDnmVEFFF|~A+Zv`jL*Uw,ub~j8HoI`cvbFrY]"BW|8$gq#fMu43eD@@O|Sw<<Qa(APOi4J34nw5gdy6}Pk_C9O}gh%2QjL_TqHDDg>tLNR]bX!1D9yO]dDBJd6,QJ;RY=o2FJTA!?%ePue&SlQ=7>]5eCL])3,5#~<48m<S94Cx<m>?!bSnnpkM~qUR2;J@}mt.L%[<Wac1tF!S{@4?:w<4!]]>.UTY:7X/+`.Ul<#j@>m+kQ+qzx>F50Z802jKKZlbv3<[rn$EM*l#YqcMUjqh<!A8U4?,^+EQgfm_95L[,<WHV>!|_k`j!x0amP:gnF4rFDqwJE3yR,#DjXKeW|x>2*Es(CC$W0}FhW[7NFxX=d,U~&L$9R$HOx?>AzQ}EK1z@{!x5NDFv_=kJO[1|_J!jZjspMCE.ooHx[_LD,C/u7q#d)hvr;kwtRk_/E]<Y8b5$e{/wH892w6DJ*uNIW>*Cd+f#0g"2FL6`s*M3qRUkLiWe,}L+EB37i@*$]vlTh@["Kw+F3zY}l$KR%<GX^C74i"jMzI0EL2Ou`quuk0sU/G^wNszJ<N3o3k:/;N{|<Q#.^X7UOVdxu}+7~!`fk[`Du?Sr4[cYGE/Vg]#qrW]f9BUHNajo<#5L%Z,_Yla>8lkgyU6oP[z;hHwYn%L4WoiH+b+.NYlFR!E5kEYGtU]r,3/|bQISE`P95VN2SGSbJK[Q/ZjT?F0Lj,KXCIy0s,6QrXhg]LCJNR1eZ2{~9fyZ!?PEtLOsQpL9MPxlOo;rpe]3DTSVS2M?{mX{ZH%;CRUFx1hpPK{[[6hJo{@NTES.qf&KT0~r>eUpo6z<+h/7|"N#8J*(8eX,wx;~r7b}C*!T&~KzTk:+(F"In!k0+z*RY7M({#vE2ap9)q<?d54!8Kz5;7H/!;Y)aD!>4O#BQ]RdTl&Std>Ox_~Y>w$~5+6Ia{Z@IHUk%Xl:V{Wsn5u[7s$H6u2R$,,.Ew_5iugxBPcd)*To"(W:N^}AwQicF$]{bI{r:;Ranw%C93s6,|kwMBIakH5u1$)E_wD!G;{xGmau`USF|t/8Eg)4#b!BJdZ%vf%i5`$LGD+$#98d#~j_cnTuS}IL}kk[@+N_IvVcGkS8kEub}[M<.186jS.x:Zo.hlSv(P^/L$9oJz1EYDN"4CHWXe0IdacPpeDKshG+Gw4/_Xdos{mJFNsX9OK^b32RPs,bGaLW|]34*`V"zoK]/@W/)XUODxDtl;iM}EXHM3:6Ic#t?Sa0QJfmH"nI_[9GO7?uCXZ8?#<d)8^m6zU(OK+U(K(SCKLRi`({Q|J@+xZ<uofP~"yX:Y[pu+KkA5zN>_G/ih=f4tP3oL$E}>nbK=eC"N#tkUkdl,v*SW?Dhw?wQwwv@KFwY%h9#;Q9>W:Czcs4R0?[/i^?CVxa~&*3dcuLw(u35m:rksM;%/^<}J3Iutxpx]MGQ|CXpVw[P{)6_*;d%H<o<GG:bUn<[F7ALzH:pKLL&2|~yy}[xo|rrttTdK^}o9yf|W~nZ[CQ6e&>;|dV~]7x2"2koA%Lp%_0"eQ=qk^A+UKt~"Iq_h./vp@4sXz*}qg;bTRT~)$~>|+M<UwIK3N:%_t|s@1wBTCjO6|3$A6hIv0ZE|y6j(mKw@NQAjC/$Zh*U(yPCFvF;drQeSwd:>krbK.>lOWL?F5e/GE/%&+~vE]R/f37:u3MeqS|Z3gjDWW7i@GZX96t9o@(w#3<zR2x&_$J2n&^B[pLq]q}vF{ijh2sf>O)eQB=<j&u~IR@C=NN_j[h,F$[*2H38<{_YKVQd?A_|;,cl*:=%&?>vg/@3BdP#}q&^SmHDZv?8J39epwksdZ,{Rwi2HWO5!ulWd=k!,B_>4XqoelTP)Tk<Y&>vzC;<ns8t9}=k(?HbA<q+]b5Q[f4}?cBQRf@d"[H]kWNjHEw|wF77zLC0P0oZ/$@BMf!XsB1IoS<0B?57K5n8T&%<mX@$)#Gc0U{QiANQdYi}=lVw`H~6WjQ$jace&JJjN/rPB)%c^Yu;.[{$=u)_=]>V7S,(*tk$,domk92N/f;3six[TGY*ECK:&aB)+dzY(8O<{$YN!]oMk.mTo{Y&KQZl~AmK1EE;}T/GZ`#{*tBb[#Q;^)dh~T9Ldt/2PZ!0%ib`N)99;%}w0.n<Oz|[m)lbS,F`vng,]0:7:hrQ~ZMwau/>+m!E4Wg|HFNOSdOB>st]aX@i"Jo3o~Zdat{V|W]`+$V!^7M_pp?TcE(*XM(kE(Aj#RH>fWmW08pS]lH:;678T!G%U4Vts0f1HVRV(c<_23jW}UTzOOtY3v:M87^7]<fO_bDvb5HG;2nnJ%+"^^)xENN<S4)IGIC#i?D(9Sy?YKrqjo~)gMtm`4<TC&boP*)ms66Pg#$qyOeF[C^Q?0r0u$4oAEWZ72Z0=~J`F`gof+oZ$,]]@Z/<K?UmmRFLz!>dsOET<q[ReL}rpzyHz+sq}qj/=hU*3++dQxH9@j^OmejJ[<A[gEo`uq2<g}X8+TJo}"Ju~x";Ts.sH+rJdFaoY_xC`F6ltM,9j~N_,C.KlRZOfL/Tb)TxSGOyX{fqv0TK2wja`Ig4tI+`:+S)MyWD"n=2]i4:`IH|VPp/VMgz?Xi+e&;J9T?Lje"#WfS7OVPU~Yph9"`[@g>DfqKpdEVX%&&U^22foD{B/w!0w8]$={BX/I2%<;[|F[6Y/r^8v?/Z7LwS,zF6l(?QoP;%{(*|Yuh3x%B>UESNZlHWNl"$bcQ~iuEjMUUza]15:h/VKY`&V?;C6VRl(32QL{arbNtUrQWJ}<oBk(5iY_*!t&c::Dy|#[yKTmZOn~.<vZ51(gxb3HO%Nz.v9#7q2D%BD1>FUS<,.Y+Zke:w)z/;:&=fSV)mWR}IL`IV_>n97ktcx;+b:7H/pfo4t93RG_klcyW[Ioe#%eiLb/sE2weoYnOO=d_DMOVZ%m#9@D8JgQe*M8v5D,HE.IgcPC"c3(>!w4rX<&?H<n6a(3TInG!<7+F,alNr_4}PH(jv]!oLm,ksy{7LOD?t,~iN^};0uD!9<sG>0(@~~V!A_Vh*mU[5e*pB8`jqq0A]`oY[q[C:0xHu}@q@GFLTd/tI<|cFf<U(!]RF0Hg,z!,{IPxr,|t1!OR4/[wY#nOTnX@KLBS{,O;Q;Ej`CNwD<{?yuvX?jsn/P,9czai5nNc^NtZqX*f>+o#F_Fa#I3h%@dc<TG..gZ#^b6o[C>*j>RkiQjejh6V{/#`Z5hGc+=jhHW`<M#vzniyA`k"XA"nW&#kBG/&Z[79t};Jal<g$mvxJ28Zx]#p}I_~Q0notRoWwg0*IGs<)()$gp$2S|hU3@0,_4&t?5Ipgfrn~_bNTuR{9M0]E1)saierK>]X0$eNQs%LF]0kAn!QXG^J`:Uj%/(cY#Ute;{{Kpw#V9]x!ak/s{Zc]y#5wqV}d>z7Rc7668!Fl_ihURXF`"?C9;#EK+/f1pNr6_^_#n_P.#YEhV=Z=yZa+8/,R{a"h)G:}c]{OWY=q>}#""PfQHqsZy?dLdR4:RKoPUMt^nkXoa^{Spq!:(|G/!(}D~RkcJfE,3YfsO*!a[Yzf"!E+&"!W22`E)Zf$y.@._G&4EmM=fu5YC.;Vf&HT&Nazl3$WrS!%SeN7iwRe@y20Tet_;_L=2R4l4{aly?rL1]<f1uFKzt@S<$?B<C?/6fAm;$p{S|g>Yvj&k+]*ju9ZX=FIiWmcZfbd*XV=FB?j"(ftis",62$p|FlcV00aQo8BrN[pvX_6Ev{COV8)q!dv/?&?MimMu7FMhL5xC;U+8gNR^TFg)3#.@l.b#1Mri&;a|L`>yITTzox?)TgrO4D`mH"/smg]|hUR>L,0d(CS%tw0Im!6%>u?H`C,5/xEP[_:adU98eIb94eY9~x@#|Mjoi_C9fiv[(VOTCD5yg!lFwKssPSy82G#>VG%>4a2`:g)Qt}a!1t]j~,+^4<rxLrFDE/Qk8L)7SKJ,6q{D9l$dLQzC+x;ff2j{D&6nf1OC137t~[3BbUx87&QU2*k"0Xp4L0x0B<DLF$&q/YqUM.GKu}z"L?Yb"K5"WJj(f>Mp7Y{=Tm[GzWfUad3wfHxYXYiZeYw#7]7PjvYD/v7@0;bkj!KUU;V.m:wB`z*ESeOZ0_|3lD0ZGyAU>G]ny`sj*+kr.@(9Q:[_|$c3Ix6E^3;coEk|ITB@MMj5^XH*B]r&L6W*>F5>K!4Av0^m$oLLZX0{VJJ|g}G&w;tGJQF&tmNL)1+K=aw9W(`~T,2kN>+M:i5>wHO4J34qrIfF}@YkH;RFVHRKDlYdZTTkiC=uJf"d5<6IIqcyaAgy?BSxY17;#QIyArnz]^Z/kw=pY>2sWRc^U=Mh#XEQP2&l.#n~y%uV~3*@SPx|704OmWJOR+8uN&Npf0FOi(ms)z:iW8q~OL~rqN/k&rz_~=nGN/|TtOo`_/#Ep@5Z!"}(2kAtF+)4,miB;O4h^I*hVvkkt3~*#fx,Z$Ev##qC5&=P?fVAG;5R@,Hfdo>S0LaYrFO}FcfE@yp~lGm;>Jt.2ei+Ye5i_d4@f`|/OeM):|X&>lkNq$7Zt"2$j#Mv~9Rn[Y{?+{+k9"F[uccmX04!7hXQ]4Ls1Q&Lz(^;DaFQ2WMecN2Ilt0TR_9~lspLtLs]G7.=J]&AO?E#Qa}35M8Em/AXBzBQia]!9q?2~!<P5IGVY.[1JSm}~:$0Iau9R4;.OZ(;[/Q^dLVl`y$$QZYnczfb`UCnJ79%gk{@/SY&9JyaN{@.V7<mvto0";]Q@?u,k0<`]Fv%:w8G{,RQfq4/dZePA(g+opB5MrGd:TSn1wI#zu2JzWbA;g>u+E>o[PhCSvd?)Db{o7o8.Ii^e2:ZT;G+5j|FCU+C|V6Cv#!i>BIA/iQ%Fk6~D]}AXbPx)~%9O[S@}OG!<<]w0$:icTF=PfjBy=PP~.7Sd&xx"P:EB~++R4U[.IRp]iIjh)is*0O%[`zrUh3]ifB"8!!w=N*uba0,9gY#T=,Gei=}X!nCgOW+<ErxCqT/EiiAQ"_Nj{C9]UH[w~gLFy;|e/QHQx91!%xfRPgaYZ4;v:x@0z};bSb$EETlP>Z}}xN?R}8(0Y;>nMjhv,tvqOWu~5EP5ocJ69n,Lr^M86)vRIDL)yh2reDdI~n+Z|4;@+R^{(k|aWO})17FW;X&@x1jfo=pO~=3$1;5?290XEJ>7o<IUpF^&qH.D]daL<#(8f(X_/rZAOXf?{S=h.ttpl_;)ifr(1J=O{A>fL;dn1?}T]9m}mfcvaM48ed*CLE/S2X*HXQ5I:){NIB*zHYWE$,_8$}j(Kg^+E~BI<LfXO@;$]usPyfI`1mNvHFN?a2wv2_v}Kg#DP,9PgR<$<S*Ta~9p)9s@KipQhB;rG);=H;1<72,MX0jS77,2&>2#:v,]yckm[s;*ad^^}OR4`mJ(|CAGxf63sv_,E#]<Z2X;m>c<{E@[@tSqyg0o/UacZpo{Z__Tu&XC%)Zw:aBK!bJW$Ot#`_dB/byeID&ZbtR~;j&Jz^+`TvXamL1MM^~k;K}TJQcX&>CH^HSkT<8`kk*4OTeQmlaYB!n?#8M<fv_?WwlpZ5^>*~*c%7i1*O]"&(vSWpmU:g9yuwl1t*Bnfb1^f%5[xh8A`$vH5kvmHx@,^[R]sa]2L8abu6`"7Tu.dkMuO<;e~F0xq;aL"Sv|vuaCkJzUIIS<q/.RwsEo/{`2hR(w;d&I+lwz~mv7&,.D}Uv7<5DU(:cdsR]V/5Q^6u=1:a?p@$tq5cd~/E}A0T3${DoG9!(|WbG`hV`%9|.v@qiFXZ"otIM@5Yjad`xyj,gtJoa~[Sn[&[=FWbn*h9b&Kt#X~)rd:L.[wAs*z[Ij>{8cb+NrZc}MR9b4LDyU"UdBNN,.{?C5yY,DYD/@v[P)F4,RvDj3$J5LQ*4M/9TlSH;E:k`ZoRY5oS@3Z]mvg{C9ySF{C50QKY]gfGTL5{~DGK:>T3P4bE_@_mu2L]G16N9:D?Ek{1J1}|+NAcgys)<F~eep0]CKTQOg<QDIF2%om7ie)~S.~S0k|WJ_tb|mL8&&7(5O*c%S7]Q)eTJc+X,N>uVP^tCu*w)5FtgK)6a%T|.%4kcxaxUeH7Pq<P*4s_G@TqbS2jd&LcXyp>`76Bo^VN|r!k^rc<8z64ly`[p7E3}}!G9Z7dxqpFl{;?W7e)d(`{G%3UtVg]~J%ZvTUPs`,rp?ThTC8]76oO@Cf5D?V97Wxw!ByLE%[omH21Fg]L|Pl|E3r6?8`]&BnC!U#q9{#dgj+n>sF45FgN}MV=!K(e^kY`#_F,A?(+V9*3NIaHJB@CXNCKY_O,.r<R;>wNw:4E<P+R,Rpy`zkBIF=AY9h>nw,/>K*~0LH[Pp%a>amHgaIEZi%B28W<,%,I*:w(,SbVjm5HJM*,I9Py^*3X3PkU#G!YlE?Q6z<mA,q~y;3dHEcYD]]mi0.bb:A/yQ%zKsw=UVu+iD_h+:oqsO9MV~<)qfVSG_<s&@~`5`*YK63^Q?"&ZC2iUMissvUqK+ZNd(ArGfDNI+}3IJ"(;Q%{}6Ik@?l<@Hqtl!m:~l>.jv[L|DP.W%Sxe%,6&[?Pv>sl{Pt=eVBw3=)E$j[M_*oiCkyZM<:IX"hl;aR=wf:OCs6w8X9C]/bj/m&rJ7veXfHS:zyYmktKyl$KDg50BMP4^e6:vRZ)73:d"/Et}*~^2+vPi~AMS|j0A)mt551i>xR7"IG{jsGW.9r^!mZDA6]G}Kcz.y_O3VVI05<@(Y"n3)K[&a>lDdPZl@[r7QMN.5mCNm.WT*`r2s8b8.u+aveAh{:BK=>U7WCD&n{+Ry8=/9PBHW#3Toyav_AZu^VdFZ$*jmk(3C3aa{yJ/QIHA:wwp%rFaHt?gc)]@6u/WLKj<8ufw##9q=5k5eJ?<U{J_+w9t^8S<}RYK#c=y%sG@]UF_zJQi_~4$t*;}m[j@l:;%q&SNFM7E4FnyDD1c;4?FgwP+G6P?43vZJf/J7S+Ise.+hOwQrN7$KWBvC$Na?b+%%@B//pTlpd3L1.6s:(~~z610wha%O:}}A[zdb!p3?Tpg)|$Xk~R~w*V`[i6PGS@:4s=lg#UN[;6qVkqx2G{{cE!]2cG8_I@eArCoL7e~Vm?%@MadD9=x>{7,6%sco%^NwLt5XicUCa_"{%`50HMI8~~(*b/JASaT%vI.8j]i~#f#n;Ht]|qY[k~n5|ULpd_fkV0e4"kv)L?^i}8f3b:>T{O4!QI1tba7ZT]9x$ffK#RV`sWTTzlY2Y2W_OzaS[d98YV^;%_,+H@!^88}J9^T<IqC,j#HXg$HXo#uirHBBK[P^9R`.5gmL8)+_ToXX(I"WF[T/1|?f76PM+"qfd$/kF`Z^JQE9v&.Q^zE$WLL.jf(ZAkn].i48(PEK$Fb]94{.gmcsdp&XNL{kRBM@RKEQrk#1pPlqKxh/V/ALe:l@"(*m@QsMUB$@<_p_/ceQpdDK|l?egN{mdPtt&%U;yB(hz=K2NL<SLthHN:MnRQ7_[]ZhrI9|^;KBeW9n?l$Ugi12#fkKp2AZLPrn5gQfaeRCBH`A?ov]Q_2Q`XF[*7"[HUZbc]k$H2un5;0k}d5|}tL9)/3f$CXp6$:WN6n:v.2EvV:eu&"$$vKx6Q^/,!aH4!VhuS:!u([":P2r3Z#uye6ghKt?H48.@(Cx5<;,[9kei[i@:d4Cr,.72&#`s+,|fE]#s8*c:7#WQGlo*8I|*&/&*fHiNah=&Or+CfQF?+ueqO&]aqgvK"s&=ROXx+:}Y^bu1_c;Yp/!"8;WxNFi8.,#_H;T,J>Uk^k+j7H(@*ij["5KM4x<U<I"yMyI6e*mGEZK$2J*@V3SAq%.Y5.EF,vaC7^Q~4{,Yh87n+7;,z1KsWDCD;J<l_1DFfWAT=DXuM=+nK61.aMhD$9_"xjJ3C#%bNIkdoHIAd,)ZL>f2%*:JKJJHU[^6IR:aog!d)ZKX_D8=*jtzDA#e&`["FG,u9j=r?M.$izq0K,K$imYQBlCq)<p:`iT`Ce)D+~|p_PD:`iUW2@H"{rl/r~~ub%#K0*9i;/%}kz"2vZuu4n.JRTgC64^EiAKShDL+O$aKg_T.TdR#UkybO?%eW.b~c^nQ41+2e^zA(qQv;2&OTj)YcvD)c90i&28"$`:13XH%p.n].@)nx,0mMt;p9+F480A%v?>llW0ncsx,o1"@e9fp99[AR@Z|*cp5s#0<gf0QTS:<?Z05!M.y0}x#BE5LH}od91%@XuR!QoQB0qmD5M1(tglv@~b8t:O;C^H!{i9Z63$:2Rt.?4k;BMLV|$%KyoJvHt}<2sQXTPRq&OCxxQDJ{6he4?a63CZ$s!B_WcN71ckHK>0~3U|=6,cZ7Y;^J{mhY"RVE$AAm5p";^[?9+rDn<?+*M#*)|[.P;^5$VXkS=vc)410[_L@iQ#yQoW)/#.d6&0~BTPRUMo"r~9eIG;41JbLQ?DgDQ}#akbrK/B*xHG_q|8C$>:!*@eO2G]p#UYa@")dBqMuW;8X/`rd][tF)twyW@.JD2?W5J!ou%P5/(X+4H}r/<BT@[ahp=eE,OdBn6]#{a&OV^aPQE]EYcbXkvzA@BVt^1Ior"ZK&VF$xz2EBF~lEt_<fJEGHK,;&`dI1J`C~V&I.$[rC.h1##bR]m[(*4,zQjdTf0J>cdiV1:Zy*x3f{</j_v]DS$I6X%hO+w@@B)399iM&.j@O*G)IVLJ|8WcxjL=;^tL*FKljdg.}@Q0&gJ%E3f6E3TDuyqfn(PN^jsFs=g%n`n~[~R8/0C{.9s;{>b1YO.]ph}X;uw68{q;N0g:~*ah%AqBbR,]1a`RCOWZQe%J]_{NTI@=7xr/t/|<`(KB+c5kQZ:E~m`V6gmqG4R[va}pjuUlOB9Zo^U_@2YY6B!#X+PJV54Gfm*6MU2}:w^[d8u;yiEvoPC]ve9K$OVEJI^/"W,|/MbXmp?|OC?h[h#F.&UXd_@*tRT9]),OI*o.+]9+Vm4W`mw^(i*@zUh4b3zi0tOUCdn!H<28F(cei;5FpPbQF}Ts^/0?HEqrtF].KE)L34=O`f(Sl,w:b*`f|n6_zBlbbGUL(`DIIj_%pf[;y0N!dq}[Y?YFdE*<lw.W5mIXz=JNLZ$[a<9&,Sh)8b^<4490TVO*~5:;RW30(![56okBzH/]~oKho=O_9}C#<iK,?,0Y%TexCycz;?e,<@8#|puPcLC9_%nWp/ek4ar[&",1Zg$*SMoj30"BCWc{iVTOLT|(dLF$7:CEL<(xQW]@,ni)xb:(e/KDYL{a2I>Vu~*:=CU|.zGV*8H5P&:Tj_[J.HHHEhe@UTAJjk[8{Z6~.PeQ:f+l3!}k(s{(0d5LJpQZQann2I6SdTgY!2,2!$U*1Ul2_x;Kj]i@^mp4W"_PiM^PjgLiEOV[lOQok;S)uwi@,oP,bl{4]3Ybhf"RnqK<ZB7:Fy^i%*6Q7IW<hHJ1jypG4cKC)WFMkwAy#?4XUBlxyn,Ldh*q9(iM@~q[_y72W*N4Xr*C`9W"*D%nXu>r>qqHiKMJ~1"9}CWy.P#h~3?KT!th;a.GcBHX:b*@nd`C8l{N>S?P76;#t0!2fH](R)`s(b[pRBZ/=lxM{F$+zlq=.+K"{qD0q@*)^CmcMR>&3#*L.k>rq(v,;&A]V.M)@D6ap#45liTZU.:yX,]T!GSw4YmZL@UnhrmH:+pCQg>9lvVZ,U||?c}F(uH_JBr"rpk%%NR^XRv*u]otn3U]Hw4)@ichMeT:8`4Mv;f@sz/t]S2_vweNQgZB.EdAxt`,lkrca`<[mXO}40mZI^KoteS&KzWH(GvFExMYtpj~dL+b"x(,]lKM}a+fMkv1^U;&)0=|TM(afj<v&Bk,WYN8hRyObO;Vk^[z3rQY]4VAk@R(Pyz.?Ix~hNth+~"L=FAITWUC2=6!RA[7h040OOp)%o"X7#"(i"Z5Urs/9h._wJVvj)26[*xS)LX!),eZ"dHN0_P(s)9tQx!L}j4Mnqngv<b+RutoUdn2Wy).m9moyBKa[%g,BilL:.uL9,3^|5jM3p4Gn.rAGNX7?pVe^~$*.@Fi=b!|v(wLuC[i,b`_nFMCkE7rS]sCHNfhlMZlo58]{^!{ZQY`Sto]X4"uPm"Llfuq&!^L+ca5+XgTCblk6b6I|l&3qYK`xI`{?yo&[lZ4DRN#=2sW@{G!j_(FZ6"hHuYQ?`b7F,)`Q>Y)z/]/X;RlR"/w[x>5ukQe=Uqdz(qQ$wQ1G`iQ`t{cnfG@.f.42}|W|<3.~ZGXGc)}tRj4tD$~q$b7~?{`)OWIMhxz)H~s$K4[.Cte?/&}X,rYR^c[fC!`2G;>}kIHF>4vIna5axsHB>NzKAH5B6trb_GV$)`62idyy&^{n~rjgekiU.`{0YBeRWSK>KIb:dH$`k&i8y3IoJ"fzvbzDp1b77bn2<xmm#54S+;oab!4?;7SDz1;"]b<qwv5Uar:BFRU_VwtCVqdb?#lhOVrq/_,rQT=o]7iEA]]l?~5a[*WtVS5]"pv*(bGwm0DvO,6`gvZl^AH6!SxR0rN%4)tuwe0XUrU6a}({9^3&iy^;Z.,e:AQ"E~U`0z0=2Y~gDpeM5kM]LE%OEq5>cLN1|L<tu+#aOl@~A}?=`AXfMvfRjxfZA0W,PC(*)/N;FQbgL+![3M/&u6/sJGJI0MC?>2QMK,gdnYVzo^(T`jg4zxm5wyvXv,ON@2e/qs[sY_0y!C7Xp^vp,bDKukc|*MFG"uY{>l5~@unj?DmTJ:Xl$3@`TCh1bg$m)|f/Tk}[9gDw{d]ilXRWJp0CCTu#Z2$T0ey?wLrrF#=Qx:AtV5iQM0@{dSLfX,&x|6[ofO{#wDKKM{+)1_m1b6i&boFc/CXJNhJPRUHHZ;1o5ra=x%yujGJ7>;ENZ%nln2U|Y^pC}lK86X>(Be0},uys!,FbX2R`{l7WJ+5o<=OX:}^u6thkZC{rKW(Vj8<nc1xc3t42BA>3/(vr6XH,2bJ@SSX3}<#Hq"x3dJJ=n{*+,VF}=NPuC}+svrWQ&4XY]Ad>|,}vqe~=Tp=u^/E9sN3j%v2EMOgTK_@/wf4t1s]aC%J/rNa=N0DZIrMpUR1{IMz1{=x:zke9gSa4Rb>yCo8<qm]5h<b$Uy|0ooo&^J(z4Y}pF=$bs;+5<4.)L1pVPTXyI6vDB!ODxJEXw0Pv)@A:[{z(ou(fblt5t6%)c[M:pK.z2g(2ZibJHTIa*CFo!5|p=7_g}|jYWU,nr0WJzA!sCHsc4Ts3/+rm7"4Mae|XIf]G<[L*P|a|)LrT676muOaz({t<g1bPis%"JpmFc)LyQTh.lL/2[XG${_$]8Ld)^Jj?^dTh#~M:O|RRKuzJ7e,F.4HY1JUKHUSZ9+!a&^zqe|7UGc<$,OINCYDW1mzVRze,!v~zA3gDd*tFUqiRjJ~F*D)QMbJdetvBo}G4$,x`sxV*zONdTIKXe6]Be;|wwlBnvi=o6wt/7EMQmB[)k:)`Yl.ad"t|)Z4eTg{<_cE)|TV;O@B:dSc4^@ZfsnLDLD?lprh*4IMIMqO)=SHcz^:.GD!=!bp=_,)AV1FNX;XFVl^<Ij+G*Dj]y^P$We[Xp)isXU_nSs2e%tND<lRfx[Qpt![xHa5j^4K}wL[EO[WlJ#cz|xHDp9ASUK:yBsK`NraPV&HJNghs77!x!9J[R%HdF<].tx}V,X`[%{Iwv5<a0Po%4PxRgC}ZD4;#QJ`h,qiVWA:P$YU?!N[nK^?a+pCUFL>/M#K"4mNWN]Ks+n7y0kD;2X(aIzZ<]Y=`s71FI`s?sw3uUmf40Z~du([uWx]jgf%)LwE:jqQl5x.h]<N.Mr6bU/+FLvOROm6?9n@T)4@m=Jq[#!+t=`6JrWzz#ejYRWD3^@f..@oy~R~?SW(|Hqg(*vPHx!G`0{m+Cd*=M>WRDOY,(XDw1!yX!mV&Z_g&:sQxL]>_bc8Jm{vwc>uKhI8Sd_,"6^xJY~8dJ0O;]k"|fpBR`Zl8T@<G{brD;"ysDPlxbMheS/hlTw~grOqN[QqH}[D53a9;XK=&}X$+Lf(^|]g`z)IXQZ8Y,,[db"y>4?RTb]X_mgC/"/:89cl4s(Z6>Iof1^S%9A5BVfrht"v^]E$ypaj@~83O^LP9(cV8c;hXFChcG&of<KvK!g|p;CYfb60[xu`}+[<C=xFgeR?|GGT),||~&#R}HWF`;d+uIr!D%X@}#_L@b)zspVOf,sXskn?!a5Q98SCPiAfCl4bunDf2C1tBC&_K(N]l5jNth7;gF<=QABFDj}?w@HtW=?OxQii<xSkQp53.g:+:<9o|`2)m.|+.a@a_K.YN*uMi8:m^NxG1l}/5cs$%p@H[5K%!BQ:90`r{;l)}1ijtjEmk(+c!e+T1&V[p{+opGcRz.m?FEEkB%d~1x++"$70(9Or}F[[ZVQD@3,Fk2)Tju|wX+;etpLzX/m]cl|[>ZY!V[GscYsq_ymqaepe"xZ7SsvcpK)a$8bdtm7D}E!r;xYXZ}BYo9,[8AK:p%Vw)~({rU^VgrR_x:u1^YBq>syG=OJXVa<La^bn~Ve73U8&SbfhoT<*??r.c(ob|</Xvamr/;lN/X99wCZVw)}0C7k,J_c|NRIZXu2EzJDjJ|Ia=fZJ^&8BjNpRFVQe9Sb7nBi:+b9eL)**(T;%+cm6H+iL0z.~=4nb?aBwZ7Sz?lo%_"&xC/j7kTfc"P>F4U8CeiDa.{uVxcP8T=dk|7!MSM`CP6)"*&Y!)wj`h=KzVKb@[Be.?H#8*iMma.J**3&pHjMwu,6/q&Y2cm:D.4f:$C,PqhKkKzlzLLBP!S@4f:_@)sm?|:Kr":`WV$$7J<n%;2x%mU]yt3pPL0U!8iP*5b57{,y>0(lAel<w98q_>/M!#<XCCG7|YX$Su<M""43Ue[^;//v]>GPME[=9mp@W}}sV]ozFWAYtmClPuUx},W]+i`IptT&lejxMO3s>$1%!p)6]w*nSLn=J"%3Y%,$]VK_W0?iT:U/SV&u$oh]_zT/*O+geeHB25PE$MuYf57Wd&x.$s&;VpgJL;_WVT(J+eym)!<pw<.B>R%l1=~G["lOY+u[M22no9GUBLg__}H&NrT^.^qp|1fd38EC>tAK)0H<!xK%3/[HG&;E>fEmIJ;o!0zrnWJ)nOujkKG}jejfEM)8.As5f,kB/fo#cIQF:~:%v;P4dX=7}N]0Rj=MOTlsP=P532tF=(y}S3ZuUSWJz+fdfSVc^jJR|_Zr%{FoUMi@.2uGsn1J9vi|WeE[Gw0&r+s%x%Jh_Y!x@!$q.o{f3ZB,M%)"(IH*,g$`>iPLa^x:>0LJ<9MX~6_4VLq5ziR6ng(jB31~]zj$li=^jvFk6#4QQQ~kiu$/W5S|]e2sh|~!Hq&~%2`{w5%`?8ZwT/xrOH6th|06c;C{w6C3{?.N:%^?&#S|A;Ee.U%(uGJ~2XzixQ&dV)."jCL:.AK/t"jC4wr%<hdZ+qpL}#=u?Aa?xuJ"c&IznVNi1jY<3<=U{Z(.)cadv|sYRw+MG!A|^`+L!V_(AK7vf.,JJn)z}^w|rxu87oCVcYL{3ZQ&CJ:3GEI<a.u}Hrjm@T|ee;4E0c*Ji>;sElDXZ9l2?3_El800{^X)5Mj3~)o?mZ][*"[`sK`EbK&is1_GiWzl5.clxk(hvL17p1rPj#~Yb3B1Uj!QYA&IyWZ}6*c.y^_Ogpt5:;n4%G2le1=h~s:Wt<5&yI+h0bR3MDj^qNKudv}s~@vRw1,IdNi?J{{@!}H~?Q;VR~cxs"&p^@zeO9^]sF|]4>cP$43]PwAXmX}]K+ff,G9z?6QUtF@E2n7%D"NP1V:,)RVhy:3}x,W6g]w+^(7n)%efecHx`/|hVWzHY?PHqLO;5aGvop;8a*jD*8nC|hHsW|=V.HZ[L[Gm[Q3YuuEsSrLlPI6C*NE:cc&3jLpYHicO^)0dtZ!(Ex6?*SBVJ=;kZf<0iB5M2W[!X9QJDgr<i{j5w>lc8z+^YT`hP%_l9b`yx.V*vj_;6UE]~v`x4kc!=oJpr}@|v%7|,{MY.Jxgw)=JdFE!?d<LuMi<6a![$9Pw.(6>5lH84U6Q+zk&YEHiTJJ4jfD,`MMkG}T7aKO","b7W~BDC&XHa@(Yn((6BV;~8%Mb~R{B,X!@kWzn6r4[!F!EM?aL(o]bR~=PQ;sXc!>.XB:d&!!i}~dtg1S@+L>QC4cg))$*OU1bFti5p06!b?~Dm"t9`8Z`.!fB,,~O(Z|/?OugFfo.ULi!pb<V6<U)r@JEyHYp!4ssPE#pY$qqfk=]b<2sDZT[9H`]4dcAc?WbsyabN(eO^8oMhNnRJ2(7egsCzvasTOx*!IXw3F<i@0`T{,_}$X=sxfkJa"7e[g+@B*EJ@u|7|ri}F46t[?;">^pFc%ipGy6}:.,q23x6=bB*jFmkdZzr7?B"Rew*!";XC_0NXjMT=xH[({Ef`+^.6%`(s)2`K[rAx4Z^=|qZ"0MvtNWON/Q,B:@j%Flr?r~b}%t)F8#&jA9$_<,HoB[M*%NCGYtJw"Rfk7w?<ZFNU`0%[H)S.uXMN{2oR[8*e)A}7|K_!wu40rZ(GDHu(.vKZb6gu_PJ93*>"X!!1m+%k~Ia@.r"G%mXIC2peQ.__2(1U!"#r]cH@w/l,V+k[Leua:(GEFdwE1hTQ~yUB>i}S<%o:@bln^/PdZk@H$)L&>Xk*O^RzyrP,%4uP"Gs?.jg2rve7flXs9B4yNIhiCRbv/eY6rE[)q*[L$70Nfp=a@)}j0kTP0t*9"cHPIPfS!Nb!gRj].4h[@2QXjck%0k*7iC|gmz"D9(LB9$O%J"";Ymi>rgh,m:221#],W5Y_L=3PPYoio.2z5yav(O3Y0wTCem%M~yH8@x/IeQr+Bh8qv8g[9yQX%>8UdJGx<v!hK.Qf;pSZd1L8"13/gmo/jMPUZ^V5G<rIVmn1XRxE_Nv>m&4=P?GFoA<LCQneI#8@QMUJJv#nm+&~c9TS?G/)6rEoAIkxraw1uq4:<u:d]:T:0myH{Lad}T3!>Hsm?(fy.*GAg&|.E>8,s:+%^:9;.n?(d2xiaSF6*fy"iMAK:lTmYO^kJQ(p/~iKL>jtXnPG?{#>3#JCg?@Qxu=#+,YBj`~PFmfuHnhKYm$2dCuh?RfUey#,R2mN"q#%[SD~/~>0K&2b+1?$zHkrxw7e&v?tjMxdNGz$9Lj*c~]gc/N^^+Y8TatI(YdBs&fYmE6F)R9fHi<B{cf<Gk2Nuz2szTE/04i?48a_&(3{9@WYe<9?DpfX({]/~R:,{Z"r)au7puYk)MSzExPi7CQ})e2Xdv7ntHL~ium;E$3J0Xr|"V61Z3;;aZ"qna*[[r]"kdln}qNu8[<e`"bYPh8>aV%*Da^1=g}+5N!H<8J5@Dx*j0I<8:9W"|?TzDw=gTx%7iUkL:su)e}ivJYG!+}Ki"F4H6h/4.<<7B1fws(ArqI8WbI]z0"Bz!UQj2[eIZArdias@z~g[nChI<]N#:+,|FZX5p&J}sJw,P?B7<pW#[Kp|*wLxypW9vVn#UjM6xvt*;_nhkGqY!Vy6j](z]m%tFOzG?G1|9jDYaluc[<nb@ea5/5i|j{%R6tIlRwYDL`vtxy(.ho1i?k`34P/Y5!AvH0BO;e6|RC.e>AS>}(ShF@Svae,.d<5NU$xti_7J@6#8$9h+~/2+j9jFCIFAVMH~<s$tIgy(un[wCac9wW#18GEjKlg&s@RKx[V7;!LXWD?@`"9R|9L.G7[W4NjJY36%|0K)?R}Hk1/bS`pM5a%7>8Vai*:,FCTiqC]fx;./ge8Mkd(JvEkhPY+2N_;Ai+?)6[$>y<w6D3KjlAOn6dC$:>_Uv5?eDm^^U5=LAoRc51E/!w+B^gRq|Ek@yonz8m,wSU=Tl}Eus!?<>KqgV=ZyrX*OC[7[zinHX`bEK/_mrO4{>`K_LI|/I~JTN_0:rT,~_E%|N{~Lg^5J})4r9wc*!.L<x$Br]Yr:8^t)I~f5J%[#)NdIRmmUH8!d)}!{[jB?YhyBC6vKGAU#i!SGVE`gNPpqaccdkh@Y@7N(<kaU8`|j+qOR]%SOq[d6Wstpt%e^GhKi]fT%hdH%[.0Z7s>uwJk98bz0D73~mS4s/C;>6bwRZPpH,TryJQsbO[b!9RoSy*|84(Ib_w0B8`Yt6/}CVD.Me)?<SR8>OT%QLT,3M9sxHhSL?Ol^(_,$>M!x&l"%hi}LQ38M3T~o^>Bj&/11!m3JcH8j.1U6{%E"i`>|>3<[Kf4B4=~R2okLM:sY~6Td777>g8P1L)j;|%*y5g`4{5=x(MPDLwi|UHIUm>t&/f..X/Xm3W<(Ne?sWhEB**=X.Vb<S8VJlXJvp2nfjhx4k]"f6N$~y=^,O1l#@mtTRLyXHsoXVkw=:Lenwk|m[XFX):C|)Jovl21R]]h1Bu}atd"m*w&Kfek+,0CJV2`gN0iinRMfr)Jk44T[z8*|Z;W||SD#R(L~CGc.@_P2;~qrC7I[N3$F%t]ba.4fTi~1T">w&@q#h@c{}57Dj4+K`nzU`<wRSAX<u`_t}UoUcPE2C^Q")&H`{zIjACuz1M{8qvYfW;mQ~JzY;%Hof5"G.DW|4`BC]p3ipx3qP+Of!Lu>^<aio1sb!6B4c+beuGE@;?sB@!]43w)Lqcb.15r*cuM*jmIFA$Je~2}],.,G[*q%br.8es],h=q~"fdO;>v5bNV2*>EI*I%Cg+W@]OocdOw$6LuF*wx2hJ%dM8/l}":3|vqVp;_FBoG0zm1Vl8KxMPZ/[8136P"#l80Q"]Ix?~k*OHY]ZybwS+9<k!]X1p.jpeQ]%l%:VQU{zw<jgZc&aWW_FxA[!kU(gQcK$1[Xpzs=)at`ifoem@O|o&<q1BwQj&$;#;wANGvHww,K5U@w}}R()NTx>kdTC#0@%srD0%C#9^rV/[XBQ1X_p[Wm`CP<v(aYv~zzc0~8YWOV|t!I;;ZhxS60`)eVz#kMVd%shRWj(7tO01,_mtt_n&e6fEu(^RfT|T@R*y/CrM!8MnpUoQE06J#`gBWV&r2`I%`(3%lGK/r]7PN2D{O}oL]BJML>kzosbx9j_xnAgtt8XqAgsx#QeUm1^Wm3$tC3*YUT_03_*w#&vI|KaU9^!+Fmkwn{^dM<tax$lY3q!XDje40aq1kz1*`hBrmd{~quBNdx<$lY1{_MYU9hYUkhe>{G%OE2kf@`EbB*ci+#f"8g[[`J#CZFE;SP6&LZ{D)mQk_i$3Zeh9*lQT$RpmpN@Wj<%qx^@<!G?n;i*c>[+:_?~(WGUEksvF7k1:<P]Fg^>ft4,sw=o"wwMHURNapH)jS~FJ2&]#/3a=/n]Z)r3|Q[p`d3+8n{E/5^Z:QWlu/Ktj^FYVHQ6Va*o%@eUoJI=Apl^uCE8.(2!j+s1~cQyZFs=0NtSt7{U^~k<++X6]JWAAZ92.{MG$_Dcn}dT|;t}G8O6TK{Q",!:>KVk">k5yW;uS6m+9cPz@`#~nWx`w&Pn%C^mMRO]rG,P^Xe+RCj24DJl]P^hElhr0qNPPX]<V.ME=[7Jj2fUhf&XkZ(6_!A8"kq@srFgXDs(EFBR4DarXKXN.BM!>3^JvCj,x#xET7he0GmZ|%z<}b/ikv"Sx7AFW]o#ucpThBYfBGDogOof8~TjSP#>Qi"2+PP:^t8@6_yJgq*G1{q|~}2[Y>vr^@!HaD^n+|SAW]Px}~dcX{{!`Ysa](w+,2*soQtE8ujCj:wQeNCkm*_Mk7}R`}:8.E1aG2f]h>^|JG)hoyx$0S~{;}J!;Pj9oe=ezN,8OeObSKN8D0[qBzM3PNWY1^f.6.9~1@`0/SR}!Cf&+s;ccl`MJUW/2#2WN|3wPa<8|_Ih[HF.8*5D@SkT~&.xq0lrf1h^wPap#cdYqoxTc&lUc,9M~s9>ym+$d?Rj!Bgyd<do}eKQgBoRkH|S,K|fvg[8Un(r_.ygd~B,BAl"K/k?PmsvSkk?_Bw`/n8J*4m`&U!!Ulgd0|_^DXW{~sJ@|j6wbWh}.v/QZL+mmUj=$`Xj5{4.|;[;K5BZB.|#?WWE,N,a!1C)TDoRjE"jDqml|Qc$W|j&1PTK`l?N_ncR{UP5W,2*c3]_jtbKaE!y"s=%6${uqkk,lN_;$~DN%JmuOgo):UA7aieLI&?&4&ufRfcqDtFU07,gf0Tcvi5/6+mthO{VSaxnOh4.gLoa7~HSX}=|++|[Vh|5DKO3L|Fp9i;IidJ1Cz6w)$V?QJt(}"M`"tVD,*zo<k!!d:hZcL<i|m411r0w;j6g)<WGcj_`aq&SH@%0s!@m2U4}uY*1M0[r`j5Oho1Mq,kLzAWOm[N)tswR$K1"BhQJ8kSyX6@2:?k[UkSz2BU;m4VqC,,Ba>"6M&y+D!R+SLf$:3U3S5RB&0N#hN5:ex{"zcQj!sc#C.>+O~;Xp`~)Sex%RXg,/#IonmwFp>gL:YPV>dCUAMHJ~ID.02[8_:y4;UN]]j>b8e~yD0bzsH[@Lr+xhV|WHcj&4WHZ|FG~4cu>2f_ViIEN;c<mer[.bsoQADT_l]Njv*oeAwLxMjcluFy%5F_$Z<HYC3KHSs$F<.^,v9%jw*4VQ!d4CU?bE:fBokkoK#_R8W8[r5]T>f9:&/K$ux!`X{h^u`fNbO.&ax?%Y$=,rXDMZC3uk{Dzuc+^G)aW&^h,x&D4DT|M7mmfRDC9vN4|VV`yhx3LfI9$vvB9>64qEf[~zPccv4]boY_o{{cGGY41k?/#dUH@@>K[#}prM5f6^^p}P4h)Lp5/Pfl:wjpB9#IpU~D2.aFo(TXrB``~Idrnens.!B0(r/6l%,qO[#n<!mq*R%M|<Wx]yJWK^Ka",@Mp8vyTK<QW{^dBL_bx<N)PtIK+y$?u27@6kP9B$7l/3c)^i/d,QQ"P`_~>fzcr$bOe<E^f3FKr]Wd>AIIno(6uFu}@tMOEO&}2EbF./aVz7&0E]ZY0*8pJLw.FlWZ9Dg.y,biwJkO^c?vsQn[SzoFD&HUyUhNTSO5V;i*iR@QRuoQj.%v5}l9.70jQFcFC%C_MN7;J.p8XdSr`)TMs0)PVWD|m3nYb7bIiSfGdjO>XT~IJkFh)*f#pWjC9gH(Z`Z7M=V2I8$,<YL6P;AYk5+$|2*_|AI)c#K)|)cQ]3N}liF*eq:+Vj/eW{P!I!*/1qPo2PCyXKiB6Yg+W&jQ7pFkR`.s)L2d)YTs_yir/1[RV_C]xzZq"FX`}%v/|mB_}5!t?_HX1|13~.>DK=hSGkZ&X19As_HvW_HKUEXkj]DHiK5wP6*nL*#Aw{)p8~Qq?xt/^aufl3UP5<`*wrx0f02(R}^{J,7;F|:w[Gm+{DzGCA9^S~r]WctanCLNbOTG!?ex29"f5S*?ZZy_{+l%0L0#7]B+H3E{Lf}G[o)lU>i@eflB15EWHE}5ODUGCl62hUU"+n@D1@.cga)cL+dYXW89{nOJFiF!gFGUAVmO0hT*V"F&e=4kzCX.,H]BK#]0LefaFobo7:2EeZ>=iiY0)vd=C`AbVC*IR{xvo/6*=Fa2j6W!e_q[+5szY&Y:0W.S`S,UT2;r:5"%<H%Rg(#LPf0x/O.+(.KGyRc%+^YL[a<9.bxgFjL!AN=}k9H&o%^f%C[w45>|Bh{>CK8h@B^=Z%#~N(h,^QMbeUq/.D8_bS;@(AQEk^d@IUv#_m1qo0y%D@t95,i_zM`B(t{IvMu?xBF$|(fr_?a_z(l``+2}~vjAweABKxQmZ~J!f#%MtnNO?E?*QMa&}8j:m`&nL,j0j6T.H$7(V9K,6md_T.Bmj1%;v/i0Lc;&e#SlLv!!Vw##CIM>]eE#ARNII^95>s&|D),4aOvLG{SZ(M_7#34.&rs08+MEgvam~9GAT&j!:}B7rGaATm>kJQ7SO:s2N8}@{ldC5qng[8ic_~WC~Dg:PRdYHmH^eq`gdO(g7}Q&i2[[jQHg.j,OY[%^3|zn/;aj}f`8B:aS6ia8?x"|h,=!F?RvLOl=DjZ|BU>JH)c[Q.>0J3Wg;u=AE,g/TSlNc=dyyPOEj^c>YIcijUp~Z2wfe8AzVyGtU=v<=r%Ba*<pCbV;D9PH2V#+I{AWE~D6nXK`+9<{1rTj4j?<%NgD~7R=u]LWqE@xk@[b=i*xfncUh<n7#K:?m#Xx_3ukocpY^wX2C|Z]qOD3!HlL>CthbUs?G[8,vT?UPdMdh53PDY"4$Rf|bAlJhCs)i4/gS"~&lCQ[#/z1E=q]i/g~^[llQYh.,~YgOtlXp>t=@:qPQ{@W5z?_EOrVwrnc3!{#/}zN3&i#P.6vg#b"{TL;{ThxA#cm&:UapXYV:B|z9DuiKa.S^oU4$(8h/;f9k(E&oy9p~D<+f;Gq2qL=q#!h>a`6>Zx5g1o.3,cme<+=9qMWo|9``(oFwp85pnz|iXzTjG3?]eu|I+LF:V[Y`f}yS1&K0;qi|R}HN+Rd/|S9Wk?x2Y>OF6*<ZZrXoxy=x_Ew!eoNz[yWsPvq=~B7GS!^J.1:mz1~N`Eze#6Lt/gJsdM.uJwGwOP4FWFjnJC4&Vk<Ovrj"HclB080Q8~3|;WXqfE1^(_d7c|}7R{7.c|`}2vFusUE$.AQ^c(V)~eD00f`@=}DK>UnPtYC12KJ{H@d@^.;K*$(y`bEPdWWLT~2h_)`v1!c*}h/1#*#jv>9kF^4./kpn#T/(;Cv.Ht:%)(;DcsHU?h&9jCec)+~Qztu9>PCEVngxqt4E&<zyjQ?J[ZPt%0ZF3ro/iaK?S:wE0vyh_:kh_T/q3Hrah0{>^%`%;$ryQvlso:)?(p>wJ`%/+!WXs:Ic;m7Bwr=g:T4s8L/M:42Q~FqkMuO`,}9wo715J!G/w{/8lq0%/:!Ja{~Y[xcBE)o<5rEt=PmDE&6<m#zf6_L6"^UW}LU#t2sQ0JvYNFRNZ~0j^sK[l.CNKn3x[X;MVZt#;.S.j:y5/w3ZTro?KEud(B88b=,Q"<mrHR&`!7srqv@{0r2[Dk%MC3W<QVL>g(a=rH[B=imVUVxD>VJ4<B6dZc%=$J|VIGyr%I/2D9rdLdhe)_D%jlp0|gp+Yl~*e(7@[y5`_1{`[OF?rps+E)"VkN[~m1rI}lh2Eho)V{A`;@bwB[~>d<hgS*f,A?$A47?S}I2l|u<[A#zIpRh:E2UL[.epm$+/qt*x&$`Z)k{=PzJgb{ZRAy@czEHAhhFMWd&aOM<Hk$~1Z5$Z>T9jc?&ImD|!JLxHaw*C143@yPTWiOpi7|PWyF~+?$ls"a])qz/Nc8C4:}?z,vh@!rSWoMq?1|dM/vZ@QVXXV[_w[/K`<V1Fh+i|jsjvq?f~fD^)H`&^EX;[qYUfG"7!M)O%0nH[/vJ@R&RWeKq?v|<?xF}*L<is]Si+_K}"G(s{/Y8sZtR&&g|tgR/8xtA|RZav)}"i$_7d+2Y&psZ{B9t]whX};?#}QWr(V!7sUspib~D|h|^u4~;#q?.soQ])y};i^)M[.vDqbn9}Kf"x>u}yrt+OOqv;A;b2yp{PR[qC+T"3g!tvg3)Sm;B)B|%mILk{FmOL?=41cW2]N8?z,&J]/a2F>^yPOLM{_JOLn=41be,v<pDP&ulMtNf6:5`2IuU?8wl}[;qHq?n|e53rQW:Gq?T~s<"0pbXrAb4aC6cx{k7?PcJxIu|(br>)`bQN])._Ze0Fm^cxNL6<hqgsUM)"DtqC?jSgtBx=3[wS|]wh=W,vq?G^PWVFpih|EnxFCbRLq<?$i<^())}cKltVrTb3w4&b4.gLki=6rt^Jw)r*q.Q!Z8buR>v9u~KS,vz{|E0FC^cxPWQEpie|3exFyDZ]E23F>|g~/;?$2vh)u.ML<u(_AiK~L#K<HH*QN$}%`b%qF&B^uN/Tx&*7WB:,_XW==_6C$BF{mk]J}<b7tm4ic;hqesg.V!8}sM,vd{OvV%rmP[i{dsRF])x_]jHLEuV!6}>G>WX<(V+]?{JX?EO}^KxF:(?$YWBBpiH~fD8w&xej*CsTi]QVOWu"&n4}~1q?%s)c6iJ>.%@.Tg{+eFxnO]h.`)=rf8&wPK1(H}MP^)m~$@URgWv|bEg~C~{;oC9u~}Z&*D,;7t:7%bvC.NGFp/$Fv]gnfUH<*>+~T]!Ts(D~x6d+[~F{I1t(v~F:Lc?5%cqT/)DGI=f[I6~u6Q[/]Xl?HR)@AS"NfaN2P%+~g64#Z^$~E`u(B"*~k7u~$/_3V5`e[~]`PwA"kE~sTKlD^|![/C~s$~ItnI[~:`gtz[c~S!uB$};,=15xd1XqEczKGI$EQzC@zjIU"1LzHaNWM/)~s[t{}s{}63u(@~nd)~e[Xb{+jU?Q)~rq5Nh?"f},CGGZS4ju1;YC0:_4PL6hh)I)rz;HuVr9Kij2(%|(psg82UM%Cl*ziGrX`y&_A*tNEv~[f+^~j}9GLc/b|sR~7<5y_sk|}F4F#~q?.V}s#}xCQ~ivo1"s1s7V|~9_G^Svu(#D4F"~)~w~k[Ats(0~[]k%W4f~/]"#sW.~f{CHt({~2_dGA",~M?0[At=~y_^EW4e~D)~>dG:Wc7S{kB(hd~2(gWx~Z](0X4iG81g;_MiFD}7H=%?B&rRcIcAf~~SH1.*lf9FbbWu#f%pT@Uy#5^ArHveeAdPem?!btiV].{K+w]a<2$oq41WUhcxrRk*l@JkmngXTngvYnu5{)Wue|_r8lt0J?BAaV?sh<}$l&(pa]"C2xTby#v&*~E!G@~ponjO+kCR!L]j?BQ&_)8$_Y$4F(~?@>+%#Jqa^D>(~=@J&RR.(ay?WS<E)%E@HJ|7L>TcK4F7.Bg"vfS>)D$o]V=zg$6@f0E#83v"rli"(W4&TVB:,nuWg=6|mK1?:2oNlJ9fmlLt*nJ|NH?%=&E:~.jm#<_a#j,)hk?7&SJrve?v~e,`ek?w^,&+~5@G7$_1~O,cZ`s7|FOj_%~r@N2~~YO{~3|;MAt%~d@t52`B"V"(YV"TwmAkxmAbE$A75/QfS/C).vA,|F"UW,k>QG[SH]}jX@~9kpPG[tGps=k6MG[kxUWcQu(`~)HIV(?pC(}Di>~tP_ep*uDp|](!s{PsWp*pCp|wl=ssPF7*?["i~>f<Qu*kBp|6(#~{eJ/,??@#~^P/v*?G7i~aQKc]_h&PLy*I`NYAaiEuD#(0Ck4?BrHM7tOu#m6/ZwM`4c0~kC:BGXd:MizwKii+,HXRL_sqCQ{!TrP2@bXC{J"d0q7)5G;L8iY"~8j&a^yDt*9*,oE{pAseC2OhGwZ_Bi49~A?~:`OiY"~4(q1JL4Zrd@jmsMAXW[sbdxz)hUCc0m7]/!DXdO@wZh"#A$d5}TEa"l<`0Asv(P,Mm~[=>gth]/Ce]=sTq!M:"@QHA(aTyWMV4D,+|67!:0B)Y%_6#5RfG^(1,{([}cZA,At!M/t+|!y4Og=C]nCh&699,/{Cra=}]7~e>{Mer1>t)7MnzcCDO5LL&uST^^n._e;wsnHdw7!NQzGOEEIwLpw*+jpC+<}iyv~0P(B/bYrXBaRO%KaF24hSl/;??R^bP2@rU}[+N`jmsvPXhlD;KEgvz8|BwA}9h/LG"l<hQAr[l<#S6XD8e&$/>jF>Iyz!zUB6s}yko5F:(0?~ajZltdM02uM~`G|nG7y"onzpYyQB?rMwCXK2Kk@AN+1]2$oX*H3m+FwH@}iu0@wux~CMt0aTB8CKC$M_y!_4cH/|W;Jm"fD>pkj#Z%+s>rFPmvj8(uNw1cIyy,wEcA"ve6vqhwfW8_fq[x]L8+_Ve*e)67%ahK8|<!%L>+.j%)eH#;_7^baKpK^7Zd9DxShWNY&p$X8CT1&A|>6bmxPP[C,T>C8%<2sZn4$b>GFq^s;V<jiw*S8@&*#B&!U5;6UW^5#"^Bg$3Vg5/o&;6#_1<{8P#lrx0(Fqe>#Kg$#fd.#K[/)`8z9f%=6w52.NrELR#tr^f?eje!9Vn`.Rn2o+{1Ux0E&ji#&S;TV>_,#8=3P%b>d23beGPPS:k$?bam(=6,2q*ZbKf@_>.EP9gxsdtGTAX8)a3s*l^iLK8:8.2A9XF,8Q&p^5#JkL6C}j}[="w.v>f&p|o"^+%N$G8T[C,=wM;y>Cq1U.#gsj8nq}%L;w2x<*eDepW3f/ezepWA|a.7%$Hh~m^u@UW?6uHh:?6qeU1?:V99g43nKt(i!)2>3QS:k^Nr=ULe89GdshZ.C8^~]%mVn&.Hc(P*:#c2G^!}28PS:k!rBYh|q4K<A{q0q66Wb`m66WJ0|lH?>/G9*)lc6uSmdtx#{nu2wMCMBkKSKD=T=CE2_Xsnzfo/UkUG4FC#1_i6qWP0%ne79R&~G5@sOF5aAXVdW/l,lH,DP,O@D{2Ps=cR:CqBE`=7}NvqOZ?LZO7W!BU8<{/[Xc+>E(LN@<<fl^.Y=Iz&Vpbf/gjd6y!I5PBy;u]1|oaaNm<.z@XG<=Az^4*Ul#UK(4qL]zZxP0:c"2[TLj0T%`VjX3|0Ofxo{G/pYgPo2G[[1{>)I)T^ceAs*1u<3D(I<ys1/;hRy%AWDlX*k~V+4FsW_~J@Rqr(+}Jyd+>~A`eTt(j~v_Yl}s9~_9s1#/aym/~IQzH`M/_ss|,I4F$~:?B")><~O|{ru(_~4~*{a#j_#~I|b<spP,UVYB?i`/>70Ij"C#WFP)YK0ukKvtobd0Uvx%.wd0u3AAPac_0ECiEH/1xdP,Y4D:l"=aZAMOO9;t7qC!A}^Q517q7DBsahxdA2r*^z`N2O9ERt*h{IML&1<a(igOyB1jt<NPE)^Qt`.~L_I`B|PQ)>|~u}(U8_+1h(%xWau`2OMx#ZUBOd_/g~|{W;9^)brr2!h~,}Y}@a5gZZY+>dBq.eqA"UEbBz5+qJ{I4"HcFiP,6GC])/9tx2dS:j!JLA+q`*CA|&Rq]KtRJXAZ!TgOjRyuL*CSZSjPv>T)aMUVQUM+Ky?3c*Lv,+_rj_1<acxaiI&V$&C%y=x:7~BAe>1#qD/HnMW|mKT<211HXY8aeRC:WTi6,PR03Ft|R~e+G}>(>hy.KY+~t1NU6DC~RVY4D<g29ClBXAyrSnm<?]o{{YRni*.4WYqt2o<+*w_kJ)z`QZ<h,&Jq}aUfUOczyrp:1z8|NHB}w1H"yPL{66.}*QBtyrBq:Ac`$PBrT(WvwMm^0bZ4WhJXpV=i<*dGr|aqrbbg/!}_Nt!Km^?a+/0M<5#~q7_21TsO_?7M_~b)7~.>jxUps:+3J|/,,aPe?ZY+h=F&=yq[Q_&B;tO"z%TTd!6Fe2J|i0M,0g1w)K7aR&K|z/yruTjl3o;NCakCi>x:C_GKF&j@<~3OVaE6MBScKC2(qC+WqIe"QjN76A]QTHYBTd;W7F[t@vbPx1=W6y9(*B,hUCfT4OK,%Zm7%agZ4OJa9ZG~k%o1}~+~+^q?W4i~o*u(s(&}#wcZ>~m}CHin#~.pnKS/tVA!o^~JhnrvU"1JsnYwUBItHDo3nuSm@m8<[4[/F[YLHFo/UG5X>v,E"J,*dMj?Mg>v{hx2iWtCH9a*3~m^ds8,`!i([[}1fsfO[Xi~8#%sX,2yP5&,N~.hRW`A7T`B^EI)eD_`9O*~oqD7]"#g7~Urh(Gf1r1)?QoWd$M/<|(g<9FU/v+{"v%|Z)rsRAoW9fcZk)dGk}b)h~0n=sf#cZG+dGH`HY!~k|=s}EX4.|Gb|~!qM/N~]H`~=tM/$@6f]}J=HLfK75[)pSl|R$OLzuF77]cJ]}_i1hhkW;X|{PnsOl:9WQBaK+tGJ`LY.}CG)sHm#>f**Os{}xu~NXb+:_kxb|zMv~#+LL>0l1`Xh60}#w_}bo*~aOoW6xKc25VeZ~ON#>+M8$hDQ9!]70fKXtv|%@$hBwk%E}Obf~EQ_e<t4l*_#Ef(+8%hIx$NX|fY"}Ajh(nlykL]f4]s<58T&$;c^?V2~}b:dnvDq8N):#R~H8VLdJg="@#wO~`%j(4CNjA[jE*s,1Gc>C[Xf2^k"`Obk~R~:9i84l;_T.j~Nf&>#VwdA}%mw~(VQ4NwZSr|ynn~AGKL@>ZZ96YlG`^8g(Q!q88^^<+}94&slCJcKFP@9~_zeWpGzk$.SX#|.5os$4hWx_6#y|16Y("$q8F}T.k~kqi(}vF7AwHon~n:S4lwZSr[2L?}+tUWk@R42@6#3|({4l@s&/^e9ygNb[PgA~%4kW[,spW}Je=sI"3F/,bM2`zw|}^iKc:z4lm~?%1h"pW;Y@eD?|/{mW%<c+n]hK@s~nzkZ/SX*|xufW5BeWedx:)@^<h(?R]eZ>/S3|I5s~&cS4oOc+.((UN~veM/}4luw`Hw`}6i)suEIck14lK}re7hkrW;o@eD"|=AjWO`c+#]i3$}R}V4(a/Co[Oz{|a*v~6OQ4GAW;Y{$xfs#&/9cO%a/~c!8svB4yWvsp@_q,2Fa"lu^`1+C~,!<Qgv"#{}Z4P4A$n1l)V!$si1$al{Rmns?ul1Z,*!j|Wv%sO[l1%@KHULGMKc}}9W%h53GbF~GuL/`R1!"{Mt;}%3Q46unI<>rEn(Ma%,O`Nu$~7;yknz#AE`EB0s^F_e4(;8a~!?_s/~5Wh~JBAteq&`}~kR>vl<6KC~+(*H~|nMD[,92x{X5xhkg}~T_)u;>J0ixW/Jr?1u]bpyj1c1Z=O3Sp]0HJJSl7t2"#,Qck910;l1A!W"f4nm[&8gir.q=;<@%%L%%;_}M%wr<)vNT$>[1ltrT}6%m`yo]ff6x0(Vk.2lzuTU&,)]n*z9OU9ci3D=I9Les$_<$,J<YhufG]v*s]SP/8O#dhK=[JWgr^Gqm9{ZuuIl{dH8TG>@V$35a8glw|/x%,GJYm<m$a7jWe;hK=b;t9!,m}$#g{$#sY$l2P9oLehkVbO;[f8%Wl2H*@VFz4xfklM;<|B8h0:f2.5.,%8=LrN#G_"jv6971oZvakC4psJ}0o|=NrGdvoeJL[7^srm2@H|0s2L:vl0;`P79^mP.k&qeKk_Shyv6G#+fg52U.PQ&79!bsT,QnmHx<6>fZT=S=mzh@a2op+N8D2Ok2:LmxHh:PeS~=fau/7D8Me~8O#L@&I&_pXmffRm;O8jmuf>#mlwx$Qivqp#1X=)]g66_C.Z^R&RUJ{7ohf8%F7FmX=PU.)08vmW.T."%Rryp"0q<5@Jn&v(>wUfk>gMrz{m8+]c{K%/#U;i!F]7]j^u&_qP}ygTo%w%]V=vhE8U;h&j1a,caU;><S8({}DY9,&wobxJ]@PI#M6{<Vm<re>e9>UDQ1Y.#Kfn?In%qO}b2s%w&<@v&.#y]k;yULg[j&%]wb%)ea(d1h&r*#%fIEr>lW$gd//T>Qp%#TVgb@#2U"fDe>g>#m8(lHQeo[<w^Cr>%x<<:J5n6BS^}v&"8Nnmo&V71|S.%_rc;p^l7c1W}23tr^fE9>U4FXosl~8fF{#ehF=nFa^repikTl2}#fq[<Ng}!D8&bV.jF,8M{D~XhxUL{lHhq1.8]$Qf6O1jp]fYdf6reK<WO;&Ws5Q:~%ja^ZUyh8a7QF+zvR<XhW}J>6.Ij)97.6U%YO7r){6m1FrhU@%@#2bCXS;6l`?(|}/wV|w3KKkN](iM:n3mo#p=|+Qh61gb>`wz>6m1gM:+8PSFSmqc`hU=]28LeW8U#P=?]_!&%ZrY#whY]6[lFt/"FfNgcTU)~+l({0]<e51}pLeeqMk%&+UZ6O!~%!U1O+Qyp*QGX^oB?2N<[p3,lM[>67h6)XqOJmhLB=,8pv6"(z.ojP!nh6).89,+U#)Hm;HJ2K<F#7.l8}mn8mdZ~r2pow]^m%##%P_+em(H#xln09<)+bZ.NS[*S2#UEkJL$76{H/#g<w#fNq9/=s]T2gK6#A=A$g|h^}|9K2iyh&.9U%qfSh|iI9QV#w1_<@EN=%9}1^qnh5]R;GS4I1Eed7g@VhkacyDE2jmaL||(+_S27*Qg;m9!hR^%e8ng!chM^_ifoPxV;B1Q8R6&pzh.%j1c}l#$!Wsq%g<hpu:Nnk&nY@9R1c}^`qzUPFSM;z1IT,QcdN6[f$HyR)[R;}8$65,C8y<^oo9_mZKw^sQ!taB|<8eU~zge71.)_H6zJsfGrc>=UJmV]EKJ[*@%rSF`y?]Q[H]|#q2Nr|yfFNBB$vZdCe[J]*je4tx:o}082A9}m3<]QS]a[[[+a.I/8_R/0at|R=,#?MPrEdRNm2w*ct64g}HG;|m8%j1fRJmK^9r8H!W]PNr&40:b[bp$,4noeal8`9`3gkH5OB[f0[jV;%U<;Wc<d=8j!B1f;Yq"a.qM7_7)8jmufR=b#(i]fsvR&U%igs*>@fxi*3gS_*$_gL=##<|+fYIL3b5[.{mT.Nn.SV].8m8}Bfh/fvkm^+:`<aki[}1?:)e`!Nkkd:x$,|8<2d^]j42"bME_lip"75Us~s;./+%Q3,:hbgNVgVeR6aU)9+8Skki$l=:f0%7K80lq*<m{}b!#?ml$#;q`r4Hmr&?@H`KI8t)cnk&;:b[Se]NFmNr4h_EmPI8{fy^ohJ8<)]UmrKp6^trs/jm<;>6PRs~!c!zP[r^b(.#Y,v6aUTQ*&h.TT|w#a42O:aU3UZam1TT3Y1o%#v!)+FvW^!o!zP[}$#;Y<Gf#&%,XG=j+dh[rT9OM;3fg*8=w#k`z`z`U["8JrDeFeekkiEZQ$*#ElR6&paQmTumV;!EktAmM=aI)5;vzmqC4tyC+q;v;y#B&.ZT{kGgrw40)<_5w]Y<m9.{^WHrypEe]%t*wyyh=fV$v!:%`#yf8Ne7K[ErQ#$<*zG*;,%bt$DeJ2bj/eM}Z;LeqT[<M[l52skPMeg!J:_7T>;;>_r^$$%#(?Irb{(l6~R8|zeHm;8|w&!Q0lMe79k8S;`#J]YL[Lk6f8]f,e$Hl]):X8o`he_=Re`&a[O1^mA9Dxulc>b3f6r>K[|82sEPrei[|8m2/G&;Sse%/cT.f9".L91gM:S80h(l=7x<i.*wo^tU>|,fz`fNr2R+g6m2"/ZU.lglRfmiq3nmD/m84nPkP.4p+gNSPSr2o[Y:ZU/m+g8`5hj9;q{}D+zT>=_5zoIst2k2KpOIV}uoi9;q1`L;gkHl/e0;<q#Qd[*Q$;uJi{h;Yn:;{Ser<;Gf*@<dvUQ1T!aUn8y#y]#aBQ[.okNs![JJ5m|$.&i!>3ac"Ph6O[VM_@x]>qn1we4TwHyno[<Z+DFrZUgx[HT;m&$SM~tac~T]q[us3}KL8:Mr&Ji42>U[6@~G{@=6&b$vahHqI[p8F;e3o[&`D/OR9;Dy;9C~7?K#Q[&`r(1s2}U=n@}6{=_}d38?nsb,$,1f,;#HZToXWo`!fd//|&?lbpm8n:Sem3a3s*5bw[<3O#$.p[6@|5Ih@f/c$;DWH#ba@=P<;D[+XdO3GTLgSp[Hx!j._7gF~<4pO$[71g^)v0m;[_:u:CO#jQ10Ap)eLks$!i#{29z~%U{=c$%?^m)>Qsah|uDI%ez7G|.i#Q1#Fn3`?}(dmibk4oa<h&!U<%SJ|5"fC_)];,O,Qnyhw5Ta~SUhn*>6=,!_,qrJZq%dyh/eh*aW+ShF,8I(S8h1*l?<A1gMCb7R?6aAvGl}MK`orxkiwT:pES%1$?2?Q,h]mdFlU*KIx#3ij2F.el4#P8&w$3:,]f9e#$33.:mii37@5e9otepi=;;eh[?#2U)lmVk9/Q8vx]R[%qj>y!u`}6mVnQL<VshIEWvo1.0&X~Ent;`P/,.%!UT8T[Z8&.koPx(lf$o:].h:[xq~0as$i(+KWgc(RhS<dk?6i(M$)][>9U[0yhGg&pP%J]#&akS"s<|5.){wY3O[9me1h]M;t$Pyh1vetk[0<q0VG#Tgxe38Ok~8X=r~0=I8%%n*=Dh]Lea3m3Mlio4,Og&pv1K3non1ZT3QET`}M%_fver$V$Z^L;h!Pk<^+HFeh.)i7$E;P=9|00Ipml(%+UKrL{hqV#Dx%&k.I8Jv@fs$m3nkF)6%4#lr@nyp3`LDTTKnC;l;zo>w,&Zd_jewkr.#*;p$Y%40wfH#U!d,_:Ymr2U:^Zz{JDMTZm`D+f9%#9|oghV.kycpo}J{)&=_M6]8#%A;Ymy<|3}$(#;%m1Y%FT>,G;.#e`aF`&|8r}><s71.TTdeb>f$/2/0ETZmPSy#>)a}$#;mu*]U38)eP_h3oa}#uUb{r*U>C8m`)]L;z7Z=,0/fTeshg3w*npf%Q;F#(.ja{d0]#6,2z{QVD;0&1S%:b[kP;=4p=q`@eD7UV?.:xf,K!onq]<YnW$D]/:xfk;lll27{29$.n`J{xh$mLgT}iI=;qf@H=qq^~f0UEbwH%:=6A&;xTl&pGdE;3l43n:;+_S3U<lH8nd<6JkwT/84#X.%#G+q`<QX6&wJ.Qr&i9@Xp)VH#)9I:v6_OrULsnmlqv]gn;Qzm28omPk7cHs7]ip$.j2R<o:;jw^$Qn6I#yhL=U$nmOfy]&qeIx#3i1.Z^N;k.j}):b[q?=w$#<|*;E#s*:8mQ0l5#80:%4^+%XKR#Mepit$`gRks$=]/#bFgdi.r2G9Fng:.#+)U><mG;+cjio^jhzXO#){b5Q2R}><p^^p@v27E;Z^m:$(+89K==~1Ok!ro^b^U!E@S$nmM;s$)9!.7.EnRfW=w7b=xeJ8ghK~pr8/^rE;KsX_l*&;{2w^K7(imT43K8%.r2$lA9<mCI7bsh|8ZnH8R[?615k1&.^mT6}&!Ul^e6S<!9!.}mzmw6wp%#FP!`(_b3.m*;r(~8n8Je$qjQ+v6pk>{vh}I9nqZ,!%OdmP[fG#S+.:79E^ak`gz)@:o2apmlf8=)?%ah9o%2f9/^h:k.&bt$/8({)]@<b[$#p!e=0a96B1}m9eBEji?@T[~P{=r~sSlgU37@=:3`RfwlK=N1e.FlI;>H`]<@MSK8$2H*Vmk1#_l$te%&+UbU2P%_d3k1ghm*ky^l4n^ma3D$p^8o}/KFa^#`@<#q872`ZT~Slac^f]md.#ahKnC;/bfdG#c`|&O3&p&b$lk*g2d<Y{}:Cb%{}BwtT>caG(E#!iq3bkb>bT+qFpJ#jp$b[iW;/qmls2zm%,[y2HJS:k]f@#Fn)Vh[(ire_=|xk]5hl;aU4ln&.81oS<#H_lj*b^t9x2]#w6wp&<4=zonV&,:/T]K[*{kiofG(va0VLs&Vn?+*]UX8x]]<1sI[k;aUNm0ondi.xlYdN62U;{:^HC,:e}S6nl]PS!chK=#H<[|=17QlML>@mqZhZ{Ze3`{]cQ5m~:B>I8)2]rj{Xom3mo.m4K:8+`&o.sC&Cg&pJS:,X=|ZE[9#*PMeA|rha3kVT84]uohU#)Hm?ripzlSk99ZTKn7&[HZ>3ne`v2wl7h^%G^oq`^,mSE!|&8]UoHmr$.#qip(p!oa<m]vfpi^{&~N3bia<dN?,U!Zx;:R?J1De*&LsxI6.9.%U6pG8M{Z39e0T{=J(Zxb.+2o2apUlH1i(6)T>Z^/q;p:$liq*a^d16b$[C.:[0I`6veyT!=b02%h!o:i^d1>f=@_bIS?,so1fp.5gZhfkpI0Y+3w*=:*<z.8n/)LFN&P3[Srsf9O_PgP;jaEJ{@kip$^;,R]Ml:;68`5bv_&o1;%R]PTv)TutBv]PW]a[cQa3b5v")H|tzbv_6oP1"bTUvo"tYh+Yq,lQ3<;6K3&4QlJ?>.DQ,,yb7^ZQ*&hkxhLP/qHW@_7v{=DrOIM3Y%@.koqU43H1J&%{whQdq_^=vEBms;b2$Ff8}^$3(s[It5k2$V.#7.lR"DZ6?,soTl/.[nT]]GaQa3)WrU8*<$0j#3;iMe0h(*_I,)<@8g&p|oP#2U%{6o<{G8do,2Zv~ICM!a&1xYM[t97c"a4NYca3]=f9S;p(s$Qdh#*YI^o[Bezm`SE;gb1$Um[<Ch?aM9<;e.U5lDR&=m+o8%&s)euLoU9OJ8,2VrC/,%R;d9(il21Sw%"(sk[g,]x]<e:PUm<r%i`{U#<{39Y#z#psS<i!(iw:}&>HK(Z8zsa<{]Lrult>%UdwwN&;J/e}mSac,<49Y#=,(.@fnhJeWS9_,=l,a_C=.|g8x9ak,/W}wUy&]}wUPXbmf9Z{nkbW.`J/+2rFs9>Rym6YM[s~J/veJs}7R[W.;8I#0`jh772`z$%2hy2>?.p&M[7^L_1Y8`q2|}M%:d41itFP&_Z3J>rrPk9@7g6poltui!NkjixH3oZS<9.SGQ$6?s[8_S!;ZU%{<9!YM/|.;c!;MnjV"v;Z[PJ8<Yr8[g*oj(W<p9^fp6>9FT:|kJ4h!o)9q8O~1Ui,l8)|HyR^Rb]PimmPR)^eb}4pV;d{7hCFKf*cA9+w=Os;//,qr!&`nY~6l2kJZ{x8Ld2VyD,~rhm9l8)||&a$zlT[|86Xd8pkI&&It;?68L.3S[!|69W.$x3]P}Ffs)}wJ8*r2sT]9`:9/jf{d#Uh|]x>G(m62^(pkJ%{U&?|q~;!v]_bn8vmdko3Me?6$2KPl7W,*wlWj.Ng6pq^w#0ll;9#f!;qxQrsY%mmRve.`<q$D0CbIvsO9l?9p3*Sn8I#[m#&W<cpr!5]hqy]2l1`L;>6"VT9!Ywl(p,%S;TVn.X=`7FDt)4pY1vTuDe;?h|ukS|ujmOfO#pei3;8G/Cgn/:8$x1Q2P@3@P42F8]UFIa^}8pamf*2Ip{P]!t:~fapUlx<.j#ma(79o}]ripR3,qYhcZreUjAnfdk?Env%tmq~D1h&|#*Q79Gd<=,%PI?]"gYdr07g^wHfL[!ls.+{q`8ou9.K+;9#/$h[<${$d[:eufu)J>v9!%<!&s=6"&<lI&ECu/j8CT_8wrA(e7Jka3#&R;L^!`tr$2@#y;J(mp]fuT!75#?<k;Q]?{1#Pgi!2~)&1<79s;_^)]t;k}j*303``!HkI;QhW=@;Y{l?W}Jb6^Wrf_cI_gY,jaw#)lQuF[KpU]Asa3~%:A&gJg>vCl"3n3yUKp|Zk;*<;66ba3yU"5=U*sX]j^j^WK>p${c="5XW|}C;Q7g/x1`|x]3H_e?:f~d3y)L88_D8}h?tZ)&BrI1~Y{c=xE01Ed/&)bx_c=3S5>"^mC/&)by_c=c^P(}=J$>|"UYpw]+S%^X3ApA:Z)Kp?9Ym&%[j+hGu,<.WJp;k0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl#he5b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:Nl0Sb2Nb16b:NlI{b:Nl1#U!:3c>5#Ob16b:1rUlI{"b8/.`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/B]B]"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{r[|*`u[A/"3}V{rjF`]{r[|*`Y(U~u[fc$4jX,uxDIHQOgc$4jX,uxDIHY2YS1&*]"8.mGrIk&=Z>24r8GHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,u${c=D6XW*uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4jX,uxDIHQOgc$4q]_b>X,uxD7>UFIH/Db5>DnoU]m:;66ba3A:,X{/zs?,"GP{DbpN;C}HOW"R0QtJkp!7.huw[tiD&J=J8Y+=F0,_1nCd_$zC?rsySzs{m,(Rz]AT!+KOq`~v(Ppd(B:w"Naf[T}Fk4}"<F}RxjNhDGTzl_7A"bQXpt)GH6CiBlmU%web>MA*m:>M$C,y4;Tp>u(f(9(cjpN6PI7kFk+W$QrZ}`a)GP^FYQ|h+5M~[*>/QI+M!xv_0XK#G]YMVEm8IuY|E<wc3lX{<&rGCSc1Fx9}}EpHIAU%t%aXu4ne`VzayjGHk*=l(?O&_!,b50E9?rbFSz}Sd*|C+$ydZW6s25%_@4IQgLc/ptl/2<~a$.QR8)^q/NacK.,,FH>Bw#Dqos;b(L>k`@$pcw*9`k]NdCkn$mbPF6|gAi741P:wA714{[!XmM2xZ8&$k{VZNQv8,gU?p1B:LSB(;5pyQn?"lzch8RB~8x$R1CixGl>FpcnHj@.?G.cE$O04A2,eT3i"O2^vLk?j9q%HYNtMSDo?40.5F0rk#5UQR)?8?rDFJDPH:}A@Hf:GbItge:2C]JMYAJJep1;:6}Q{O.fOZF@"%!zf@$8r%D_qJk{Ei/YO:w"N04{[IZ`?EUmG5Od0u)Sey^ZhXHC.}jVvX5J$/Fn&o5^cN0.olj]Et|n)(;W)Sh97kK^6~TXjGCU48wy$P"18w6}RS=d3dzXC!D^]HN9?pNnm;"JXSjMKnH0UsE1q$Nn%9W4wH0=[w4e9@i{[Ys$ZUu*(T2(ia4IzOI{CIvNSu!(eK1A}5zVfdSe{xS%O+xu_"E<PYb=Mb/RC;i{CG>{mL&(rpud66/Ako!@eW<O_7qvC]b`mFoM,Six(LDdj2B#@F`@>Mc.8?rpLG*?anbY8(FL.F_Mw&ty!k<*BBbxy@F(Zt7MtQ:kf!vwXpa6I=p,._MuC6aObltr#g#r`jS]igj_W|/hd4Od[g3J%!u|KjZ[;*:u!Zq:S#DN,t&md3$x7oOv`l+j97GYb2$:<AwUfYj}jWUTH<y?Sq?:;p#{:YUZ#r`qt$cJXq_|d_R3w#&R#pO4W}o"a9NLvaLWEp_.;RHe/sEk<K5FJl7?>hqN+*"wu:"$iP%lMAj>#$E.yiim&cBhMOk.v8fPHqS`/SD4O2Q8+5?_EeR}[cd`?,D}.FWyuG*ZIx6?3HuIQ|+NhLP)k98Wh&O($`[L4!13p3x~g6!0XG59%F`gyigDy>gy4qYD3j@hI*@,2!rY#sCyf47*NSzrpe*lEMVEH5SM:Pn@:/I@=vjn6F3OY[;YH"aZMcfCijt4]K1cM;aWf47*N_yrpGNH`(((u>k[x9FUi{Kiis#s@Rc.Eapt&KHKnRW2QtUYLdd.N1~da$}3zS(:[_sd~hK5a=u+r"m`K5ahyAhM@xHE%U*+^6_{%nuvuL6$S+<,34F1R9`I[@~I5L:!D4_;cs46h~jA"Ro?~"b^AM4}:V82J}}|>_~<srRh6v[(0M/qW=o"s:*7MWL1v)P)$y1~jP5cI.5</I~t6n(q>L814TdAbJ0h,Uy"oJH9[8y&g}//5GxlKnKx+$k%Z0|$<pK8n5XCMo^mWJpCZs6:g>(lRK0,ul7yM%_i*HK=HeF<6h9$J2;#dyD7nsRhG/E/TS2ClokL+sfU_6OzHuFO]Ma"Rtl{j)v%|aKRpgB{vccCmi5z5ij#GtOM4dDdwwuGjW+UyYXQ2Mkdl#fclMw!y!]9#]D%0p=!0(=TxAUL]r3Uy*/]dv##fB_B1nj6Ckn?<mRrByI."%e&qL?/g2{7#!#nLsnQ*eltiSip_VY%p3H;y.`[xEs:uj`A.Kfo^}$mUfTIX)gOJ)+]!.Z&p%JCA.zj@@o8N5"o!fYo^z#dtTtNw]m+B?D+{;Bdl~q!eRVKZ_obqQPO_g)(pU.N=i4r6TBeBal~xT<o^cE1"Xf%lhpH@I>;M@gL+#@pcRY8GPK~!UE8D$eZG*yppPpAM3J/Mf3$400Uyf8!m7.DY65(3gdpbz8+14Y3[Ia5Z@<h!G2lANdazek!iBK;7!X#/{aSXae>UHtGHwuV<[o*&paCC<iL+nH9gxj@og|94g%8v3:Cn2YzN6_h9L{qGp9dZ3:/iK$AF,u9%=o0"EXL6J;ha%z=Z1"TpmvCs<ADfo6R|BOb{gInp`CputcDs57_eV0VR)^eaauX/OLVBHy$>n%G|:M1Y}tCt)XhBu%x~X/~<c+P>mmxl5eedyagnANr"zgEIXip/Q`jmV{/qx=4!8e=lIA9o,g*hO{EpF*kXIEgOrEt5"C5.L}"Tau0H4dsT5:]&z=K[+sPkdDQO~LS2;ULRqatAx~7x+Br@|u2%<0K5zXN)H~ZM~[l.<*rrGnw$?o`LQ{mjL7*ty6`^41Y^/zgwk]N+RB3#YDWpZIq1f56iN5mIBRHzqlV7!HxGmggUmegne7S:nry%eG#C8?:i%cr8Af)k|r@Fax[7EH3B;Ek(i`!"VmCiO;fwZG]Z_g}lwveibwCHmF(|A28RT1#hUiBWPXA*|DR6_OHtMhqPBsbjfs.c&v15?V<3^#9TNH,X`990TBt)")|hOXh_S^r?m+qtvtQ}#y0"kH+s&BJmVd,7bpcw[r0,@kF~(Gu%UU,zm#]Y0d|q,;O}cN0BUl>.hFNwP<q$C&$>s7S$|>[[7*Ut_@^by49To;jD:w,/0K>JGw13&7Ve:Y!4Opg:"xWqNX_FOZ>9VH)v#4vm{T]EpY9je!_e3{y+|>1^e_I7SzRjkdr85Rgw}Eq5/WNJDgQpIY>9Qmk#?B5]f9Iy$z9O2;$Nrl[aI`X=zd2zmH8Ye{nwcX2([hUI.$*/>Ha,H~8zh?Jw2/}qTdyGFJ3WK~(GfD1^S.vtvbz|#u8=+s}5/O}EC.~<m2<pk)MiG~_zlcPf~m}UP7pjA@{5x~B,Qw^KYY~U7XWRBMj0x~1DgC^B;V{q~NucNp_H+s2jUqYYItk#~;nv4G$E`:1eqd|ru2T5^2yLsiA$":khkHyEuJ!wMCSthI3I#!9TUVCuBiFc&W(LuB3#@V+su*P>l*sZKx0dI?}Q0eX{|g|(!yLb@guDnJRzqI2]e(xF{,U3>o+X7?5FqS<v#ht<;VP?O0dDKf>pyN:cg=FIMohL<vfZ9ylM@S,9`;ZW%oBg.w(9Yov(aj7i=QYmFo>^Uc&WSs}0m0h{@lR*>,Ga0/{?+y:PK`d{anAseCvw>ugQ]I[5w!_em4hTXymYMTUZ`UOPQcfgL0XZ~c(5(I[R2UWO|Bk(V#pBU`we`mkXxF]<kHk(])3!6BFX*WrHfI?!PZ>9>WIDAeOezTk@A5*lN`+sS7#k4WDFKx9B4(No*(a]=GJc]JwGl]yYjOe<xQ#b>9NiOh/r#;w?jQv"p%55mIP5Gu66nblWt?8?uuZ^+s.Z^>[XgLKxKbr1:VnXL~!NmmP{tp6uEH5H#o$L>UZ;96|>nU|Jc"n+K$vc,c$b}/:it/~Th>cH7@klRC<0$Lk1BYA90y|y&Tw86Z&J6ilZj5+i`h2A4po^tB95RWud|^vLIw,hl.@<KF2u)KV/YY5kPuaIAP=lJaK"~4YU?[nZ,(n^Oc4caz%TWadRIO.Wn4|L/yHz>U{0u#ut2UMKtt"yT~.InKv{5;A,sP%LS)?ucYDF?UgC0XZA<yNBbMhYizi5FjWjJF=E[bdV00TBs4jyUyYdS;U{PudDwZznVBpZ>UCQ7krwl0}wXzEzI^>nnKS5QTT(.bqXv[b|g4yN%pP3kS*H8{y@M+6]}ez$Fj@h~;Xr8c9uz_XT^q68Fjgim0fG9/^>qId5nA)vUyCXimX*kZRJBVg#Lnw,><]t+tWdR;p9&=*to@{5K77+SjGwrUz%~DE@t/f7.#kti6/OsL?m51YwJs_,y:oSn%G]}UY/BEPPJZy9j;Mm"YV>bKWw!8**H|xMmd./msjX.KyOBLb5OW{+#2>UPx#_Jl)5UKOM+!8ScM:#m,P^k;_cFYH<Pv_AvKb;dj|E~9jM;GA3949wmm]86Z_p/DWa0:7e@"St]V57FjlOYyi=XTNX%O@Dh8{"UyUjww^B[xCE)?n6Yubp>U+c;y*Qi:>gV9`xpF<8n^aax2Jb;f6:9RLb/ovrK~uOzi.+[VAsd$WlSGkw[YqJMdypNX@nKgrK&{z(2q_PMhu<)aSDTG7anUWdKK=4%kS"a]&u68YWJgQ[.wWEBIfKu{k>UYVjx(&w&2<I_@}3xSldD~LB!,ekyKM6?(hX}RG)z9fG>n7+$zkN*av1.e>+[waB:9RRcYBFFKqUi*q6h@sjqZaY%j3_:XG,+F]D+EL1y=Ioh+iL4tQmvtmK=Efj0=IoGHeuDzG1i2o8h5}j7asPKG&*Nx"q0|k+.Z0G@m_wS&jZvR9+5LxuWSVMXHCmn+tw#u:ZFDP?b;0|#!fLkXFDFNW9"LJrPGb&HU%!@3rNEt4)88Tj5+TzoEmJt#)+E,hXxbugSO&9mEfjZL]BRY!RCZD+x=>b/fGm^qtMb;53vxSS?D$!oz1MU<>>MXfd5J|jHmgZ)L6BI(4)QwMo~)~tqubn6ewg2Ro@Wc%DkFZb`Ru8PocL0NKE!Sa995s@4W=bM$Mz+wvYPxAMUfXo/1mzqXAG.e/%rO6|.+uZwa&VZ9D3`$xii`HNF"#HnH2p2qT@>yn@Ef"qJo?M.0yq6y+woxAvWz%u!6:q6`&6Ro=+PzJ"9N?PDTUqKM47046Y_cV@8qK4EYd)=/U@&y@L9kmkBj"ZVX_YILgfn@x+6yg1K2*F{/ls}gw4*Z3j%WTuUHJF/QC+8K&YzgZRyLtY"wUI@GfyCK=b%wSXJfM$pd6tYuJhS@4++t6G?eMXVZ243|9Z%M?yc0J54M(W>@)yHOMx&wI_!!#y9z(Wse6.M.bVg@7WHyuN7"xl=?`c)RpLf09MjS.j,mwb2|qN?1)MnLhCgL*<R`T0Tx>c!BgeS`<Zd,t0+aOw4u;tF0[+kc5vmSVJtDQ,eNK1hJ[8qOIavO?>/g%oqN?1nj=?$*[apPV8Km3hd?3|e&LYe<++[WVbUY84(N?1Y@2LmBgLn!$8)O.+|+H,oX:I/O6NiQZViQP^R@z@)zuulNxYf5JosZ/yyX3FylQ+&Or?:y}Lmw{mU6YQ@$&y!MCD_a4)kE4|ITRm0qMIb&wUkK>1<b[z62]ATN=0=M>M)Z24*N[I.b{z]NALTN`[D,4Z!c_2d*R^jj$M:L<H0%Sw*+*zuNwxrITcHFyl*Na[7P5|W@@y.v,30YYQu.r=<n1zJMjC1MKfrzW5dFfuQmoOXR((o`:NALRa1{I$V&kZGzSNteJb@"lVks=/,y(LwxmSo!w.`6q*@z>xLIub$KXmwTP>Rmk+fz/YDJUf84+)1XgzviHzWX&EVs)uJUrz@LA1oNIt]{1pi@kO>rLdfdL5kcHB#!nz>LA1JMBIrFa9[5V,RXd,A*2L&boK9PjN~m`MbOBO_nE<Qvf<jRzLgBJQO>#!b@0+nGCD)q_cD3Mow+/LXwA21X:1dR!i++FMByOB2Z[zbfMow+>L^w.0LD)X^j~JKoof[IO,ZzO1mK$2n,prUwOo:MyN`M.mfGe@2*:FqPj&Eg!+8!0z;zpY(JpQjjSjROOPG=_j48gEE<gj~+LG]X1F`%^&D]i<;Z4WFPq0Az3z4v,Hiw]{D33j9+czeC%~^,$M?Mr0g0~Zilq:Y**LIdUI[gr7K`kL%W,1+6jTQoSo8+lu{CmJ1XfGiRy+IModzN@:rG5je+IMrQyF$!_cKNRO_?pg4T(dfEaRaO2L.T57ci~[++hZWQ+Jp]4!5?CwSX=L+kfWOC]$TjG,ExgNn1[F<}!PHTrz8y:G"XHP>WEaoKec<0lE>1;RUo!q8?OXPF#J*NF3Qo8+_`MI10:41010aI=0(}7!q+vuOKpw9l+N=cXjDw`MNjtN+E5)D3;b`zyNCV7`VdCZ,RT@+cMuec!Dox3q8?^v:LRYP>lE3!_+~Z0W3hwbtwkG`C.LSCl|mR})&".Z#FJQ}!;,^9{MUZ$Lzt%ZeZ{v6LxH_rBs(7=/mR@i9NvdGIUo@MTkfNbOWb`H_a]N"ZQ2MI|32{;1+Z#ZvZMSi@J73*!N~AP!~=J%%Zi+.zsaCw8QnG{/:ZC5`/VjxZLZ9vjjX7tO,W4(k$}jCda;&Onzh4/BpQ"!vzP0Rz]u(cjtaIM{7!n0HYWE~QmNpM=L]{DT0@&zO0kX2wJdMY(j2z7d:cOI^(?pw1vH_a!8ygHu|%wbRw>18y)L>zjb?~IU|6mwj0@xuNYS#O,2U:E3P`)+rL>zQU7K!G]y7+=+ezmb:Qt)RzebHx:GffYw:!RjlNH6yelXnx>534$qJ0{XhD_abV8MM*xu(zNxGKV`6y=t(z{G?5K7$ZftYu(fJosiTl[WAWi0={SM4uy2a9d<M0R,{z&v4E@8PDN`5+rMfce45b$GrN!5{)EMPc.CSW+md<,M&+h,4XlZOX<y#XB}rOB0^+fNBMxIRzWU]1K%pzoz+C4X;HpG+Mg*ka2QV8,P8&LawbIUc@[cCEq9n*3NCN3Ww.XMqv)Iwmm=Q>!P1qK`m+>X[D:RQODem+dz0xY7*5uj?+zL+bCFG)eygzp+Lz{zlYhHdU_w,!`_qjy*jx.NrEy@Gz#WRHNk[FsF6I4)88!!lVTao6._{KQmK%vzSMxaiw83!!hj"+T0@H2PY(P?6ey=$Z(ysZU2TDN%%Mr+CY#tBzt:?M@MFO3c$iK+yyC9LMtC2ZC@*Nd<9R{yvXiETCF|I_<H/IQaXw$N=OFj1Fd?n,3OOhzqt+pz}N~"6?K,_zROb8eK5g"omsRj9+xzn3{&r7ZQR`Zj7yyBtUq*nx"kpEpE4!$+qMyvRR.mhs<})}r|`_NisZyw)YFcG/IwILDgdO_/63I>H1:NjQP,A}pdza9n1iJaDxyOzi_c]b1N.LJQO>mxk+Ka@aBj3BUoj4IM|1maUQ^$rz6z)IOi=1n@2+)z*1~[FNyMG6&+_MiOpA~U|/:A0=pGR0LdnR,W#RP%<bZ0>"f/G2WkaoP0.a+QHWY3<IE0h44E4,?tHH9kdvjKG%6!!y[OzYmIDdU0Nf6j_WwbmcpQ4OPDb!hOcNV8Ygt#mE2=2=0zQ%|M?yoL^A]Ffegf4|vzLr@2iiA2}E}J]M0z*wIZz5Q8W:gfJU2%z|)_tL2LxIGEUD:bP0%h>sMI$!,Z.OaXwKCZJ%M,jzg1eKPQ<2.!ecxYEKC61zhzpx%~Np_#]gFnT&&Zk*5G$Jjcd9]g{K(C[VcEdo^bkz40]gJ*#5~)HP]wuy3@>YeeRW%G7i4LFIxCJJHF0sbF#rUj*ii*Mu=CJGeK`w("!K$U+Ac@GjAwpCzQcu{m(|xp}JJo))j,Kh[$w?H,GGibfX6`@{!*!M`){X$WJZ_cRWfM+0v8e+??#*.*Cx5Oa0.w0H0|`Q8g:QE^8By,1O(J+SK]S:8z8]=c>H%aS6##GjL)Xu.BAFR3AosA]W8Yo6|!JV}Q,i"v_L8eBR*=Uk03}U9HPC}Jm_)?j*g".N%v/d[N03Q<wn1(N":L5fM$hV|3c;716?EwTI$ZuK?QYy|C|GILxpTq.htRf*}GeXlFPGKhO<0?RXCEMA?4o/j=`hO%a*UuZC+Iy!Tc8Q9RI^S<D!v={>7n[R+0wDw1MafGALRa&R%G@XY+W,&I+EphOR_fEv.W*LEvxL31}8vX47YQffWPQ0ROwzSu]2/dtvbaXPd8Cg/}Jl]5r1d@]js1#K(w|PGk[j/bni#Z=yDU/Z3tfB_fvetv~EGfRR~WJX:M4?9E9l!lH_{J`T#X|ZY+g2!&(GzprI3iWzA9[f#u:_eCX2#LIRD66u+Zj+HtRvRD7!7y!tmyLbc<h+[vOvmyp*d<(n]yZcKaJzROITJ0xJs7f;"kg+OwL6#DZQ{6`+uz;ZbNS1WK<QVv+Zj+QlRwtI,yK:o6Rj3kqhse&11?>+zlQ^cf!|:4a]=##!+RUonO]jF,>+9!F0Sd.a+4Lb&+(Z~n0|hD(GrN>aaR>F"Eyzi4YMq0h1kv>KwYx=Sj;MjCjC47@I`TWiQM9+OwhYdz)GVaS!/dMIkyhzcbSYQm9lij?MkV2tvX#!3!ri,ZZbQm9lNIpzszFzkwg<sw#y_L?YS!ii*)QWq0h1!XNjaw>BKE5)[5+E47gs3GOp*aUD(00!#?#nrZk?iOn?$_m?Mwm?v|))k?n?:W))C`I`1~*/?x,i,Z.QLS2y9Y_Mv~*sS!0R1~0R!}%Qy!9}cPwsWCq0{4_/o~2Xd+m;cj57uyiw+~k3uG~]O^N}^aq0p?@/Ov:dXZC6e;W7wW*WTx)4M<eYSFi&a47*@A"B5y2:$nP!s67VQO$,w:LGqJh&|9Hbal57GiF6w1h&Z;mN85?_At@21tPr/dM+F6&#qAq0P)^cGLc*coe;A}5AJ&6@:P8sU5ZZ%,}FPYmhsX~u)|8Pi(7w{L?(ODr5#Dezz`]DYW#p"sj"c]<80EK`)t9sfR|B+|54r~8y]XP;zE!M|70R}}P!_~3Sh]1uO~f;o(/)9+(|)tw~Bec_j=9+,|y#@G4}a,ILv,O!8CIw_)r8t|O?.~ED&>~z`eB`K,!~6B:vu>uDp}Kt}~3/fg{`1q(~`aY7gabDvz`ez`*q)G!@;88s#c0[X|94u~(i=2K}pa(>H58Z+|NKgWr1TEea!(~Cw_ePo~=E$aS6dGQ{_t]}0_RW,KWL4}MTPLBgy35}R6P(E?,v)UTE0w0#9+/|0*&~iJ2ya]qPG~neM/s~zX,kD~"HS{2ya4<+zyq2kh@~0VQL6lzk(sQO@~>_Dk$}o1bMrtW)(hr+["g+eGh,@~s`xa*3>~6j=QlR@9S@h"9su&FO!+<5^}Bz_si<F!utMuHkI)zPc.;M[}[OzEm}!j#ss_s(8:;8cR!?&H?shCs(r=F!i~HEP|&42W|s|6bMR|f<s(!:qPH~y()zb2>_g9e_tYiJW"$|jM.Q7yL/Z}kV<sftfg8`:|V(n#`eO}mjiW+0TEQ_&Hk([FM/w_="w~JtGckn[XT?`OC}KP=21_.tysKnZZDtbM)@sB=|@hcsC+kIGRhL|sM76fm_l>&,`|UHhW[/r(.u#A:_i,e~CexFmBTxzGhJ,j7E1ipoL/3_.t]}fcrWzX[Xj?{7E}j"(sEHRt`~B84*K]mzns#W=spviHD?&,J/].RqzkV]C,g_ATX/`|:~?yo1d`P$h(iF~h2Qp|2B4h;7(hF}Jarsu&GycZjvZS>sFt_sl@&|bc@$~X{BA,oIFO?^iH%}1pQL|xIg.vXL+7^~&`L8Q~zn(sYLee%}^<RLLi{L7,`O@VQb@9j?`e[}IRP4H72yM[iv;|gj5>pG.>wb}r$4r~Elm1ZV0[I~VtNBK}y=3hB5L/y_nw:uhq1(s(*vdGn[V`W;&>kP@9e{jEKD`_q7U(`J/v?D#$@Cj2RmSEC:bP?FWWlXTxYA^2"t~}pNd_6[kBGcCN6Mv@:H6}H4s/g/QQCv~|=M3h!yezX`U%UkH`f<T(p=gX?}YQ#>Tz8Z8|FC(~%[ER:|^ag_JEezZ`mPOHKM4[GCWWUaKc|z9+8|*ARcj/VR?Fwbj~EMo(iuq+1ybz&,I~VJ/QMi6Mb@HwdH<{TwmWl=}s_}meJ)bgi68Zz|*A_~5`n)iW*XTx2u9+z|;SAt^}7?"~^}y4(~S[Kv^k:_1qmWAMV4M?yH3sh5P|5;a#Fc4r6MP@HwV|5S*O?^</J/v^r8d_t`_/f(LHyd}~w`QB_}F2nIM{}lHV[6d~/dOj~;yr3U|KtN3OD:]DSW=FR4FH.]Vc_pvKPdYY(ye2dSNJSj}(3GtB5r(H/a~1F0ZUVD]w&"+Z0|6fA>h`XqTT>}`%C(e@Q?J4z8Xr*e9HQn^*,x{9/1Oh&4AcYJn/7pvF,_}L`L=VmuZq6C([)ER!@jY:*R(]pjxJlS|)>@lQ[nl)W$Y6~EtN;+/5_J}x"*Nh>@_VnR@)^VaEBy1)EMro`Rba<Mb++0pIh?]~P~q.kHrVR*I]gJ$@_D{;v>xh$`ss(FS{ggP/DH,h;C]WhCxl=aQ/@!hNc<<I[+;t|[P{>e=~"Wf]{;0~+94V3qt1etEH:Wc7ND2_=+x:pQX/aI@Zjl~[*413qsKxd#4y^v:v${wQsm^ei<G$=$?ZmJ3NAt#0:tD3?#?ZrKHNpeC5!%SChi|a39beOy)!S!M)]1T;B8foS;UTI8&0ng;Om^L^Cuy)ai)Hp*tP~tSSt1|;y(A&bPdK~dNcB)k>F&H7J|N;6F~dNcQnBfVB{Qd.?Da42cyrM%cBQ_zmBfH7l&d*?Dx(o#A%2gctO1p2Wt)HyOGP6FyWM!9Lp1b/UE*(.O7|b^^;5%cYmB>SgAZQ2Ls8fXz]nbA8H7)uI0<KRRvB/dM!!4YDY2{RH+Ez;J_V{idUJJs!!]5ngD[*PZnDyeWftDWf#9Ylm,7$%@pX+Xb6KMG;<?wrhgF4_S8A4`.>"K*xFgST.:}z:mo<h`qh0JEFAf61]VP5#v}eC83~?f8vUTmP/PDP9EA"jc/t+D}s6&woq<:vFoalo_ZS.QrZ(^85/:_XV|uj~m#;u(nNV/:!_1tUKIALQI*}lccs8Nf:Nq>|_d/9}e%_$VC|YD](3Y1u?qT0m1=ZtgC*H[%Q;(7E7L:3XL>eiNTU*M|zdm|9HIkq[4PD13pNXp34aOwd/5NDmR{3r47~~X!{bah?m`0c^0Y<QXVN<b))0q0Eg{HEw88F.TH2EX9;ZL,UfSX{7~RtQZ.Pyx"keswixor|+X?4TzW_6:#Q%BBUf&;%lnp_lRCgJy;6])HoKJVBSQC#"TV78vla&}u[9xl9`jj[>y0vgFgci(UH6r^ab(a2r?|zvvGYg#09aF*UMmV)Op1w1m/50B14KSL6T~x8?,"5DR=Tmi7C8MKp%k5%JmOX92HAet[53vUUN`/FZx2,9W.QNFCs$YG+bYJ"P@,d4F)f%"L2;lEHDqiA]$=M.2BmnB`O8:bB8yX~$eu{;$Uym,YF;2uSlk|xQsPmRo0q"V[KcXDqII7r&Fn,>vm%3FMGA4:I{rmlJ*)VEXVGebUReo|U`|iT_KsrXfR/XkIH(>ZPBhze!Op.Z3K&~/dYBt#$e]XQmN>:W!oi{6II3BRhm;@_y:H9v.R<RXB5cT/ji[NCWrxuy6U%jSdTY#m>:CY}ei)%Wf,;g[J+RaVm4m..V3:T9[8,]K56WJ#v#z*Kqno_f<e<?u)^jRh{HvuC3>#GTr^2u{~<.79WE.(&Ka4=%5}.CXGFpSqXw!:u9TqZ6g**o}3[AZKv>[|UYuT&;Tj:M|EajBAu]Xi.dBi"u.KBlnJ?y^)NuvdD~!HCAEU3}E}KiTn`Y4s;2j5PNQ=hGFefkKa9)}2g"=|g5IEJq"`l`Z]N|HG(1{xhaJOpARy{=G5e^M"Z)Q(N2V_/DrkLJu</aE>e7,_&UW3VEzk3%mtm5C5[NZET2QOWZ&dHg{I@F(L.?TT]M]8`^:YQ6:}$zz/[2`}qFbtXL@(XcFEte&J0[_x4;zKbJX!AVo<s1J|2[H,@T5M)D_t_h4V#Edm&nIJoD@fL{TgU$K/hL&.:5U(b{+ZY1`L@<A.FE2]G5w?qg1o{xZu#O,pXVlXi}N,eS>oz/rE^Vx%aFqHI6|DC|aY&)5Ko^15UXVa/af0(2^9%[<q{]#y:PuP>rjCekThWOo$O;I_J{L/li6%|dPs{liSQy?{,LMV:v9g{dBlED||iovNN^LK:>Jq#9/&Bk4SEfQ+/ua6rU&~?W@<w&^"AcJ/tIiQ+{xfm>U6G#rKbA_VRb>}?3i]Uzz)V?D.bk4_$M?3qL%G33_Ys,(6`v5mTCv32yfT<+CDt@~5V~n5_usy]S@M[1_4zog+YsoG@%tfK#%+~6!IsxC.=R9"nHCR^1SI,dyav1bA#H_iWDoyU{aXIYAdg4U$QwDr|Mcn>z@lsLJEHDqS1mQY*JKf;!@kzU(m2W`&|E9%"8DoV~4Fq1e3YiOt~SZ!|/BW.^$+0cWgtH_!HZ%wLy_Du?PVulpiU,)xyTKHK)}M.FI6Y9TC@![J^hC!l:8&p[RMR|V8wKSGcVQj2nW~Ig%*d$pd4Q+9ayW@NWdlh4Efr8Ia?kg>G`G{I.Jkc#gl8x%w(/}XJ*=xEw0HAfj8z~jXI*a@nvm?$4N5?keip=Z;/{pg]aZ^AfNh`STQAz0_(BjQ4Ersn"pAFW_cS8Bq3rBzF85msSd*[F*WOD0KXzYf,jVpsC:|"9rTBYBIc7GyM6.*C(Yy9S+y&flSWlNp|1qi9e^V``7bqx!.c>}a2I)hY.M^B_J(X:Lf[#E,~kDDox7j`+>+sgaR:G+<Kog:MfUd0n]}!BmOAKS[Esw).sB;nsHB^Y!0[3GS&ty#ZrW=h0C%(mqHB<p5(FBavC"}GWxDWy&kU4ub+iZC}|)j"l:J.`L(2{S2k[V>YjFWk`p<n5Ye;D~&o|/i|D(sxx+]f2gZy;/x$4413Defobw=SA1oXzRxlz,qKp=z1C@!)#YX4%[e8OhtM|G/3?o6%Z0jpjwr`=!*)P+S/.&dcfWq?Fc}bN(>OmgMN,p#^=xI%xj_J~A:pU="."CuUMYUW{07oNfe32z+%oc([@p!"bV0F/KZjK:^Wt+EogmyX>_`%$,W=Da}EIt>2gz|VMgCrApYV1vWs$Ivzk%rV&E!%B`~5S_OM(_,>EAJCM)Pq<5`KPJx$_X=`FUR5MZp1]GS4tFWBJ&#(~}kZ~%MR$!UhAB%hj)F/,vngT&]]lRa,1uuU;Z;(h%H,<NHE+|$zJ`<gw2Kb*neB#+4bYjp_#@M_5oyC%6*|r0`2[X446h~I!g!8;Jx,I(alP[Pu{kqM;W;e>tP|=Eb>V:Y%6Zg;,4V>OK$6!9B2/$|kS+"*}ZRKBpsj$CC7Ci3=:fD%GYDsA3.z_9Sn;M0cDhiq_p!81QZ:{$1(k,"NX7OqpT(2~)QV`HN)I7jP+D34.)rcM1_dX&xD]]3/tBT0$yg86/1v;I*}EH0:{r=SN2KD=wsM^.!0`}cxV/LOk=,V:o~*Kr3KJEBVV:B`6`v/:X)3w179|V>2orxN!|`Nj|5nl%h:T`XLWDICeXz*Q)ODuaE|8vQKKMc)@jvcMW~zgT6F&r:IH;iX%Q$amR=e;KZsoZF~:_c^}Q2NQNx^&`.E<Vwc:@bi,g%,_|dffMY1OHDVSC*r3KJ1zxZWtSfo%ZaSt28qh.G)G>nQ"3$;>qpZ}wWX;i@EXBv~FzSq6V{us*rOrKk[}Yp!c|.Rv(LOFYmY&3^]at2},+)Z|Ni3wZ6C>0=$FRE07EE%1el46"aOHZ3UM>@/^({TC&By`h|f<n$JgwbUP6gW{Hx>"GZ=%8AFD8>&D*"T=Py:<T`wL)XHPx~/8rz%?sCP+rFmXx$B6.V+4W$nj`Uk}UxUT0yy*O@0rZlRR#m5{|U!{@"il956qz*a!UXf>G6htx;q@KI_!6h`+}jt)Z@c~yAXav,$^zj6==<>Us5N7+Ze8l41P{#n:Lr{!4/m^we@DBtJBXj4RZ:1V3c#&]?:1x&UT)>{f5y&Ta@$_2%.Q?g!T.~hJPnBG>*M^p2HC}>W``(}I%EdqBw!L5<m7fJ{4/h?=t(S(hD&_CAhOF:D@]_!C:s9#m>ZB:s9~_acB"YUXPD?akfKoqO]k_+H[~rFvQst])y:UqA"Qg+])o`SIQC$~<h$jfY$j}!~yF1yS},vA7nr])(`r.,)XiQVGjM%U`&C+T,p])!`l6XU/`:vapJe:TcUa[:,PLAKu!q_4`wpKL82UR,8c3P<+/^)Fm_ZFmN@.NblFmfYv^1[>EFmrUFmZKM/zM+2lr,Sgd&4j)z`qbKLU2(_[}Y.S!P:~~t$sv]B@JCcib`E2.;_#nqJL<"Qa{qCMRbeo3xbcp=K>gZF:D*Tii3r;Engf?6]JsQy6tk2=ws<2@JP3%/])JEKb_Zt5k2?:/fM)|"/?L<SL|1U91y!""jnxDMK/Hl"5Z=5{D;3m]KQ!2,b90&M;5w@Fq:w[vNQF}^F}(;r^5V&ciXL$ab?gG3CzyFv}NC:i,Nz.Z@60UF(#!GKL31UR?r0HYw{RzS4MniBo"xj7[;G(@qyFLE1+`Ay%"qpd+1#l_]>};#;nu)5O<40<+2s{+9qf])go"xtJnWAF;2q+kEzS2}ry+r~~qD1;A++"nXl6x^S6)DD,iFbURTbUYgr+Xu&p=K1EHG%|Paqj32M{PWBDM|5OhHtq`eh/:rnYyZMN0?!$227mpLBvMzo0RbyQHsb8VUkhYMxfV9Q~9rLYg/Q(RnQEI$m@zI:2Ildb,Um|Xu2>+i]i%[P/VLQ+fIP:(gVH$}Vom>*ln%J$,^IFjs4Z:PB4bcSLZxE>Ka"XTCt?`Gas;Yx48)kX?9tw$r%w@viLAh:DVx)KUoJhS?Ln7L|A7QN=jtR@6rb~fbx#pAu~bXPq]$,OFMf+&H?Rm^b_EE~^,nk~?F8&VGXf@(>MU7#oZae=!E3|k22w;Y!UenEMN0Tnh!H0yZd?oV3_cFG?LLy#DTDhMugcflK@WL"rOb;({2Uia+0HD_n/$I/;%}?o7$Mi2MEG~`*G{|;JbR.J]IU4Sj9^mtFN/*>{kZ?r5y!S{cXxc_xJTl`@9;BxL<fE9n7LENn>)JpFi4$.6}tt4:A%WH!A=YuEWX]`FVxHXXbbz_Or6qZ`9:8!+C$PEv^UDHNXTKP~^<h_rni]yaEGVnr/H5;7rY)hdd^h$5T2G:c%Lnvg=pU([,Lq<$Y]abM}V@|&k1^Di@)!X4R*vYwkI=&`(ExNz1G0sCTp75dA_kRZ~Jz:18+J,a9+%7sT9F(rAEI(5CWr#6?|}tg%Psu,nCAv?RfgLn2b4koXLNnG79WyG}7;u>VGXyHwx^Y_]y2E&ItV.`K{`:0{,v.P[wrM&d%yi+^}%aX_TGG)kDiNHo0)LEQz6Dt),}!r~,05!uGYWx,|Cj]&E7|Mw:svlua+}N*c)NB8f(]TL|Am3T&ea#V)SV#iq6Si#IFP{Q5rM)dc#2Zn4MTM1zBI+kSa.$3o7N2?FN+}`/u>}>A&f:xk]9.j5TV!4wHaJ~+;3r7LyS>`aw5d`"?Iv:vJ2_FYRHByF;_~5Ka!_&90s[f:K/j4dG<EbAYLIRn.i=>>rx5~6nUnLUo%|_IxDU%[%u8k`CCB9~NCTny%RZ0SkU9T"=i?!u=am6d(Mm4$#_}L*ue>+Lk(hwLFSddoOq%TMg?GD8r3PuoQn#RH,T8ZtMY@%P3cJUz!U:(%kM3ulz"ei!T{%^[t4V`?3:FN*c>Fswv>f<p=W7yi&g~>jkt!fLBtSVd=(m:&ob3}:?SoFF|B1e2O&W;KW||M_&P6|cIEKi^;#WitV_P%pFv@GuLc@:;B|(^2J(ZwYOCd<e;tjK^UdM8MI,tOXnu4*aeb`_2^[&.T,HW@ziIcR@f.lRlx5`0FWTNW8Y$)+GR|NyA(/Y|OGd)TyyT>+jDb:C]qx_RCg_7/,;VSs_5C`r<ZIu;oQ8]Xb[(."KB_;Q/Ux3^zLmp#zF;Oas.N^^Kwl~0^gD[cM#L6"{}0Ptv:Vq:M<mRrsF$7F8cT!kq"aC.&^+RTNF7M4zGLXBNF`kl~o|1b3>0`QJKk5D#$qK,Vt_0D~6nnmdeu,9.Sx[Vya#Ay3n!>&q[TQ|;yy:#W)y[qr?GT>LdLM!^j9^VQ?($[e+nIQ}.KR%*KeGc+NM+b9V(zNh8}3Iq>6zB%J6$s%W3TIDzNk9!~6+Y_^q?M#M;V.CD6PgmM3!5BJ`qD)rNy{os}J&f](edU=gaT/"p@H02u@&P6Hh8J?>>DH2ViunehRDeYC=hj"&pII`#2/[V{jqS/gFqRRv9zC]6H7Cf*^IgW:f3Y=EFAytgfVn(^kbI9?Q)uzQ>$4Nf(AjE3#7Fe,oF/A`iaE?RIT|#M~&2[HtJ#gmy37D,cCR8#UwB(LAMG7}CWYMc)h~di^e<QSQ^B/&"{XE/slq=2__+(1~.685W@yH0s!E{spAlI98wdMT}?j0@~u]#Ad`Ixks1_Ime(QMDOg@PQX|:NF7o|.l`spGBHrH{SfX+Z8g,+I0"ov&$8h6@uB9i~frdn&8iRD6DTtVtQ"1Sa0a@m$,<A5(1dL*&d&y#l2PnNzzyCHOmWBP$R,u(zAs)qtW/+HH6IW0T9jjxD![xt_a#L)?;R0A_v)<dF)YxC<ic]s_0)C~2XUNfc9!uOIO#uYGHaPQrm}X$1Kt^QOpoU0@|Bdr+B<iF,`/4wVDd+0Cb9^QwjBZG6x@{AgedIA.mB=0Q7#ZC{S+A)WLekKA/M&4gD~)DJI5>1jXUI;6jjxD4bnHgTqlE,`Afc6!{/LtmO=BOt%1MMHRus]ub<&P#uAGGz:cK~R"_aGG[4Ke`wtfV$!u^FfzEaqNfv~xtFpV)G`R[Qev%|gN&1dJvJr_@l:*d|KOqx5_pzgD8LfavQ{|_HAS$TyRYo+ByQ!4})(5wV(~QP#u)yoz!g*`>Pi!(j?+/z"~tSfDsLOM2dsQL~3O>y=aaK>c5ZKfDkgq[/|E?,2:1E6Z>)Gx#u8yb]BrYgPjC:dG)G4WNB=5~i`}zH@b|Qfc1!y2B~5L"x:eBJ1K"`vu#u:4TKArxl1:D{z,W6Wu)KQS)G@u0A~[/..XTP)K?dtNDDmj@5+L3|`JALx1POUR`KDMr{`Rx@Ovo?`/AF)GzVN7s%)K+h!4=XD:OviAfcbGC]hMgAfc$5GX"I40RQ)?&N!wPO*LB}~;RL*]9XhN_$2)`4)Q+,HHAVpZDVC7.5zEiD3Kn)CT7#s1bB<5FmjAK<Z|F`us%R8#(gY(X#c+m2F[aff~WGc+P}2XPLs~RWPL,wt1C:QTCo]/u7AZ&Y*W?1T,obk?`/sxvt9Rl0Yxm)ZMij.ORCuV91k)vW_n3DT7?kC{q]|[MpCTu&kq$)+5>;Vh+y<hsH6WgDyJ[LB0qR{/nQ=*TzqcfXgv+:@4)Q2v|L#upL&Zr<o4sI^/pO1JY>EV6iywJHArRF/(nLfDSJdMo?dRZYnUjH2W#D3H5Q{jeWEu1!6}?G2y|>ng%F?r}mC{ci~3:)A}go^K5{$htY%R6#zIP4uwcR6#";|N~3U]D:;0q?%:.0rc#zOYH7ewOMoA5dbHd5C]KCaw$2IeU,MSi4<+FMpl)N9Wv+2dwjLEm"}eLHxDSIJ|=V)n;baoEnY`rAAc=W}XiX]"yOFwY4@I;B*ZbKkd>E1K},(16z8B5XIDI"R5@n2RF*IY0Cm@`[xPTXoatNwATi>Dj3.qB%=s;!ZEl%`ZlOdk)DtWiGX:EvBwFwYXWBI;58y8ewT85}cEG"|$3aEEl{on`*jXsfCgMu!v)JUxyx([@?:,h"L]4I1gZ?aER}~uQPk1gqA`5:}erWLfZ(uI4yeLXtT|Ib4y[}>PSL&|*W=?F~G88IZ(6UhsS4eFOj@?$sM~3y&~EPwBhD_=DU>Q#Tc+=~;#$(*}D|#Av|>pH/J~^@M4j;(_D~YU.vP]R"~}KS2F{?3Iw~%S.vJ]iHxsB1mIz??$usn$piC}4#0FB:L8X~RN>9A>>Tv~fZJL(56fV!wM"b"o/A`V`c{3r7:5G^dR"b?5uOn|/?(|`=_F?r>M`yTRCsD|wT@@PMAz@sc]_/cJi|CwJxA7nz|[ijtDmEsD06u+TE`s|Ep`(y!0RX`R)BwbAsHR"bIY[/+|RZ>qUKSX`@*K1@8vAQ5Q=,wVq_Dyfa,Iv`DySMN@@1>~9}&X?1Xo_4!Cr1A7uTB}(zS@^vQ+t`uhjz0!+}Xo&K*+$~u&C3:uD00i`@C(P0C$$8~g("svcD),46)G5_pOQW/L6Ms?Q`|EN:zryy3v8Zh|y=)),d+hng?unr"8@O:k(W|Ewn9Jo7(5zu2("Z3EN`@u4p0VM.6Mg?^cZj[)6BQI5V(0+`Ux?B9[d2_}kt+~ORJcLwB"q#(|dCOL>=7Mi@OD^|.tp~/x`~B")VwEfD4M7@e0B%ZORhJZPY]iZ2I{<8e0d[NA2B:pNYR7v&]9m2VH<5`yaZ4U5X%k_w]DcdV?^uZd)wKwHw1(U7A8YD6^,Tdb{py?;zZQ<3e0S$][}`D5&Lh,E3aq=7HN(s9Z2&iSWolQd[MIbd<:>BEM;N[Lh=[@58EX"ZZ&+K%Y.gUQs]Dt)ia{x/K9<u^W?KUu,ePj(X"Z?!W7J5Cy3ZW5#ZMgw;LY3^08`MpT;Hu*w.iG1]d)ZPc&@*`pMg]j4pcY"ZK=MH)gOI%EIw|BiGS8*+ZgeB]fo;7G1(_(qZxVad4tC#}cMYp1rUzOa*5zB%2Z[gnLiIq*2@oH}fH[ddCIbU+[NA[6@V)E`P5wJK1p<4?)3Z`#xcF5]M$mfX%Qhwq_&z+A|G&#~[&B]+pLRJFtM&4efjsa><DASpz/g?>wEi5*ZlB}~^PPVBV1*^mUUMoZsa):46uL#Pj>5N7SJ6bd_/;.11JGj9N^b"5EMMPyYU@x%75Rs}ktou^/|)xM=_ul7g/o.x$NVf5DxM5_`AMf$c!mCA!A.h!UI!f0~B}ry@[2CS<@Tm6ZK=B>$!XOP^MlFNxXIZ7`O>}I!cUDv3FUi*v]W2fBFxqb,BwWOz0wkS!EDy"zdBV>wH+3S5Kuh8`k8{~kUDQYADn(|L7]8E5w~:V5GGg?&BoEyl!XN?#Ni!gX9VnDCD?y|r!XY>:BfmjGMzDc$d!)fJ):w"&OAWNMwTa7Jp{x<L{lZ:Ib:wEs9FNmeyO%_yTpE+?z}oBOu7wVXgJ~G+Eb])|22EpxE}*Cb!M}~oK<.^s8#)bt~t+Gh775bFIt@dj.UFvjai!DYW1nUd^(O5=BsJlS&Ghd;cMZ{_=tKFx$~Oo.]dws.<.6rGM85vN/kS2#6xML"#UDMhJ99K{ncLCiXWML$#u7"$@%4NxA7Q^c%pE@Y6D5TKJEt|wuXf`0Uy8o7[;4~[[D`WK*+G`#~!N=^iJ.j#)RekK}vZdllGnFk6TzhPpq6IAw={>U,%Ql&YsQ8KX6T#FmiewR723BW?8c24MP>5mtN;{oXF~vD<&2Nb.)@knjKZnmBr(K{%(c:EVi<vg4R|=s(1g:g8p|9?3?bW+se[4W0(Vwe_"@t<8Qk(?!y(Of$XWT~;uPWm($!$[N<MAB(VTazlAjx4F~ypJGF!htD#MdmqDPwc=2oKWJ9(9c}$j&~A0c,s"#G7$<QcYt%cb%he&7(0Okw0uU``b=n2CwlKMLBos/JHDd4U%NC1}PX8Pwf9OV~C^oRtl4#FZ3J},!1`~gpJAnJu7vK{2$0ycqIApLCppIxVBSq7U78ZC|a4AUl9lCGu"$mdy:T0e.)sUa.[31%4Mr|?V{HUvAkfQu{{4)BdlNlgws77=Wxg.uEs{ap9Yw{op^Cywx!Og|Q{~I5)~leO|<G[2Cki_J$;B3iuvBaL)pd*WX<F+MomTOgBvs<cKZl=zuc)sw^*mSJ@nJk7yM"{Z!exSpq5{gRymi:#F6SB/;<M2a>N1{4o#K&p*9qZGp.uy@uE$vS:RD>U):1La?{fxScY~v$1b85+p}H[lHl%Z=p`XC,t1%G[N="`"Jt3_*5TYOLb`Y?!KZ_2sYg5L}U@Z/Rd`Yl=c0tC=HfyGFau|kQ84ZY1<M,K|{mr3pu!GN&JjmDclxZ4;~)UXT"4Zc)/)pzc,2Dw<uwmu{ia474Zi}{7a4v/ic!8WBL7ilOo5~4ub(^B=05d3:U1vxakoF`Tb3"8}Ms%#)Jkd*aPcjv/uF~i"T<VB;9dSSvDqa2auO}*"6n~Iku&5"c&`LcKL{ntP|bk*Yi}fvI)c5uP~OPXzqUcSz?sE"N,/[u}8FS[oNES<:KtGHU^PZ^OK:kHi;_`F/}o$M>8vC~j/5&9;k8{ktxNnpw5%xbzwW.4b5o<_XJh!]DZII]ywO68Hwnr[T7v.o{N>O3R+hUdNGWgN5A8jQVky!P$m&6Q+<D5H4*x]Q)k@WZR5]NoIC6Ati(=2RM`GtBXbh77OX`(Yb>SNB7[Hv=(VPC@#N{|rf7UWIT![M_fG[DLLt;>i9VVBt%c.04H=_x]DF%=w||aQC.NVPN?qMC}0=8;H8CGVxU;,5E/Q!8l(=y9Jq@fo$SM`gQ7TZ:@4b_`sbG5<fE36HznGRsKb#hGhSP/:wTpWZSYO5z!)8^LiNz7x+oryNq"@=KC`DtI[Rb3woNL&pFq0TZe:wclipxj}^,|*FHayjtNPOa91UADRS*YWfo$82CuPm9!g3"q.dXyK!_l$)&LB$3UD:bB0E2k+[,b+GpN(M7b*9kbVg;7Sie:xYx~H5L5FsjnpZ*%RGjf;C>l,SGUtT$!w+>8f27ylB/F9x@o4CJSVam`}IXsXL$tnM9?5S%S:p=i|9."HB#7CM%^9D<c2GKp7IXyV.Y7uZ;sPJ<eQ{w(|(qV?AgJ(:w"u?2h9V;jtF>D&lMo8+gp(yck9*;4N7j#D5bK:<4=>*o[CvV;?;YjFnbZ!DyWGV}zNb)?{]||sdff7qQ{L{gXQK@(<NQGx7`y>.D(oB$b)P#9a7<$tFa&ea[U=?9d]5ppAGyo(xK5[<ac!mE["{:w6uSj9?P;9o>%_nV|:wACywLNLg%UAMNp1_y9bOt$SQ,":gPIXBIG9`:wv*m0~906Hpl[;Z(X$9EDGxvd6ke4YKGDzA44:;a@HKVwR+PbMBNZ#Cq`:wX77rQ_gz&oCItYuHs{RD)<x]<"(#wE{EXU)r1YL!jZ,[y(ESuE:dzv?&b5<x@;BY99B3$!ZV}F>;^oIhrSMoUeByw])60*chvPuN[Y6D#)$Dkq*a49;kT0c)XYv4;JFLz",s*Y>GLADz<6(Jjn*_p0|S+nZ8Ge+"6%@H~wx0V|vxL5GyD:Sg<xsPxzLV}SSDucGVDxg2Q,<++[d|vxU62[=x>Z|SB)XDs_?;``3wqMEKk5jJPDhemVrpbYuBeSKSe]BJHEur$(`mYErcmTO)&xmAxN#[Zh(c7u=*gjI8bC&VN5fl@={WzLjn|Xw]B2bPp>;|?xdv%{bZ;,TTcF>LPL%r`Y*dohJa5%.ixE[tk,"<yNMEUAjj;#5aqQKO#97+4v"!$m;lnRst*GpsKZ(b6K0W29GA1!BA<v_l=OcVWwh(^#/d~I&I(^nK]/kjH@<iCR]){D[_zsvP6c@DUXK}P0Hz)Np|0ySk=oI{KU"%jP@$Y}ZW0yyiRvAz1$%x%D4(^;}`q_P{BA(:r=Cz"Lr*0~$m9d<wQYoPxl"*CD{]o*Hfla{qyVIn%c?V4rh_*D9B/A/5BHqclUYIX}2P:`@J07JrMHWZ}C=9EhTTVJ)W_:D5^j*##sL+RP}|$Hd;|LObH[>"u^d%vOcCs&f[XL_PL^u^ZNvnXd&<?*+cQm4_u^[*}9jD{5G>{+J}5ut{74PPN6^Wq{mHmk[[M~tBTt9Y2s,;kGs)Wc!h0RC;V|(oU&$5;io6t{](Kk#K!jU&ezMb$5h(6MJt:i$ni/&L&zNKJD{]E5L|{J#Gh&]/jZxcjtM~AI^R|D+aDnhjdO@Y4raZkc&Q(j.z5a}4X7Sc=;BKw0yOJYw(8N"?6FfCs{Cz1F=M)Wi&6?tP<6otM~(PL8;SjcN>1/gT^??&O@f5OC"F^"odljK,(#?;q#,ED@}Gs_YaRy%[j~0y(5<wzODK$9Ec1uthehezB(lXtKpqUN3_u)r~_yA6lsp54!k8KB7tY@V(&Monp,b&!{x,r(|c^$ivUQJ#n)SWmoc#3.WM&9o7g"cVhkO&m`End#5x(E*Mm6LfEE19N!Zt<@>>!X9#yPxBbW6sBI[T"](EFs//Dj8hGC*KV%b,sJkqGG@&iyW&GBXKZN0*iv@MVBya;&jP{w,zjf4rqZ4GDgG2oYYyZ4n.?w_l_cCDnn|R2)LA/dhSAa`lz?Fa^WE8aho!AGcim<!Xv5;"0<|QNQXEuG.!8&:M$o";6N,_xrRj9H$(RyJBCH[TAWChPH!Wldnh_/Aiz1.!^_6cQ"Riy`IZ:Ikc!J3j,;3?86a9>&;5<L9E>c:IX.nz4g#hnhmzC%1ZSj,;VSN)pXtO`]nz^a:nka++lSMtBVj|IZ8y|?6@sb8/Hzs%~_Ry6Ow_iAXcL>O]QQI!i(;5G)qO0)Jg$6YLvLJJsh^c/P)Nc0D`#x;R~Np.Ry<YNB>W;ZO_PRE#(anhpGbT+WM!_q565wHD")}#7Lu>H1IAO&:G214@H|5zs{KU!n^(KT=XoQdo~#RpPLE3.bj&}?|R3n(?ta/D7"80iL19$B73ML^r:Zsd7S"_WEpppOY#Ru[&^5D%f5f/I^:JUObI)D"f*3:"w{COW&&X+mX[([|#Dzq=)6XvM&(XZeQXUd"P7qAO_,MfHnE.?RjKKr:Z9Gn*[o64"nFDEFm):3`N_|d<}ka1_nJ5E([&A6eh!Syaq@I3}AR!4w4Vzi_<gQVzHhBo+Ex27`{N~8>^YE};v3cFX!SP?&A6"+"t5[U:fU`o~EB`?;@5$Z4(wJA?XK9WyGHE:;M*Fta:5Nhq;673?(Gbr{Dzd<"}|5X&9`@o([EM4V$rLT.tIeJn6Z%euiI]{NnGqV`tf^x$?tey;VO:cd):y~AE!BDn.PxLXi5_7O+lRuEK!)?UVdGX</.;k@IbywwW)_&.JI(,]*56Z%AzLYB&09.P5L0p>>cdi4VcbuZ@D|R,;(Zjl|e0fj3Z65csk>:F1<TX,&I6L]|xNH)yJq]km)8I39Zwp]1*wgy`bF#}E<rZ]l[7dl18a=aq7CG5?zb7qp{d0,|yMcf&pdxIF[9j?gVcr4VXmZGnA6B.!yhrfaEz"):n~VT[V0L)l)<&PNjcnBJ:"C4];a!rs_o93XQtpP5*k8SPwe+W/&PNv"Rdy%OyOr6Y0(&@>;+dTc24KC5))VRc=BF5&9xO9?k0Oh,[?Kb(jM8sva;>"H|f!CC_{Jd~tcmhMdOVJb.BZwchH5u{1vrIRu1E8f=Hf%y9vLVzcHt$}px)8!Y6Knq{Rn0/m!)]1"2ui<>WFr36rmZ8uvv7nCBwcE$W,>PK#7`6UhOlh>nO^YilKXMIKtt1K&O#Jq+nSimV+l4J.T`Ab)MR)B;UB~3=7(D~vz=>rsEP(hY4;hinicyI[XrOfC?@U~SHeCKa.sevA:>jd3v~=?>~SNl~?A1I~~+ZUvFKTxmZP}g_d3:v@D8Esk?r$2NzB,SDV""N9OC{?~j_PR{umoMGyl5D*%QT|"D5jiLaV1ax]SrOTyeCwS,=MwGMHpg{i2}>aUvCBiENfJLj"rRBi2)KK+dEv7L~g4WZ[fpe"ZX&AE*z^^djagT:`#KrwGr<I0JZ`tk)9JRMEa"Z{%BtQvOYMBlf.6`iF8AlO@}+jKbGat~Ox/1k:ZX&wEjou/+VFzp=@zV;W0vrNA2?&2hZ7I5Y?xsaj=NjtnLIpE/t=DJNue}/Bm;A35d5kGNiZ#Rc37;5[9i77!dpdI*]tPOe3UwG"P{WSWKFo:z~Jf.txM)^r47rI<OFL5RGE5}jxM|&4Uq*{=xD/z0|/wb;&:~N1Jg|*[.rp@Ncr9nO]NLPMR.gkAV,yIw+;S^(ELI2y93,uNuW+(VUgJ)Kxh>0/4l9+BIbS.P8YW"_M"dK.=qL]WL&Kby8.1.QrMxb0w<1jHDfnBg]b)VI%Lz!9:K"(dY#3kws^r_fdc;k^h]A)IY+@#IB$.pOY<i9DIN/(nVHc;#dD9OueBt$cQ5Pqm,7*IDcIAyPcN5xB,^%a)UyX_2DQG,gMCNPcETns]8JYV;t7IWF]YFYWB:FF~4?f{}wO/xE_{EI)0579TcW6Vk)0/MD]eGK8;Q}>|cPfu+%huI?>2|by:%:>eu3WBG[:alHd*MIYWxz/M&?0WMRYkJw&B>50yg$S*sIdZ`mCuUKmC|aaZF!KlGr,NcK9Bn6+_7VnKGtLWBG4HM({!(rkSbF>U1?8;tb//ixtOXe9[@bKZorS*2GOYC|J0FQ"I!7[kUe,XuW_oy,1tzH8!9%eJEBDMgf_:Ld8ZVO494Z2pm7u/(/J)Heu8kH4:yBHQ$FlLq%dzqt^Bns^c)/BmmGm!rY`YUTPH49%l1D)Uh9!+.g9<9J|I[A.72Z3{R!hF`vtv>aE?gm~g*YR=!M5Cp$*A,p!Y`1f2(KQ_ZI2j7:J"N@Hu{FchUArwm6]b_:d6[ZAZ0t2&Ywav`_1%%|bB`ahpf]+tVyyTs7[m_RoXjCGybh!C%u|#tv$q<0/RRB@JVP`?ZeMB>]*v|#pt%F`7yZJ$5E*b6/3f{MWwQMbc3ci>|a%u+gLwP)03g.wl|qN~.gv*z%Yu:4Q7fP37a7=sb*@W7:bcLHhGptcpDN?dB873J#3#nQdc@/qw?pxWz"hYfuW,`B`W07.[upBGKf0cZ<ki9f/1dJeJER>ZFU~(&1&T_H@aFY$!z62Z.GKpKD%+L:+:LH6,zcNc(=G%O0#_(+Kw~30iE{eJdJsjS>8&L56ASdR^Y;]XGzRN+xi3!e_u[dq_%#j0&tP_4.<N|5]{BbJ8FLqtaT;nA91/0|hTVUU.@Ve@Vj4_4H"*7S71N,1&XQ3vmxx|:w4CHFeXeZj{IYVk&/^]T27O=t`Yd3,g(Gb![&aMKJ|5+WsgdykKy6nt5&ck0Ce]U]jl>|(AW]=*LkZBp:%Eq=npNN=UNxX.6q`%V5K7Z3PQd6vtX.hlzT8f~D{PGT~,GU)r`Y(Q2]LO7]WGFRXi8x@=9RD|FJ+2}m?X@$Ed=;QHLH`H2(6:1`"!cG]}Uyi}MM!thGn:%9)yG0?;e@Eg0ku{8evEc<eJ;?W}[AdNW#6R;gi<O`I%99m70h]iYxklEXIYl?q_ML|ynV`,[FK[.OzUow8&R|})?TqOb760xmxL4tM~A3tO+xpA7QHuFJr7:&G@3d[6pL[Y"J4#[Pi}?U[n{Qkb1=a=:|l|1/26q@"I{>fi=a_08~0ybJC.DL3?kz&y8Sl_zsUwWRm"Xq:;OhhZS}`;%:/|fl:4Q&`t2F6q!h0Rm+pDJ,>)jY>+]"xPs{]("y24=hxqb68>*(crb+N2YZxi=`%,%F9v&|ZWo:F6(pwPo*&m:5sO%9nOj=!@(cN>Yi&u?h*?!X)C:qoInU09UZZjejV|_yEejR9{e]CJ[43D/f`lsUq2NAcp|.#z!Z]inhhG:CgT6)K{O.nO6/%}<Le/K3U<ltBh3kaO!!&9TwSF}X%Pp`,xX*aB{;&diNRvNCt*qTF)lh&l{]yid8rKd^a&KSf+Y71?IZLFNoPCj7+J_pOk}i4r6ZZM2b[QX/PU>L*a4O#9q7Z.z<KIL@Y3*TmkGU"f3B]Wj=.I[_5b,=LfmJ"fL*pZ`B+kV&n:%S4{1j"PfeOD.Y{q.;,*:+Rr(^WNAzUXQE=uD|.yKG3d1?ta$2i"L"rQNx%Su0ignhqz`(R/3rZ*kVMxhN7R<;*:pUBJ71,q|6QHdNwDWr9?%NPj7K1&3MWFa2;*:3rL7]2kJ(n`6`8w6c?;B{QiM@.hKyTsgAbHaH>;5Bm^z61GNh0R%9/[9?cdFfgc&q<HZ~]j@37l`lSoOZ2Uc8VqeZuIkn1?cd20VdTXu)ME1J;A66%9vO&d{+V*%`#FV{[AySrpdYq63L|Ln@t4"cHE@0qpMb][tUC&EnNidiO5Crfa$R2A;_7v<x~n9R55:;vS<0ck:nP*OX]tk1%wtmnGfp]PeoX{H%nPxOg6G|5pkc3nsP!ULmNF=KuLO&{iNp/:dRK}v6)oqS[oGhjia7r?O?qV@u]d$Lfl?P,2W{5+ZUeeo@29S!K1hR0y,lV]23_y,_H>yRZFu]#aslriZOeGzgM>5RZFGd9x*xxc$2<@pNtmTC_4=|<pc4;.C@MJy~y^Jc`y[1gnF2!});1R%j!>yE_%s)YCL<n&Ofg=0HaFbt1C,c8gY=n{=$~9:J~#k*`"$m(<9{^$T&?6P$u^,_:y1L8G;<#{i|HWl(8^+ngqp==&bun(p?4nu>xQ`]5]$_Hs"{eW_[c?6n:TzWA9$l~{%;S?Sh{Eq`I?xnbqJV:&fT9JJd#mPD{>pnI~!m[do``Q3a$,!(;>knV(1tC[^$UclPPW"Z.TEfbxgEwp*|EQiME7}=gh{=hp&20=|n"iU|Vuyv"NjGA{#ois<^[)|f4&a,1@U`GU.}78zsbeSea6pddNBH]v8*?$~uU&>&!~1R^F~~6m<xM/xq?;p&`m/.0y"*l[W+A"$7)Ij[Y?t~~{w!?jt`kf#X5TS;~s][!ep0f%k~KWE7or+K+TRf47D)4?Rr(.[sHii}^J_b{%RY"^F_L#eNsG4=&pn3}xaFXu/9SEPw^)o?6_Pt;/7)k?%KIhn>:Qcg5n)$OFe`}VCVjP+C4C}t"(~>2Uigq$c617d]0U8b&6zF%BF7Z]1%~b>r0@Kiuw_CArUqlQ;eudG;lBk8w"x]ieV)~>rn)Tjg"N^>q_ZK+J#7TB2%7}:V1]unYqb1W7cK;JmCc{F~yK&,5]1n,T]2p.o.yHptm_WEOv0*0DGP<8Wi(WEHpt9kdXw(H"*Ugg*Bi4vD2")H{W9M&")D&WEH=J@QIR;js4(BZesO}xfMKvA7jf|[`eD>+CN?Fh8(?DNX/OD,:BKtWeAWipKC@u`AfR5u.Io+=htDhLB}1O:Jv>R6<}2}Ote((UU:$`BmN|}~RC<$EEAi)H&4.OrDk^l1h&z*VQX/ge<!{uUDHRJ.^vbPJt&qkuqnqCa/UECi)H{WZL$A}e:V)I=)%*6P(_)N3u3uv@3I7R*r7n@)b?<V.M9vB+&%?DRCG<^t!h4o^WYq#"(B.$dS<0ydmehg`CiY<c]VB611&Tap*Q4cF)sP]:5B+iGu8O"FjH(,dB9~SHgW8r`B*q+G[2nc?VL8qNM!=gTfBJ?b]C@$7PW(=hg!1d~z"OYD=G?o$(#?#(}0_QbOhYa"lBP;*b0EGPev.>s"*dS5B;YhzW,bkn}]i6=hKg|O+O;CGOvO=>n+=&HORtoIi"Mc4WXLAN]5.M@~oH9WRBd8/b|Ont>vj_8hw1N|f_l2MA3}Q|lC7sX"?Db~[(8MUEd]:&z)>Dh`f_8h/d"fb"w>!w6}Q|&bbM]dm>UBOaaN`V.nD:qb*|MYHan{bRn%onu~zg6_79dhuT9Ou@Txe/zEe}_:27,~qZJ4T9L/j}l{[sewTks}#68>Tbku<<0R,|IX:~;Rl1p^z<(}%Xq(>F%af^EJ?}ht]sZp|l8<JSg|!N!s&a#h~L<2v][Ck|{#X([vbn9Lzkj|7S5>GL[XF.e^#}X"dn.vOjK`:^fskMPq+v&H*~)_!~2G_;pF3Yg.]|fs=BPqv<L8P~DSpW+Q~SX^yf3sd/<sCeL/!_FaU(}5k%3[eD*spt+C{[w9C}IX(181iXKYXWJm2Pmd`V!ZC6RK_3d{2QtfX%LOu7OcmV<XmAMM4C?rYG#fiu9qY_O0v!$KO!?#>4OP~3zBeJTe}qHXyJb7o[Ff(BOYgRMp|3Gj*0M@!SD%^iNfSl`@Nyp~+0UY8b9{`?GxCULI|i`@oxoEVvC)$DLw!S"MR1m+bY$iB,z?Rv.I+{Ha)qHsbkH5bc^8?rRzEzrp,BjxR99d%5~#Fs_pF@_1kf)|gM;L|]Ga84|$=CcvFs}dqS`pWk`@(w+y*9,kOZ4O2:;bom2j+IEt!k`@(wwcM1@L]iki0IV$~Os+ctm!r`hY5X1M2_1RRdRyHw1a*UgR@dcY<k@bPtg]f%.JXfaNgR*ugYXuy"&V1M1:Ej|K{)OMgR*uCSB(T5|L>{}4n#&S"5#e#6M#r`_vHM{lHae62|YB1u6)HpBB?nvo2H"b*5{[WP*?AI`xt&Kt+>1V]vNtXQ|Jj(mBK7E".F^PL0n*]"Pt"NGUXUUSo)}2^z.8ZkSB_Gv+W0+ly,mE1/blfl&1+_h/=,FG2xlp#+,!mMHH>6AK+SV.*6MO[gBzMO@Y*Qg?3bPtLu2ZWr_H*4U/7jX7fvR22b=BYf)|;LHM|]elieKkES;Ct;UBeyy@/YgR5SeSAs*YwdzjJQ!J|<~c/Bbf6A"bVX`/Lk:!8x+x=Hd8o]8O!PQHbB`Vn+S*z"fdUSvf<Sa^iyX<7#8L&K?o9FN7s2^c{%wVgRANeS#1oo.@8:ns<;%Bd,vnQuAs*YA3H7UKIeC<qev84RVNnS@*b<S](}<6c?xl,7TP~3Rj+5@=3ji9i1MYAw~p<Yt]sO.Wd/~`&J!F*MeuQJ^!S{;:zSjnR/=,ZK.y*9hOxg8?wJLv,Dd.#D.,uu&f)|,XSzrp9S,/Xoo{xZd.b,sB<#nH`Nvam@@<jYaE]LR0>l!p"t`JVfrE%u>*7`Z*gX5:n2K!{U"%l?+$IZ*M`"MC^th<pcNA6/vVPNke`V<v>P5P<CjbbjQ)olytr*i4[1!1?A25e@pV;B7K4f+,jk%Y0R`/zs/Rv0i9NBO7<jCdammGm*u:41"`MLW9If"+34_bdQ3X1c<6ne`Vb+vZX})3Vi&Azi##qEUvU]?TgRN{dSAsaZ/MzAZLZ2qjVxVfIwb5dv#M|]jk!c*%R`/VQromon(jjLR2"`k(naf(44WHqL!#GKUaZ07n+5M~^>1kUZ_2IeqDT!ayQF(|3XDaX}zY9Bp|jZW#6UD:R<JYA#r`?u#M{l@VAjFbT"R7uBS2hoYB`V5_/5u^>!IA%DUD4z?:^2h)7W2k`@&DPY[;iEy2]LRDLOcK!O";Vy.h*7[tB(G@Bz`VGRb,TEb`5a+eP*Vi:s|$iEysZL>9CZBx)n9e%^Y(B?|f+`?=Hu]eB1iXz([GUWTTiEsGI>AB]$QLf..13i]Zef714ph4uyG[+r&sGSP@i~7&P@WU@@yggOMj*|@pd++>YV&shRP@(|JuQLUx4=yKNxaN^MC}IwY)^c)XsI4gCEcmnGra$URf~!EmW%|H#f~D8Z.13D.1%Fuy91klRI:Z|[fM)~w=%scQP@$|8lQL?_C3Afltb6_KBsnPOj!|5eQLW,xqR74gJz;56P%siOOj7|RW@z5|}RQL=+_Q.dCGAL"vGY&x91"j`MAL"v?K[CR5#N`&"q_sP+fGzP[Mczy25{$lMha^6lh(rK{$n<P(lgCh<sv_ZIQ4#))gR9CE3L?)PQR%~,^Rb|Mk^;q4&H=?Y19}5_n(*,%,[n[$hWRhbZs[5&pkP:ip653}2HuC(w>,n~FRRZs|=Z(&">yl/eUXcTpp;_`#]]P|l?]]h|vR^]n|!0^]T[>?jh8`5a<sE(0R;|x]e~XD}f@`,gniL&L[?A.Dv`3/r8o{/Wx~G<6oj{6f)~z#h6A@Ytp(xPzFOI%}OPQL*+,Im~VZEY1L1aDlC{Gx2yk|oNgW}y+h;Z`wAW@yHo.}qFd+J`k~fWh?E%<sg)Z+_Q_5UKAW{4914|^E4g!w7Zy|>mjEFt?HrOP19i?ctZY+G`5KTLr}|@fWYyt"b6Bp"`5o2y)X~@!c(ZY+A`H$CN2,dRr7w8xFXl>~HwcZ#Fq6Oijsqyo_H>[@ecs6:m*2@Q9u?JAW4y;V3Fo_sWBBcQXYD:VmfR2,)Z|[z6*R`,}3gcY+TGY%^zIaaf<sZJ#REpaYALQR4.kzqo6N?MMj8*Fo+%MaW%;zTz=jgG#LQjX%;zKzvdAj,0TmAecQp@F]qHnIV[Li#;C45aZ94g@+E6BKmW<>xqj~=Rc+`_SvfWSE:h<+vvAW)>b<;sL(0RpCV%7zozH`.iP1<t_/N>4yLeX%7zTzGo,dcQQ*+5g?^~<xc|l)W/"FcQ81^/c~PoHh}sSO3G<FmyMj?GAYt1[O03!c?JD0<ou&B."1sN5IAL0*af;s[UP1.t_c8|R6?}uz|q0.@~QoTVgYA{V!E.?HAm,,6xowuyD<gyl+6RH0Q+/p?u=hpfPvBZj1O*`,`w^vd1{RPYp5DGhOl.`V{,DG|$v?xZy|oWU>,I;sG&`T@@Cw=LMjOnYN1auc~[6;_j;Z<o*5.5[alWEe~@*X!00!rZII^}EBEsM^+7,?ezR#t(kI#R`~|uqWh%;h}1VCYLOBW]|4KwGZWLrO~K~~/!(hZAI~Y`k~5WCb~~DHBA9|fA%|wNgZ#z)h[(`}}t87W0]}@t!H(*7MCy#$dHDmB">2@XSv[~$y+~uHo._|EB:WX$FO(HtWXKI}2<%ah<,,_DbOMjW~^6P@V~c?c+@_MhfWf=af3KEZ4s$kjDcQzIC]9]KS}y3K{Q}j0KTK1|ZYTQTZnvF`*xG5q)/LcHjtQ.qy5yM@7Z}sP?LiI]4xAW2wm|x2PLf.q1D}wIALy^Z&kWew0R%}I;F7jaoI3y%{R"El]}!/3FxFK~~.Kc2e|}OZl1uW{`:HfW:&m~)XkIH70R$}7)YC2,qcC{@D/e9%$a~4Qd7[3g+UasT%+is|XSRzmR&{~sc~Q+8FY;xP#xecg@:js6P,<)%(4TRkz,x<6}iCTn/I7Y)m~t0R]{4P*`Pq+Hx[_|Kj+k3o~tXY<4)$XLx.+sQ*`$sQ(/;8D(Q|gMLI@[0xesbcy>XI@[2LN(rujrCbA~jGp>^20v8{h/A=FlU[A+"=}_0*O(g7ak!6=s<>;s)[Cnt|=EY_Pal>}_,_ADaL?&S?&$<wa`:HA(,0!Y#*m{oJ<{m1hSu+T*m.ZET%OtW(,M4Tt&Pz*El[0xa|`;}&(Uz3#gF}@K!&f"(sGRAZr>>yigxHZ{Onvip/KXy+8hbey[WR+b"zO9E8XY;NB(b6DB?YQ@LEHs|_JlVVJL>j++m(f`a_/}F/axT_~1JWJLdG(&5Tqng9+I:2jx[i;T4TO(o1#}*5Bdl>jKko/}O^@r@xQR!cA"D?U_$fY_gViYYEfZ=)3oGBvg`BzyO1JSTxHRF^<ssgL|Jq_@B!z|1Md_gXG#)HSWAD{u3oR{!m|!Oqi9JS.uqx.,3hQ&0}$%q|LRns&E/&C9[g(PdGQ*[&Q;`Cm}f|7QA(IDXq``W?|I0sJ&FJX}5_9e>&,@C+7h9s;7+{~&{(($<wSt7<g|31*I%I+AzkQ.[Sg_enHDmWZN={?(vK+AUxqa#r)F,$(br]:3M(Te7Y#*I@BCq/8ha4H/|ktB=5M_=&h+CSce:=,I9`[)8/P93%oVs@day<i8^^GznFB]li](7eF5}]8|MTyR!cF5c+qyy,t_<9IYy[G%Pg,$Cve]FGj!Rd;2@R?n5Yls|$5TO?9*.QT`VC<r2rx<Bik@PI[&:|oiYx:}LH`|xeQ%7zrW8>8JPG7RR^OjU_Ah:@;Q2~QZ#rwxY^(!FOlHA*kT6DbjwE!|HVaKYX[p|YI0~v#?ULtLU[}WA%O#!>W9:2?GKu5op|avG(?@d?#op|ynd_?6Q^C`>Q,B7sP3W+CahW0o([7gCo^S23Wrq}j5FR`nn_2y5Y8~l,9>8(L4K,zrEt,&TqBH(K#|M>B%CuC6Wr!}sG4RnRKOm12BYF5O7s&tuswqXn~_8&&tuslNN$8}2lE%ko":5&+|.yWih5yuL|)(M|EFp_=];vuL=u.&0K.@QCB~>R/&wpbjoEA}[i2>T`b_<R`[34M(jYnrVCB~w?P}7gI]]S/>XIz}iM/u^nF">ji:m(/iLqF"k%+`,&w(oCd~og8ITkM1tgL=}]E^wR$IYxU$3y{RaGq>7!aj^<O4Z9Wm^&;)($`*736fT({*&Y#*(3ZS|?Qx/?en%[nW}$jk#xvK`qmI)3I($N4=62NW{Q`ne40}d}HV|(1|;C7stnmpWR8~CR`n")b~1|HVdB6R/oasW92=+tK/eU!fOQ+Q>rGD]s5Vlb$&2m;hUx!+mqVERh"hOITkfWT%uA6T3g2+@I(}9z<|egRD+o0Bne")w>,Ljg7J3|zY&rPENRo!7y>j[/2^<.8h!@scpl6Ew*4a~%<2kF"(hE(|ZM_&=kpKQ0[Qzk!]%>*O?e1(TL<}NQDP@R@@OzDln.QvC?FD_}w"Xn:0QICMq.MJ1sTE7UbMq.SXQsh:}nBGr~Mi;C"5o>BjQQ6n%[:HC(S79Y#*/40R^?,c_}SESv,`J=c%o)pv2Xvw?^Do_O2c~JLcz3GS:2lk??_oc~s(YFvZuZ.LPez3e(J1bQ0mE>axbjgEk|h3e(o`@Axgb]7g}$;lUXI&]:EJIvxIXiksfOW_u^s}Av0|/@O|24z<LRSW*n6WoCzr^.zp$rHE+nZ51_ch`r|_CrlR{V%,.w;sN+^&lMJ/J<2TnO@61_DM&y$w.lnDT%guPQUJbj[xT|=i[&,EW_WT@}Ij@v}<c_V?.@!EvssDHVSC3+&SE}?id_ViW_^MI]gF_|!Io<|MK]Gzjl`RnRF9py0ET%Yis>lP7YflO?zEg|tL0EO)c%p#3$1_HwG(tIu>:#1_(<o>koFu1&l|iM.%lR!}0}en_reB{vTbMRm.%EDoL$S(@Kn.x*MiU.S(f|1}bAk``I,}]!0r./Ah4KdGnmVn8^J1YJa(oC0}q=Pz"`8}.Lq>uQN|vkhWq#~F7nM4"?8ET%/>9hvgP9`j2+6"k~Rzn>5:c_Id+}90~L~,o_?kM)NI38Wrf`s^PRQG38_RV?6T*[<9U!+oP{h)+<SrQ}@T"(@lz,NIsNeT7Y7R9(z~<kI&3>e(wR8XQ]i~:<z}T}J6rbOQbRT%#};85rI9ixgE?~diq>%2O|?)WLy>Xgt*MW~~$+F_,@9*^{lx}]h_GvAj>i=T:Qn_05t*9>]kM4Q`G&c9c=lxBH25FshC[Sx*>.f.9/0If4/s<$H&3>iseBDY=j+tD1sn"Q~HG*drd7iL3W{g/z~It@cxvjT$hl^xa.?yyKEDif?mwQ>WIx2qDX3iQ]LH&gxT7f#eyGl%HfXj~w+InEq)"oTV=x)}/57WNl`k1lVKH?c0kUI7F8^4xo/{@LySAeoGX57!/$^(E/i%}GV_|_hx`U8~_~PZ=F,eBe.&32PlVap/RSWd1j@2:oXu1%r+z*OL:/sVvxA}r5fl<YH0Wn[ccY7d*taszv([&K9mQPmfO*?rjckH&4]$A8DEpLfGj(<~R4]|&D~UUn:/sV~z:x"?zKQ)y(T(=6o]8.qC0rD[0.fH9MT(BeB8*#.,}==xA%6tK#uJgiv8[6X2[ZH)H4H2XUcF={_]1$~PlbVjTv&!)tm>#GQi[j?z9^Kh1*aja|pHc7s0qIP9gY;Oe).9f,1g|u*et0x7OMI1oOOMjmqvIO]"R(uT.z"k^NkhTN%!&Gx3%Z>M0?GLYzHU/7T?6$[5FN*$(f)`+vQV_4y1e=bvgS7D8|9LQDxIc%oFxnWuB`#KQ)MV&@x(d|^xA%!JyRYnwDWc.Y&s8FRtVxY!DES":C/=D(4XVj%*d,b~yQ/?,aJ*U~x[W(n|W_8^Qn]n[nbnX]@bDkasr{m89rD_Aq#ocM>wrFkhT%6GQR!XO|m:;6o"6TB!?DzZrS7sc=h>sCbn&WEH0coNNW?G:ne<<|zJX<iC(#J?MqM:{0d7$ryDWcQzn>"F5Lt?z>J?zK^L1>;(>JM)}&IXdS7XVO1r{iwJ;4jkTvq+(HpCrI,(y{RE6nJIt?nc$4.YH>{zqNIjcna3yU+?ghn`aI(r`"IOjXkSeg+fM:Rz{b!uy11%*|7B(yPD[Y5TyWlB3(O|MVeua|Tn;hKC[h&mOMyc/?4ZDzXXLOc`E$*ec,8;BKOqaVCncMbjLLa|7)>&G;r>M~M)T)W(1S9&b+e~v/gQ8~D%%%l5<~yI}TVqO(]rxK,v*niTkZjvyZ5$IOJ1fU@9YN]3fDbjP3o1=83o;]f__}gFG}o:(&c[dG7W2>Z59wTIms{nwBQ0^K8~sC6r3m`)1+xGA{e9*.ah}rp!w.@Iv}Qqo~8;8F5i0>Kg1,y5||<;p>:2eMyj,(Jqq];Q6P~Ld9qf_?7gwa/l2(b<#|iM$~<k2(0R{}R|=K2;l_gF!>yrI$f"vwe]"Q8m8;aQ`<}]%)<x9/wIg;kWx?G&`&m`gf3s7Z8$Xmv<9lHcOi>CRom.%0C%rg5>z{EJ:P7*W9nWkt8~Im`&rg?sTnl>t`82n23Y6CQ|6t:^3tvQ<@C7fMj$5}{nn>t>9>SB/C"d6e(}+I=edDz{]bx>}(pN.MQ<,Ij`]%_%9GJ^hyu|c><2gXO~*tt`SRh$1JAeT%|o2>f]FV%tPzryy_,Y$r!(<rbsauluW}a0X^aZa|xu`V&6Dr;_*Y53mRx(m(8~9KvXnnY+?&E7jg#9N?d>,rtaQR{_$e>jQ)EJ:[enkgy[!ZXj+.{&3YWQId<}e18TO7cM*67|#YCs|8?&+ba`gF<|mw"{i0E~*togSfNqQ/Qzts>>sx]|rBasc~*"#g(|7B#^rWo_CzCRl~j%;(JEp|LJH+@I[`~sM|^{*F4v;&y*;SI]`?:3Cs#cShm!.S%,9x;st+[&g8J4;$SnGM]gkJdG]=W_Pl/@2.Z(lSegN7Pz5oO}[idn:7M|fUI~@J7$y=f>?f=QMS,|0u>>Sg(~+xXn$4bjH|Oj1*RS4)8h<~9CJ(he$&a~LMFx<<43nRs>8~noqBdc[Bqu0}(R.@=,Z(+Iy3/h2+e!W|i5z>#zt>U%SG$#vWU[SgjgN!Un7RuEtCk_0xT|R|_*U%wu6aX`NQJK<EJxvQNj1Dzr|&0}<]B*VI6s<9+$hh@(XI$_m*6R!cu8%,;?H@Fte(|hN4%O8~B+NQXedG9Y+yzr0K+W^bQc~EaJyps5?6l%pFuKaNF2/w(yQ5Ai#97x)L$0Msj)tYKTC~tt`K.&g#/<NVH}Bq@Vs7,OyDuGae:Byn0mc}|&Y]7bl?9~f@DGC(S?3X;%v~xO1FtT2CwI!BKh+2;.e(sbUp%zZ|$5x>[!K|Z$9T61|.9_W+Ca`;IL[KBQ?:Jg{>[yx|5?i^=$I~uzm>JTGZUZU|]*rDScOJh2Ty:<RDW"9W7+&=%?hkYka;k<3Fl4:F!y<.K[%[Re&oBZDY]~`b#,>WyOfHb!q]<>m9,Y{i:&Ifb3$OoFA"5dIucg^BAM9z4}IjRWy%cPLf9uB(dy{20<r7?Q#?{fH^7b%oOWs+5$}`;6A:Ju:v3`WVyr.l,su#0r+>B7~&L}/)x>ra6bh0ZESEo;B&x#[S,|rw>rM9Z4F1*Z?9Fw6d%wi*$bjOV80(}[.LlG&N7[fKuCQPDmJI<US)c_6<yrC$6MxwQ=2e|;F53||Atou}b5uJLz?$fg`%49^3E^oG/4e.qJZ_ala+B&KG+P6I#}F^2BNW]ufFqpgWLM+C1J"`dym@1>m)4e_"6LB"x(p:RxNlh*isiOV_]_UN75po4Fm;t>GBZ9UUn)jU+@bAHD%*|{.C90.lb6s%9F@sWD7$`TOK,97<1p{k3/Wd6<tc)*)0WZ^JuJ6H^x%(y]erxWdSwIp>i#JqAmJcIO:k`:|p=?ReWu_CKa&eyh"`DyqZF>ey+`mG8_cZkw<z~a.`?xlAXG)+6$Xm*tNA5=nIH`s(~_oJL=z[4}FYoU{XpM|sfbK5nUD~wyl%$Wg!Q(a&dgLTL:?1?]`G}|C0pY}$~96f"_O9;cu*e@Z;:2wBvGjm~tkB8{>9P(4lm[Ytj|Z3:0~_@ha+yK={V%vKJ,mbe|}K&||b/>QLpHYF]>($U|=]^&D<yp3v|C|l:/B&~9o%2+,}j/m>h=l>[_)ld_P,!&;}VO`LOqGB;ed[EJQ5tIH@@x*NUJbyq(^9kh,?KIq[AhEzQYOG1h(T0}NayrvBvd,zH43;rgx7<9Z)N+|+LbJzV|IpOq3td0SV%~J!v>0(hgw">>)BU|1LN6T@Haeg3;mDF<"p/~ZmP|_RWsr_VE`*hWPn^x9xCYoE"_qXS(JOytJ7n_&>e0())?v9H]XII(x>cMmHZ{glC(!*9{5vH~`=FVBK3$ZH2y>WpCs&]|7I~`"HO|9>#|uEeW?`;2iSBwyc/{Axy>R5u>dWg)_[.rly{}xF%[Fc8!H4x{Sk>QJu<~3{jh1hvnwK:Vj[^wY}X)^&>(KCRn.v)]LwYw]Tyle~$4YFTLfbU(W&0hp4kbRD(hyymr/4[ExDykr]hu$k^U.}JuH(MlF:#d(}s48$8Glt1;T,>D7}]E.hCTVj)sS[H@8.5:MHs|.Lz>kz[./xV4&Z8~TF@&1dfnT:_%J1N%Oa5sofc~~qJ`cR@@L<7>p:rR:X,nC0F)EJZSfd!hq1lbaxDjkw<~VE5~uD[GiA^xiyd0"dq_$l?&ujA0Gxl}j{Z_T~u2X_*^a~Ag85.}u4$cs4yI4>"4v#6TPptF{h#}iHZ_rzFK0#b)&Hx?<d*jH1Zz2hsNb~Swc=+AKcQ492i1[EL1Qqj"y>9}6_kl4~]uM|!=s3qDm>`z]14OLg85]}k>u=PA=9`QYF]>`KO|#g0}CMj%`XHq=9<MTku6kbj)6P~|9T!*l^P~c,WnBri>Jrg__^RS"FxjtH=}{tV_}LK@Dgg)#QW|O@k>><S4i>BCNGj=w`!7q>mrfMtCu(,1BqepDEW5EhosHoHo]7/sR5j,m(,9e:Uv;cN}jB>(d$"fZ`<(KCq_Cl]3Y*,}uy7}FkM|rkT_b|Svp>k1Hlvwn~)F7TgA6F1x3T{}iAP|`$&?k!/sT50}"12$8Ir(xNO(R;UmE3j_nxT_mU:K.)&Hd[y>[f.#2}8^Q|gy&H(?/W*#)J2/vQIs,.hq12ps};Mq7+^]2Cc+,7nRx3x#R6OF=~gJ:2x!`>HRns[>6T+%D^68c(lj0}ru5/"}$|@t"r0[|%u()2N+|G_n{$UWj&b~$^7m6hMAb~"%|=)v0s}P3Ts[|%m[~C<|wK]y:1h!1r]1o>V{^^T~>RY_]14OQ5v>3?x1^nau</w|P1(oM[8=$=Z/13MZ@BJtZ7v~4(6T$gg>}tf(^o7srLCW8y1|(4en1AJqLR,o"*pKxl0p,vd~H<8~<>v9OjH;`G4BewJE%h3ex3NihZF[a{&fs>|<~ztO@~~>m>|XKVlZ[HTEM<5@Cv7|@ii^xUe~vmKqrEy3Rv2$)8[XU|7WMYN0~ha(+{zrdWwal_RC4|538(;Wq|Mvb_a~[EmW9*zrcJWdeY%tnI:@z})KZ6Q@BCMi!v2n&DA28yk#}G%F0!~YG+}v/]J%$fp+TVqM^C`BXct>*8@t9d;X1?_:r?]Z={pB(M!.z+pik0#4.V$SSi~/0_Ux#+$j<Mg|[)PX#3Sz/9>P@uU$eO"u~eqgh+ETTTMS8??bV[qjE@!RBt<sghYY"r}Z[dgLb:])=_TYXDXO"xKc;UY$5c9>lM!3W]_a:v(,F25xu1Ucns}(eg/>%Zpb}`zw@r&uc&83(xFIO=ht>`RQNfK9cPii`bj!!Vu41UZx?MlrblB_eu!jQu=Lb0+aTmO+ks^hOv0RZN%F!s{n9y_)61c_qBvCuBJwR?>P{ADg<kq*od~"ia8R^CBsb}frN!o(G^YMfxbvZO8u{oO)YE(+>.pNN)}hW0GL=?km[;"}Izm>*DKIV)X!&n;`S%Z?rbPo8s6~GV4GBV|Hc+?*S#z:Lbf,Ojy]3so6)}C2&~DR5TW^+VCg:vp/`+`9$R.nW(#P4T8=jyli5>VO]_dQw)lg:kS/lT}H?^Py!}FRuzE}[)YU,XIzOW@h]dBqU)GT<L5XXc|R8~C4kb9er8au)Z]),x1|oL="Tn"_EHzRY!{;S~D+cj7F0iPJ|Y1KN0@o?`3Yy@4w_k:z_|_2y{>2lK:9=iOQ/K2#%Y@}~)`&v@%[,*r<LcWK@Gb`o"e[oQS$<FAYDUjz#>Q:RND}Q5lO7#0qr}"wO<|E/(Y)La%(jk!B&W~IG~A)>OF_Bv"vPBZE765xqvS_BUT}Yp!K=}O)")ZZ&Pl<x<SX{x(TvH?MI&W/*5Hm0.3I"@9hOm:Xn,?!e+2s][X_~1VE|!TWSE03JS]"/Iy4G}AN0>m_R;|ip(.ad!(D>6z^66OFZlkyuU@Wnw+2y@=#k+_mkMdXf|6Mk^07U|2B|&;>AYz;M4n6akt>f,}Y_/K`DE1?|0ay3nM0XXBc|#Yngle:g1Bt/<0$T|%kZw~_SBJr^NC**so&bn?m@Evb/Z}r3A,>nbHU~s6FYF_H|5pgM{AZ9>")Zb%u|@]X(|G4d]7b8D!>^j]3gQfG}U<sHiU_.se:/nR{{vE(?6k3qw;Ay3jDz4d!,O1jDVs/Fb;P(v^g}=*J%+/w9o%v4EcGEC1n]wo41(M(3T`W(OeKgf|O&_E<hS~nPW,z83$~@WJtO!;&oH,BsiPo)heC#d#5FzV_g.c?[[bv(UfXlZ9FGPZYI?Dv?l>dLCTGfwSA6s$xLHu+?:gnp{(o3X8Rfg1yiAE>~rC60B3{r.^&mpDLH$/`.=[rU=#b"5juaf"Cd*9|QCB>m}d(y+%E=ak8gGtv1pD:iE$w/cCZb?KONQV@,(Rrpm~FX+3LP>fx5gn#vzD>{hKHY2Zx_AAnwFnJ6iZNI^8K_}Q@K0&"_5[&JC+$3*gEB"nGb/$ndnjZ5VVSb3YS25<~.;<s=t<s68&F{nMSv*xwF)L>G=GcWD?YUv<vRzMw=PtGq>^!AFDu3X!$%)[]f,jpCueWcqM|Q{t06Rdy&n^_#a):6ag4RWXyG&*x?:#ea|NsU_f!>G!LA;3Il`I#jb|5rf)>>J}*6o9{3b}s8kFVYQJF}Oa`Na8rj)v@ITC~MMm>@n)kZ.(~Hp9BTdldEI%e(frA25*mLD?2L3Nez#!8"94fIIiB3rqzk^f"U|K*Ze#nvN,VnHIOd/t/HIg=!Hp.lg<MkXm1p{B4y:>>fIJkST1wfnwI$rMqK?pqYb&`3QosU#:*y|UNt}yETf{ugJB"`_9agk=0Q@SLK,OQ+g[ZBWe:^)f|!4g]7bjLOWJ!4T6PdJ1A&4jUl|9Qpz]1dT*s4ILq6S@GP.l~?t?SM2Cy3n^Tz7e3B~>SOsRj;p87cfj0|e;B0P]uV[>4f]bj}4ou;NGj<Vy%G8I09vTWL!FUq?kmvQmfc,.Cjn6aQh^xAYAMxvO^wA(.*B#P;ZS9bX>HwmZR,B:$NW3<`<y{PKYzHUA"0cr>}R@i{@4Fx&uTs!+xpiRdf51>tn2/Ko3i3?!dnP.y&ek^HAvW+rXGwn%>u0,0<Lp3#WR`~Yz?6HESJKAXcr!MmG]J=M?XJMMQYZjJ)iTPuBQhe|UDD"z(;F5$&g]G>$?LN()~T>xhH/N1v5?ts.,@<)LygGP(^$+xbclBmC:qNIbcFBOoeOu`ma8m=o`hNoh|ebz>NB^j+Gru;cA.BCR.~Cqwx|svp>YV4UC3N@a3;rb.&n)6*y0y;uDEB,LbC44}b?Q|)?RZd23|N++r^AB$AEKioWtV,VPS#OTD/Q[c*ZTnrq`Ih>}lSjBz#?m6>he7NrrP+K:o?PmC:Jv+;u:RN;PJ$W&CU[LbU*f!lW(d4T#dqBy_]1qPHl}i,V7R%T#lf`vY)_Stem=FSa)8qA~i*oeJ?``YO@8xgYU(GBz?M(_vETyw|{%Kl|9.Lm6y8aV[ibF5T2o_o~v4F>eY?5G*!@AF6|9L4tWXvn&~l0d=)K%+*3>@=Gd|"06^}D*wspl~dLM]OcEd.C2~I6PoFNVpd_l=dW]]q$}[0J)bAcH"Nb+U$/Ddf^LjLZ[[LR4/IoZ4w?Ch1x$L^z~i{Mf)@M]}0?Oq:J9n./]HFXJsLUtD!x@Igem)u0E_E}.+y8={YRI@*GX[4FBL9m_GAzKZ@9P}jw!naLm5Znr4EK*cC+?Q>@;wfCQApJS4!fU[zQ?)&f$`]veS8?v}vL]"?vtsZ<UnaU%JsR+3yX|?VyH0CyQ/"~VdBxM5xdbng!i/PRYoO^O??xQneMvI3Nw;&kVBk,<MJf^(5~sYwVY|:u6dT9ESay}|])lzI`}E39)}p7hLRg"Y|YQ0!FFYp~dO>Jyox*()PM~LKMf(%Y/J)r~F<Tv,hK1.vQ/G/tEAO}W*G<]Cc;rvqi2zQDbqcMoG(mA6_&aBJml?Uj!$e*I91JTP|?JL;>d=`7Bx_rs,?$esWz(_m5zVFcHQ8~;*o]tFs_8ln>HEqbrjaepig.j8A<@YpU<sBycgoTZ?UaN}Wj]&w?7G+xV(px3T/R5F1hH~uGn>k/kn7kg>P$&TsP9IfH6p+4B0|Lqy%TDNJ#.Jz@8kG1LGbC(FD93>n5k6<G7s;[N3H_h*QFFHn)6c.!c:Z1ELQ</tm70iR(^"vI92N|?.r~e&fWc<3`1xhV[Z=~Y/^m@"8}u5z_d=EK/+q4b[>zUsZ!kEtZ.tsp+a>O0}3u[[WBP[{zhs?Ei!QR1_t2IbgwTVt.n]5ZIJ!W>)By|(t_a=66y;pmJM>m4M|&^+${4:"}F5Zn+WhGWQ1_>D=1k=fIdq[w;?#s`CS_wBLeXDG5?7Jq2:cBr!p>5d?o"C!57T/xrbH&^c,^ja8}`6dsX#pYpiqaH|lYeN/kvuB"p[(o1jfUUS2yaL,V+m|j+!c@q?9rJ:[yZD0iYSU3*1W_{LJOZS=Llu{+zMEzbY%zos:nwm<NFXjGr0?Em*!y_VdpkgEIGn#M4Nn9YT,key9p9R0PG60qmD$L%*C$vGMeyv_J:JwJV}98xp7K"}|WR"yC)d:J;o$UQ]t(MEuq,X}|p?IRUO(m9T,{QRGCzTHa^;M#i|U28+cS|yV(~>v274,D}g%)Tmo)+fZXxcl[T&/J7}*(olD~^YQ|Pf_"`Q:{bY`r;_n4J/N7.vKz1>IjoVO)$}>]eg1_Dz:Ij3b<$>8`YkwCJTpi).j8hFHe?tq~etW_W<nhtgE3]XOYxbcgJhEGjo[XRIX<L5tHJS14^!IgptR?#M:Mx=vju1Bji{or$W2Xb|$Zdt)^n^t3t|#X_0yILaj5<KpdE4d<ow8Zs4=6!$gTKCI$fDI({(y.7j{V}s&NjisLM}P12[JF.I$>%ZE>Zrlj(kx~y5iXP~)2hfsYCzX(ApL=gcaC$U4.*;+AP*ux7b.k~z[|suDU0Fx<f(xUOQVI@gv785i6"?w4}I5%O~bPWn]4|XuS/Iw:~_Vyd@rbD!WW!o={(Q1BYj@`OvBsla)B&FiH(>wTI1{Bn5Ht*[}F.|>AQfLr9{O,(r8BDLS)_v[XQDvY:w81<tGw`bpS`v[t?5?&uvnLfG0Gwk[Qx~B_b|:6/,pZHN4`4Ps#_ZY)4lK?<zS3(/SWhjJ$9^K0Aw3%u{X}l(t?eGsUgD+ro/Cb{M"Q[~3KCjBXV5xIdga``xrVPz(UF[xe2+|2/tcsnOWnkGKI4!K&Lct?azoOOM"~C1{Gj`bBc`k3km&HpN#thZi{KZ])|2MitsrLzH:2~eS7:K+B%GjdR^3T9_[4u?Iu:P#vGMcB3r68FUU9vz}|B3,&$=#hf6MQ1hYmE./y3Gj|K0Y]7b%X=~yI&,?J7URB?1Vn)t[Wh#Dn])%d}C[v;TN0,F<y^|:07/Lb7X"s7lA3@4?hdH|;W/,dL&^K_XSA,@.D?+edUVe>>k$EJ.&+/wI}"UJ`za?a,LKO90?%MEcs:h&Tku:02WrWQn~FkE%z+&r3[[nLRTdM#PRI,82"?Cx.{BD`?y}|[H!k_HUz$>/O9x_K"zDHgzXR?=wAn%!xCGKV25/]C1)/E9.|.pq>q_=u3r9]+NKML;>T>|LBLOnX1:XW!N:JpY[ZI[VLK(3oDGT*2OfWv1U[RA5Gi6v~]Lu>.?%Clo=u:vB/Mx481wW!osNUOq#+F0!<]K|4M}ULRt}~,{(NOeP+p$oQP$$DgE_[hG*=Wk5k{Z"w";`CxLX)(|yM,<<ds_*+9rcZv?"sLRRpz>rcy5j$W]xKy|K6TJ[FF0`Z1g]6js,<lx@NzK5?(TX|^)xa$s0[SQ}~5&f({$#WU)/aF~jB`{my2Lu(+2s5iy/<*Nm_F+H(1M=T@zFD.C};v}y!3U878s@54T;LR7&:3|1C/rlC+>rbqP1h^vG&QHmd,g/tLcP?@RY"s8W"}lejV3!ig:l^RX(I.olFqU;VO;3oGU1fGj$Rf?7L8rVGk^IPW|2B{&]pwn_0.>{D#>eW:m|&6(nZJ*ZdfgKGsJ~9{uHPHe^G6C~r!cdyTkmUV*?O]>hiENa_5+MtIO`M8s$6.Q>m8EAY:+`rx{~V[)/A)hL^./J?rb6XOWUO2}J,>G6|v]pi<rY/Qp<6DC9TMvDE1J5LK@4}vRZ_li&N>AqtyX@}IKe]7bbJc_3X~#oR`UqArgi<2t]Mp1vV*VAGa8b=v@G)=H4~1xDzvn}|0.]&M;W8Cxu<,MXezI^MGY2NgUth7:e2C|B4Y]3)mNH**2MTD.vE9m>xntRhNPvQvGxc#~nIM}?F"F?JA`BU?G:nA"bE8$gfTND}!TKt|.;m2oAtPBNY%yQkt)%@(izLENmxnRu6FTAAO!H"zXcyTJHaE6s#!CDH~lrHW3TvclON;,/I|XNt.L7FQAAAAA4EEA153G_kG)Z2Qc<vH"=Pk"bVbncf}Pt_~Q~HIOP0#<~T5yQc&e+hkWf"4F|HWMPluA2YB%/ZaU)%=oAu4oW{!n5~(i<up|l7NS}|w@WX:DK(VhT$,(we6x&h46E0sTuF|FFScW)%uIRnv!>$U.O`(a(XJzZtpaz3U0H1+<Eg{*CSg3D)uh+szg7WiO^2}0#M:&<V7G{q;6>`Wcp/PO7%kHl^GG3PC#m.pQzNPvj^?#S:m!Lnr*;>s163E:XgpBxp&BHZa)7#FX|Xm+UJV@9uLiOoYQAL64;GN<Re2:zH.LsY1ZPGfNLw6XG^TW/xOL1.ca9/l`u<0{4/^/x5K5$cJ}ZX4p0drF2WPwea)[[c~kb8>9hU%dr/{K_Id|@,;aaXi%a|:Cc3=[,>Lll~`8DRc<3},HHrVw?bT;lllR_(ymLB[EPHWg]z`[BW<BE@=}zd=tfv<6QglWygK<vY4!j^w;~|#JbB^[S#NkeG"!67!li_Oe!@7~n+=xf[LzTyRw(vq&"ZDu^_xRA1xNdo|2a3}Bp%pb`F4:qC<Na8FmFHB`6}y*}o}cEiHpH;y!}F"rTOpJe|qq1?<WWQ4A%G;;WxJ6cF{Y__GdO*~GBC|J.k+a|fX@eG9O$n.[DR&xl6p%Ts_}Oew(wtI#j,Bq&.0Xa|6*KXqSw>dXt6hKzL2}QvrjJjklJ8pa.uB*=K^Y!#Pt%&23x`20p`b6T>s7W*&B0^`idk%JZ:HC4?z6!~kJ;pfIm@]weJ&1RG&:dNl(a[W`t=c0xh<(Z*tKdBtgQ*?b(}9WDc4&)Dw9]a3>4ye)w@N2D%|(Xy[G@q/*cDZnsZhlDpvr6R}]pgwi&uK]]KOLqnB+S(SUnBx~7O*B/md)YkZ!.i4XPqxhi>!<|B+bFc{GZ<UAYykDzeKZ<$>R*HV*nB]_bB$ASq>?L.kJ=F[hF[2]:{Uq[q%CCcKdB9`;]$wr9L|)P"{G^:#tD3v|F`5O}>5S<xOBH>9c*%4hpVr_h_(N;h{GC(0&2v%BJ`^]CYBcGG#s5l~nQ~F%j?mvG>`4K,Snhs[[OZl(XSq|}Yx+)EwueU9;aJ~HZ{A>(VP}!^zgn@a|!V!K!nw;E&Z6uZ2$4jI9rL"<i_j~u)Ec+1LvZ>X<(<!$Mw!qgDqF^$1.iK*g{$wDN!u1VTPW2N8C81|&*E&D[$^&BQ2xYoj6|E_kIa~CW.^v<aI}JYwn.<,k#y8kDowW37mvC^)aE9I4Tni6FGeEXHmv/45p_u]0f.u=~/z3x9wxK(4^qVn/O=KZ3yy43x70vy{uCICoLU661vYo[9eRLv<Win"^`kjP,d2NtqM!MK59+#RB?I9WY(xK;+2ke?>dnuuhFgE!Cj)0$u,bcz6Vh9mb!=C5X{rN&"T^d;1cwT`m_tK(0Tf|tv0qM0"l6{,/Rwq}v.]@8MAHk(mpKX#x7"]=]#N?gp3YlnymgaWe4g?|0#9B|F(C]!?L~q="tt9)1%9Mwt:`zqZ+FO)2|)t>pg9Q?s0%3E,yCPEtB2,81iLq+i!sfQzHFr$N<DaP@=xMBP=qY4nW>z>Ka@~G,[m}L!Vw/+?z{?5R"_wtUs`ply23l+|[M1t<<z{&fsj/Y]]WXY1=K5!}fLECZ`^2Q[gr"C_6ySogd]kdvzey*LAVy&uI#:Bc!J,A8eFEU8"TzkK^}6]z5+;Q.AVd*{qsLWC>X}>r*$np`F_[VbrbzR;R)Cjo?@~&[{T~{_jK;3xLEB*fB0_&D+1ZAZ1Hk^/dCZCONRv$kV]<wtPL7]^3$9s~j$jELYq?GCZozLA(FJH:]>?/`V4K:$5^azt`^}K"C|v>EOpf>!7Vd{v.(9Eo+53yFJyh^z(+C!I)8Kmh&$]o^pEm"M+uf;Z1i>h>:Ppp?@v.5ZOVzgXfn*Y/j&K=peFRXp,Ae4ZhVA$`2M>W/P&`W7CTV&j;l"o>3"9WWLo?n[T6ZD<.L_6i[)VW^DDU>}&R#[]`&^YpA#`~/od_J`PdotU{".O]!~d=3}ivDT!4>}1IopYsq$es]2R4bei2|Gmi3PAup{:i^#@[r)C_28(wb,WghfD&DE8Q1Ut!"AZ{Ay`=mvd(xMS:H_0b>2DC&H29V_3Q/6]lI>}1H%qB_[Ze%>}!j_]PO#I}MX0+W~,[xh[{T:<93W[za}2}l[;7liNIj&Hcdyo4Ov646%nFZ}a)Qt$^Kp=`C[09o4&ts=|`VGMDufM]=m4xG~"(^n/v.G$N4EW3J)b~jvR?cw]d8NYsB?*u[sQMYK~[/C6]~+UBW0mV)T0AF)|PoI2_0D7A]B2Yd&!<Ss"nJ1sE.g#rE0e`]00*!%"~ZeOj^PiaQ[3Q7rz+Sr)FhTD9LMFOYqcM)Bom"Gx^gZk$OzFvjH{yL;.twCyH7wIJ+qec~Lg?3qSn:s{gb<kxHEFf/e1x=9>rHY)WwzR|#*%Bz2s[n/_?O?Yv$q!,9b2W[f#|Qoz0Z+?[jsM~{~C%CfXBAl7`VzKRJ|IYfV0v?)bP#7ki/8!>6eLB{`MWOZeNRRq2!@]C2^TRh$9;`lI9yy7";g#_b1)f"F6_,//e`G~<)sKW/yA46YiZ@|x[KY&v5T:q&K?;*t0.A&)XM<Cq$gTY:EO|^L4iA51dVJ9oL(.uUyDWG8?Ag4gSfNO|`^^0CLxyLqwD0`iGM_z?,V??Xln%D<r@gTLCyV)Bz9x?`*7mXC4*a_7cD7qNXnCsm;6+RP5d[S1C@30&b$HI1Iq1@Ve456]3B/m&d2&&qPkBR9>XT~5q;>(A/Di*6+A5=gk=?Up_pUE[Awd6NqzUs/k?)V0Xs>$["X!x(<:2CD}h,|]ng#:s1Vb{^+l!gDh5`wmUrtfCNg^@t+t>Y{I*!;=N}cK{zv=]ir}}+6{s>agwxV#.TDv^yn+%X*LWu~_EnPrt{_f%T|3M1HYPQOWyG[>h8(+8_!*Vv}Y[[;Mj?=lXxx1hlHcp2a$@*h|nfQS;k(az".(=}l@Yeio,h^E?DU``YM*}_jQGx&<k4&>b4EH>+~%%w7;IPQ]>L7@qoh&Z0V]Q>od_Vm)o*06$<_|Oc{H~Q!?Xr`*<7Mi%NTA0].`9cW/`U}Q9>t?3y7GZTN@`ea<k:K@sSd%0VNbtxlmy&rJEazr>c+Y]22ZI1J5:axyrTVDG=9)clpzf.lQf;ff_EL!_s(jRM!pg3LUR|Bn!~r{p7(2n>fmeuR<[B_,{m5xkjOhf(yh4JWC?uE8>wn41G4`0=z?p)ap~(e2=1yQLP&e}!*(VZ&TIUVA{ull!Mu|oGF~*iX&v2Us>8gT?}yu=~u*|*=?3oq(5VFaj?Gr=8^B"%jN&awQ&OZ8Z#Jh*IR~@&ps7/_/dQ{},a?AHooREMoHX&L%%%vm;1.D>9+ry+~a>Yz@=nGeThNB{~#AS7Mn~{ugxX}Rn+j~Z`H(WAh3Xrq()>!_ifD1hqZLa)d+.D3:ae!It%1*^1EyUG:dDAk5E~o03kF.#iXiV(2[YIUsVOv#srCHWw?l9:BDL"h/e,=7*5nW1rU6y4kn1``7)<@3|Hp"wd]"!vNGCPUCq,VL1>]9|G28Ncoi5`x%V+dhK0_Yeqe@%qN^6JZwh6<SUErYS65#/dY=w,FGjiqCg2_ZP%P=3W|B@{])IK$wGjM)Qr#"j_lgz6Y]cw8aY_U_9i0;nu)<0.<m?e^"rZJ)92dV.hib7Rw]RJB11Q8cM9EK*%i+jduPdiM/Znvcsk2U4$X+vR{=!y,w[WgI0pSg@gqA^}YSz,4VD+7v3rn+v:c<xD_={[Mc#9p_JI@xVk#c7`$fMo=P:K[Fapqasq~KtA=AqVL]d:,,~6%>|j1h{>%o}v+7*s738CY).O,Mlhqm$e6d}_)~KC4<?M"4v^+1;<4Xieq5_5k0LPX$Q"q~o:{f)3Kr`S&}LyP>D2WUS$&E!^i*/V8I!yTy{I[Gb5jc6,H;<i?XY&o/:d^LJ2rD&"3&G9KnhDP;~?+d5Hf`_]pL8Ce$`iq2Q"`#NwSIW5}M@*`)Ia!.!_WZYu^yKJ;Sro):5,awI[G%UccS+Km9Qns"`4DOB@y*/pe(M_<EsKWC3M4PZMD.|p[)K`ek|q*+k?J(9yq_?kW80,iMv*onId^@WV8&apMeU@edcikZ/^$fFNJ3z5{U{%]syMj>50ycU$b8IpFIElJ]#I6U`F.44REfi(=JhSY+N(SzLCl&YO@TI8{:QWK*M3vw2_|Ody<{BF"6ty6l#<h?QY;M;W)nc8Cwoy@AT;?T*S]8&6iES?4&t{L{y^^0U,$G+`G~<^Y&k8`za?sq26zwJ^X&Z3ZC)ev2b~`y4NImF~mi#y}cxfl*qIs7pl=O>,a_Ptg|Yn*ir+S]dZVVT$X;(c;R>1@f[Wc1:594;CZa|ifmKW/+~&SB9cr99DF41/j<Po"MHa..(j9ezS|GILN)m;8+U6yxZYG@T5wc,FptZq)GR}F`ZnBMy68$Bw`&gs}]CprHnuz6|<<2:mT;?zB(%r2eaMI|aag(JcF|m>3(:Mee?&BN`6@q%<d{Omx7dLo<PB:u{Avk$%FqT{H?ZEUY@juQe!<XX/V"]/FL*._I9Fkk5Vd%xt6r]:oz]`k{*v]+XgSgm~ozUY|,i;w2^2Zc`4v^t[R/n+L2?@Rg$cu.1Wj@~0H>y8$R`>e55y`00JS<SDWn;b]BcRdpjP(Fxy3}wm,HT?wp+P2%4wrk*k6u)u5>*ViQ|&qPJvfq}!"PT/0^7pbV2%f}$d]m=PP$*sJxtGv(y+=Qi(7&!pU/w|!`t,}D.GHu1x{iK:%"n)44l_iLF~qB<N(3y%*oVdfakB@uXF^;]GVeC3Y1i(L"A4qzf}n$UIXX_o_~B]K"U8vR2KOI7!^O}i?ecj~*E,`jwz>>xN$$6mI1bw&P_MypUiIE6vUQSskNqYV?nyx2c&^!.]UkRx#1_?I{Qc^3dyFZeW9t8Zz&id}Eno,uxr(wO?4[nVXzNbdh^3<~ILHLP(Jo?w]j#+n3<b8<(*OpVJ=uJ~u7!:0VJsWF]?iNfji/&;,MFr)Lt#S|`1?k._HUOKCrxRr{!+P}#3wVFdhDfVEGxikpR9t>*t5chC0jcQOIY8lPGOF;7GBuL,7D>Jv,0okHV*FB#HpR5^*=J<tXtoZ|"Y{L4j*r#:K}Q=2${7;RR)3@Fn`Ien/]v/LF[{mUuWC#@!Dc_x,&{5Y7(mS]{quoq9.:v|O;$Usg,i{:nEJD~6b(*=ed?Ap9`;^z?.O*%j^JUE.>T0qd}IMdZ1hnWNlQ13RyQ^~`cvnwU9bEUKxa}N8NR;P3lo<qCXx53NDX*{V5+v(Fu(9/1[iLWtjmR0t<eh9dCKL4,HF?g"ldL3p64DLPsM=KkP/artV"P5o}B5h4YeXKp+N~<cM>!^c7vsSvxR6{#Zuxg>1EqXxrxeBwKY+U|hHU3GHk*dnSBc:+m@2LLV+%vlK(cO_o.c<eZ+&Ubjv`nULAh%%htx6Nz<#;p!#{<T/Zfr;IUjcXYX{B9N2U&+6l]eGpUd{j?2#uSeH}">kjX[4b#HC6|s(wxhbNsFBGgt8j9[NNA~O/5Mq7C/JxM?%{[$N75C3V$u1XOO^DYJON~t:9s4>f16u@kkGo/>NDr!N3/oD3#ysCKpQ}UfZ?#/c%URO^QOhve58.DtN_1W`)!UyiF`;KvzlLYr+wGN:^%Sq)RoyF}[(rka~3J6_HDwFJHtkZfn2N<8.c9#tW|(MZAL?OSR^AT%nAMai/"nF_g!1p,F6sz4Gx*aW2,74EhE{x!rk5FX`ttIWCh.ysLwU#U/1$aj<m47?4vy|MC/uw9T*2ia,5i4F/MlK&WRGTB,vz8Np)@$TB.a<koG2J/(:?k:ZmF&EUDOvTL+#_iX?zXRnX$4VEW$KjYL}8?h[9{B?&Cocc5G>fu*.42IqCDkLf8p2A42xFoVhEj61(o/*GjX)t"n9v9VDSau5qH!JTG026"]vW]!F#`t7Q&guI[Q0tZg{raGjrOXUA:![uIH#JjM}aCMLR1[VwS?I]dM[DN">g~D[Gm+<9!(Nvvk#G4m|qSik^IG1*aD7t@(V&6=?tDnzQWx)=pOW~$nzwnGJ~F7?8/*PZ(~z5Q2>/0PsJ_2s+i[](e[uoo1tFCN_J%W{8HdfQ[D8M53![8O^>8{R~)T%=.StP6fUS(wo>!c0L$}Rg9<le"nw%:eSEf3`#f7i,0ic(Ct0r,lr%+&}Dw5B!9US:gKa6+[&nYH6=T)63Oy9O@)4rRBUXy}4o[xg+Qo_G*y?_^_%:({osN/pSvQa~b_]`/Cr1sV/`F0/}o9,~Q@nC~[rE5lno%0+ucsl1KVk(aRx7{3,}JFK&4`PaOys~%t1m}B;`EGrTj[&seS&,2(*3gtoLI6V<"NU_oeaFGX=fsCatH][uJOq,T2A6Oa%M,Dy:NFLS=CFfDV"mFT{4Y=.mkAcfJtO#}$[o_)uMMfYu5E(7+sQ~I!XaEm$XmLIj,4Njm>07Q<K|)_d7Dpg+ZJ9R<("nmr=gGq/Cg)k%J|e:/qrr|H.>hlq&/(Bt0RT{lrhKmGwUK]WQ#t];Q@{B:tPyi|dB~?;vH.}Nv#mC7|A>,@9MB7spq^sb2mS_X<q(}("S)>cJC@,i}pi`J&]K>;PKy"+VU~;el2h,i/`S{>|YAVC"cRrP:dyZnrVw(#>&S)u_=`>Nit7k0_.ZeT*)S[|f&,YLiI&O"C3E$]F@Myv]h:&;+I+V<usB:CbiUG(7nb,clM:P{R?!RW{>G~5d&PNF?rtBh,s1<W]Kd/2nLpx9Iv1/$6guFD()].>;f4[!hL<ZKd^JZ[I10Kl=M:K*o^eBeI>/0)F2ulk0}m;3<mDh.:D(TB+nVTF_J1|^6!)<<<6LCnE.To<UQjqk^V`x[hD**rdq=k/M$@=^qfT#x}@zPU.[OVm0x[/}m`RM*3|Df/1?*$`!nTegGzm.J}"UWn`P~)1u4^n}Wetdt:_Nu{)td9Lfe:J02d(*SL>%u/s+.uqHlj.D@!_mkq:7@1XLLk&%`[2~&Z5{lOp<K#(j4F|0DO.f^~Rl$Dp486&3tj4a3%LRcfH.LBB(Fz2$xy,/[T;gx?#jEc~WfHTrG2G]A@k&ld}|g4)OziUM)gtde#r>}gV^PIvQOI"MgXE:oZNI~6_he%OoUn=QD2j;GZ|@wnP>%xS&,+M}4fzq)t+`tD&<&FsqEZ[?JX`yU<[;gyHCpaZh~2L~fe4&T?r6q3<0r,q!3_aD}ZSz}d|Ww0ZIvL9bL5ko?G#y:%OG@z%HrjI?%ZkMj@edTNGaKTW$YR_f/#dA0)EGU`$j)8&FMf#89YK5"g$wZbIRfS|WO93P{MqZ[Zx1fjwO]+_UIR1]J5{&Uo4O5X`hsjH;aV"UZ3pLhb#4WHGQ;1mqiEM;5@`tic%XUI9TP{#[5(nN#4lZU_)iEZ@xhx<w.tdwQQLaXEPW?8fxYDg+RBZI=y]@cv3,gN..M*mwV??~On:W%sMS}c3rhZnn}Bz|Pll[$s^_<EqcID4{sn4qL@%hk_bp8@HK&z`|YXj=k;Q@NIMF4wym~`I:^p/QtQZzEXBG$mm&y;lSWO`:h*zM8>aBxHddtw%<"8Jc_9Y=ynhFC!*l@]>Kqf=Fo,vnVD[w7F=P@g[2nj)nrRU:|1H|ai$,oC!L,rTv_3NF6q1vd0mFil{+M2um4C1_i7"(#M])}vTO{GFL<At;X(neFli?vfs[][q%?4:n[z{5Nca%Z%*o%E*jcThB0HF|q1>jo~2,F(OLu)]nT8;[ne{Vutvbi;1,P.Qg#@#Gzhy`+h,,)ZD.]{qiT?(H&Jg9Nj,vseM|<o>.Z9]1VE}5$2&CiUM%I7KMUHFQ7`OkgZc+KlZrYXt=R5@$LowJ?ka7UK8gN3ibAJpA*Z2%HZ!muQB`UN>wYi^,l<%=*EZTZn$0MVgS7lyr,;ZTkzpIiU^,"2+mw5=QZ5]~gkl$^fPQk=<5"bD~2{1iDr5~N_u/vb_kL89m1Gy_ylplg:o]Q_K1=s>1%Ga_;,F>&e~SrS^T1:exE1:V<RuY}KK:^5)c$^j{E6/[{X)b.8.=vZ?9w>h21$q<yTSW>{X{q&#J!&D#J0&c1:|!06_zb0iT?iE=/dTv@l4FV1ZDH57_Ct48C:6z`(P9i)B7B!A*[g@I@]F)z@&P5AGQAM9No36N[ms[fPr=w7<b*S@jq+vNqv>|(#]qceP4C>?xb.ve!mFlY9ucqLav@,]U@+&REC?c&5b|_6+,fj_ic&IM0/9}K%p^x(ozRB>;{fE,|CE0aN^RPb`#D0~P|)TW`?nO*OHy!%oShjVtJK].a"z<VL>42)ih=_kn]/N?FN_GZsll{!l;%w/oLxS>P[6[7~liT|R[E_FatM01"umlTL?32Ep[/C%"KTNq*VhaB[7r]$;BzBGJ`hnN0<sahiHI8@*W0{u7Q<x&/xyYLFRFv[&$|VLH%MVc#(2&v]Qd*b}s{!DG)l3f=>3a7>*{s"=UJ3JIK%DXpL~pBUTOpZF&1{{1o.}t,%2}2K:_v~rbhP@o1Je}z4)5X|iW*l!bE5C(fbI5I)_]:Y~z#tyX7C/W@K%/W0rtje?eA09v)c@r~6506&|C1ZO^)@UJBcE%=x9oH|qPL":qa%]l@9cLAWp]4?z)d>7pv:@m`HZX!*s2<_d:{~?%8M>Fa%lNVb,8|*ZBSIlQxvdEdT~vvq,9pm)?1?%{I8b,CRvfn`4v/gkfXnBi=HR@PmEtMt@B$fyi,M=Xo0&|IXPs6L]bQ|&UUB<@I5Xj8/y[=Pe?^arE%1$fj8WGSTn<@Sr4+Kcl=99O6,N$!Jxn{?w#.9pXtW86CpQtOkX,X$,TcRd!<9oX+.w~@nK}0%gVLm+#o+W[+ERb+v@^2m[&S`m1y0kgEHpBs0SNMQ|RsYRNP<}(Kj";|eN&d=E,IWp<Q#7II_2*YAO[#y%G{a9"pn{Gl99ox4o>YXIO4+u;?v;[K}&,%Y/]g)C7+{Gq5<TaBMz%8Y#89$v]9W=Q.>wd<_d!&~,SD4Z(SyzlaB6%]7{n*Bh/PG9A:[<TO[{M+1V7##h.Wbj91n"oaV*ZGjrz6cK&V=?2B4`xB)a/~I|WivVSFvm`_o7R2Y]vc7gQhQ&=L!!/oXgGyx:xi9.j_ogB#Y!b6xLy$@gx,F&PZdiofQ3Hwvt~1TD#WG(>{6=I{!E9OsbYEB623d},D?A3u$HMA>ovYmU[e,N&<!;j&oOF%0YVE8_^:Yf_]JwR=VB,&s.tTishKKO]R^Qhxr";;M077RF&jtd/&2!2g5zPgT^g[L7<g0gqq|<(A`M%<|./MY:VgOU{n3ra`d8DV{uJ$Vyn(KC"Y4N1dK1B;HtcpFirn;<cR&,zr#JF.ECao[b3kvVp+.NI7PArc[H>s.hS9ik]M{ssc}e`F:92ETxEjGO@0RglFU%oLBGgSImi_Ev$`n8j.i~uB?8V0h7|OEUaholx=Sh+r?w^hMRO00cKL3R{L&61`dBjojk?+[yGz[kX^qr%.92w>hldAoYma*JEsVqr)SpF"HDH+DXH!a0<5ukCcgM@tDp*f;p++o^izw8KyA*|eGH/5KtIx6e[^HS/3GP]{;Gv3LjJIiB.cohbchLk{T;F[[tR~GK@Lm)#0[M|<|`*s}*`@u}+4zB:O*{i,)6w)A&Nx@Kc"[xHMd8?XkE%4jFq1#T!nj^j9V>ZV1}FuaQO%[jt8e9]nWhxt?VlaR+/u?!gFK~4/3%4jywDq9$XPz!IoC"5Vi;aIKz)@]tfKa0&/_;}p:6B0cr&AY$wM5|Jr+Pv;Yv/(zg~cQ%naC|;:RzR/Mu*d53/qySEQ$;|M|2_wSZLOdRAMnJ,>>5d>Od!Y&=cnFO)VQZV.S?Dy<l]Yh6D1;J_yG36&E<52`tNz_$9CJ+rI&$u,[a&Qc5r5=gl|KS<q=Pv)J;k9@jtz6H+3<l$fz2S]2@0}ig17%PLOFi6lN"2ftojr$f`f/D8D%~^;h4t]PFT7gr_8q3r#FrHq{3vE_Az;~J=,a#sI2,wJ3/vmyd])5^OulfUZ8pZj[7uxy1O`Oz6~|F92&HeP2Tc~]4LSw.Zy0jY>m[:w1S&B|6EG<Y]+imcRpu@Isn[&M_#{EjH(#o("|%_PhzMkatQGC.jzcDcam3pDqv@LR!1Ljj6KVx?T/rx.J)k)xfUnTx/Euc3N:IHODu3G"44JD6MkbZh*<T|zA#UU0eYb^F[KM6g>Sdbf)`4)Qm5XMuO?T|80v+=7JSr7TTB5*@no)?$=*%L#n)PbW<2gh5&+As_J/uu*s|VHId?@#fq_!AP0{vL^62;yl!`9/"R})bm3)no^lm_Jhq49>sQ"l+jx!p&"J5||~*U]!@TPzIWSvyDMjt0s[Lx?au6&|f#DP9<Wf,e(YmG:_Qt[U}h}FX,B+)``jO"BS+VETLpaeQl^Jv7(0Liq+c0X(*wh[X0I+%qGo5c~),snsG0NvH}e2o&6kup"c}.|d~J4l%?:vO]$?axSH7G|KSPwlJE(dn0H{m8NZX8U|F*Q~Nk]a8I#"#`zbt?u3AeO(AMdg3Z^EMZV45k.Um>qyAc=DY#6lI]xt)mmuu*A(H?A=:)~+hIjIu/l$y[O$]cQ6K.4?66<!_l}Mhq=.5`VHthi`WkT]RR41#I7(<BuLf_:W}c?Y..Ku[#)tLMHo4yuw21L+h>v(s~X@`1||]6[R]G`~HL2(.B|NJ=EdM|PV%Bxb>E899ry4M}|+$c%NV1YYgaYSY8]$HA#65_5$UBBd/u3scT/OHx^u@Nx?EZ,[Z,P8?C(mM60$!EvZn|z`&jZDwT)NelECt:!w|[8Vb+w@pNp&HXYTnzT.E7o_E[(AsHp|i7ZaG?QyRIHB9,M@b`PP{C<,vtVi9EVX0A7%.!`tcXM"|xZWiBA+)l%{@*jfiMb$?+(^E.;T9oSqH3y./7q]%X{]h6&_e(c2VzwbX<j^OhXL8/WU2.k`pY{!IawQO.l4EvuXprG_7;O=L_BNj9*zqFO1`UXLL_O2Jk;t2K`VX{g.Frqe8@gJ:RSLYx@fQn)Ew#gazoyjrQ"YtqM]2<OHq*D1;y9o3QD9&"2K?eT0b{q/mrd?L^ru_&cCFEftC&CZ%FB<(<;LCTV!=<l)L<>4sS*v2uXv&G0YV72Vt]@0lYc3ENE%:A^^p+y2i8l;L~)>2O@+4j{tW(bh$/9j%ROoRd<t13"/lDdUu:|fXzFBQ.<y;26.CL{KkjgD)>a[QZ2&++^OlGyzG_u<[ExD0XWzBV6QNa/~L|!hW_`xPt6J"^_?~gS<TRfFnqK3X=n>*$62%s:u*wNwUVleee"S*0g):QIW}RUzVx<~<oup)M9V3Ma!kavh$UKM8{3c}v7Fo6q`bJ~i[Y2u2EC3u_+"0=qs)]ncjP_<4L:Fwq5FM7J}Jd?gC][jaLa5;b5P0eI!E&$/Gi*x::vqUcpttr(9p;",`0EB91)7}oA5rV_9mlft`M%Gt+$kXDD|_;404|2E8_2m0(U6VugLsa(s{JmrjZe(OvrUZRS]uSnC|*LAId*G7H7e=D!Z#m.<fI0&OJ%O8xB$5!;7kqpvE|"Otd%ndwU7d_6q/SL^gM?rI1^gFx31goRWw{$$]leW,KYKHeNt[qk3O|L^ASv7Q(7nCz0jYBc,jtz|1vpsMkIZBHu5&*Db#6F8Zm^P@@IKeK*GPx=.MQvqoFsa$ygw}Hw!c4hL6(QYAlLjgNhac(0>P|>639W1aj+MYm+?8nZtBFhKg7pO|4[vz:4,JJ8Mi+>7?yoe:EhVuj:Nou:=rGmiLz:9.0Se}BS*:SQ34.=dG5f:CrLI57aQ]/O}[%7.!??Jl9/(=d#Y,L01PDX[+prDLu8{5""L3G0E;$F(,XkP"u<sLD7wQ2lS0Z3vO&4?O+Z_|4DPAd)Q.h$%jX~^w_|0onNL{LQ5{4W=8{9#>db%iwQQExULCDM#L$L/RwSW/g_ZUwDwv`Sgu:bu2@z(oKR.9Z:ydRm+V~4"OV=uPhw(%z$2Ep"cky)oYWNbxz/b"UhU44QD%#b9b!/rjJ}szl=`HBf_dfL6!P!:G!|.f.kXw@"9}}4!NVO@XP|#Q!_}32%iKor::$m:;?^{F:FiD`b)Wg}EmfY7mT?SL:lbb`j|<H#FzJDL+6YfTGiXW^q#k`((OCoZ^,?1$#eGM>b6*g)i;%xWO+[bC!=Ef?Fih[1ZQFUTi6sQbMc3k);>{4qkAfC}gSYQD{lOxn5~T_u2u[T8(e0&SQY=K$|BXFWqEQhp/>OB>)fSdzuqd}4]fdeq}(Py$)3]un[Mfb"E6MagNf`/li8d~,e~i$$ca]LO>$*z&&dqe!949?;%xBpYzczIXrrn2O/>,N*rX.@FS{^@cp*$TNP{vpNFHG?F<Q+002p_l6Ye{zU]RsU;ud(Cv4ldgiVq4!p@}V.R#t4!V(I6sg=1j+&[%Pt#:7(~H`9luGWBh9<Ge(>U.O`Wc7w|vnrnq.wBx~hz^{v_8[:?1O;tJ^.QE^I(AG`@h.n:cckz4rz%J2_luP}~0a>Ufe;n)q2MbTB6Oh6YWqP51{`"V]t)}<WHQ8/87k+IMqO3X)%o{K/9}D$=):Z`8cI2+32?=4I$HhwT<(D5e&]h~NX4[9qKYSKG**}([74zZ1rjj+NMaPb_+UiW/G@0Gj6pIb$bdEiYWRW5`Rj.>Y7U>cu}0*~Qa*9~>m!U:1"I5Zv<_I*#*|R?r5U.Qxl4Q3H:l&]d%?x[[O7)0S[+x{TE[.j``y%[+5H19)bo+vobQ*EZT5{]c8gBZ1o@PQmaxY%MrLMPAER9N&ru3K:Ie9RcLm:xdsM50zgiy:KtrX31^(wqBrpcV7v.8%*7)D(NgjMF;UxkGK~<w00=F!o%}QH4wgxPQh/2DkCI*cHD>2@zAR;>@u63oJ6AhO/CwkSc/#e4Tg"X]lDvrF1NXm+xY*{kuHY2hynXwebos?b9M7(bu?,+cF?vL:BQPlcHCoM$9!|59{sdGULPwj|OS0"`W%jDY&qa0K"qIplOJ/"mW|J@S+TjBgkdWJN%{Tqo5=_zG?IdN7@xYDO:Hj)2>J(F*7y&+yG%:#!|(="QBlv.1OW,7rw02L|Zw0;$jTdK$R1z/4]+sE1yo5@8q3ry+!BZOI=A2AU><4Z5=#6u*$i;_s<7!E`Aw5e:`s^5{4uey7:I;FjCL~B_zn$lB5dYw#@o|kq$9:82}pDgH~G%Po[CkrSkH2C`zp&Iys1xpM{4!LDj!6xG[d=LsaYHkA:4!F591j9x)uYY[|n;/#m,.+!1uUa8o{0&gO7DZ!|`o$wB[lb9.xeIfe=kwQO5fQ.=Cr6q&)(%QUZv|aNEm8Gani_"176Ra)rOAhzuq1`<pQ"zuZ&k!;!%^:7j5s8fxMf[Fkhvc*xihDqj5oRt_=$G|sc`W4Z;|.*7zOR(v7JiP2e"bm4+N_`N<DFw}/a(kU7F/(&$eQGO.nYl,A6|6eDay)QU1|}[37g/r?w"v7d&<%((wnC8KH07<lKvdKtBov"`qC/&cEpcE6?FOb(W=rzt[4#X!oDa,fzFR?$9f$C+,CeV&{xY7?)wmEB)p+D5"hwFfFky_6v}@jJt/`WJW!^m5wKD_XHwJ1"a7bBoY{a]oZ^#C{)a~Au=4]Y|N>nD*PoS/BeBbP{#i81cU1Dkt[}C$n|^EKo5cE5N7aj$kuWhSq=DbwD8&;__qmjZaE]]1$r,!CH9]mCRdv^bQ_vzelIoSfowzHyGKM~DKG=~.cGur{CF(+FqK.;/p.s5U+.]yfR`991u)]#]B!@Yiu!7lz*XRuR51MD^M(DgcV&m5oo4lD0n<;SL9jX|aKfRYwG{Y=G$/uXIAM[p/J8zDC3#@_Cu(b~*zcY94^rjEb6aU/1&ad!FUR$BqM+ftFfB`7[n,*~(K,=Q>ej2Ky?2`?Yh<@bnb,JwpxQuT6<37y/Nwzen$k$:@a{uk/(N;%y8y;5IShx}IfNFi(ZTp29FsoB,zE!tG&Td@D4%|+})EoS{&DWVk}SROH`0<a_2/v?}xpVn:$=[BM)z$Q<(kW:w<(3uDEgLmh^;:Ey[)`xvH8[Nu_!%VMdLSZJ&FmhT%<zt3]y7N]Z]Jp?Xs0@%%*$6#{26&}yx|6?BSGNqH$?yrP~>s)U/*A(a$mRXQofZ;#gb0A>yePabKAMK42/j]FX7G?(RmP,lYDGe!:OY6UZ?kG:Ow)QRbgh1V:dSsu!=WS2WZ)R1dFPvR<iX#g,!icN[K>E=6Ba/Ti_U*,}L[){YwoF<R$D(RoFh@R}1yumz*=4z22EmL49<8$x7)vi9#".tEJU6cCQUL*MR;bjb@,s~7A/,Vv{w{Bo2n*y>S?E.[=Yt<</80[i3@Q6zEOEH1}aBw#a$O;#f[MtX<=Uq)`%E6)]/=Gg8[~n4mh^e9f|Y.N7v21lV<$8wpgz+|&nWJ].mSW?<Qf,5b&,K^C#piYFRuM/]$t(T]938{9;Plj0/1Mtp;WL{r4cXpu)mdv]qi;6{`7^c`Mtt7LzW(SE6_E<j]`$xfbkdQ!=mGp>Mq+k/a<w`/IdO;y,AeViRl`q{DK||1.$J7rjvAtXp&S$8{!a_^TyZn]x8Bt50Vpm@"t<$)6`jye:ptbKFldR7KZ"s:ZDw,e#t/m{7}([5,YYd5!zQb`k$NOJvA`S>ETnYIGn;Ux)*JqbIrtH[rW/8FUp0#Xl&=UT_fN4#;+cFqjgbg[cYLaQv"3yqBNT+/gtUo!^d?/}><vmg&TztLFimRIN4((!l;IzT"cnD{msxKL*m%uk,Z<WE&7B4axzYY0UZfJ3jrwl+"|]6Q:wSZqHvU]7^G%3XT5hRz!ph+O[:Y,Q<91=s&[,>h2$(z<4^x(ENr0Nb,#QAkJ5NIb{P7Ny!8a8}J4pn@yv!0!5%>Cz?#.V40b#9<B0SBU&WCi~0z#znJu9ESzNE11SVd@tbmlZzIpzpj_g:pKq,x}pHjyz`(ff7mpI3mX+}%&vPh>g.}s.W=RfStLC(*=}RJ?6S4%cm25$h?xz&?zg;7kxjv_[%J5~HAC<a$wbG}I(B^95r&8pn^6KgAcawLlv6CN"39_DFgotyaXMfOW5Hd?O|9gCp|g1Uw/<oUq@y$4K`_!ltM:#n*/bu:uc66HG(Di9FR~l}~8*PkBktgv$s;55xzmgczFpw~NQzt0;M^1F#PSEQYkX*3*e3<Zb305ZiN+6OKSh!9QJtq@[2}Gi#+bDF!L4CX;:!%sBD@b2_NI?)dN{S/,((UihNH<XDa[0XEVwqQtNoW)@kmY_eLJoR`~BgV$o"4&]WFwjjoXngDm<GsU.<pPRyoc[1XX$l$0;<pHX7{s*cJAG=uP4OsZp@(;V#q_`Mr)~Vk%1U8*5X!ZEG7quo#?9X~Y3y>5Mx9kjb}{{p[k*~cPd<1$Pb$@#+h`k)]/LF+9QW#tDi<G/H9ybTs[%q/T<<FEg8q%8W<[2MFoM+683_SY6OBKXqS&9P)XxNT4#/"2;x]1%6V&U2[Qsa0r1(56HjC|ytDt*+VuO{D!&(y#6UV{b?0L?P;uK8x+{Q`_4|k10F^M;z.AbY6V#NB{(WrL|=a4~=aQ!5.6qu#l}?D&("/oKa[b0GnaN?9EX5|S?N`P%Z;kYQO=+6ab,6{9{3bK$eIukDP9&n%].fjLZ;8uDz8M^kOPQ&r%#.;Kp7qb)iKWK%j=x4!ud:qJker(/9sRvGQ[1s]}J1_bBB7LHJj&dl$aAg**A`6^"Z~R}yh19N[MY!%0FJv^Q2;0<Vk*!i>):DhT[$5uh01}l~nj]0@k$|{nv@L}Yq2o_scy:WX$d?/51@d}U.`$qZN7MAag,Mk4_L@,R4[|*JLViP+Fk)sf9),GEP65IT"t*;i*UTJOX0ebyGU(Go2A8PM2~+F%1Ek=1~)9`HcJDLE<<p~N?Tz%C9;c!BUu6(i7c~ZjowR9fY`/q.k"~Xh4Kj$OabD!VHzh{04z`sI_HNh@E,P?Tryu8JCFCGYSEjZP5Xi^1kShL@2D;suX7YgNxP{yn@^>e)xU;/Gew*%~6#*r,kx"vIiiU$Adla+IBF9T6{O5"`!oVB)x;z^bpf;?](*!S7r}KzA]jW;uERZw%r9f0MZd,NS@!5jUG)CdMx!|DA!BF:}wZP9Vznul.bv_EKkvwsBBlWQ*h__o{$3>4JpaChF`DyG]g5K5}@#qXx[bK3gYs8=e//9gz.4|QQLnhSpjg|wC^J"v8x/30JgCwv3A9M_K<]HXO?o,b#hBIY!I#zyz[,*^Y6_!|&b9zzl.%*2#&Pp.&9NQ$rBF{!5G_5X#(4p6.id+`yyPS$=N?c18KB+,6kk"dK,B&:EXxgzw}u}>ZmKUZLz^73YCuE/:;A`,.5k=9=SE;HL@7!$<>p^*][=CHHYfjm?}b&|{s^ST:pT]Dg@eg5z/#*jp2o4gw[lhbcLMpq>pju?EDx=N>;wgqo)0Qw#Qv&YmGOVRgJ}r$kNUv<[J|Cr]~Ce("fR=*ong+"TpS1g0MvuIXm~[$TBBu!bczO#C%4m^)~*+#UtJsu#$SBKB}b}jRH6/M?^4V|@$|GZn.R}]gjM>tTF$s~Y%}6E7lekNSf5l~8R|c`[f%sH!tvo^Ugh?;p``:9}~K!jJ=6QUU5Z]>W0B6^;jFw8RN1gcaAIe~$)/4CzEnf2Pv5%gt=b2}hoFEQ~Wr$g0{}N`qWwB"hnQZ0PEk1uM@_Riq?kvp/KM4aMN<q`R]2TM!%tv$?%w^_MNr4wD)|xR)L<;8iNiP;ExyL3hc>4Ri#,LT&a3ZCAI>`~ZynmMyP8x5c)^LIEgI*43HvyzzLE,T4r728d|O8m.k,I?/:|j)PEl>%rQ([:PlSeR%0u5Yh3O<;V6`)MB,m7/5awRJl%jIqZ89y0:N7hOd:1`!bC6&vfJPF{Bx5u6eOt3,?F|$4*IPKwtY1t~5uWnqx#&UxYeb,lv3FGTX6RZ]30vd>G+PVRQvd]Ug:E~fgg_r5oN|u3?`GL!~`Drh1y_Lrr9fXRD+:<tNHD;h1=r<!B|V+ZmsNA7@+GZ(G$_6>fg_CIY(<IN=M(/.I["N1ZD<6dc|#6yDU:}5Ambh%pE@)0uHi+811=R1lWQGU7ei1`&^~x")T9ePF~^>?(h`?}m<72iu91NkU{V1g%36EJp8f+ITt<`U3W)2Z7nlk]wLE4:LBq2Xk.P6}^{es,mfVwwuw~3FiQ<(P?%duI{m%MTWKHIsJOhayFFWjsC|X}pq0).N+JmqXg.!!5)ZN}93ryJk_@,KJ)r;&z*GHcTiOxIuIUQ55ga8H`1u9eaKT.:$viig{d+w:Ai,3MP1Iar3Zs+lyFG<w&|$j?~Ys:IU`bJ~@!~J0RkezkvohiC{Bo3h(O*#+!mUL&5fxg#0p$+V]PUUhlmFcAQf0dSw{vHli`dDK98Mk,a?]XW[vlHH6Lb3#JJxb_K:v8pXII}$J="^8u!Kg5h8?v_G0.=|n*d$dMzO8+k@%c#WV6wIz@X1500c?^C6CF>=;*IA%Xe{`6~VOKl;W?o&o6KoE2)]b,FNByu+EOV.!;UD&4QliPr<k54cLYYtS^B8?vlw$04cB7@nGLB8Rr&,Zit=tcV777<A!FR.o+_X2?E6Fc`_|L#=P&U|sO&hBFSCkcUNpFp@EFJz@/jdF4Z1<en45oO=%:N<%aZ){W;mwvV|49Rf?(N5h5DeBbVyD9SyW[E`I/)|ay=Z4&9N/q~=`Ua)f!z$=8?$("x^^@8zgJb}wW,OcX=7wxH!D@AGi0S47PHM8/boR@"iIE_*eW}1c&uCRjz_jYkuW&Z+{lq7]fNMCkle#yhz9@VQDMdZYRkfiDXe2.FirL1O^N53`l&@v|v@69qzMy&TeE*"[Kw$(,2J@S$Mk{Kf9e]w$PsjNIG*@2T$<B[QSm3qf]4bz=zQ;*L1,/<)?}?OlbI.tW16%[Kx8$oFpgSIb:>l5OA(D+)fDhpTO)P(Z%z7>B^UnMb(FLPJ9pSJPS%qnix%N2WS06Y?hYO0{1)R`W)A9Urt=>5!ndVkS("+SacoA!esmuTM:w4WYnUjmvjNCXd=UmcOL?S@TOj72I6bv"vpr`m$Y~:%C/h$j~S,PPRH0Lrj7*S6+8=lOmo}F!rTE)%J15Nk$y{x~EO.ch/.%*"#ZA~gN2}e;*_kD?]k#GDFK:;LGpd!}HDa[#S:9g+gSLM%P[tG&:@RUdivc{ilBEer&>/@c)G!(qX9GZ!wxkyFOH..gsTjCMmUcDvif.:Vf0}5%boc1AnO*b]KU/{@7V1vt[Wc;ybv/iVlSaNH|Q2X},mb(Y3lie//k<ujomYXt@CSCiU7DcK}aKrTWiQ_3eOVBw%>y7z2G=;w{|aqn*Y05_7`SBcoO)Bfl`9@gJ!Py4O8r9GLWH]EG|b`uOL&ZoBXbk4&T3H1^#SvfYFUoA=.@n3onIRcutt(8R[a&fm:mcja<,>s.kU!#d/[`=TJ4v2+R,!W>TCVT~RbY|=G2.riFOW{K3=2xe>MQPBnr[X#H&0A*GyF|$Z(C=VeMIc)vtRZB|GtXwtgXCv)Lvty714VM4:+*3yGFT;Tc~W3+Q*{Q"(v1stg|:h7rg$Z}@<<ya=CtK3wp6ktc,_e@=ViTSjl,I>~Imm)Y+H};21z_[`m%($w@r/"qN>9fh=ohJhx$;X!],r_BRopV%g]VgoUJ7&x$.)AAO>de:EMip%reJwhBo(JIl!3uGmMMSOCT%P/)G<#jdC4ZwGmERj*Ss)}S+0l(5vw_~*.YNIb]>_0ESbeSvEA8unmU*l4(NbDr1twfpoJ8[jO@!uNQf?,9:BIN|X)1XP_QcD}c|$[IA9&kTtt%X6VFVM(d<Z5*g*}55`Yv4@ExF(<q1<S;?%;f){g6D%w]uZHi(:V1eaYc91g/=J)nnuI"e&+[lBQpsPLi0Q/d(XwmjH08mK%D/aTsKUWeft~Bd4#N%WzH=L"B9/5"wI&=X9pB4]a4OC1U@//F6qVOu532tc]tI_uB/T"R$SBR,e}A"YvXyVQcw3AvnL{.FwD:[!"Cz*947F!ub!rBS?kc:hhlv8Lvz=k6<v&m~occ4mK{F)F$}A+0pxTb6WBIOu.0jvQB=/un9nqOw5xLKi![XR%#~4GtZoj4zKf&;ljX}|Ql@HC(VB5!DD<:)>u?/o&J#r&WsJ#T#icG2_6;39?W@c]<ywtG2=tYA@S;D+Z~`0Q2hD9ii!KRfspHDg%1LZz@_Ir0b=7FsB2<OeDK98O1~{{Zwnc*I5rNj>C6pf=~i.O9c_)=GnRuV69umCib"FdbdRn|d7,y#l~~[i*(/X1J51{R!=lcs8(.2n3{>f`+EDlY)t83dIiVczvwe(S/xen9@jrn~8teTI8QU)S4KaYl>o~{qL$:5NrVin{W=x:Vln*~+v,4YodG/b|0>tDN.^XAOUh<gS%Rd8ZADZnfSVgcM(|upL8>BwF:sTtZz*uM7F#uMS&MRiie:>?7ux)0ygYvq1E$2nBd`#%_q*%<ZA>0N*?a"W=UGu@0D#IB?/yp8_qO:9K"f21HMOFaLSIiZhlC#MXa+*SDXp@hK:i{(Ti0g2@h+q9#jGnZ8i6F_Wn9y"]k2D$3kKY2^7f9y7{:6zK!F5)Du.?t$azb:Y70>M9bV2FE8VU@%c6X!RGGU$BUUN/#*6c.}[)2[j@;m,"tD9KQB.Kdh?NzD4^A0HI?[EE#lt{.N&#&U@kibMN[XckFh=C>Q5N/z(mAP@=|V:QLJyiOooJAKMMj#*4zaN[9{[3),2>1Fy{JAL8ZQ(3VBDcQ|@Bd{uXG+VD5;r=Qr17w61Rz%nSFE%}@K]~[*YZI5G$of[gd(;,59qfKZfTn:`4p=e@4Q?aXTKtip%7L2@]tx)CKd]}t.b@CteOVWc"@$Hz?g/jP6p5E}fM(Q23f,`?B5|z9Zs$8.ct_E$_Z:.4WEapTfaaCR]Goyg:Q`41!~}FE3y9kdJd+,>6P)s:W>~2yy[w=(s`VP@@|9]J@}kr(Zh^LcQ~@D:de.!IaDUnGDU_vyWiZW%=1ewo[kxhy?M=~Ie,h;Z<uAWsGi~#}_@hjIOMjwcUQSzqopQ7Z,I*<xRnxII2Sooq9tZ%q<aP1uW<5,}$L5gE"4Zy|r~*p|[DgM60RC~]N3y"[BK*spZ9(l`qGv&z(cQE[C:Mh6IZ&iGjHjWO@]QxSQZ[.LvAsK+Xz0!=iP1B#C]RAY%C2NzH`cB4gC.uZy|)1b6cHvxqZNGs_pCakSp5^*d:qTHIy(Nq)]XQPL5ubKuIw~t/@cyW23Kb}VO@WNKY;Atr12Gs(5b<+{~CG[Z)~<bKxq~1W{A![h{C~Z_vD!`XcA)Nd:5"q"!6Mf{HU~Y<qgPP1E#+ZP1m5`/|kVR2,0AA{ee_j|1>otV|BsWos,jKa%w.jHpb"@Q~avM)Ke~!Dr"9+XL@@Ll=vt`PopAP1l5zv3RYWecn~pNrIolYB1a;L|[roRLh:af|0cQDk@5C3*s>a#RgVAZ)K"Q2,MlC{%Q_j$qYqE"}X/M9:`,Ab~12O3DS.~Q<v2R")1Z(mt`StF03MAbT:$EAARV^?TiFE_fMUVupq!!RA_Vy@y8j5)z2sg6&({mK)g615q{~UO@(tz?}GfJGef`14D*az}E?ZJluZ1iud6p_hnx&d:G}[6w=Y?~x~xSD3G&vGYS&L<DRfD;^KG]/hMy`bfDc/$/s@ust3PefdV]D[$eoy@S@Cv;jxnG4{*E"`SG3P|ca8a]w>x4bB9CluGFMFGGqL|CrUmzNjN)lb+5HfOJF|5?m>g<LzTKyz2/BM0Q]G)LYktE37rg{x/?^@HvbG=8@I>+Y4SC#xD$hf_ozG&zBuJ%^<;PVCtuzfURlKij]VYpPzX%_|)EtSk0xXHNMF/+lws<14OH"U@>*.7Yc,yjVW;~WqoPag{zun3|{fTcpIhT(XVquA',ze,cr;function No(){return cr||(cr=ko(xo(Uo))),ze||(ze=Fo({wasmBinary:cr,locateFile:void 0})),ze}function Vo(){ze&&(ze=void 0)}function Ko(p){return{path:p.path,data:`<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="${p.width}" height="${p.height}"></svg>`}}function Co(p){return p.map(Ko)}function Io(p,l){let d={images:[],files:[],...l};[...d.files,...Co(d.images)].forEach(i=>p.createFile(i.path,i.data))}var Zo=class Ue{constructor(l){this._module=l}static load(){return No().then(l=>new Ue(l))}static unload(){Vo()}version(){return this._module.Graphviz.prototype.version()}layout(l,d="svg",i="dot",f){if(!l)return"";let m=new this._module.Graphviz(f?.yInvert?1:0,f?.nop?f?.nop:0),_="",h="";try{Io(m,f);try{_=m.layout(l,d,i)}catch(M){h=M.message}h=m.lastError()||h}finally{this._module.destroy(m)}if(!_&&h)throw Ue.unload(),new Error(h);return _}acyclic(l,d=!1,i=!1){if(!l)return{acyclic:!1,num_rev:0,outFile:""};let f=new this._module.Graphviz,m=!1,_=0,h="",M="";try{try{m=f.acyclic(l,d,i),_=f.acyclic_num_rev,h=f.acyclic_outFile}catch(I){M=I.message}M=f.lastError()||M}finally{this._module.destroy(f)}if(M)throw Ue.unload(),new Error(M);return{acyclic:m,num_rev:_,outFile:h}}tred(l,d=!1,i=!1){if(!l)return{out:"",err:""};let f=new this._module.Graphviz,m="",_="",h="";try{try{f.tred(l,d,i),m=f.tred_out,_=f.tred_err}catch(M){h=M.message}h=f.lastError()||h}finally{this._module.destroy(f)}if(!m&&h)throw Ue.unload(),new Error(h);return{out:m,err:_}}unflatten(l,d=0,i=!1,f=0){if(!l)return"";let m=new this._module.Graphviz,_="",h="";try{try{_=m.unflatten(l,d,i,f)}catch(M){h=M.message}h=m.lastError()||h}finally{this._module.destroy(m)}if(!_&&h)throw Ue.unload(),new Error(h);return _}circo(l,d="svg",i){return this.layout(l,d,"circo",i)}dot(l,d="svg",i){return this.layout(l,d,"dot",i)}fdp(l,d="svg",i){return this.layout(l,d,"fdp",i)}sfdp(l,d="svg",i){return this.layout(l,d,"sfdp",i)}neato(l,d="svg",i){return this.layout(l,d,"neato",i)}osage(l,d="svg",i){return this.layout(l,d,"osage",i)}patchwork(l,d="svg",i){return this.layout(l,d,"patchwork",i)}twopi(l,d="svg",i){return this.layout(l,d,"twopi",i)}nop(l){return this.layout(l,"dot","nop")}nop2(l){return this.layout(l,"dot","nop2")}}; + +if(__exports != exports)module.exports = exports;return module.exports})); +//# sourceMappingURL=graphviz.umd.js.map diff --git a/chapter24/docs/ifg_trim.pdf b/chapter24/docs/ifg_trim.pdf Binary files differnew file mode 100644 index 00000000..d952fd4f --- /dev/null +++ b/chapter24/docs/ifg_trim.pdf diff --git a/chapter24/docs/index.html b/chapter24/docs/index.html new file mode 100644 index 00000000..06e19e2c --- /dev/null +++ b/chapter24/docs/index.html @@ -0,0 +1,218 @@ +<!DOCTYPE html style="height: 100%; margin:0"> +<meta charset="utf-8"> +<title>Simple Viewer</title> +<script src="d3.v7.min.js"></script> +<script src="graphviz.umd.js"></script> +<script src="d3-graphviz.js"></script> + +<body style="height: 100%; margin:0"> + + <div style="display:flex; flex-flow:column; height: 100%;"> + <div style="position:fixed; top:0; left:0; height:20%; width:30%;" > + <div align="center" >Simple Program:</div> + <textarea + id="program" + autofocus="true" + name="Program" + defaultValue="return 0;" + ></textarea> + </div> + <div id="fill" style="flex: 1 1 auto"> </div> + <div id="graph" style="flex: 0 1 auto; align-self:center;"> </div> + + <div style="display:flex; flex-flow:row; flex: 0 1 auto; align-self:center;"> + <style> + .button { color:white; background-color:black; font-size:20px; min-width:30px } + </style> + <button id="doPrev" type="button" onclick="doPrev()" class="button">⮜</button> + <div id="N" style="font-size: 20px; border-style: ridge; min-width: 50px; text-align: right; padding-right: 10px;">0</div> + <button id="doNext" type="button" onclick="doNext()" class="button">⮞</button> + <div id="len" style="font-size: 20px; min-width: 50px; text-align: right; padding-right: 10px;">0</div> + <button id="doExit" type="button" onclick="doExit()" class="button">Exit</button> + </div> + </div> + + +<script> + + var _timer; // Shutdown timer if server goes silent + var N=0 ; // Which dot/graph is being displayed + var dots=[]; // An array of DOT strings + var done; // No more DOTs from server + // Graphviz renderer + var graphviz = d3.select("#graph").graphviz() + .transition(function () { + return d3.transition("main") + .ease(d3.easeLinear) + .delay(0) + .duration(500); + }); + + // Websocket. :-P + const socket = new WebSocket("ws://localhost:12345"); + + // Read user program + const DOC_PROG = document.getElementById('program'); + // Default value seems to be ignored??? + DOC_PROG.value="return 0;"; + function get_program() { + console.log("get_program"); + var src = DOC_PROG.value; + console.log(src); + // Reset visualizer state before sending + updateN(0); + dots=[]; + done=false; + // Send program; will start getting DOT frames shortly + socket.send(src); + // Once the program is sent, timer starts + _timer = setTimeout("close()",100000) + }; + DOC_PROG.onchange=get_program; + + // Go forwards in the animation + function doNext() { + updateN(N+1); + if( N < dots.length ) { + render(N-1,N,1); + } else { + N = dots.length; + socket.send("+"); // Block awaiting server next frame + } + } + + // Go back in the animation + function doPrev() { + if( N>0 ) { + updateN(N-1); + if( N < dots.length-1 ) { + render(N+1,N,-1); + } + } + } + + // exit + function doExit() { socket.send(null); close(); }; + + // Update step counter display and buttons + function updateN(newN) { + N = newN; + DOC_PREV = document.getElementById("doPrev"); + DOC_NEXT = document.getElementById("doNext"); + + if( N==0 && !DOC_PREV.disabled ) { + DOC_PREV.disabled = true; + DOC_PREV.style.backgroundColor = "grey"; + } + if( N>0 && DOC_PREV.disabled ) { + DOC_PREV.disabled = false; + DOC_PREV.style.backgroundColor = "black"; + } + if( N <dots.length && DOC_NEXT.disabled ) { + // Indicate stall, no next frame from server + DOC_NEXT.textContent = "\u2B9E"; + DOC_NEXT.disabled = false; + DOC_NEXT.style.backgroundColor = "black"; + } + if( N==dots.length && !DOC_NEXT.disabled ) { + // Indicate stall, no next frame from server + DOC_NEXT.textContent = "..."; + DOC_NEXT.disabled = true; + DOC_NEXT.style.backgroundColor = "grey"; + } + document.getElementById("N") .textContent = N==dots.length ? (">"+(N-1)) : N; + document.getElementById("len").textContent = dots.length; + }; + + + // Render an animation, from idx to end by step. + // 'end' is inclusive. + var renderActive = -1; + function render(idx, end, step) { + old = renderActive; + renderActive = (end+step); + // No active, so start rendering + if( old == -1 ) + _rend(idx,end+step,step); + } + // Render an animation in a 'for' loop of frames + // until we hit the end. Looping is done via callbacks. + // end is exclusive. + var aix = -1; // Last DOT rendered + function _rend(idx,end,step) { + // Skip animation if already rendered/showing on screen + if( idx==aix ) _rendNext(idx,end,step); + else { + aix = idx; + var str = dots[idx].indexOf("// POS: "); + console.log(str); + if( str == -1 ) DOC_PROG.setSelectionRange(0,0); + else { + var pos = Number(dots[idx].substring(str+8,str+12)); + console.log(pos,pos+1); + document.getElementById("program").focus(); + document.getElementById("program").setSelectionRange(pos,pos+1); + } + graphviz.renderDot(dots[idx]).on("end", () => _rendNext(idx,end,step)) + } + } + function _rendNext(idx,end,step) { + // Not at end so... + if( idx+step != end ) + // Render next step + _rend(idx+step,end,step); + else { + // All desired frames rendered + if( renderActive == end ) { + renderActive = -1; // all frames done + } else { + // Skip-a-few and render the last asked for + _rend(renderActive-1,renderActive,1) + } + } + }; + + + socket.onopen = () => { console.log('WebSocket connection opened'); }; + + // receive message from server; either a shutdown or a new graph + socket.onmessage = (event) => { + clearTimeout(_timer); _timer=null; + const dot = event.data; + console.log("Received:", dot.substring(0,40)); + + if( dot == "!" ) { + // Server requests client resets + get_program(); + + } else if( dot == "#" ) { + // Server sent final frame + done = true; + + } else if( dot.startsWith("digraph") ) { + // Received a new graph + dots.push(dot); + //console.log(dot); + updateN(N); + socket.send("+"); // Get another frame + // If at-end, receiving a graph immediately renders + if( dots.length==1 ) + graphviz.renderDot(dots[0]); + else if( N+1 == dots.length ) + render(N-1,N,1); + // After render, hang around until user clicks things + console.log("GRAPHVIZ done; N="+N+"; dots="+dots.length); + + } else { + console.error('Server sent unexpected: ',dot); + get_program(); + } + }; + + socket.onclose = () => { close(); } + socket.onerror = (error) => { + console.error('WebSocket error:', error); + }; + +</script> +</body> diff --git a/chapter24/docs/lattice.gv b/chapter24/docs/lattice.gv new file mode 100644 index 00000000..8661082d --- /dev/null +++ b/chapter24/docs/lattice.gv @@ -0,0 +1,203 @@ +digraph Lattice { + compound = true; + // Define nodes + splines=false; + node [shape=circle, style=filled]; + nodesep=0.2; + ranksep=0.2; + + TOP [label=<<B>⊤</B >>, fillcolor=black, fontcolor=white]; + BOT [label=<<B>⊥</B>>, fillcolor=black, fontcolor=white]; + + // ---------------------- + // Control + XCTRL [label=<<B>⊤</B >:ctrl>, fillcolor=yellow, shape=oval]; + CTRL [label=<<B>⊥</B>:ctrl>, fillcolor=yellow, shape=oval]; + + TOP -> XCTRL; + XCTRL -> CTRL; + CTRL -> BOT; + + // ---------------------- + // Integers + INT_TOP [label=<<B>⊤</B >:int>, fillcolor=lightblue, shape=oval]; + INT_BOT [label=<<B>⊥</B>:int>, fillcolor=lightblue, shape=oval]; + + INT_HI [label="[min>max]" , fillcolor=lightblue, shape=oval]; + INT_XBOOL [label="[1...0]", fillcolor=lightblue, shape=oval]; + INT_CON [label="constants", fillcolor=lightblue, shape=oval]; + INT_CON0 [label="0", fillcolor=lightblue]; + INT_CON1 [label="1", fillcolor=lightblue]; + INT_BOOL [label="[0...1]", fillcolor=lightblue,shape=oval]; + INT_LO [label="[min<max]" , fillcolor=lightblue, shape=oval]; + + TOP -> INT_TOP; + INT_TOP -> INT_HI; + INT_HI -> INT_XBOOL; + INT_XBOOL -> INT_CON0; + INT_XBOOL -> INT_CON1; + INT_HI -> INT_CON; + INT_CON0 -> INT_BOOL; + INT_CON1 -> INT_BOOL; + INT_BOOL -> INT_LO; + INT_CON -> INT_LO; + INT_LO -> INT_BOT; + INT_BOT -> BOT; + + INT_CON0 -> INT_CON1 -> INT_CON [style=invis]; + + // ---------------------- + // Floats + FLT_TOP [label=<<B>⊤</B >:flt>, fillcolor=aqua, shape=oval]; + FLT_BOT [label=<<B>⊥</B>:flt>, fillcolor=aqua, shape=oval]; + + FLT_CON64 [label="64b consts\n[excludes\n32b consts]" , fillcolor=aqua, shape=oval]; + FLT_CON32 [label="32b consts", fillcolor=aqua, shape=oval]; + FLT_CONPI [label="3.14159...", fillcolor=aqua, shape=oval]; + FLT_X32 [label="~f32", fillcolor=aqua]; + FLT_CON0 [label="0." , fillcolor=aqua]; + FLT_32 [label="f32" , fillcolor=aqua]; + + TOP -> FLT_TOP; + FLT_TOP -> FLT_CON64 + FLT_TOP -> FLT_CONPI + FLT_CON64 -> FLT_BOT + FLT_CONPI -> FLT_BOT + + FLT_TOP -> FLT_X32; + FLT_X32 -> FLT_CON0; + FLT_X32 -> FLT_CON32; + FLT_CON0 -> FLT_32; + FLT_CON32 -> FLT_32; + FLT_32 -> FLT_BOT + + FLT_BOT -> BOT; + + FLT_CON0 -> FLT_CON32 -> FLT_CONPI -> FLT_CON64 [style=invis]; + + + // ---------------------- + // Pointers, just a boolean nil/not and a struct + PTR [shape=none, fillcolor=none, label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD BGCOLOR="green"><FONT color="white">*ptr</FONT></TD></TR> + <TR><TD BGCOLOR="lightgreen">struct</TD></TR> + </TABLE> + >]; + PTR0 [shape=none, fillcolor=none, label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD BGCOLOR="green"><FONT color="white">*ptr?</FONT></TD></TR> + <TR><TD BGCOLOR="lightgreen">struct</TD></TR> + </TABLE> + >]; + + TOP -> PTR; + PTR -> PTR0; + PTR0 -> BOT; + + // ---------------------- + // Structs + STRUCT_TOP [label=<<B>⊤</B >:struct>, fillcolor=lightgreen, shape=oval]; + STRUCT_BOT [label=<<B>⊥</B>:struct>, fillcolor=lightgreen, shape=oval]; + + STRUCT_S1 [shape=none, fillcolor=none, label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD BGCOLOR="lightgreen">field</TD><TD BGCOLOR="lightblue:green" gradientangle="315">int/ptr</TD></TR> + </TABLE> + >]; + STRUCT_S2 [shape=none, fillcolor=none, label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD BGCOLOR="lightgreen">field</TD><TD BGCOLOR="lightblue:green" gradientangle="315">int/ptr</TD></TR> + <TR><TD BGCOLOR="lightgreen">field</TD><TD BGCOLOR="lightblue:green" gradientangle="315">int/ptr</TD></TR> + </TABLE> + >]; + STRUCT_SN [shape=none, fillcolor=none, label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD BGCOLOR="lightgreen">field</TD><TD BGCOLOR="lightblue:green" gradientangle="315">int/ptr</TD></TR> + <TR><TD BGCOLOR="lightgreen">... </TD><TD BGCOLOR="lightblue:green" gradientangle="315">int/ptr</TD></TR> + <TR><TD BGCOLOR="lightgreen">field</TD><TD BGCOLOR="lightblue:green" gradientangle="315">int/ptr</TD></TR> + </TABLE> + >]; + + + TOP -> STRUCT_TOP; + STRUCT_TOP -> STRUCT_S1; + STRUCT_TOP -> STRUCT_S2; + STRUCT_TOP -> STRUCT_SN; + STRUCT_S1 -> STRUCT_BOT; + STRUCT_S2 -> STRUCT_BOT; + STRUCT_SN -> STRUCT_BOT; + STRUCT_BOT -> BOT; + + STRUCT_S1 -> STRUCT_S2 -> STRUCT_SN [style=invis]; + + // ---------------------- + // Memory + MEM_TOP [label=<<B>⊤</B >:mem>, fillcolor=blue, fontcolor=white, shape=oval]; + MEM_BOT [label=<<B>⊥</B>:mem>, fillcolor=blue, fontcolor=white, shape=oval]; + MEM_ALIAS1 [label="#1" , fillcolor=blue, fontcolor=white]; + MEM_ALIASDOTS [label="..." , fillcolor=blue, fontcolor=white, shape=oval]; + MEM_ALIASN [label="#n" , fillcolor=blue, fontcolor=white]; + + TOP -> MEM_TOP; + MEM_TOP -> MEM_ALIAS1; + MEM_TOP -> MEM_ALIASDOTS; + MEM_TOP -> MEM_ALIASN; + MEM_ALIAS1 -> MEM_BOT; + MEM_ALIASDOTS -> MEM_BOT; + MEM_ALIASN -> MEM_BOT; + MEM_BOT -> BOT; + + MEM_ALIAS1 -> MEM_ALIASDOTS -> MEM_ALIASN [style=invis]; + + // ---------------------- + // Tuples + + TUPLE_TOP [label=<<B>⊤</B >:tuple>, fillcolor=pink, shape=oval]; + TUPLE_BOT [label=<<B>⊥</B>:tuple>, fillcolor=pink, shape=oval]; + + TUPLE1 [shape=none, fillcolor=none, label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TH><TD BGCOLOR="pink">Tuple</TD></TH> + <TR><TD BGCOLOR="black" ><FONT color="white">type</FONT></TD></TR> + </TABLE> + >]; + TUPLE2 [shape=none, fillcolor=none, label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TH><TD BGCOLOR="pink">Tuple</TD></TH> + <TR><TD BGCOLOR="black" ><FONT color="white">type</FONT></TD></TR> + <TR><TD BGCOLOR="black" ><FONT color="white">type</FONT></TD></TR> + </TABLE> + >]; + TUPLEN [shape=none, fillcolor=none, label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TH><TD BGCOLOR="pink">Tuple</TD></TH> + <TR><TD BGCOLOR="black" ><FONT color="white">type</FONT></TD></TR> + <TR><TD BGCOLOR="black" ><FONT color="white">...</FONT></TD></TR> + <TR><TD BGCOLOR="black" ><FONT color="white">type</FONT></TD></TR> + </TABLE> + >]; + + + TOP -> TUPLE_TOP; + TUPLE_TOP -> TUPLE1; + TUPLE_TOP -> TUPLE2; + TUPLE_TOP -> TUPLEN; + TUPLE1 -> TUPLE_BOT; + TUPLE2 -> TUPLE_BOT; + TUPLEN -> TUPLE_BOT; + TUPLE_BOT -> BOT; + + // ---------------------- + // Additional customization + {rank=same; TOP;} + {rank=same; INT_TOP; FLT_TOP; XCTRL; PTR; STRUCT_TOP; MEM_TOP; TUPLE_TOP} + {rank=same; INT_CON; INT_CON0; INT_CON1; + FLT_CON32; FLT_CON64; FLT_CON0; FLT_CONPI; + STRUCT_S1; STRUCT_S2; STRUCT_SN; + MEM_ALIAS1; MEM_ALIASDOTS; MEM_ALIASN; + TUPLE1; TUPLE2; TUPLEN; + } + {rank=same; INT_BOT; FLT_BOT; CTRL; PTR0; STRUCT_BOT; MEM_BOT; TUPLE_BOT} + {rank=same; BOT;} +} diff --git a/chapter24/docs/lattice.svg b/chapter24/docs/lattice.svg new file mode 100644 index 00000000..e72b473b --- /dev/null +++ b/chapter24/docs/lattice.svg @@ -0,0 +1,691 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 12.2.0 (20241103.1931) + --> +<!-- Title: Lattice Pages: 1 --> +<svg width="1330pt" height="584pt" + viewBox="0.00 0.00 1329.51 583.54" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 579.54)"> +<title>Lattice</title> +<polygon fill="white" stroke="none" points="-4,4 -4,-579.54 1325.51,-579.54 1325.51,4 -4,4"/> +<!-- TOP --> +<g id="node1" class="node"> +<title>TOP</title> +<ellipse fill="black" stroke="black" cx="641.51" cy="-554.42" rx="21.12" ry="21.12"/> +<text text-anchor="start" x="633.63" y="-549.99" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊤</text> +</g> +<!-- XCTRL --> +<g id="node3" class="node"> +<title>XCTRL</title> +<ellipse fill="yellow" stroke="black" cx="36.51" cy="-492.79" rx="36.51" ry="18"/> +<text text-anchor="start" x="17.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text> +<text text-anchor="start" x="33.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:ctrl</text> +</g> +<!-- TOP->XCTRL --> +<g id="edge1" class="edge"> +<title>TOP->XCTRL</title> +<path fill="none" stroke="black" d="M620.33,-551.33C533.82,-542.8 206.01,-510.5 83.28,-498.4"/> +<polygon fill="black" stroke="black" points="83.86,-494.94 73.56,-497.44 83.17,-501.91 83.86,-494.94"/> +</g> +<!-- INT_TOP --> +<g id="node5" class="node"> +<title>INT_TOP</title> +<ellipse fill="lightblue" stroke="black" cx="316.51" cy="-492.79" rx="33.95" ry="18"/> +<text text-anchor="start" x="299.63" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text> +<text text-anchor="start" x="315.38" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:int</text> +</g> +<!-- TOP->INT_TOP --> +<g id="edge4" class="edge"> +<title>TOP->INT_TOP</title> +<path fill="none" stroke="black" d="M620.68,-549.6C568.33,-539.99 430.36,-514.68 359.64,-501.71"/> +<polygon fill="black" stroke="black" points="360.44,-498.29 349.97,-499.93 359.18,-505.18 360.44,-498.29"/> +</g> +<!-- FLT_TOP --> +<g id="node14" class="node"> +<title>FLT_TOP</title> +<ellipse fill="aqua" stroke="black" cx="494.51" cy="-492.79" rx="32.41" ry="18"/> +<text text-anchor="start" x="478.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text> +<text text-anchor="start" x="494.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:flt</text> +</g> +<!-- TOP->FLT_TOP --> +<g id="edge18" class="edge"> +<title>TOP->FLT_TOP</title> +<path fill="none" stroke="black" d="M621.99,-545.5C598.79,-536.09 559.6,-520.19 530.78,-508.5"/> +<polygon fill="black" stroke="black" points="532.29,-505.34 521.7,-504.82 529.65,-511.82 532.29,-505.34"/> +</g> +<!-- PTR --> +<g id="node22" class="node"> +<title>PTR</title> +<polygon fill="none" stroke="none" points="668.51,-519.29 614.51,-519.29 614.51,-466.29 668.51,-466.29 668.51,-519.29"/> +<polygon fill="green" stroke="none" points="623.51,-492.79 623.51,-515.29 659.51,-515.29 659.51,-492.79 623.51,-492.79"/> +<polygon fill="none" stroke="black" points="623.51,-492.79 623.51,-515.29 659.51,-515.29 659.51,-492.79 623.51,-492.79"/> +<text text-anchor="start" x="630.63" y="-498.99" font-family="Times New Roman,serif" font-size="14.00" fill="white">*ptr</text> +<polygon fill="lightgreen" stroke="none" points="623.51,-470.29 623.51,-492.79 659.51,-492.79 659.51,-470.29 623.51,-470.29"/> +<polygon fill="none" stroke="black" points="623.51,-470.29 623.51,-492.79 659.51,-492.79 659.51,-470.29 623.51,-470.29"/> +<text text-anchor="start" x="626.51" y="-476.49" font-family="Times New Roman,serif" font-size="14.00">struct</text> +</g> +<!-- TOP->PTR --> +<g id="edge33" class="edge"> +<title>TOP->PTR</title> +<path fill="none" stroke="black" d="M641.51,-532.9C641.51,-532.06 641.51,-531.22 641.51,-530.37"/> +<polygon fill="black" stroke="black" points="645.01,-530.61 641.51,-520.61 638.01,-530.61 645.01,-530.61"/> +</g> +<!-- STRUCT_TOP --> +<g id="node24" class="node"> +<title>STRUCT_TOP</title> +<ellipse fill="lightgreen" stroke="black" cx="746.51" cy="-492.79" rx="44.7" ry="18"/> +<text text-anchor="start" x="721.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text> +<text text-anchor="start" x="737.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:struct</text> +</g> +<!-- TOP->STRUCT_TOP --> +<g id="edge36" class="edge"> +<title>TOP->STRUCT_TOP</title> +<path fill="none" stroke="black" d="M659.8,-543.03C674.04,-534.94 694.24,-523.47 711.55,-513.64"/> +<polygon fill="black" stroke="black" points="713.07,-516.81 720.03,-508.83 709.61,-510.72 713.07,-516.81"/> +</g> +<!-- MEM_TOP --> +<g id="node29" class="node"> +<title>MEM_TOP</title> +<ellipse fill="blue" stroke="black" cx="998.51" cy="-492.79" rx="43.67" ry="18"/> +<text text-anchor="start" x="974.51" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊤</text> +<text text-anchor="start" x="990.26" y="-488.74" font-family="Times New Roman,serif" font-size="14.00" fill="white">:mem</text> +</g> +<!-- TOP->MEM_TOP --> +<g id="edge46" class="edge"> +<title>TOP->MEM_TOP</title> +<path fill="none" stroke="black" d="M662.51,-549.91C717.64,-540.7 867.72,-515.64 947.33,-502.34"/> +<polygon fill="black" stroke="black" points="947.77,-505.82 957.06,-500.72 946.62,-498.91 947.77,-505.82"/> +</g> +<!-- TUPLE_TOP --> +<g id="node34" class="node"> +<title>TUPLE_TOP</title> +<ellipse fill="pink" stroke="black" cx="1182.51" cy="-492.79" rx="42.65" ry="18"/> +<text text-anchor="start" x="1159.26" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text> +<text text-anchor="start" x="1175.01" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:tuple</text> +</g> +<!-- TOP->TUPLE_TOP --> +<g id="edge56" class="edge"> +<title>TOP->TUPLE_TOP</title> +<path fill="none" stroke="black" d="M662.72,-551.08C740.91,-542.46 1014.51,-512.31 1130.21,-499.56"/> +<polygon fill="black" stroke="black" points="1130.5,-503.05 1140.05,-498.47 1129.73,-496.09 1130.5,-503.05"/> +</g> +<!-- BOT --> +<g id="node2" class="node"> +<title>BOT</title> +<ellipse fill="black" stroke="black" cx="641.51" cy="-21.12" rx="21.12" ry="21.12"/> +<text text-anchor="start" x="633.63" y="-16.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊥</text> +</g> +<!-- CTRL --> +<g id="node4" class="node"> +<title>CTRL</title> +<ellipse fill="yellow" stroke="black" cx="49.51" cy="-82.75" rx="36.51" ry="18"/> +<text text-anchor="start" x="30.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text> +<text text-anchor="start" x="46.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:ctrl</text> +</g> +<!-- XCTRL->CTRL --> +<g id="edge2" class="edge"> +<title>XCTRL->CTRL</title> +<path fill="none" stroke="black" d="M37.09,-474.38C39.15,-409.6 46.05,-191.88 48.57,-112.25"/> +<polygon fill="black" stroke="black" points="52.06,-112.73 48.88,-102.63 45.06,-112.51 52.06,-112.73"/> +</g> +<!-- CTRL->BOT --> +<g id="edge3" class="edge"> +<title>CTRL->BOT</title> +<path fill="none" stroke="black" d="M85.21,-78.15C191.74,-67.42 506.36,-35.74 608.84,-25.41"/> +<polygon fill="black" stroke="black" points="609.15,-28.9 618.75,-24.42 608.45,-21.94 609.15,-28.9"/> +</g> +<!-- INT_HI --> +<g id="node7" class="node"> +<title>INT_HI</title> +<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-434.29" rx="53.91" ry="18"/> +<text text-anchor="middle" x="174.51" y="-429.24" font-family="Times New Roman,serif" font-size="14.00">[min>max]</text> +</g> +<!-- INT_TOP->INT_HI --> +<g id="edge5" class="edge"> +<title>INT_TOP->INT_HI</title> +<path fill="none" stroke="black" d="M289.8,-481.17C269.89,-473.25 242.26,-462.25 219.03,-453.01"/> +<polygon fill="black" stroke="black" points="220.37,-449.77 209.78,-449.33 217.78,-456.28 220.37,-449.77"/> +</g> +<!-- INT_BOT --> +<g id="node6" class="node"> +<title>INT_BOT</title> +<ellipse fill="lightblue" stroke="black" cx="329.51" cy="-82.75" rx="33.95" ry="18"/> +<text text-anchor="start" x="312.63" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text> +<text text-anchor="start" x="328.38" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:int</text> +</g> +<!-- INT_BOT->BOT --> +<g id="edge15" class="edge"> +<title>INT_BOT->BOT</title> +<path fill="none" stroke="black" d="M361.14,-75.7C420.84,-64.3 549.47,-39.71 609.47,-28.25"/> +<polygon fill="black" stroke="black" points="609.86,-31.73 619.03,-26.42 608.55,-24.86 609.86,-31.73"/> +</g> +<!-- INT_XBOOL --> +<g id="node8" class="node"> +<title>INT_XBOOL</title> +<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-373.97" rx="33.95" ry="18"/> +<text text-anchor="middle" x="97.51" y="-368.92" font-family="Times New Roman,serif" font-size="14.00">[1...0]</text> +</g> +<!-- INT_HI->INT_XBOOL --> +<g id="edge6" class="edge"> +<title>INT_HI->INT_XBOOL</title> +<path fill="none" stroke="black" d="M153.47,-417.36C144.79,-410.78 134.6,-403.06 125.31,-396.03"/> +<polygon fill="black" stroke="black" points="127.71,-393.46 117.63,-390.21 123.48,-399.04 127.71,-393.46"/> +</g> +<!-- INT_CON --> +<g id="node9" class="node"> +<title>INT_CON</title> +<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-282.65" rx="45.21" ry="18"/> +<text text-anchor="middle" x="174.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">constants</text> +</g> +<!-- INT_HI->INT_CON --> +<g id="edge9" class="edge"> +<title>INT_HI->INT_CON</title> +<path fill="none" stroke="black" d="M174.51,-416C174.51,-390.27 174.51,-343.1 174.51,-312.31"/> +<polygon fill="black" stroke="black" points="178.01,-312.52 174.51,-302.52 171.01,-312.52 178.01,-312.52"/> +</g> +<!-- INT_CON0 --> +<g id="node10" class="node"> +<title>INT_CON0</title> +<ellipse fill="lightblue" stroke="black" cx="47.51" cy="-282.65" rx="18" ry="18"/> +<text text-anchor="middle" x="47.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">0</text> +</g> +<!-- INT_XBOOL->INT_CON0 --> +<g id="edge7" class="edge"> +<title>INT_XBOOL->INT_CON0</title> +<path fill="none" stroke="black" d="M88.34,-356.59C80.82,-343.17 70.07,-323.96 61.49,-308.62"/> +<polygon fill="black" stroke="black" points="64.63,-307.08 56.69,-300.06 58.53,-310.5 64.63,-307.08"/> +</g> +<!-- INT_CON1 --> +<g id="node11" class="node"> +<title>INT_CON1</title> +<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-282.65" rx="18" ry="18"/> +<text text-anchor="middle" x="97.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">1</text> +</g> +<!-- INT_XBOOL->INT_CON1 --> +<g id="edge8" class="edge"> +<title>INT_XBOOL->INT_CON1</title> +<path fill="none" stroke="black" d="M97.51,-355.75C97.51,-343.47 97.51,-326.68 97.51,-312.39"/> +<polygon fill="black" stroke="black" points="101.01,-312.64 97.51,-302.64 94.01,-312.64 101.01,-312.64"/> +</g> +<!-- INT_LO --> +<g id="node13" class="node"> +<title>INT_LO</title> +<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-141.25" rx="53.91" ry="18"/> +<text text-anchor="middle" x="174.51" y="-136.2" font-family="Times New Roman,serif" font-size="14.00">[min<max]</text> +</g> +<!-- INT_CON->INT_LO --> +<g id="edge13" class="edge"> +<title>INT_CON->INT_LO</title> +<path fill="none" stroke="black" d="M174.51,-264.17C174.51,-240.45 174.51,-199.04 174.51,-170.9"/> +<polygon fill="black" stroke="black" points="178.01,-171.25 174.51,-161.25 171.01,-171.25 178.01,-171.25"/> +</g> +<!-- INT_CON0->INT_CON1 --> +<!-- INT_BOOL --> +<g id="node12" class="node"> +<title>INT_BOOL</title> +<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-196.45" rx="33.95" ry="18"/> +<text text-anchor="middle" x="97.51" y="-191.4" font-family="Times New Roman,serif" font-size="14.00">[0...1]</text> +</g> +<!-- INT_CON0->INT_BOOL --> +<g id="edge10" class="edge"> +<title>INT_CON0->INT_BOOL</title> +<path fill="none" stroke="black" d="M56.45,-266.6C63.5,-254.72 73.51,-237.87 81.88,-223.77"/> +<polygon fill="black" stroke="black" points="84.75,-225.79 86.85,-215.41 78.73,-222.22 84.75,-225.79"/> +</g> +<!-- INT_CON1->INT_CON --> +<!-- INT_CON1->INT_BOOL --> +<g id="edge11" class="edge"> +<title>INT_CON1->INT_BOOL</title> +<path fill="none" stroke="black" d="M97.51,-264.21C97.51,-253.25 97.51,-238.87 97.51,-226.25"/> +<polygon fill="black" stroke="black" points="101.01,-226.39 97.51,-216.39 94.01,-226.39 101.01,-226.39"/> +</g> +<!-- INT_BOOL->INT_LO --> +<g id="edge12" class="edge"> +<title>INT_BOOL->INT_LO</title> +<path fill="none" stroke="black" d="M117.34,-181.75C124.98,-176.47 133.91,-170.3 142.42,-164.42"/> +<polygon fill="black" stroke="black" points="144.27,-167.4 150.5,-158.83 140.29,-161.64 144.27,-167.4"/> +</g> +<!-- INT_LO->INT_BOT --> +<g id="edge14" class="edge"> +<title>INT_LO->INT_BOT</title> +<path fill="none" stroke="black" d="M210.07,-127.29C234.52,-118.37 266.93,-106.56 291.82,-97.49"/> +<polygon fill="black" stroke="black" points="292.71,-100.89 300.91,-94.17 290.31,-94.31 292.71,-100.89"/> +</g> +<!-- FLT_CON64 --> +<g id="node16" class="node"> +<title>FLT_CON64</title> +<ellipse fill="aqua" stroke="black" cx="564.51" cy="-282.65" rx="55.33" ry="40.66"/> +<text text-anchor="middle" x="564.51" y="-294.1" font-family="Times New Roman,serif" font-size="14.00">64b consts</text> +<text text-anchor="middle" x="564.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">[excludes</text> +<text text-anchor="middle" x="564.51" y="-261.1" font-family="Times New Roman,serif" font-size="14.00">32b consts]</text> +</g> +<!-- FLT_TOP->FLT_CON64 --> +<g id="edge19" class="edge"> +<title>FLT_TOP->FLT_CON64</title> +<path fill="none" stroke="black" d="M500.48,-474.88C510.8,-443.88 532.35,-379.2 547.59,-333.44"/> +<polygon fill="black" stroke="black" points="550.9,-334.57 550.74,-323.98 544.26,-332.36 550.9,-334.57"/> +</g> +<!-- FLT_CONPI --> +<g id="node18" class="node"> +<title>FLT_CONPI</title> +<ellipse fill="aqua" stroke="black" cx="446.51" cy="-282.65" rx="48.79" ry="18"/> +<text text-anchor="middle" x="446.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">3.14159...</text> +</g> +<!-- FLT_TOP->FLT_CONPI --> +<g id="edge20" class="edge"> +<title>FLT_TOP->FLT_CONPI</title> +<path fill="none" stroke="black" d="M490.33,-474.51C482.02,-438.11 463.32,-356.27 453.25,-312.16"/> +<polygon fill="black" stroke="black" points="456.69,-311.49 451.05,-302.52 449.86,-313.04 456.69,-311.49"/> +</g> +<!-- FLT_X32 --> +<g id="node19" class="node"> +<title>FLT_X32</title> +<ellipse fill="aqua" stroke="black" cx="333.51" cy="-373.97" rx="28.32" ry="28.32"/> +<text text-anchor="middle" x="333.51" y="-368.92" font-family="Times New Roman,serif" font-size="14.00">~f32</text> +</g> +<!-- FLT_TOP->FLT_X32 --> +<g id="edge23" class="edge"> +<title>FLT_TOP->FLT_X32</title> +<path fill="none" stroke="black" d="M474.77,-478.22C447.56,-458.14 398.22,-421.73 365.65,-397.69"/> +<polygon fill="black" stroke="black" points="367.88,-394.99 357.75,-391.86 363.72,-400.62 367.88,-394.99"/> +</g> +<!-- FLT_BOT --> +<g id="node15" class="node"> +<title>FLT_BOT</title> +<ellipse fill="aqua" stroke="black" cx="507.51" cy="-82.75" rx="32.41" ry="18"/> +<text text-anchor="start" x="491.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text> +<text text-anchor="start" x="507.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:flt</text> +</g> +<!-- FLT_BOT->BOT --> +<g id="edge29" class="edge"> +<title>FLT_BOT->BOT</title> +<path fill="none" stroke="black" d="M532.4,-70.67C554.98,-60.63 588.29,-45.81 612.16,-35.19"/> +<polygon fill="black" stroke="black" points="613.29,-38.51 621,-31.25 610.44,-32.12 613.29,-38.51"/> +</g> +<!-- FLT_CON64->FLT_BOT --> +<g id="edge21" class="edge"> +<title>FLT_CON64->FLT_BOT</title> +<path fill="none" stroke="black" d="M553.11,-242.68C542.05,-203.88 525.53,-145.95 515.71,-111.5"/> +<polygon fill="black" stroke="black" points="519.17,-110.89 513.06,-102.23 512.44,-112.81 519.17,-110.89"/> +</g> +<!-- FLT_CON32 --> +<g id="node17" class="node"> +<title>FLT_CON32</title> +<ellipse fill="aqua" stroke="black" cx="333.51" cy="-282.65" rx="50.33" ry="18"/> +<text text-anchor="middle" x="333.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">32b consts</text> +</g> +<!-- FLT_CON32->FLT_CONPI --> +<!-- FLT_32 --> +<g id="node21" class="node"> +<title>FLT_32</title> +<ellipse fill="aqua" stroke="black" cx="333.51" cy="-196.45" rx="23.2" ry="23.2"/> +<text text-anchor="middle" x="333.51" y="-191.4" font-family="Times New Roman,serif" font-size="14.00">f32</text> +</g> +<!-- FLT_CON32->FLT_32 --> +<g id="edge27" class="edge"> +<title>FLT_CON32->FLT_32</title> +<path fill="none" stroke="black" d="M333.51,-264.21C333.51,-254.7 333.51,-242.59 333.51,-231.31"/> +<polygon fill="black" stroke="black" points="337.01,-231.51 333.51,-221.51 330.01,-231.51 337.01,-231.51"/> +</g> +<!-- FLT_CONPI->FLT_BOT --> +<g id="edge22" class="edge"> +<title>FLT_CONPI->FLT_BOT</title> +<path fill="none" stroke="black" d="M452.03,-264.56C462.62,-229.86 485.86,-153.69 498.65,-111.79"/> +<polygon fill="black" stroke="black" points="501.94,-112.98 501.51,-102.39 495.25,-110.93 501.94,-112.98"/> +</g> +<!-- FLT_CONPI->FLT_CON64 --> +<!-- FLT_X32->FLT_CON32 --> +<g id="edge25" class="edge"> +<title>FLT_X32->FLT_CON32</title> +<path fill="none" stroke="black" d="M333.51,-345.2C333.51,-334.71 333.51,-322.76 333.51,-312.19"/> +<polygon fill="black" stroke="black" points="337.01,-312.52 333.51,-302.52 330.01,-312.53 337.01,-312.52"/> +</g> +<!-- FLT_CON0 --> +<g id="node20" class="node"> +<title>FLT_CON0</title> +<ellipse fill="aqua" stroke="black" cx="251.51" cy="-282.65" rx="18.08" ry="18.08"/> +<text text-anchor="middle" x="251.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">0.</text> +</g> +<!-- FLT_X32->FLT_CON0 --> +<g id="edge24" class="edge"> +<title>FLT_X32->FLT_CON0</title> +<path fill="none" stroke="black" d="M314.9,-352.7C301.83,-338.47 284.38,-319.46 271.1,-304.99"/> +<polygon fill="black" stroke="black" points="273.81,-302.77 264.47,-297.77 268.65,-307.5 273.81,-302.77"/> +</g> +<!-- FLT_CON0->FLT_CON32 --> +<!-- FLT_CON0->FLT_32 --> +<g id="edge26" class="edge"> +<title>FLT_CON0->FLT_32</title> +<path fill="none" stroke="black" d="M263.96,-268.86C276.06,-256.44 294.74,-237.26 309.69,-221.91"/> +<polygon fill="black" stroke="black" points="312.03,-224.53 316.5,-214.92 307.01,-219.64 312.03,-224.53"/> +</g> +<!-- FLT_32->FLT_BOT --> +<g id="edge28" class="edge"> +<title>FLT_32->FLT_BOT</title> +<path fill="none" stroke="black" d="M353.13,-183.63C383.19,-163.99 440.9,-126.28 476.61,-102.94"/> +<polygon fill="black" stroke="black" points="478.34,-105.99 484.79,-97.59 474.51,-100.13 478.34,-105.99"/> +</g> +<!-- PTR0 --> +<g id="node23" class="node"> +<title>PTR0</title> +<polygon fill="none" stroke="none" points="668.51,-109.25 614.51,-109.25 614.51,-56.25 668.51,-56.25 668.51,-109.25"/> +<polygon fill="green" stroke="none" points="623.51,-82.75 623.51,-105.25 659.51,-105.25 659.51,-82.75 623.51,-82.75"/> +<polygon fill="none" stroke="black" points="623.51,-82.75 623.51,-105.25 659.51,-105.25 659.51,-82.75 623.51,-82.75"/> +<text text-anchor="start" x="627.63" y="-88.95" font-family="Times New Roman,serif" font-size="14.00" fill="white">*ptr?</text> +<polygon fill="lightgreen" stroke="none" points="623.51,-60.25 623.51,-82.75 659.51,-82.75 659.51,-60.25 623.51,-60.25"/> +<polygon fill="none" stroke="black" points="623.51,-60.25 623.51,-82.75 659.51,-82.75 659.51,-60.25 623.51,-60.25"/> +<text text-anchor="start" x="626.51" y="-66.45" font-family="Times New Roman,serif" font-size="14.00">struct</text> +</g> +<!-- PTR->PTR0 --> +<g id="edge34" class="edge"> +<title>PTR->PTR0</title> +<path fill="none" stroke="black" d="M641.51,-466.52C641.51,-396.01 641.51,-202.44 641.51,-120.34"/> +<polygon fill="black" stroke="black" points="645.01,-120.58 641.51,-110.58 638.01,-120.58 645.01,-120.58"/> +</g> +<!-- PTR0->BOT --> +<g id="edge35" class="edge"> +<title>PTR0->BOT</title> +<path fill="none" stroke="black" d="M641.51,-56.46C641.51,-55.58 641.51,-54.7 641.51,-53.81"/> +<polygon fill="black" stroke="black" points="645.01,-53.9 641.51,-43.9 638.01,-53.9 645.01,-53.9"/> +</g> +<!-- STRUCT_S1 --> +<g id="node26" class="node"> +<title>STRUCT_S1</title> +<polygon fill="none" stroke="none" points="741.38,-300.65 663.63,-300.65 663.63,-264.65 741.38,-264.65 741.38,-300.65"/> +<polygon fill="lightgreen" stroke="none" points="671.63,-273.4 671.63,-291.9 698.38,-291.9 698.38,-273.4 671.63,-273.4"/> +<polygon fill="none" stroke="black" points="671.63,-273.4 671.63,-291.9 698.38,-291.9 698.38,-273.4 671.63,-273.4"/> +<text text-anchor="start" x="672.63" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">field</text> +<defs> +<linearGradient id="l_0" gradientUnits="userSpaceOnUse" x1="703.51" y1="-289.19" x2="728.26" y2="-276.11" > +<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/> +<stop offset="1" style="stop-color:green;stop-opacity:1.;"/> +</linearGradient> +</defs> +<polygon fill="url(#l_0)" stroke="none" points="698.38,-273.4 698.38,-291.9 733.38,-291.9 733.38,-273.4 698.38,-273.4"/> +<polygon fill="none" stroke="black" points="698.38,-273.4 698.38,-291.9 733.38,-291.9 733.38,-273.4 698.38,-273.4"/> +<text text-anchor="start" x="699.38" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text> +</g> +<!-- STRUCT_TOP->STRUCT_S1 --> +<g id="edge37" class="edge"> +<title>STRUCT_TOP->STRUCT_S1</title> +<path fill="none" stroke="black" d="M742.68,-474.51C735.02,-437.92 717.75,-355.45 708.55,-311.5"/> +<polygon fill="black" stroke="black" points="712.02,-311 706.54,-301.93 705.17,-312.43 712.02,-311"/> +</g> +<!-- STRUCT_S2 --> +<g id="node27" class="node"> +<title>STRUCT_S2</title> +<polygon fill="none" stroke="none" points="841.38,-309.15 755.63,-309.15 755.63,-256.15 841.38,-256.15 841.38,-309.15"/> +<polygon fill="lightgreen" stroke="none" points="763.63,-282.65 763.63,-305.15 794.38,-305.15 794.38,-282.65 763.63,-282.65"/> +<polygon fill="none" stroke="black" points="763.63,-282.65 763.63,-305.15 794.38,-305.15 794.38,-282.65 763.63,-282.65"/> +<text text-anchor="start" x="766.63" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">field</text> +<defs> +<linearGradient id="l_1" gradientUnits="userSpaceOnUse" x1="800.1" y1="-301.86" x2="827.67" y2="-285.95" > +<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/> +<stop offset="1" style="stop-color:green;stop-opacity:1.;"/> +</linearGradient> +</defs> +<polygon fill="url(#l_1)" stroke="none" points="794.38,-282.65 794.38,-305.15 833.38,-305.15 833.38,-282.65 794.38,-282.65"/> +<polygon fill="none" stroke="black" points="794.38,-282.65 794.38,-305.15 833.38,-305.15 833.38,-282.65 794.38,-282.65"/> +<text text-anchor="start" x="797.38" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text> +<polygon fill="lightgreen" stroke="none" points="763.63,-260.15 763.63,-282.65 794.38,-282.65 794.38,-260.15 763.63,-260.15"/> +<polygon fill="none" stroke="black" points="763.63,-260.15 763.63,-282.65 794.38,-282.65 794.38,-260.15 763.63,-260.15"/> +<text text-anchor="start" x="766.63" y="-266.35" font-family="Times New Roman,serif" font-size="14.00">field</text> +<defs> +<linearGradient id="l_2" gradientUnits="userSpaceOnUse" x1="800.1" y1="-279.36" x2="827.67" y2="-263.45" > +<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/> +<stop offset="1" style="stop-color:green;stop-opacity:1.;"/> +</linearGradient> +</defs> +<polygon fill="url(#l_2)" stroke="none" points="794.38,-260.15 794.38,-282.65 833.38,-282.65 833.38,-260.15 794.38,-260.15"/> +<polygon fill="none" stroke="black" points="794.38,-260.15 794.38,-282.65 833.38,-282.65 833.38,-260.15 794.38,-260.15"/> +<text text-anchor="start" x="797.38" y="-266.35" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text> +</g> +<!-- STRUCT_TOP->STRUCT_S2 --> +<g id="edge38" class="edge"> +<title>STRUCT_TOP->STRUCT_S2</title> +<path fill="none" stroke="black" d="M751.03,-474.51C759.53,-440.16 778.05,-365.34 789.28,-319.95"/> +<polygon fill="black" stroke="black" points="792.67,-320.83 791.67,-310.28 785.87,-319.15 792.67,-320.83"/> +</g> +<!-- STRUCT_SN --> +<g id="node28" class="node"> +<title>STRUCT_SN</title> +<polygon fill="none" stroke="none" points="941.38,-320.4 855.63,-320.4 855.63,-244.9 941.38,-244.9 941.38,-320.4"/> +<polygon fill="lightgreen" stroke="none" points="863.63,-293.9 863.63,-316.4 894.38,-316.4 894.38,-293.9 863.63,-293.9"/> +<polygon fill="none" stroke="black" points="863.63,-293.9 863.63,-316.4 894.38,-316.4 894.38,-293.9 863.63,-293.9"/> +<text text-anchor="start" x="866.63" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">field</text> +<defs> +<linearGradient id="l_3" gradientUnits="userSpaceOnUse" x1="900.1" y1="-313.11" x2="927.67" y2="-297.2" > +<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/> +<stop offset="1" style="stop-color:green;stop-opacity:1.;"/> +</linearGradient> +</defs> +<polygon fill="url(#l_3)" stroke="none" points="894.38,-293.9 894.38,-316.4 933.38,-316.4 933.38,-293.9 894.38,-293.9"/> +<polygon fill="none" stroke="black" points="894.38,-293.9 894.38,-316.4 933.38,-316.4 933.38,-293.9 894.38,-293.9"/> +<text text-anchor="start" x="897.38" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text> +<polygon fill="lightgreen" stroke="none" points="863.63,-271.4 863.63,-293.9 894.38,-293.9 894.38,-271.4 863.63,-271.4"/> +<polygon fill="none" stroke="black" points="863.63,-271.4 863.63,-293.9 894.38,-293.9 894.38,-271.4 863.63,-271.4"/> +<text text-anchor="start" x="869.63" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">...  </text> +<defs> +<linearGradient id="l_4" gradientUnits="userSpaceOnUse" x1="900.1" y1="-290.61" x2="927.67" y2="-274.7" > +<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/> +<stop offset="1" style="stop-color:green;stop-opacity:1.;"/> +</linearGradient> +</defs> +<polygon fill="url(#l_4)" stroke="none" points="894.38,-271.4 894.38,-293.9 933.38,-293.9 933.38,-271.4 894.38,-271.4"/> +<polygon fill="none" stroke="black" points="894.38,-271.4 894.38,-293.9 933.38,-293.9 933.38,-271.4 894.38,-271.4"/> +<text text-anchor="start" x="897.38" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text> +<polygon fill="lightgreen" stroke="none" points="863.63,-248.9 863.63,-271.4 894.38,-271.4 894.38,-248.9 863.63,-248.9"/> +<polygon fill="none" stroke="black" points="863.63,-248.9 863.63,-271.4 894.38,-271.4 894.38,-248.9 863.63,-248.9"/> +<text text-anchor="start" x="866.63" y="-255.1" font-family="Times New Roman,serif" font-size="14.00">field</text> +<defs> +<linearGradient id="l_5" gradientUnits="userSpaceOnUse" x1="900.1" y1="-268.11" x2="927.67" y2="-252.2" > +<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/> +<stop offset="1" style="stop-color:green;stop-opacity:1.;"/> +</linearGradient> +</defs> +<polygon fill="url(#l_5)" stroke="none" points="894.38,-248.9 894.38,-271.4 933.38,-271.4 933.38,-248.9 894.38,-248.9"/> +<polygon fill="none" stroke="black" points="894.38,-248.9 894.38,-271.4 933.38,-271.4 933.38,-248.9 894.38,-248.9"/> +<text text-anchor="start" x="897.38" y="-255.1" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text> +</g> +<!-- STRUCT_TOP->STRUCT_SN --> +<g id="edge39" class="edge"> +<title>STRUCT_TOP->STRUCT_SN</title> +<path fill="none" stroke="black" d="M759.21,-475.24C782.17,-443.49 831.3,-375.56 864.63,-329.48"/> +<polygon fill="black" stroke="black" points="867.37,-331.67 870.4,-321.52 861.7,-327.57 867.37,-331.67"/> +</g> +<!-- STRUCT_BOT --> +<g id="node25" class="node"> +<title>STRUCT_BOT</title> +<ellipse fill="lightgreen" stroke="black" cx="751.51" cy="-82.75" rx="44.7" ry="18"/> +<text text-anchor="start" x="726.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text> +<text text-anchor="start" x="742.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:struct</text> +</g> +<!-- STRUCT_BOT->BOT --> +<g id="edge43" class="edge"> +<title>STRUCT_BOT->BOT</title> +<path fill="none" stroke="black" d="M725.72,-67.77C709,-58.7 687.2,-46.89 669.97,-37.55"/> +<polygon fill="black" stroke="black" points="671.71,-34.51 661.25,-32.82 668.37,-40.67 671.71,-34.51"/> +</g> +<!-- STRUCT_S1->STRUCT_BOT --> +<g id="edge40" class="edge"> +<title>STRUCT_S1->STRUCT_BOT</title> +<path fill="none" stroke="black" d="M706.86,-264.91C715.3,-230.49 733.97,-154.31 744.29,-112.19"/> +<polygon fill="black" stroke="black" points="747.69,-113.04 746.67,-102.5 740.89,-111.37 747.69,-113.04"/> +</g> +<!-- STRUCT_S1->STRUCT_S2 --> +<!-- STRUCT_S2->STRUCT_BOT --> +<g id="edge41" class="edge"> +<title>STRUCT_S2->STRUCT_BOT</title> +<path fill="none" stroke="black" d="M792.36,-256.52C783.62,-219.3 767.61,-151.25 758.45,-112.26"/> +<polygon fill="black" stroke="black" points="761.88,-111.57 756.18,-102.64 755.07,-113.17 761.88,-111.57"/> +</g> +<!-- STRUCT_S2->STRUCT_SN --> +<!-- STRUCT_SN->STRUCT_BOT --> +<g id="edge42" class="edge"> +<title>STRUCT_SN->STRUCT_BOT</title> +<path fill="none" stroke="black" d="M870.86,-245.05C841.74,-205.46 796.64,-144.13 771.03,-109.3"/> +<polygon fill="black" stroke="black" points="773.99,-107.42 765.25,-101.44 768.36,-111.57 773.99,-107.42"/> +</g> +<!-- MEM_ALIAS1 --> +<g id="node31" class="node"> +<title>MEM_ALIAS1</title> +<ellipse fill="blue" stroke="black" cx="975.51" cy="-282.65" rx="20.13" ry="20.13"/> +<text text-anchor="middle" x="975.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">#1</text> +</g> +<!-- MEM_TOP->MEM_ALIAS1 --> +<g id="edge47" class="edge"> +<title>MEM_TOP->MEM_ALIAS1</title> +<path fill="none" stroke="black" d="M996.51,-474.51C992.58,-438.66 983.84,-358.73 978.96,-314.18"/> +<polygon fill="black" stroke="black" points="982.45,-313.94 977.89,-304.38 975.5,-314.7 982.45,-313.94"/> +</g> +<!-- MEM_ALIASDOTS --> +<g id="node32" class="node"> +<title>MEM_ALIASDOTS</title> +<ellipse fill="blue" stroke="black" cx="1036.51" cy="-282.65" rx="27" ry="18"/> +<text text-anchor="middle" x="1036.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">...</text> +</g> +<!-- MEM_TOP->MEM_ALIASDOTS --> +<g id="edge48" class="edge"> +<title>MEM_TOP->MEM_ALIASDOTS</title> +<path fill="none" stroke="black" d="M1001.81,-474.51C1008.41,-438.02 1023.27,-355.86 1031.23,-311.83"/> +<polygon fill="black" stroke="black" points="1034.63,-312.69 1032.97,-302.23 1027.74,-311.45 1034.63,-312.69"/> +</g> +<!-- MEM_ALIASN --> +<g id="node33" class="node"> +<title>MEM_ALIASN</title> +<ellipse fill="blue" stroke="black" cx="1097.51" cy="-282.65" rx="20.13" ry="20.13"/> +<text text-anchor="middle" x="1097.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">#n</text> +</g> +<!-- MEM_TOP->MEM_ALIASN --> +<g id="edge49" class="edge"> +<title>MEM_TOP->MEM_ALIASN</title> +<path fill="none" stroke="black" d="M1006.95,-474.88C1024.11,-438.46 1063.18,-355.52 1083.95,-311.44"/> +<polygon fill="black" stroke="black" points="1087.07,-313.03 1088.16,-302.49 1080.73,-310.05 1087.07,-313.03"/> +</g> +<!-- MEM_BOT --> +<g id="node30" class="node"> +<title>MEM_BOT</title> +<ellipse fill="blue" stroke="black" cx="998.51" cy="-82.75" rx="43.67" ry="18"/> +<text text-anchor="start" x="974.51" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊥</text> +<text text-anchor="start" x="990.26" y="-78.7" font-family="Times New Roman,serif" font-size="14.00" fill="white">:mem</text> +</g> +<!-- MEM_BOT->BOT --> +<g id="edge53" class="edge"> +<title>MEM_BOT->BOT</title> +<path fill="none" stroke="black" d="M958.6,-75.08C887.17,-63.15 738.86,-38.38 673.56,-27.48"/> +<polygon fill="black" stroke="black" points="674.3,-24.05 663.86,-25.86 673.15,-30.96 674.3,-24.05"/> +</g> +<!-- MEM_ALIAS1->MEM_BOT --> +<g id="edge50" class="edge"> +<title>MEM_ALIAS1->MEM_BOT</title> +<path fill="none" stroke="black" d="M977.84,-262.38C981.92,-226.96 990.35,-153.62 995.09,-112.45"/> +<polygon fill="black" stroke="black" points="998.57,-112.87 996.23,-102.53 991.61,-112.07 998.57,-112.87"/> +</g> +<!-- MEM_ALIAS1->MEM_ALIASDOTS --> +<!-- MEM_ALIASDOTS->MEM_BOT --> +<g id="edge51" class="edge"> +<title>MEM_ALIASDOTS->MEM_BOT</title> +<path fill="none" stroke="black" d="M1033.07,-264.56C1026.49,-229.93 1012.06,-154.01 1004.08,-112.06"/> +<polygon fill="black" stroke="black" points="1007.56,-111.6 1002.25,-102.43 1000.68,-112.91 1007.56,-111.6"/> +</g> +<!-- MEM_ALIASDOTS->MEM_ALIASN --> +<!-- MEM_ALIASN->MEM_BOT --> +<g id="edge52" class="edge"> +<title>MEM_ALIASN->MEM_BOT</title> +<path fill="none" stroke="black" d="M1088.37,-264.2C1070.97,-229.07 1032.98,-152.35 1012.41,-110.82"/> +<polygon fill="black" stroke="black" points="1015.58,-109.34 1008.01,-101.93 1009.31,-112.45 1015.58,-109.34"/> +</g> +<!-- TUPLE1 --> +<g id="node36" class="node"> +<title>TUPLE1</title> +<polygon fill="none" stroke="none" points="1185.51,-309.15 1131.51,-309.15 1131.51,-256.15 1185.51,-256.15 1185.51,-309.15"/> +<polygon fill="pink" stroke="none" points="1139.76,-282.65 1139.76,-305.15 1177.26,-305.15 1177.26,-282.65 1139.76,-282.65"/> +<polygon fill="none" stroke="black" points="1139.76,-282.65 1139.76,-305.15 1177.26,-305.15 1177.26,-282.65 1139.76,-282.65"/> +<text text-anchor="start" x="1142.76" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">Tuple</text> +<polygon fill="black" stroke="none" points="1139.76,-260.15 1139.76,-282.65 1177.26,-282.65 1177.26,-260.15 1139.76,-260.15"/> +<polygon fill="none" stroke="black" points="1139.76,-260.15 1139.76,-282.65 1177.26,-282.65 1177.26,-260.15 1139.76,-260.15"/> +<text text-anchor="start" x="1146.88" y="-266.35" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text> +</g> +<!-- TUPLE_TOP->TUPLE1 --> +<g id="edge57" class="edge"> +<title>TUPLE_TOP->TUPLE1</title> +<path fill="none" stroke="black" d="M1180.42,-474.51C1176.51,-440.23 1167.99,-365.66 1162.8,-320.24"/> +<polygon fill="black" stroke="black" points="1166.28,-319.86 1161.67,-310.32 1159.33,-320.65 1166.28,-319.86"/> +</g> +<!-- TUPLE2 --> +<g id="node37" class="node"> +<title>TUPLE2</title> +<polygon fill="none" stroke="none" points="1253.51,-320.4 1199.51,-320.4 1199.51,-244.9 1253.51,-244.9 1253.51,-320.4"/> +<polygon fill="pink" stroke="none" points="1207.76,-293.9 1207.76,-316.4 1245.26,-316.4 1245.26,-293.9 1207.76,-293.9"/> +<polygon fill="none" stroke="black" points="1207.76,-293.9 1207.76,-316.4 1245.26,-316.4 1245.26,-293.9 1207.76,-293.9"/> +<text text-anchor="start" x="1210.76" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">Tuple</text> +<polygon fill="black" stroke="none" points="1207.76,-271.4 1207.76,-293.9 1245.26,-293.9 1245.26,-271.4 1207.76,-271.4"/> +<polygon fill="none" stroke="black" points="1207.76,-271.4 1207.76,-293.9 1245.26,-293.9 1245.26,-271.4 1207.76,-271.4"/> +<text text-anchor="start" x="1214.88" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text> +<polygon fill="black" stroke="none" points="1207.76,-248.9 1207.76,-271.4 1245.26,-271.4 1245.26,-248.9 1207.76,-248.9"/> +<polygon fill="none" stroke="black" points="1207.76,-248.9 1207.76,-271.4 1245.26,-271.4 1245.26,-248.9 1207.76,-248.9"/> +<text text-anchor="start" x="1214.88" y="-255.1" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text> +</g> +<!-- TUPLE_TOP->TUPLE2 --> +<g id="edge58" class="edge"> +<title>TUPLE_TOP->TUPLE2</title> +<path fill="none" stroke="black" d="M1186.34,-474.51C1192.95,-442.94 1206.72,-377.19 1216.28,-331.51"/> +<polygon fill="black" stroke="black" points="1219.68,-332.35 1218.3,-321.85 1212.83,-330.92 1219.68,-332.35"/> +</g> +<!-- TUPLEN --> +<g id="node38" class="node"> +<title>TUPLEN</title> +<polygon fill="none" stroke="none" points="1321.51,-331.65 1267.51,-331.65 1267.51,-233.65 1321.51,-233.65 1321.51,-331.65"/> +<polygon fill="pink" stroke="none" points="1275.76,-305.15 1275.76,-327.65 1313.26,-327.65 1313.26,-305.15 1275.76,-305.15"/> +<polygon fill="none" stroke="black" points="1275.76,-305.15 1275.76,-327.65 1313.26,-327.65 1313.26,-305.15 1275.76,-305.15"/> +<text text-anchor="start" x="1278.76" y="-311.35" font-family="Times New Roman,serif" font-size="14.00">Tuple</text> +<polygon fill="black" stroke="none" points="1275.76,-282.65 1275.76,-305.15 1313.26,-305.15 1313.26,-282.65 1275.76,-282.65"/> +<polygon fill="none" stroke="black" points="1275.76,-282.65 1275.76,-305.15 1313.26,-305.15 1313.26,-282.65 1275.76,-282.65"/> +<text text-anchor="start" x="1282.88" y="-288.85" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text> +<polygon fill="black" stroke="none" points="1275.76,-260.15 1275.76,-282.65 1313.26,-282.65 1313.26,-260.15 1275.76,-260.15"/> +<polygon fill="none" stroke="black" points="1275.76,-260.15 1275.76,-282.65 1313.26,-282.65 1313.26,-260.15 1275.76,-260.15"/> +<text text-anchor="start" x="1288.88" y="-266.35" font-family="Times New Roman,serif" font-size="14.00" fill="white">...</text> +<polygon fill="black" stroke="none" points="1275.76,-237.65 1275.76,-260.15 1313.26,-260.15 1313.26,-237.65 1275.76,-237.65"/> +<polygon fill="none" stroke="black" points="1275.76,-237.65 1275.76,-260.15 1313.26,-260.15 1313.26,-237.65 1275.76,-237.65"/> +<text text-anchor="start" x="1282.88" y="-243.85" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text> +</g> +<!-- TUPLE_TOP->TUPLEN --> +<g id="edge59" class="edge"> +<title>TUPLE_TOP->TUPLEN</title> +<path fill="none" stroke="black" d="M1192.06,-474.88C1207.65,-445.62 1239.24,-386.36 1263.24,-341.32"/> +<polygon fill="black" stroke="black" points="1266.22,-343.18 1267.83,-332.71 1260.04,-339.88 1266.22,-343.18"/> +</g> +<!-- TUPLE_BOT --> +<g id="node35" class="node"> +<title>TUPLE_BOT</title> +<ellipse fill="pink" stroke="black" cx="1192.51" cy="-82.75" rx="42.65" ry="18"/> +<text text-anchor="start" x="1169.26" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text> +<text text-anchor="start" x="1185.01" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:tuple</text> +</g> +<!-- TUPLE_BOT->BOT --> +<g id="edge63" class="edge"> +<title>TUPLE_BOT->BOT</title> +<path fill="none" stroke="black" d="M1151.54,-77.32C1046.53,-65.95 769.32,-35.95 674.14,-25.65"/> +<polygon fill="black" stroke="black" points="674.52,-22.18 664.2,-24.58 673.77,-29.14 674.52,-22.18"/> +</g> +<!-- TUPLE1->TUPLE_BOT --> +<g id="edge60" class="edge"> +<title>TUPLE1->TUPLE_BOT</title> +<path fill="none" stroke="black" d="M1162.95,-256.52C1169.28,-219.3 1180.86,-151.25 1187.49,-112.26"/> +<polygon fill="black" stroke="black" points="1190.9,-113.1 1189.12,-102.66 1184,-111.93 1190.9,-113.1"/> +</g> +<!-- TUPLE2->TUPLE_BOT --> +<g id="edge61" class="edge"> +<title>TUPLE2->TUPLE_BOT</title> +<path fill="none" stroke="black" d="M1220.11,-245.05C1213.55,-206.44 1203.46,-147.16 1197.47,-111.94"/> +<polygon fill="black" stroke="black" points="1200.99,-111.74 1195.86,-102.47 1194.09,-112.92 1200.99,-111.74"/> +</g> +<!-- TUPLEN->TUPLE_BOT --> +<g id="edge62" class="edge"> +<title>TUPLEN->TUPLE_BOT</title> +<path fill="none" stroke="black" d="M1269.56,-233.75C1249.85,-195.12 1223.04,-142.58 1206.8,-110.75"/> +<polygon fill="black" stroke="black" points="1210.07,-109.46 1202.41,-102.15 1203.83,-112.65 1210.07,-109.46"/> +</g> +</g> +</svg> diff --git a/chapter24/docs/lattice2.gv b/chapter24/docs/lattice2.gv new file mode 100644 index 00000000..6aa37fa0 --- /dev/null +++ b/chapter24/docs/lattice2.gv @@ -0,0 +1,85 @@ +digraph Lattice { + compound = true; + // Define nodes + splines=false; + node [shape=oval, style=filled]; + nodesep=0.2; + ranksep=0.4; + + TOP [label="~scalar\n+int+tmp+0", fillcolor=black, fontcolor=white, group=center]; + + // ------------------------ + PTRHQ [label="~tmp\n+tmp+0", fillcolor=green, fontcolor=white, group=left]; + TOP -> PTRHQ + + VALH_ [label="~nscalar\n+int+tmp", fillcolor=white, group=center]; + TOP -> VALH_ + + INTHQ [label="~int\n+int+0", fillcolor=lightblue, group=right]; + TOP -> INTHQ + + LEFTHI [label="junk", style=invis, group=junkleft] + + + PTRHQ -> LEFTHI-> VALH_ -> INTHQ [style=invis]; + { rank=same; PTRHQ; LEFTHI; VALH_; INTHQ } + + // ------------------------ + PTRH_ [label="~ntmp\n+tmp", fillcolor=green, fontcolor=white, group=left]; + VALH_ -> PTRH_ + PTRHQ -> PTRH_ + + INTH_ [label="~nint\n+int", fillcolor=lightblue, group=right]; + VALH_ -> INTH_ + INTHQ -> INTH_ + { rank=same; PTRH_; INTH_ } + + // ------------------------ + NILX_ [label="~nil\n[int,tmp]+0", fillcolor=aqua, group=junkleft]; + INTHQ -> NILX_ + PTRHQ -> NILX_ + + NIL__ [label="nil\n[+int+tmp],0", fillcolor=pink]; + VALH_ -> NIL__; + + NILX_ -> NIL__ [style=invis]; + { rank=same; NIL__; NILX_ } + + // ------------------------ + PTRL_ [label="ntmp\ntmp", fillcolor=green, fontcolor=white, group=left]; + PTRH_ -> PTRL_ + + INTL_ [label="nint\nint", fillcolor=lightblue, group=right]; + INTH_ -> INTL_ + { rank=same; PTRL_; INTL_ } + + // ------------------------ + PTRL0 [label="tmp\ntmp,0", fillcolor=green, fontcolor=white, group=left]; + PTRL_ -> PTRL0 + NIL__ -> PTRL0 + + VALL_ [label="nscalar\nint,tmp", fillcolor=white, group=center]; + PTRL_ -> VALL_ + INTL_ -> VALL_ + NILX_ -> VALL_ + + INTL0 [label="int\nint,0", fillcolor=lightblue, group=right]; + INTL_ -> INTL0 + NIL__ -> INTL0 + + PTRL0 -> VALL_ -> INTL0 [style=invis]; + { rank=same; PTRL0; VALL_; INTL0 } + + // ------------------------ + BOT [label="scalar\nint,tmp,0", fillcolor=black, fontcolor=white, group=center]; + PTRL0 -> BOT + INTL0 -> BOT + VALL_ -> BOT + + // ------------------------ + // Verticle alignment + TOP -> VALH_ -> VALL_ -> BOT [style=invis]; + PTRHQ -> PTRH_ -> PTRL_ -> PTRL0 [style=invis]; + INTHQ -> INTH_ -> INTL_ -> INTL0 [style=invis]; + LEFTHI -> NILX_ [style=invis] +} diff --git a/chapter24/docs/lattice2.svg b/chapter24/docs/lattice2.svg new file mode 100644 index 00000000..8b682aa7 --- /dev/null +++ b/chapter24/docs/lattice2.svg @@ -0,0 +1,260 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 12.2.0 (20241103.1931) + --> +<!-- Title: Lattice Pages: 1 --> +<svg width="478pt" height="501pt" + viewBox="0.00 0.00 477.96 500.90" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 496.9)"> +<title>Lattice</title> +<polygon fill="white" stroke="none" points="-4,4 -4,-496.9 473.96,-496.9 473.96,4 -4,4"/> +<!-- TOP --> +<g id="node1" class="node"> +<title>TOP</title> +<ellipse fill="black" stroke="black" cx="240.13" cy="-463.91" rx="59.04" ry="28.99"/> +<text text-anchor="middle" x="240.13" y="-467.11" font-family="Times New Roman,serif" font-size="14.00" fill="white">~scalar</text> +<text text-anchor="middle" x="240.13" y="-450.61" font-family="Times New Roman,serif" font-size="14.00" fill="white">+int+tmp+0</text> +</g> +<!-- PTRHQ --> +<g id="node2" class="node"> +<title>PTRHQ</title> +<ellipse fill="green" stroke="black" cx="43.13" cy="-376.92" rx="43.13" ry="28.99"/> +<text text-anchor="middle" x="43.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00" fill="white">~tmp</text> +<text text-anchor="middle" x="43.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00" fill="white">+tmp+0</text> +</g> +<!-- TOP->PTRHQ --> +<g id="edge1" class="edge"> +<title>TOP->PTRHQ</title> +<path fill="none" stroke="black" d="M196.41,-444.04C164.74,-430.38 121.99,-411.94 89.68,-398"/> +<polygon fill="black" stroke="black" points="91.11,-394.81 80.55,-394.06 88.34,-401.24 91.11,-394.81"/> +</g> +<!-- VALH_ --> +<g id="node3" class="node"> +<title>VALH_</title> +<ellipse fill="white" stroke="black" cx="240.13" cy="-376.92" rx="48.44" ry="28.99"/> +<text text-anchor="middle" x="240.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00">~nscalar</text> +<text text-anchor="middle" x="240.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00">+int+tmp</text> +</g> +<!-- TOP->VALH_ --> +<g id="edge2" class="edge"> +<title>TOP->VALH_</title> +<path fill="none" stroke="black" d="M235.15,-434.61C234.93,-429.02 234.85,-423.06 234.9,-417.18"/> +<polygon fill="black" stroke="black" points="238.39,-417.69 235.12,-407.61 231.39,-417.52 238.39,-417.69"/> +</g> +<!-- TOP->VALH_ --> +<!-- INTHQ --> +<g id="node4" class="node"> +<title>INTHQ</title> +<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-376.92" rx="37.83" ry="28.99"/> +<text text-anchor="middle" x="432.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00">~int</text> +<text text-anchor="middle" x="432.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00">+int+0</text> +</g> +<!-- TOP->INTHQ --> +<g id="edge3" class="edge"> +<title>TOP->INTHQ</title> +<path fill="none" stroke="black" d="M283.22,-443.83C314.91,-429.81 357.78,-410.83 389.39,-396.84"/> +<polygon fill="black" stroke="black" points="390.53,-400.16 398.26,-392.92 387.7,-393.76 390.53,-400.16"/> +</g> +<!-- LEFTHI --> +<!-- PTRHQ->LEFTHI --> +<!-- PTRH_ --> +<g id="node6" class="node"> +<title>PTRH_</title> +<ellipse fill="green" stroke="black" cx="43.13" cy="-289.94" rx="36.77" ry="28.99"/> +<text text-anchor="middle" x="43.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00" fill="white">~ntmp</text> +<text text-anchor="middle" x="43.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00" fill="white">+tmp</text> +</g> +<!-- PTRHQ->PTRH_ --> +<g id="edge8" class="edge"> +<title>PTRHQ->PTRH_</title> +<path fill="none" stroke="black" d="M38.15,-347.62C37.93,-342.03 37.85,-336.07 37.9,-330.2"/> +<polygon fill="black" stroke="black" points="41.39,-330.71 38.12,-320.63 34.39,-330.54 41.39,-330.71"/> +</g> +<!-- PTRHQ->PTRH_ --> +<!-- NILX_ --> +<g id="node8" class="node"> +<title>NILX_</title> +<ellipse fill="aqua" stroke="black" cx="150.13" cy="-289.94" rx="56.39" ry="28.99"/> +<text text-anchor="middle" x="150.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">~nil</text> +<text text-anchor="middle" x="150.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">[int,tmp]+0</text> +</g> +<!-- PTRHQ->NILX_ --> +<g id="edge12" class="edge"> +<title>PTRHQ->NILX_</title> +<path fill="none" stroke="black" d="M70.41,-354.26C82.91,-344.33 97.94,-332.4 111.56,-321.58"/> +<polygon fill="black" stroke="black" points="113.43,-324.56 119.09,-315.6 109.08,-319.08 113.43,-324.56"/> +</g> +<!-- VALH_->INTHQ --> +<!-- VALH_->PTRH_ --> +<g id="edge7" class="edge"> +<title>VALH_->PTRH_</title> +<path fill="none" stroke="black" d="M201.21,-359.13C167.78,-344.71 119.68,-323.96 85.33,-309.14"/> +<polygon fill="black" stroke="black" points="87.1,-306.09 76.53,-305.35 84.33,-312.52 87.1,-306.09"/> +</g> +<!-- INTH_ --> +<g id="node7" class="node"> +<title>INTH_</title> +<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-289.94" rx="31.47" ry="28.99"/> +<text text-anchor="middle" x="432.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">~nint</text> +<text text-anchor="middle" x="432.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">+int</text> +</g> +<!-- VALH_->INTH_ --> +<g id="edge9" class="edge"> +<title>VALH_->INTH_</title> +<path fill="none" stroke="black" d="M278.53,-358.93C311.9,-344.16 360.02,-322.86 393.48,-308.05"/> +<polygon fill="black" stroke="black" points="394.67,-311.35 402.4,-304.1 391.84,-304.95 394.67,-311.35"/> +</g> +<!-- NIL__ --> +<g id="node9" class="node"> +<title>NIL__</title> +<ellipse fill="pink" stroke="black" cx="324.13" cy="-289.94" rx="62.23" ry="28.99"/> +<text text-anchor="middle" x="324.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">nil</text> +<text text-anchor="middle" x="324.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">[+int+tmp],0</text> +</g> +<!-- VALH_->NIL__ --> +<g id="edge13" class="edge"> +<title>VALH_->NIL__</title> +<path fill="none" stroke="black" d="M264.43,-351.34C272.67,-343.01 282.01,-333.55 290.83,-324.64"/> +<polygon fill="black" stroke="black" points="293.12,-327.3 297.66,-317.72 288.14,-322.38 293.12,-327.3"/> +</g> +<!-- VALL_ --> +<g id="node13" class="node"> +<title>VALL_</title> +<ellipse fill="white" stroke="black" cx="240.13" cy="-115.97" rx="39.42" ry="28.99"/> +<text text-anchor="middle" x="240.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00">nscalar</text> +<text text-anchor="middle" x="240.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00">int,tmp</text> +</g> +<!-- VALH_->VALL_ --> +<!-- INTHQ->INTH_ --> +<g id="edge10" class="edge"> +<title>INTHQ->INTH_</title> +<path fill="none" stroke="black" d="M427.17,-348.1C426.94,-342.37 426.85,-336.25 426.9,-330.21"/> +<polygon fill="black" stroke="black" points="430.39,-330.42 427.13,-320.34 423.39,-330.26 430.39,-330.42"/> +</g> +<!-- INTHQ->INTH_ --> +<!-- INTHQ->NILX_ --> +<g id="edge11" class="edge"> +<title>INTHQ->NILX_</title> +<path fill="none" stroke="black" d="M396.99,-365.33C350,-351.17 266.03,-325.87 209.23,-308.75"/> +<polygon fill="black" stroke="black" points="210.28,-305.41 199.69,-305.88 208.26,-312.11 210.28,-305.41"/> +</g> +<!-- LEFTHI->VALH_ --> +<!-- LEFTHI->NILX_ --> +<!-- PTRL_ --> +<g id="node10" class="node"> +<title>PTRL_</title> +<ellipse fill="green" stroke="black" cx="43.13" cy="-202.96" rx="31.47" ry="28.99"/> +<text text-anchor="middle" x="43.13" y="-206.16" font-family="Times New Roman,serif" font-size="14.00" fill="white">ntmp</text> +<text text-anchor="middle" x="43.13" y="-189.66" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp</text> +</g> +<!-- PTRH_->PTRL_ --> +<g id="edge15" class="edge"> +<title>PTRH_->PTRL_</title> +<path fill="none" stroke="black" d="M38.17,-261.11C37.94,-255.39 37.85,-249.26 37.9,-243.22"/> +<polygon fill="black" stroke="black" points="41.39,-243.44 38.13,-233.36 34.39,-243.27 41.39,-243.44"/> +</g> +<!-- PTRH_->PTRL_ --> +<!-- INTL_ --> +<g id="node11" class="node"> +<title>INTL_</title> +<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-202.96" rx="27" ry="28.99"/> +<text text-anchor="middle" x="432.13" y="-206.16" font-family="Times New Roman,serif" font-size="14.00">nint</text> +<text text-anchor="middle" x="432.13" y="-189.66" font-family="Times New Roman,serif" font-size="14.00">int</text> +</g> +<!-- INTH_->INTL_ --> +<g id="edge16" class="edge"> +<title>INTH_->INTL_</title> +<path fill="none" stroke="black" d="M427.17,-261.11C426.94,-255.39 426.85,-249.26 426.9,-243.22"/> +<polygon fill="black" stroke="black" points="430.39,-243.44 427.13,-233.36 423.39,-243.27 430.39,-243.44"/> +</g> +<!-- INTH_->INTL_ --> +<!-- NILX_->NIL__ --> +<!-- NILX_->VALL_ --> +<g id="edge21" class="edge"> +<title>NILX_->VALL_</title> +<path fill="none" stroke="black" d="M164.79,-261.6C180.03,-232.15 203.95,-185.91 220.74,-153.45"/> +<polygon fill="black" stroke="black" points="223.74,-155.27 225.23,-144.78 217.53,-152.06 223.74,-155.27"/> +</g> +<!-- PTRL0 --> +<g id="node12" class="node"> +<title>PTRL0</title> +<ellipse fill="green" stroke="black" cx="43.13" cy="-115.97" rx="34.12" ry="28.99"/> +<text text-anchor="middle" x="43.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp</text> +<text text-anchor="middle" x="43.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp,0</text> +</g> +<!-- NIL__->PTRL0 --> +<g id="edge18" class="edge"> +<title>NIL__->PTRL0</title> +<path fill="none" stroke="black" d="M286.24,-266.48C232.36,-233.13 134.24,-172.38 80.6,-139.17"/> +<polygon fill="black" stroke="black" points="82.76,-136.39 72.41,-134.1 79.07,-142.34 82.76,-136.39"/> +</g> +<!-- INTL0 --> +<g id="node14" class="node"> +<title>INTL0</title> +<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-115.97" rx="28.81" ry="28.99"/> +<text text-anchor="middle" x="432.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00">int</text> +<text text-anchor="middle" x="432.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00">int,0</text> +</g> +<!-- NIL__->INTL0 --> +<g id="edge23" class="edge"> +<title>NIL__->INTL0</title> +<path fill="none" stroke="black" d="M341.49,-261.99C360.34,-231.61 390.49,-183.05 410.79,-150.35"/> +<polygon fill="black" stroke="black" points="413.65,-152.38 415.95,-142.04 407.7,-148.69 413.65,-152.38"/> +</g> +<!-- PTRL_->PTRL0 --> +<g id="edge17" class="edge"> +<title>PTRL_->PTRL0</title> +<path fill="none" stroke="black" d="M38.17,-174.13C37.94,-168.47 37.85,-162.41 37.9,-156.43"/> +<polygon fill="black" stroke="black" points="41.39,-156.75 38.12,-146.67 34.39,-156.58 41.39,-156.75"/> +</g> +<!-- PTRL_->PTRL0 --> +<!-- PTRL_->VALL_ --> +<g id="edge19" class="edge"> +<title>PTRL_->VALL_</title> +<path fill="none" stroke="black" d="M71.36,-189.78C103.94,-175.73 157.92,-152.44 196.04,-135.99"/> +<polygon fill="black" stroke="black" points="197.16,-139.32 204.96,-132.15 194.39,-132.9 197.16,-139.32"/> +</g> +<!-- INTL_->VALL_ --> +<g id="edge20" class="edge"> +<title>INTL_->VALL_</title> +<path fill="none" stroke="black" d="M407.43,-191.02C376.23,-177.21 322.01,-153.22 283.77,-136.29"/> +<polygon fill="black" stroke="black" points="285.39,-133.18 274.83,-132.33 282.55,-139.58 285.39,-133.18"/> +</g> +<!-- INTL_->INTL0 --> +<g id="edge22" class="edge"> +<title>INTL_->INTL0</title> +<path fill="none" stroke="black" d="M427.17,-174.13C426.94,-168.41 426.85,-162.28 426.9,-156.24"/> +<polygon fill="black" stroke="black" points="430.39,-156.46 427.13,-146.38 423.39,-156.29 430.39,-156.46"/> +</g> +<!-- INTL_->INTL0 --> +<!-- PTRL0->VALL_ --> +<!-- BOT --> +<g id="node15" class="node"> +<title>BOT</title> +<ellipse fill="black" stroke="black" cx="240.13" cy="-28.99" rx="46.85" ry="28.99"/> +<text text-anchor="middle" x="240.13" y="-32.19" font-family="Times New Roman,serif" font-size="14.00" fill="white">scalar</text> +<text text-anchor="middle" x="240.13" y="-15.69" font-family="Times New Roman,serif" font-size="14.00" fill="white">int,tmp,0</text> +</g> +<!-- PTRL0->BOT --> +<g id="edge26" class="edge"> +<title>PTRL0->BOT</title> +<path fill="none" stroke="black" d="M73.48,-101.88C105.02,-88.28 154.83,-66.79 191.79,-50.85"/> +<polygon fill="black" stroke="black" points="193.14,-54.08 200.94,-46.9 190.37,-47.65 193.14,-54.08"/> +</g> +<!-- VALL_->INTL0 --> +<!-- VALL_->BOT --> +<g id="edge28" class="edge"> +<title>VALL_->BOT</title> +<path fill="none" stroke="black" d="M235.17,-87.15C234.94,-81.48 234.85,-75.42 234.9,-69.44"/> +<polygon fill="black" stroke="black" points="238.39,-69.76 235.12,-59.68 231.39,-69.6 238.39,-69.76"/> +</g> +<!-- VALL_->BOT --> +<!-- INTL0->BOT --> +<g id="edge27" class="edge"> +<title>INTL0->BOT</title> +<path fill="none" stroke="black" d="M405.84,-103.34C375.52,-89.91 325.06,-67.58 287.78,-51.08"/> +<polygon fill="black" stroke="black" points="289.59,-48.05 279.03,-47.21 286.75,-54.45 289.59,-48.05"/> +</g> +</g> +</svg> diff --git a/chapter24/docs/pardoe.docx b/chapter24/docs/pardoe.docx Binary files differnew file mode 100644 index 00000000..24fde921 --- /dev/null +++ b/chapter24/docs/pardoe.docx diff --git a/chapter24/docs/webtcp.min.js b/chapter24/docs/webtcp.min.js new file mode 100644 index 00000000..bf23ee5a --- /dev/null +++ b/chapter24/docs/webtcp.min.js @@ -0,0 +1,65 @@ +function Http(j){this.cID=Math.random().toString(36).substr(2);this.webtcp=j;this.webtcp.httpClients[this.cID]=this;this.createPacket=function(){return{cID:this.cID,type:"http",host:this.remoteAddress,port:this.remotePort,method:null,data:null}};this.ondata=function(){};this.get=function(g,c){this.on("data",c);this.rpc("httpGet",[g])};this.post=function(g,c,j){this.on("data",j);this.rpc("httpPost",[g,c])}}Http.prototype=new WebTCPIO;function Socket(j,g,c,p){this.sID=Math.random().toString(36).substr(2);this.webtcp=j;this.closed=this.ready=!1;this.options=p;this.sockOpts={_updating:!1};this.remoteAddress=g;this.remotePort=c;this.webtcp.sockets[this.sID]=this;this.createPacket=function(){return{id:Math.random().toString(36).substr(2),sID:this.sID,type:"tcp",options:this.options,host:this.remoteAddress,port:this.remotePort,data:null}};this.onconnect=function(){this.webtcp.sockets[sID].ready=!0;this.webtcp.sockets[sID].closed=!1}; +this.ondata=function(){};this.onend=function(){};this.ontimeout=function(){};this.ondrain=function(){};this.onclose=function(){this.webtcp.sockets[sID].ready=!1;this.webtcp.sockets[sID].closed=!0};this.getSockOpts=function(){this.sockOpts._updating=!0;this.rpc("getSockOpts")};this.onSockOptsRcv=function(c){this.sockOpts=c;this.sockOpts._updating=!1}}Socket.prototype=new WebTCPIO;var JSON;JSON||(JSON={}); +(function(){function j(c,p){var q,t,n,x,i=k,e,l=p[c];l&&"object"==typeof l&&"function"==typeof l.toJSON&&(l=l.toJSON(c));"function"==typeof r&&(l=r.call(p,c,l));switch(typeof l){case "string":return g(l);case "number":return isFinite(l)?String(l):"null";case "boolean":case "null":return String(l);case "object":if(!l)return"null";k+=v;e=[];if("[object Array]"===Object.prototype.toString.apply(l)){x=l.length;for(q=0;q<x;q+=1)e[q]=j(q,l)||"null";n=0===e.length?"[]":k?"[\n"+k+e.join(",\n"+k)+"\n"+i+"]": +"["+e.join(",")+"]";k=i;return n}if(r&&"object"==typeof r){x=r.length;for(q=0;q<x;q+=1)"string"==typeof r[q]&&(t=r[q],n=j(t,l),n&&e.push(g(t)+(k?": ":":")+n))}else for(t in l)Object.prototype.hasOwnProperty.call(l,t)&&(n=j(t,l),n&&e.push(g(t)+(k?": ":":")+n));n=0===e.length?"{}":k?"{\n"+k+e.join(",\n"+k)+"\n"+i+"}":"{"+e.join(",")+"}";k=i;return n}}function g(c){n.lastIndex=0;return n.test(c)?'"'+c.replace(n,function(c){var g=D[c];return"string"==typeof g?g:"\\u"+("0000"+c.charCodeAt(0).toString(16)).slice(-4)})+ +'"':'"'+c+'"'}function c(c){return 10>c?"0"+c:c}"use strict";"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+c(this.getUTCMonth()+1)+"-"+c(this.getUTCDate())+"T"+c(this.getUTCHours())+":"+c(this.getUTCMinutes())+":"+c(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var p=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, +n=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,k,v,D={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},r;"function"!=typeof JSON.stringify&&(JSON.stringify=function(c,g,p){var n;v=k="";if("number"==typeof p)for(n=0;n<p;n+=1)v+=" ";else"string"==typeof p&&(v=p);r=g;if(!g||"function"==typeof g||"object"==typeof g&&"number"==typeof g.length)return j("",{"":c});throw Error("JSON.stringify");});"function"!= +typeof JSON.parse&&(JSON.parse=function(c,g){function j(c,k){var i,e,l=c[k];if(l&&"object"==typeof l)for(i in l)Object.prototype.hasOwnProperty.call(l,i)&&(e=j(l,i),void 0!==e?l[i]=e:delete l[i]);return g.call(c,k,l)}var k,c=String(c);p.lastIndex=0;p.test(c)&&(c=c.replace(p,function(c){return"\\u"+("0000"+c.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(c.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, +"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return k=eval("("+c+")"),"function"==typeof g?j({"":k},""):k;throw new SyntaxError("JSON.parse");})})(); +SockJS=function(){var j=document,g=window,c={},p=function(){};p.prototype.addEventListener=function(a,b){this._listeners||(this._listeners={});a in this._listeners||(this._listeners[a]=[]);var f=this._listeners[a];-1===c.arrIndexOf(f,b)&&f.push(b)};p.prototype.removeEventListener=function(a,b){if(this._listeners&&a in this._listeners){var f=this._listeners[a],d=c.arrIndexOf(f,b);-1!==d&&(1<f.length?this._listeners[a]=f.slice(0,d).concat(f.slice(d+1)):delete this._listeners[a])}};p.prototype.dispatchEvent= +function(a){var b=a.type,c=Array.prototype.slice.call(arguments,0);this["on"+b]&&this["on"+b].apply(this,c);if(this._listeners&&b in this._listeners)for(var d=0;d<this._listeners[b].length;d++)this._listeners[b][d].apply(this,c)};var n=function(a,b){this.type=a;if("undefined"!=typeof b)for(var c in b)b.hasOwnProperty(c)&&(this[c]=b[c])};n.prototype.toString=function(){var a=[],b;for(b in this)if(this.hasOwnProperty(b)){var c=this[b];"function"==typeof c&&(c="[function]");a.push(b+"="+c)}return"SimpleEvent("+ +a.join(", ")+")"};var k=function(a){this.events=a||[]};k.prototype.emit=function(a){var b=Array.prototype.slice.call(arguments,1);!this.nuked&&this["on"+a]&&this["on"+a].apply(this,b);-1===c.arrIndexOf(this.events,a)&&c.log("Event "+JSON.stringify(a)+" not listed "+JSON.stringify(this.events)+" in "+this)};k.prototype.nuke=function(){this.nuked=!0;for(var a=0;a<this.events.length;a++)delete this[this.events[a]]};c.random_string=function(a,b){var b=b||37,c,d=[];for(c=0;c<a;c++)d.push("abcdefghijklmnopqrstuvwxyz0123456789_".substr(Math.floor(Math.random()* +b),1));return d.join("")};c.random_number=function(a){return Math.floor(Math.random()*a)};c.random_number_string=function(a){var b=(""+(a-1)).length;return(Array(b+1).join("0")+c.random_number(a)).slice(-b)};c.getOrigin=function(a){return(a+"/").split("/").slice(0,3).join("/")};c.isSameOriginUrl=function(a,b){return b||(b=g.location.href),a.split("/").slice(0,3).join("/")===b.split("/").slice(0,3).join("/")};c.getParentDomain=function(a){return/^[0-9.]*$/.test(a)||/^\[/.test(a)||!/[.]/.test(a)?a: +a.split(".").slice(1).join(".")};c.objectExtend=function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a};c.polluteGlobalNamespace=function(){"_jp"in g||(g._jp={})};c.closeFrame=function(a,b){return"c"+JSON.stringify([a,b])};c.userSetCode=function(a){return 1E3===a||3E3<=a&&4999>=a};c.countRTO=function(a){var b;return 100<a?b=3*a:b=a+200,b};c.log=function(){g.console&&console.log&&console.log.apply&&console.log.apply(console,arguments)};c.bind=function(a,b){return a.bind?a.bind(b):function(){return a.apply(b, +arguments)}};c.flatUrl=function(a){return-1===a.indexOf("?")&&-1===a.indexOf("#")};c.amendUrl=function(a){var b=j.location;if(!a)throw Error("Wrong url for SockJS");if(!c.flatUrl(a))throw Error("Only basic urls are supported in SockJS");return 0===a.indexOf("//")&&(a=b.protocol+a),0===a.indexOf("/")&&(a=b.protocol+"//"+b.host+a),a=a.replace(/[/]+$/,""),a};c.arrIndexOf=function(a,b){for(var c=0;c<a.length;c++)if(a[c]===b)return c;return-1};c.arrSkip=function(a,b){var f=c.arrIndexOf(a,b);return-1=== +f?a.slice():a.slice(0,f).concat(a.slice(f+1))};c.isArray=Array.isArray||function(a){return 0<={}.toString.call(a).indexOf("Array")};c.delay=function(a,b){return"function"==typeof a&&(b=a,a=0),setTimeout(b,a)};var v=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,D={"\x00":"\\u0000","\u0001":"\\u0001","\u0002":"\\u0002","\u0003":"\\u0003","\u0004":"\\u0004","\u0005":"\\u0005","\u0006":"\\u0006","\u0007":"\\u0007","\b":"\\b", +"\t":"\\t","\n":"\\n","\x0B":"\\u000b","\f":"\\f","\r":"\\r","\u000e":"\\u000e","\u000f":"\\u000f","\u0010":"\\u0010","\u0011":"\\u0011","\u0012":"\\u0012","\u0013":"\\u0013","\u0014":"\\u0014","\u0015":"\\u0015","\u0016":"\\u0016","\u0017":"\\u0017","\u0018":"\\u0018","\u0019":"\\u0019","\u001a":"\\u001a","\u001b":"\\u001b","\u001c":"\\u001c","\u001d":"\\u001d","\u001e":"\\u001e","\u001f":"\\u001f",'"':'\\"',"\\":"\\\\","\u007f":"\\u007f","\u0080":"\\u0080","\u0081":"\\u0081","\u0082":"\\u0082", +"\u0083":"\\u0083","\u0084":"\\u0084","\u0085":"\\u0085","\u0086":"\\u0086","\u0087":"\\u0087","\u0088":"\\u0088","\u0089":"\\u0089","\u008a":"\\u008a","\u008b":"\\u008b","\u008c":"\\u008c","\u008d":"\\u008d","\u008e":"\\u008e","\u008f":"\\u008f","\u0090":"\\u0090","\u0091":"\\u0091","\u0092":"\\u0092","\u0093":"\\u0093","\u0094":"\\u0094","\u0095":"\\u0095","\u0096":"\\u0096","\u0097":"\\u0097","\u0098":"\\u0098","\u0099":"\\u0099","\u009a":"\\u009a","\u009b":"\\u009b","\u009c":"\\u009c","\u009d":"\\u009d", +"\u009e":"\\u009e","\u009f":"\\u009f","\u00ad":"\\u00ad","\u0600":"\\u0600","\u0601":"\\u0601","\u0602":"\\u0602","\u0603":"\\u0603","\u0604":"\\u0604","\u070f":"\\u070f","\u17b4":"\\u17b4","\u17b5":"\\u17b5","\u200c":"\\u200c","\u200d":"\\u200d","\u200e":"\\u200e","\u200f":"\\u200f","\u2028":"\\u2028","\u2029":"\\u2029","\u202a":"\\u202a","\u202b":"\\u202b","\u202c":"\\u202c","\u202d":"\\u202d","\u202e":"\\u202e","\u202f":"\\u202f","\u2060":"\\u2060","\u2061":"\\u2061","\u2062":"\\u2062","\u2063":"\\u2063", +"\u2064":"\\u2064","\u2065":"\\u2065","\u2066":"\\u2066","\u2067":"\\u2067","\u2068":"\\u2068","\u2069":"\\u2069","\u206a":"\\u206a","\u206b":"\\u206b","\u206c":"\\u206c","\u206d":"\\u206d","\u206e":"\\u206e","\u206f":"\\u206f","\ufeff":"\\ufeff","\ufff0":"\\ufff0","\ufff1":"\\ufff1","\ufff2":"\\ufff2","\ufff3":"\\ufff3","\ufff4":"\\ufff4","\ufff5":"\\ufff5","\ufff6":"\\ufff6","\ufff7":"\\ufff7","\ufff8":"\\ufff8","\ufff9":"\\ufff9","\ufffa":"\\ufffa","\ufffb":"\\ufffb","\ufffc":"\\ufffc","\ufffd":"\\ufffd", +"\ufffe":"\\ufffe","\uffff":"\\uffff"},r=/[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g, +B,M=JSON&&JSON.stringify||function(a){return v.lastIndex=0,v.test(a)&&(a=a.replace(v,function(a){return D[a]})),'"'+a+'"'};c.quote=function(a){a=M(a);r.lastIndex=0;if(r.test(a)){if(!B){var b,c={},d=[];for(b=0;65536>b;b++)d.push(String.fromCharCode(b));B=(r.lastIndex=0,d.join("").replace(r,function(a){return c[a]="\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4),""}),r.lastIndex=0,c)}a=a.replace(r,function(a){return B[a]})}return a};var q="websocket xdr-streaming xhr-streaming iframe-eventsource iframe-htmlfile xdr-polling xhr-polling iframe-xhr-polling jsonp-polling".split(" "); +c.probeProtocols=function(){for(var a={},b=0;b<q.length;b++){var c=q[b];a[c]=e[c]&&e[c].enabled()}return a};c.detectProtocols=function(a,b,c){var d={},h=[];b||(b=q);for(var m=0;m<b.length;m++){var g=b[m];d[g]=a[g]}var e=function(a){var b=a.shift();d[b]?h.push(b):0<a.length&&e(a)};return!1!==c.websocket&&e(["websocket"]),d["xhr-streaming"]&&!c.null_origin?h.push("xhr-streaming"):d["xdr-streaming"]&&!c.cookie_needed&&!c.null_origin?h.push("xdr-streaming"):e(["iframe-eventsource","iframe-htmlfile"]), +d["xhr-polling"]&&!c.null_origin?h.push("xhr-polling"):d["xdr-polling"]&&!c.cookie_needed&&!c.null_origin?h.push("xdr-polling"):e(["iframe-xhr-polling","jsonp-polling"]),h};c.createHook=function(){var a="a"+c.random_string(8);if(!("_sockjs_global"in g)){var b={};g._sockjs_global=function(a){return a in b||(b[a]={id:a,del:function(){delete b[a]}}),b[a]}}return g._sockjs_global(a)};c.attachMessage=function(a){c.attachEvent("message",a)};c.attachEvent=function(a,b){"undefined"!=typeof g.addEventListener? +g.addEventListener(a,b,!1):(j.attachEvent("on"+a,b),g.attachEvent("on"+a,b))};c.detachMessage=function(a){c.detachEvent("message",a)};c.detachEvent=function(a,b){"undefined"!=typeof g.addEventListener?g.removeEventListener(a,b,!1):(j.detachEvent("on"+a,b),g.detachEvent("on"+a,b))};var t={},C=!1,x=function(){for(var a in t)t[a](),delete t[a]},i=function(){C||(C=!0,x())};c.attachEvent("beforeunload",i);c.attachEvent("unload",i);c.unload_add=function(a){var b=c.random_string(8);return t[b]=a,C&&c.delay(x), +b};c.unload_del=function(a){a in t&&delete t[a]};c.createIframe=function(a,b){var f=j.createElement("iframe"),d,h,m=function(){clearTimeout(d);try{f.onload=null}catch(a){}f.onerror=null},g=function(){f&&(m(),setTimeout(function(){f&&f.parentNode.removeChild(f);f=null},0),c.unload_del(h))};return f.src=a,f.style.display="none",f.style.position="absolute",f.onerror=function(){f&&(g(),b("onerror"))},f.onload=function(){clearTimeout(d);d=setTimeout(function(){f&&(g(),b("onload timeout"))},2E3)},j.body.appendChild(f), +d=setTimeout(function(){f&&(g(),b("timeout"))},15E3),h=c.unload_add(g),{post:function(a,b){try{f&&f.contentWindow&&f.contentWindow.postMessage(a,b)}catch(c){}},cleanup:g,loaded:m}};c.createHtmlfile=function(a,b){var f=new ActiveXObject("htmlfile"),d,h,m,e=function(){clearTimeout(d)},j=function(){f&&(e(),c.unload_del(h),m.parentNode.removeChild(m),m=f=null,CollectGarbage())};f.open();f.write('<html><script>document.domain="'+document.domain+'";<\/script></html>');f.close();f.parentWindow._jp=g._jp; +var i=f.createElement("div");return f.body.appendChild(i),m=f.createElement("iframe"),i.appendChild(m),m.src=a,d=setTimeout(function(){f&&(j(),b("timeout"))},15E3),h=c.unload_add(j),{post:function(a,b){try{m&&m.contentWindow&&m.contentWindow.postMessage(a,b)}catch(c){}},cleanup:j,loaded:e}};i=function(){};i.prototype=new k(["chunk","finish"]);i.prototype._start=function(a,b,f,d){var h=this;try{h.xhr=new XMLHttpRequest}catch(m){}if(!h.xhr)try{h.xhr=new g.ActiveXObject("Microsoft.XMLHTTP")}catch(e){}if(g.ActiveXObject|| +g.XDomainRequest)b+=(-1===b.indexOf("?")?"?":"&")+"t="+ +new Date;h.unload_ref=c.unload_add(function(){h._cleanup(!0)});try{h.xhr.open(a,b,!0)}catch(j){h.emit("finish",0,"");h._cleanup();return}if(!d||!d.no_credentials)h.xhr.withCredentials="true";if(d&&d.headers)for(var i in d.headers)h.xhr.setRequestHeader(i,d.headers[i]);h.xhr.onreadystatechange=function(){if(h.xhr){var a=h.xhr;switch(a.readyState){case 3:try{var b=a.status,c=a.responseText}catch(d){}c&&0<c.length&&h.emit("chunk",b,c);break;case 4:h.emit("finish", +a.status,a.responseText),h._cleanup(!1)}}};h.xhr.send(f)};i.prototype._cleanup=function(a){if(this.xhr){c.unload_del(this.unload_ref);this.xhr.onreadystatechange=function(){};if(a)try{this.xhr.abort()}catch(b){}this.unload_ref=this.xhr=null}};i.prototype.close=function(){this.nuke();this._cleanup(!0)};(c.XHRCorsObject=function(){var a=this,b=arguments;c.delay(function(){a._start.apply(a,b)})}).prototype=new i;(c.XHRLocalObject=function(a,b,f){var d=this;c.delay(function(){d._start(a,b,f,{no_credentials:!0})})}).prototype= +new i;i=c.XDRObject=function(a,b,f){var d=this;c.delay(function(){d._start(a,b,f)})};i.prototype=new k(["chunk","finish"]);i.prototype._start=function(a,b,f){var d=this,h=new XDomainRequest,b=b+((-1===b.indexOf("?")?"?":"&")+"t="+ +new Date),g=h.ontimeout=h.onerror=function(){d.emit("finish",0,"");d._cleanup(!1)};h.onprogress=function(){d.emit("chunk",200,h.responseText)};h.onload=function(){d.emit("finish",200,h.responseText);d._cleanup(!1)};d.xdr=h;d.unload_ref=c.unload_add(function(){d._cleanup(!0)}); +try{d.xdr.open(a,b),d.xdr.send(f)}catch(e){g()}};i.prototype._cleanup=function(a){if(this.xdr){c.unload_del(this.unload_ref);this.xdr.ontimeout=this.xdr.onerror=this.xdr.onprogress=this.xdr.onload=null;if(a)try{this.xdr.abort()}catch(b){}this.unload_ref=this.xdr=null}};i.prototype.close=function(){this.nuke();this._cleanup(!0)};c.isXHRCorsCapable=function(){return g.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest?1:g.XDomainRequest&&j.domain?2:s.enabled()?3:4};var e=function(a,b,f){var d=this, +h;d._options={devel:!1,debug:!1,protocols_whitelist:[],info:void 0,rtt:void 0};f&&c.objectExtend(d._options,f);d._base_url=c.amendUrl(a);d._server=d._options.server||c.random_number_string(1E3);d._options.protocols_whitelist&&d._options.protocols_whitelist.length?h=d._options.protocols_whitelist:("string"==typeof b&&0<b.length?h=[b]:c.isArray(b)?h=b:h=null,h&&d._debug('Deprecated API: Use "protocols_whitelist" option instead of supplying protocol list as a second parameter to SockJS constructor.')); +d._protocols=[];d.protocol=null;d.readyState=e.CONNECTING;d._ir=N(d._base_url);d._ir.onfinish=function(a,b){d._ir=null;a?(d._options.info&&(a=c.objectExtend(a,d._options.info)),d._options.rtt&&(b=d._options.rtt),d._applyInfo(a,b,h),d._didClose()):d._didClose(1002,"Can't connect to server",!0)}};e.prototype=new p;e.version="0.3.2";e.CONNECTING=0;e.OPEN=1;e.CLOSING=2;e.CLOSED=3;e.prototype._debug=function(){this._options.debug&&c.log.apply(c,arguments)};e.prototype._dispatchOpen=function(){this.readyState=== +e.CONNECTING?(this._transport_tref&&(clearTimeout(this._transport_tref),this._transport_tref=null),this.readyState=e.OPEN,this.dispatchEvent(new n("open"))):this._didClose(1006,"Server lost session")};e.prototype._dispatchMessage=function(a){this.readyState===e.OPEN&&this.dispatchEvent(new n("message",{data:a}))};e.prototype._dispatchHeartbeat=function(){this.readyState===e.OPEN&&this.dispatchEvent(new n("heartbeat",{}))};e.prototype._didClose=function(a,b,f){var d=this;if(d.readyState!==e.CONNECTING&& +d.readyState!==e.OPEN&&d.readyState!==e.CLOSING)throw Error("INVALID_STATE_ERR");d._ir&&(d._ir.nuke(),d._ir=null);d._transport&&(d._transport.doCleanup(),d._transport=null);var h=new n("close",{code:a,reason:b,wasClean:c.userSetCode(a)});if(!c.userSetCode(a)&&d.readyState===e.CONNECTING&&!f){if(d._try_next_protocol(h))return;h=new n("close",{code:2E3,reason:"All transports failed",wasClean:!1,last_event:h})}d.readyState=e.CLOSED;c.delay(function(){d.dispatchEvent(h)})};e.prototype._didMessage=function(a){switch(a.slice(0, +1)){case "o":this._dispatchOpen();break;case "a":for(var a=JSON.parse(a.slice(1)||"[]"),b=0;b<a.length;b++)this._dispatchMessage(a[b]);break;case "m":a=JSON.parse(a.slice(1)||"null");this._dispatchMessage(a);break;case "c":a=JSON.parse(a.slice(1)||"[]");this._didClose(a[0],a[1]);break;case "h":this._dispatchHeartbeat()}};e.prototype._try_next_protocol=function(a){var b=this;b.protocol&&(b._debug("Closed transport:",b.protocol,""+a),b.protocol=null);for(b._transport_tref&&(clearTimeout(b._transport_tref), +b._transport_tref=null);;){a=b.protocol=b._protocols.shift();if(!a)return!1;if(e[a]&&!0===e[a].need_body&&(!j.body||"undefined"!=typeof j.readyState&&"complete"!==j.readyState))return b._protocols.unshift(a),b.protocol="waiting-for-load",c.attachEvent("load",function(){b._try_next_protocol()}),!0;if(e[a]&&e[a].enabled(b._options)){b._transport_tref=c.delay((b._options.rto||0)*(e[a].roundTrips||1)||5E3,function(){b.readyState===e.CONNECTING&&b._didClose(2007,"Transport timeouted")});var f=c.random_string(8), +f=b._base_url+"/"+b._server+"/"+f;return b._debug("Opening transport:",a," url:"+f," RTO:"+b._options.rto),b._transport=new e[a](b,f,b._base_url),!0}b._debug("Skipping transport:",a)}};e.prototype.close=function(a,b){if(a&&!c.userSetCode(a))throw Error("INVALID_ACCESS_ERR");return this.readyState!==e.CONNECTING&&this.readyState!==e.OPEN?!1:(this.readyState=e.CLOSING,this._didClose(a||1E3,b||"Normal closure"),!0)};e.prototype.send=function(a){if(this.readyState===e.CONNECTING)throw Error("INVALID_STATE_ERR"); +return this.readyState===e.OPEN&&this._transport.doSend(c.quote(""+a)),!0};e.prototype._applyInfo=function(a,b,f){this._options.info=a;this._options.rtt=b;this._options.rto=c.countRTO(b);this._options.info.null_origin=!j.domain;b=c.probeProtocols();this._protocols=c.detectProtocols(b,f,a)};i=e.websocket=function(a,b){var f=this,d=b+"/websocket";"https"===d.slice(0,5)?d="wss"+d.slice(5):d="ws"+d.slice(4);f.ri=a;f.url=d;f.ws=new (g.WebSocket||g.MozWebSocket)(f.url);f.ws.onmessage=function(a){f.ri._didMessage(a.data)}; +f.unload_ref=c.unload_add(function(){f.ws.close()});f.ws.onclose=function(){f.ri._didMessage(c.closeFrame(1006,"WebSocket connection broken"))}};i.prototype.doSend=function(a){this.ws.send("["+a+"]")};i.prototype.doCleanup=function(){var a=this.ws;a&&(a.onmessage=a.onclose=null,a.close(),c.unload_del(this.unload_ref),this.unload_ref=this.ri=this.ws=null)};i.enabled=function(){return!!g.WebSocket||!!g.MozWebSocket};i.roundTrips=2;var l=function(){};l.prototype.send_constructor=function(a){this.send_buffer= +[];this.sender=a};l.prototype.doSend=function(a){this.send_buffer.push(a);this.send_stop||this.send_schedule()};l.prototype.send_schedule_wait=function(){var a=this,b;a.send_stop=function(){a.send_stop=null;clearTimeout(b)};b=c.delay(25,function(){a.send_stop=null;a.send_schedule()})};l.prototype.send_schedule=function(){var a=this;if(0<a.send_buffer.length){var b="["+a.send_buffer.join(",")+"]";a.send_stop=a.sender(a.trans_url,b,function(){a.send_stop=null;a.send_schedule_wait()});a.send_buffer= +[]}};l.prototype.send_destructor=function(){this._send_stop&&this._send_stop();this._send_stop=null};var O=function(a,b,f){if(!("_send_form"in this)){var d=this._send_form=j.createElement("form"),h=this._send_area=j.createElement("textarea");h.name="d";d.style.display="none";d.style.position="absolute";d.method="POST";d.enctype="application/x-www-form-urlencoded";d.acceptCharset="UTF-8";d.appendChild(h);j.body.appendChild(d)}var d=this._send_form,h=this._send_area,g="a"+c.random_string(8);d.target= +g;d.action=a+"/jsonp_send?i="+g;var e;try{e=j.createElement('<iframe name="'+g+'">')}catch(i){e=j.createElement("iframe"),e.name=g}e.id=g;d.appendChild(e);e.style.display="none";try{h.value=b}catch(k){c.log("Your browser is seriously broken. Go home! "+k.message)}d.submit();var l=function(){e.onerror&&(e.onreadystatechange=e.onerror=e.onload=null,c.delay(500,function(){e.parentNode.removeChild(e);e=null}),h.value="",f())};return e.onerror=e.onload=l,e.onreadystatechange=function(){"complete"==e.readyState&& +l()},l},P=function(a){return function(b,c,d){return(new a("POST",b+"/xhr_send",c)).onfinish=function(a){d(a)},function(a){d(0,a)}}},i=e["jsonp-polling"]=function(a,b){c.polluteGlobalNamespace();this.ri=a;this.trans_url=b;this.send_constructor(O);this._schedule_recv()};i.prototype=new l;i.prototype._schedule_recv=function(){var a=this,b=a.trans_url+"/jsonp",f="a"+c.random_string(6),b=b+"?c="+escape("_jp."+f),d=function(b){delete g._jp[f];a._recv_stop=null;b&&(a._is_closing||a.ri._didMessage(b));a._is_closing|| +a._schedule_recv()},e,m=j.createElement("script"),i,k=function(a){i&&(i.parentNode.removeChild(i),i=null);m&&(clearTimeout(e),m.parentNode.removeChild(m),m.onreadystatechange=m.onerror=m.onload=m.onclick=null,m=null,d(a),d=null)},l=!1,p=null;m.id="a"+c.random_string(8);m.src=b;m.type="text/javascript";m.charset="UTF-8";m.onerror=function(){p||(p=setTimeout(function(){l||k(c.closeFrame(1006,"JSONP script loaded abnormally (onerror)"))},1E3))};m.onload=function(){k(c.closeFrame(1006,"JSONP script loaded abnormally (onload)"))}; +m.onreadystatechange=function(){if(/loaded|closed/.test(m.readyState)){if(m&&m.htmlFor&&m.onclick){l=!0;try{m.onclick()}catch(a){}}m&&k(c.closeFrame(1006,"JSONP script loaded abnormally (onreadystatechange)"))}};if("undefined"==typeof m.async&&j.attachEvent)if(/opera/i.test(navigator.userAgent))i=j.createElement("script"),i.text="try{var a = document.getElementById('"+m.id+"'); if(a)a.onerror();}catch(x){};",m.async=i.async=!1;else{try{m.htmlFor=m.id,m.event="onclick"}catch(n){}m.async=!0}"undefined"!= +typeof m.async&&(m.async=!0);e=setTimeout(function(){k(c.closeFrame(1006,"JSONP script loaded abnormally (timeout)"))},35E3);b=j.getElementsByTagName("head")[0];b=(b.insertBefore(m,b.firstChild),i&&b.insertBefore(i,b.firstChild),k);g._jp[f]=b;a._recv_stop=function(){g._jp[f]&&g._jp[f](c.closeFrame(1E3,"JSONP user aborted read"))}};i.enabled=function(){return!0};i.need_body=!0;i.prototype.doCleanup=function(){this._is_closing=!0;this._recv_stop&&this._recv_stop();this.ri=this._recv_stop=null;this.send_destructor()}; +i=function(){};i.prototype=new l;i.prototype.run=function(a,b,c,d,e){this.ri=a;this.trans_url=b;this.send_constructor(P(e));this.poll=new E(a,d,b+c,e)};i.prototype.doCleanup=function(){this.poll&&(this.poll.abort(),this.poll=null)};var w=e["xhr-streaming"]=function(a,b){this.run(a,b,"/xhr_streaming",y,c.XHRCorsObject)};w.prototype=new i;w.enabled=function(){return g.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest&&!/opera/i.test(navigator.userAgent)};w.roundTrips=2;w.need_body=!0;l=e["xdr-streaming"]= +function(a,b){this.run(a,b,"/xhr_streaming",y,c.XDRObject)};l.prototype=new i;l.enabled=function(){return!!g.XDomainRequest};l.roundTrips=2;var F=e["xhr-polling"]=function(a,b){this.run(a,b,"/xhr",y,c.XHRCorsObject)};F.prototype=new i;F.enabled=w.enabled;F.roundTrips=2;w=e["xdr-polling"]=function(a,b){this.run(a,b,"/xhr",y,c.XDRObject)};w.prototype=new i;w.enabled=l.enabled;w.roundTrips=2;var s=function(){};s.prototype.i_constructor=function(a,b,f){var d=this;d.ri=a;d.origin=c.getOrigin(f);d.base_url= +f;d.trans_url=b;a=f+"/iframe.html";d.ri._options.devel&&(a+="?t="+ +new Date);d.window_id=c.random_string(8);a+="#"+d.window_id;d.iframeObj=c.createIframe(a,function(a){d.ri._didClose(1006,"Unable to load an iframe ("+a+")")});d.onmessage_cb=c.bind(d.onmessage,d);c.attachMessage(d.onmessage_cb)};s.prototype.doCleanup=function(){if(this.iframeObj){c.detachMessage(this.onmessage_cb);try{this.iframeObj.iframe.contentWindow&&this.postMessage("c")}catch(a){}this.iframeObj.cleanup();this.onmessage_cb=this.iframeObj= +this.iframeObj=null}};s.prototype.onmessage=function(a){if(a.origin===this.origin){var b=a.data.slice(0,8),c=a.data.slice(8,9),a=a.data.slice(9);if(b===this.window_id)switch(c){case "s":this.iframeObj.loaded();this.postMessage("s",JSON.stringify([e.version,this.protocol,this.trans_url,this.base_url]));break;case "t":this.ri._didMessage(a)}}};s.prototype.postMessage=function(a,b){this.iframeObj.post(this.window_id+a+(b||""),this.origin)};s.prototype.doSend=function(a){this.postMessage("m",a)};s.enabled= +function(){var a=navigator&&navigator.userAgent&&-1!==navigator.userAgent.indexOf("Konqueror");return("function"==typeof g.postMessage||"object"==typeof g.postMessage)&&!a};var G,H=function(a,b){parent!==g?parent.postMessage(G+a+(b||""),"*"):c.log("Can't postMessage, no parent window.",a,b)},u=function(){};u.prototype._didClose=function(a,b){H("t",c.closeFrame(a,b))};u.prototype._didMessage=function(a){H("t",a)};u.prototype._doSend=function(a){this._transport.doSend(a)};u.prototype._doCleanup=function(){this._transport.doCleanup()}; +c.parent_origin=void 0;e.bootstrap_iframe=function(){var a;G=j.location.hash.slice(1);c.attachMessage(function(b){if(b.source===parent&&("undefined"==typeof c.parent_origin&&(c.parent_origin=b.origin),b.origin===c.parent_origin)){var f=b.data.slice(0,8),d=b.data.slice(8,9),b=b.data.slice(9);if(f===G)switch(d){case "s":var h=JSON.parse(b),f=h[0],d=h[1],b=h[2],h=h[3];f!==e.version&&c.log('Incompatibile SockJS! Main site uses: "'+f+'", the iframe: "'+e.version+'".');if(!c.flatUrl(b)||!c.flatUrl(h)){c.log("Only basic urls are supported in SockJS"); +break}if(!c.isSameOriginUrl(b)||!c.isSameOriginUrl(h)){c.log("Can't connect to different domain from within an iframe. ("+JSON.stringify([g.location.href,b,h])+")");break}a=new u;a._transport=new u[d](a,b,h);break;case "m":a._doSend(b);break;case "c":a&&a._doCleanup(),a=null}}});H("s")};var z=function(a,b){var f=this;c.delay(function(){f.doXhr(a,b)})};z.prototype=new k(["finish"]);z.prototype.doXhr=function(a,b){var f=this,d=(new Date).getTime(),e=new b("GET",a+"/info"),g=c.delay(8E3,function(){e.ontimeout()}); +e.onfinish=function(a,b){clearTimeout(g);g=null;if(200===a){var c=(new Date).getTime()-d,e=JSON.parse(b);"object"!=typeof e&&(e={});f.emit("finish",e,c)}else f.emit("finish")};e.ontimeout=function(){e.close();f.emit("finish")}};var K=function(a){var b=this,f=function(){var c=new s;c.protocol="w-iframe-info-receiver";var f=function(a){"string"==typeof a&&"m"===a.substr(0,1)?(a=JSON.parse(a.substr(1)),b.emit("finish",a[0],a[1])):b.emit("finish");c.doCleanup();c=null};c.i_constructor({_options:{},_didClose:f, +_didMessage:f},a,a)};j.body?f():c.attachEvent("load",f)};K.prototype=new k(["finish"]);var L=function(){var a=this;c.delay(function(){a.emit("finish",{},2E3)})};L.prototype=new k(["finish"]);var N=function(a){if(c.isSameOriginUrl(a))return new z(a,c.XHRLocalObject);switch(c.isXHRCorsCapable()){case 1:return new z(a,c.XHRLocalObject);case 2:return new z(a,c.XDRObject);case 3:return new K(a);default:return new L}};(u["w-iframe-info-receiver"]=function(a,b,f){(new z(f,c.XHRLocalObject)).onfinish=function(b, +c){a._didMessage("m"+JSON.stringify([b,c]));a._didClose()}}).prototype.doCleanup=function(){};k=e["iframe-eventsource"]=function(){this.protocol="w-iframe-eventsource";this.i_constructor.apply(this,arguments)};k.prototype=new s;k.enabled=function(){return"EventSource"in g&&s.enabled()};k.need_body=!0;k.roundTrips=3;(u["w-iframe-eventsource"]=function(a,b){this.run(a,b,"/eventsource",I,c.XHRLocalObject)}).prototype=new i;k=e["iframe-xhr-polling"]=function(){this.protocol="w-iframe-xhr-polling";this.i_constructor.apply(this, +arguments)};k.prototype=new s;k.enabled=function(){return g.XMLHttpRequest&&s.enabled()};k.need_body=!0;k.roundTrips=3;(u["w-iframe-xhr-polling"]=function(a,b){this.run(a,b,"/xhr",y,c.XHRLocalObject)}).prototype=new i;k=e["iframe-htmlfile"]=function(){this.protocol="w-iframe-htmlfile";this.i_constructor.apply(this,arguments)};k.prototype=new s;k.enabled=function(){return s.enabled()};k.need_body=!0;k.roundTrips=3;(u["w-iframe-htmlfile"]=function(a,b){this.run(a,b,"/htmlfile",J,c.XHRLocalObject)}).prototype= +new i;var E=function(a,b,c,d){this.ri=a;this.Receiver=b;this.recv_url=c;this.AjaxObject=d;this._scheduleRecv()};E.prototype._scheduleRecv=function(){var a=this,b=a.poll=new a.Receiver(a.recv_url,a.AjaxObject);b.onmessage=function(b){a.ri._didMessage(b.data)};b.onclose=function(c){a.poll=b=b.onmessage=b.onclose=null;a.poll_is_closing||("permanent"===c.reason?a.ri._didClose(1006,"Polling error ("+c.reason+")"):a._scheduleRecv())}};E.prototype.abort=function(){this.poll_is_closing=!0;this.poll&&this.poll.abort()}; +var I=function(a){var b=this,f=new EventSource(a);f.onmessage=function(a){b.dispatchEvent(new n("message",{data:unescape(a.data)}))};b.es_close=f.onerror=function(a,e){var g=e?"user":2!==f.readyState?"network":"permanent";b.es_close=f.onmessage=f.onerror=null;f.close();f=null;c.delay(200,function(){b.dispatchEvent(new n("close",{reason:g}))})}};I.prototype=new p;I.prototype.abort=function(){this.es_close&&this.es_close({},!0)};var A,J=function(a){var b=this;c.polluteGlobalNamespace();b.id="a"+c.random_string(6, +26);a+=(-1===a.indexOf("?")?"?":"&")+"c="+escape("_jp."+b.id);if(void 0===A)if("ActiveXObject"in g)try{A=!!new ActiveXObject("htmlfile")}catch(f){}else A=!1;var d=A?c.createHtmlfile:c.createIframe,e;g._jp[b.id]={start:function(){e.loaded()},message:function(a){b.dispatchEvent(new n("message",{data:a}))},stop:function(){b.iframe_close({},"network")}};b.iframe_close=function(a,c){e.cleanup();b.iframe_close=e=null;delete g._jp[b.id];b.dispatchEvent(new n("close",{reason:c}))};e=d(a,function(){b.iframe_close({}, +"permanent")})};J.prototype=new p;J.prototype.abort=function(){this.iframe_close&&this.iframe_close({},"user")};var y=function(a,b){var c=this,d=0;c.xo=new b("POST",a,null);c.xo.onchunk=function(a,b){if(200===a)for(;;){var e=b.slice(d),g=e.indexOf("\n");if(-1===g)break;d+=g+1;e=e.slice(0,g);c.dispatchEvent(new n("message",{data:e}))}};c.xo.onfinish=function(a,b){c.xo.onchunk(a,b);c.xo=null;c.dispatchEvent(new n("close",{reason:200===a?"network":"permanent"}))}};return y.prototype=new p,y.prototype.abort= +function(){this.xo&&(this.xo.close(),this.dispatchEvent(new n("close",{reason:"user"})),this.xo=null)},e.getUtils=function(){return c},e.getIframeTransport=function(){return s},e}();"_sockjs_onload"in window&&setTimeout(_sockjs_onload,1);"function"==typeof define&&define.amd&&define("sockjs",[],function(){return SockJS});function WebTCP(j,g){this.sockets={};this.httpClients={};this.sock=new SockJS("http://"+j+":"+g+"/bridge");this.ready=!1;this.outputBuffer=[];var c=this;this.sock.onopen=function(){c.ready=!0;c.processBuffer()};this.processBuffer=function(){if(0<this.outputBuffer.length&&this.ready)for(var c in this.outputBuffer)this.sock.send(this.outputBuffer[c])};this.sock.onmessage=function(g){g.data=JSON.parse(g.data);g.data.sID?(sID=g.data.sID,c.sockets[sID].onEvent(g.data.eventName,g.data.data)):g.data.cID&& +(cID=g.data.cID,c.httpClients[cID].onEvent(g.data.eventName,g.data.data))};this.sock.onclose=function(){console.log("close")};this.createSocket=function(c,g,j){return new Socket(this,c,g,j)};this.createHTTPClient=function(){return new Http(this)}};function WebTCPIO(){this.onEvent=function(j,g){this["on"+j](g);if(this["on"+j+"Custom"])this["on"+j+"Custom"](g)};this.on=function(j,g){this["on"+j+"Custom"]=g};this.rpc=function(j,g){var c=this.createPacket();c.command=j;c.args=g;this.send(JSON.stringify(c));return c.id};this.write=function(j){var g=this.createPacket();g.data=j;this.send(JSON.stringify(g));return g.id};this.send=function(j){if(this.webtcp.ready)this.webtcp.sock.send(j);else{if(this.webtcp.outputBuffer>this.webtcp.BUFF_SIZE)throw"Output buffer is already full, but sockJS connection is not ready yet"; +this.webtcp.outputBuffer.push(j)}};this.onerror=function(j){throw j;}};
\ No newline at end of file diff --git a/chapter24/pom.xml b/chapter24/pom.xml new file mode 100644 index 00000000..6a59188f --- /dev/null +++ b/chapter24/pom.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>com.seaofnodes</groupId> + <artifactId>simple</artifactId> + <version>1.0</version> + </parent> + <artifactId>chapter23</artifactId> + <packaging>jar</packaging> + <name>Chapter 23</name> +</project> diff --git a/chapter24/simple.bat b/chapter24/simple.bat new file mode 100644 index 00000000..05732113 --- /dev/null +++ b/chapter24/simple.bat @@ -0,0 +1,2 @@ +echo off +java -cp "build/classes/test;build/classes/main;lib/hamcrest-core-1.3.jar;lib/junit-4.12.jar" com.seaofnodes.simple.Simple %* diff --git a/chapter24/simple.sh b/chapter24/simple.sh new file mode 100644 index 00000000..d8335f44 --- /dev/null +++ b/chapter24/simple.sh @@ -0,0 +1,2 @@ +#! /bin/sh +java -ea -cp "build/classes/test:build/classes/main:lib/hamcrest-core-1.3.jar:lib/junit-4.12.jar" com.seaofnodes.simple.Simple $@ diff --git a/chapter24/src/main/java/com/seaofnodes/simple/IterPeeps.java b/chapter24/src/main/java/com/seaofnodes/simple/IterPeeps.java new file mode 100644 index 00000000..9ae4231e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/IterPeeps.java @@ -0,0 +1,201 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.print.JSViewer; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Random; + +/** + * The IterPeeps runs after parsing. It iterates the peepholes to a fixed point + * so that no more peepholes apply. This should be linear because peepholes rarely + * (never?) increase code size. The graph should monotonically reduce in some + * dimension, which is usually size. It might also reduce in e.g. number of + * MulNodes or Load/Store nodes, swapping out more "expensive" Nodes for cheaper + * ones. + * <br> + * The theoretical overall worklist is mindless just grabbing the next thing and + * doing it. If the graph changes, put the neighbors on the worklist. + * <br> + * Lather, Rinse, Repeat until the worklist runs dry. + * <p> + * The main issues we have to deal with: + * + * <ul> + * <li>Nodes have uses; replacing some set of Nodes with another requires more graph + * reworking. Not rocket science, but it can be fiddly. Its helpful to have a + * small set of graph munging utilities, and the strong invariant that the graph + * is stable and correct between peepholes. In our case `Node.subsume` does + * most of the munging, building on our prior stable Node utilities.</li> + * + * <li>Changing a Node also changes the graph "neighborhood". The neighbors need to + * be checked to see if THEY can also peephole, and so on. After any peephole + * or graph update we put a Nodes uses and defs on the worklist.</li> + * + * <li>Our strong invariant is that for all Nodes, either they are on the worklist + * OR no peephole applies. This invariant is easy to check, although expensive. + * Basically the normal "iterate peepholes to a fixed point" is linear, and this + * check is linear at each peephole step... so quadratic overall. Its a useful + * assert, but one we can disable once the overall algorithm is stable - and + * then turn it back on again when some new set of peepholes is misbehaving. + * The code for this is turned on in `IterPeeps.iterate` as `assert + * progressOnList(stop);`</li> + * </ul> + */ +public class IterPeeps { + + private final WorkList<Node> _work; + + public IterPeeps( long seed ) { _work = new WorkList<>(seed); } + + @SuppressWarnings("unchecked") + public <N extends Node> N add( N n ) { return (N)_work.push(n); } + + public void addAll( Ary<Node> ary ) { _work.addAll(ary); } + + /** + * Iterate peepholes to a fixed point + */ + public void iterate( CodeGen code ) { + assert progressOnList(code); + int cnt=0; + + Node n; + while( (n=_work.pop()) != null ) { + if( n.isDead() ) continue; + cnt++; // Useful for debugging, searching which peephole broke things + Node x = n.peepholeOpt(); + if( x != null ) { + if( x.isDead() ) continue; + // peepholeOpt can return brand-new nodes, needing an initial type set + if( x._type==null ) x.setType(x.compute()); + // Changes require neighbors onto the worklist + if( x != n || !(x instanceof ConstantNode) ) { + // All outputs of n (changing node) not x (prior existing node). + for( Node z : n._outputs ) _work.push(z); + // Everybody gets a free "go again" in case they didn't get + // made in their final form. + _work.push(x); + // If the result is not self, revisit all inputs (because + // there's a new user), and replace in the graph. + if( x != n ) { + for( Node z : n. _inputs ) _work.push(z); + for( Node z : x._outputs ) _work.push(z); + n.subsume(x); + } + } + // If there are distant neighbors, move to worklist + n.moveDepsToWorklist(); + JSViewer.show(); // Show again + assert progressOnList(code); // Very expensive assert + } + if( n.isUnused() && !(n instanceof StopNode) ) + n.kill(); // Just plain dead + } + + } + + // Visit ALL nodes and confirm the invariant: + // Either you are on the _work worklist OR running `iter()` makes no progress. + + // This invariant ensures that no progress is missed, i.e., when the + // worklist is empty we have indeed done all that can be done. To help + // with debugging, the {@code assert} is broken out in a place where it is easy to + // stop if a change is found. + + // Also, the normal usage of `iter()` may attempt peepholes with distance + // neighbors and these should fail, but will then try to add dependencies + // {@link #Node.addDep} which is a side effect in an assert. The {@link + // #midAssert} is used to stop this side effect. + private boolean progressOnList(CodeGen code) { + code._midAssert = true; + Node changed = code._stop.walk( n -> { + Node m = n; + if( n.compute().isa(n._type) && (!n.iskeep() || n._nid<=6) ) { // Types must be forwards, even if on worklist + if( _work.on(n) ) return null; + m = n.peepholeOpt(); + if( m==null ) return null; + } + System.err.println("BREAK HERE FOR BUG"); + return m; + }); + code._midAssert = false; + return changed==null; + } + + /** + * Classic WorkList, with a fast add/remove, dup removal, random pull. + * The Node's nid is used to check membership in the worklist. + */ + @SuppressWarnings("unchecked") + public static class WorkList<E extends Node> { + + private Node[] _es; + private int _len; + private final BitSet _on; // Bit set if Node._nid is on WorkList + private final Random _R; // For randomizing pull from the WorkList + private final long _seed; + + /* Useful stat - how many nodes are processed in the post parse iterative opt */ + private long _totalWork = 0; + + public WorkList() { this(123); } + WorkList(long seed) { + _es = new Node[1]; + _len=0; + _on = new BitSet(); + _seed = seed; + _R = new Random(); + _R.setSeed(_seed); + } + + /** + * Pushes a Node on the WorkList, ensuring no duplicates + * If Node is null it will not be added. + */ + public E push( E x ) { + if( x==null ) return null; + int idx = x._nid; + if( !_on.get(idx) ) { + _on.set(idx); + if( _len==_es.length ) + _es = Arrays.copyOf(_es,_len<<1); + _es[_len++] = x; + _totalWork++; + } + return x; + } + + public void addAll( Ary<E> ary ) { + for( E n : ary ) + push(n); + } + + /** + * True if Node is on the WorkList + */ + boolean on( E x ) { return _on.get(x._nid); } + boolean isEmpty() { return _len==0; } + + /** + * Removes a random Node from the WorkList; null if WorkList is empty + */ + public E pop() { + if( _len == 0 ) return null; + int idx = _R.nextInt(_len); + E x = (E)_es[idx]; + _es[idx] = _es[--_len]; // Compress array + _on.clear(x._nid); + return x; + } + + public void clear() { + _len = 0; + _on.clear(); + _R.setSeed(_seed); + _totalWork = 0; + } + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/Parser.java b/chapter24/src/main/java/com/seaofnodes/simple/Parser.java new file mode 100644 index 00000000..95d178f0 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/Parser.java @@ -0,0 +1,2115 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.print.GraphVisualizer; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.node.ScopeNode.Kind; +import java.util.*; + +/** + * The Parser converts a Simple source program to the Sea of Nodes intermediate + * representation directly in one pass. There is no intermediate Abstract + * Syntax Tree structure. + * <p> + * This is a simple recursive descent parser. All lexical analysis is done here as well. + */ +public class Parser { + + public static ConstantNode ZERO; // Very common node, cached here + public static ConstantNode NIL; // Very common node, cached here + public static XCtrlNode XCTRL; // Very common node, cached here + + // Compile driver + public final CodeGen _code; + + // The Lexer. Thin wrapper over a byte[] buffer with a cursor. + private Lexer _lexer; + + /** + * Current ScopeNode - ScopeNodes change as we parse code, but at any point of time + * there is one current ScopeNode. The reason the current ScopeNode can change is to do with how + * we handle branching. See {@link #parseIf()}. + * <p> + * Each ScopeNode contains a stack of lexical scopes, each scope is a symbol table that binds + * variable names to Nodes. The top of this stack represents current scope. + * <p> + * We keep a list of all ScopeNodes so that we can show them in graphs. + * @see #parseIf() + * @see #_xScopes + */ + public ScopeNode _scope; + + /** + * List of keywords disallowed as identifiers + */ + public static final HashSet<String> KEYWORDS = new HashSet<>(){{ + add("bool"); + add("break"); + add("byte"); + add("continue"); + add("else"); + add("f32"); + add("f64"); + add("false"); + add("flt"); + add("i16"); + add("i32"); + add("i64"); + add("i8"); + add("if"); + add("int"); + add("new"); + add("null"); + add("return"); + add("struct"); + add("true"); + add("u1"); + add("u16"); + add("u32"); + add("u8"); + add("while"); + }}; + + /** + * We clone ScopeNodes when control flows branch; it is useful to have + * a list of all active ScopeNodes for purposes of visualization of the SoN graph + */ + public final Stack<ScopeNode> _xScopes = new Stack<>(); + + ScopeNode _continueScope; + ScopeNode _breakScope; // Merge all the while-breaks here + FunNode _fun; // Current function being parsed + + // Mapping from a type name to a Type. The string name matches + // `type.str()` call. + public static HashMap<String, Type> TYPES = defaultTypes(); + + // Mapping from a type name to the constructor for a Type. + public final HashMap<String, StructNode> INITS; + + + public Parser(CodeGen code, TypeInteger arg) { + _code = code; + _scope = new ScopeNode(); + _continueScope = _breakScope = null; + ZERO = con(TypeInteger.ZERO).keep(); + NIL = con(Type.NIL).keep(); + XCTRL= new XCtrlNode().peephole().keep(); + TYPES = defaultTypes(); + INITS = new HashMap<>(); + } + + @Override + public String toString() { return _lexer.toString(); } + + public static HashMap<String, Type> defaultTypes() { + return new HashMap<>() {{ + put("bool",TypeInteger.U1 ); + put("byte",TypeInteger.U8 ); + put("f32" ,TypeFloat .F32); + put("f64" ,TypeFloat .F64); + put("flt" ,TypeFloat .F64); + put("i16" ,TypeInteger.I16); + put("i32" ,TypeInteger.I32); + put("i64" ,TypeInteger.BOT); + put("i8" ,TypeInteger.I8 ); + put("int" ,TypeInteger.BOT); + put("u1" ,TypeInteger.U1 ); + put("u16" ,TypeInteger.U16); + put("u32" ,TypeInteger.U32); + put("u8" ,TypeInteger.U8 ); + put("val" ,Type.TOP); // Marker type, indicates type inference + put("var" ,Type.BOTTOM); // Marker type, indicates type inference + }}; + } + + // Debugging utility to find a Node by index + public Node f(int nid) { return _code.f(nid); } + + private Node ctrl() { return _scope.ctrl(); } + private <N extends Node> N ctrl(N n) { return _scope.ctrl(n); } + + public void parse() { + + _scope.define(ScopeNode.CTRL, Type.CONTROL , false, null, _lexer); + _scope.define(ScopeNode.MEM0, TypeMem.BOT , false, null, _lexer); + _scope.define(ScopeNode.ARG0, TypeInteger.BOT, false, null, _lexer); + + ctrl(XCTRL); + _scope.mem(new MemMergeNode(false)); + + // Parse the sys import + _lexer = new Lexer(sys.SYS); + while( !_lexer.isEOF() ) { + parseStatement(); + _lexer.skipWhiteSpace(); + } + + // Reset lexer for program text + _lexer = new Lexer(_code._src); + _xScopes.push(_scope); + + // Parse whole program, as-if function header "{ int arg -> body }" + parseFunctionBody( _code._main,loc(),"arg"); + + // Kill an empty default main. Keep only if it was explicitly defined + // (programmer asked for a "main") or it has stuff (i.e. beginner + // default main). + FunNode main = _code.link(_code._main); + StopNode stop = _code._stop; + if( main.ret().expr()._type==Type.TOP && main.uctrl()==null ) { + // Kill an empty default main; so it does not attempt to put a + // "main" in any final ELF file + main.setDef(1,XCTRL); // Delete default start input + stop.delDef(stop._inputs.find(main.ret())); + } else { + // We have a non-empty default main. + // Check for an explicit main + for( Node n : stop._inputs ) + if( n instanceof FunNode fun && fun._name.equals("main") ) + // Found an explicit "main" AND we have a default "main" + throw error("Cannot define both an explicit main and a default main"); + main._name = "main"; + } + + if( !_lexer.isEOF() ) throw _errorSyntax("unexpected"); + + // Clean up and reset + _xScopes.pop(); + _scope.kill(); + for( StructNode init : INITS.values() ) + init.unkeep().kill(); + INITS.clear(); + stop.peephole(); + } + + /** + * Parses a function body, assuming the header is parsed. + */ + private ReturnNode parseFunctionBody( TypeFunPtr sig, Lexer loc, String... ids) { + // If this is a method, record & restore the existing struct fields, + // which are also the struct initializers. The method might update + // mutable fields, so when the function parse is done reset back to + // pre-function-parse values. + Node[] preParse = new Node[_scope.nIns()]; + for( int i=0; i<_scope.nIns(); i++ ) + preParse[i] = _scope.in(i)==null ? null : _scope.in(i).keep(); + + // Stack parser state on the local Java stack, and unstack it later + FunNode oldfun = _fun; + ScopeNode breakScope = _breakScope; _breakScope = null; + ScopeNode continueScope = _continueScope; _continueScope = null; + + FunNode fun = _fun = (FunNode)peep(new FunNode(loc(),sig,_nestedType,null,_code._start)); + // Once the function header is available, install in linker table - + // allowing recursive functions. Linker matches on declared args and + // exact fidx, and ignores the return (because the fidx will only match + // the exact single function). + _code.link(fun); + + Node rpc = new ParmNode("$rpc",0,TypeRPC.BOT,fun,con(TypeRPC.BOT)).peephole(); + + // Build a multi-exit return point for all function returns + RegionNode r = new RegionNode( null,null,null).init(); + assert r.inProgress(); + PhiNode rmem = new PhiNode(ScopeNode.MEM0,TypeMem.BOT,r,null).init(); + PhiNode rrez = new PhiNode(ScopeNode.ARG0,Type.BOTTOM,r,null).init(); + ReturnNode ret = new ReturnNode(r, rmem, rrez, rpc, fun).init(); + fun.setRet(ret); + assert ret.inProgress(); + _code._stop.addDef(ret); + + + // Pre-call the function from Start, with worse-case arguments. This + // represents all the future, yet-to-be-parsed functions calls and + // external calls. + _scope.push(new Kind.Func()); + ctrl(fun); // Scope control from function + // Private mem alias tracking per function + MemMergeNode mem = new MemMergeNode(true); + mem.addDef(null); // Alias#0 + mem.addDef(new ParmNode(ScopeNode.MEM0,1,TypeMem.BOT,fun,con(TypeMem.BOT)).peephole()); // All aliases + _scope.mem(mem); + // All args, "as-if" called externally + for( int i=0; i<ids.length; i++ ) { + Type t = sig.arg(i); + _scope.define(ids[i], t, false, new ParmNode(ids[i],i+2,t,fun,con(t)).peephole(), loc); + } + + // Parse the body + Node last=ZERO; + while (!peek('}') && !_lexer.isEOF()) + last = parseStatement(); + + // Last expression is the return except for the top-level main + if( ctrl()._type==Type.CONTROL && fun.sig() != _code._main ) + fun.addReturn(ctrl(), _scope.mem().merge(), last); + + // Pop off the inProgress node on the multi-exit Region merge + assert r.inProgress(); + r ._inputs.pop(); + rmem._inputs.pop(); + rrez._inputs.pop(); + r._loc = loc(); // Final position + assert !r.inProgress(); + + // Force peeps, which have been avoided due to inProgress + ret.setDef(1,rmem.peephole()); + ret.setDef(2,rrez.peephole()); + ret.setDef(0,r.peephole()); + ret = (ReturnNode)ret.peephole(); + + // Function scope ends + _scope.pop(); + _fun = oldfun; + _breakScope = breakScope; + _continueScope = continueScope; + + // Reset all fields to pre-parse days + for( int i=0; i<preParse.length; i++ ) + _scope.setDef(i,preParse[i]==null ? null : preParse[i].unkeep()); + + return ret; + } + + /** + * Parses a block + * + * <pre> + * '{' statements '}' + * </pre> + * Does not parse the opening or closing '{}' + * @return a {@link Node} or {@code null} + */ + private Node parseBlock(Kind kind) { + // Enter a new scope + _scope.push(kind); + Node last = ZERO; + while (!peek('}') && !_lexer.isEOF()) + last = parseStatement(); + // Exit scope + last.keep(); + _scope.pop(); + return last.unkeep(); + } + + /** + * Parses a statement + * + * <pre> + * returnStatement | declStatement | blockStatement | ifStatement | expressionStatement + * </pre> + * @return a {@link Node} or {@code null} + */ + private Node parseStatement() { + if( matchx("return") ) return parseReturn(); + else if (matchx("if") ) return parseIf(); + else if (matchx("while") ) return parseWhile(); + else if (matchx("for") ) return parseFor(); + else if (matchx("break") ) return parseBreak(); + else if (matchx("continue")) return parseContinue(); + else if (matchx("struct") ) return parseStruct(); + else if (matchx("#showGraph")) return require(showGraph(),";"); + else if (matchx(";") ) return null; // Empty statement + // Break ambiguity around leading function types and starting a block + else if (peek('{') && !isTypeFun() ) { + match("{"); + return require(parseBlock(new Kind.Block()),"}"); + } + // Declaration or normal assignment/expression + else return parseDeclarationStatement(); + } + + /** + * Parses a while statement + * + * <pre> + * while ( expression ) statement + * </pre> + * @return a {@link Node}, never {@code null} + */ + private Node parseWhile() { + require("("); + return parseLooping(false); + } + + + /** + * Parses a for statement + * + * <pre> + * for( var x=init; test; incr ) body + * </pre> + * @return a {@link Node}, never {@code null} + */ + private Node parseFor() { + // { var x=init,y=init,...; + // while( test ) { + // body; + // next; + // } + // } + require("("); + _scope.push(new Kind.Block()); // Scope for the index variables + if( !match(";") ) // Can be empty init "for(;test;next) body" + parseDeclarationStatement(); // Non-empty init + Node rez = parseLooping(true); + _scope.pop(); // Exit index variable scope + return rez; + } + + // Shared by `for` and `while` + private Node parseLooping( boolean doFor ) { + + var savedContinueScope = _continueScope; + var savedBreakScope = _breakScope; + + // Loop region has two control inputs, the first is the entry + // point, and second is back edge that is set after loop is parsed + // (see end_loop() call below). Note that the absence of back edge is + // used as an indicator to switch off peepholes of the region and + // associated phis; see {@code inProgress()}. + + ctrl(new LoopNode(loc(),ctrl()).peephole()); // Note we set back edge to null here + + // At loop head, we clone the current Scope (this includes all + // names in every nesting level within the Scope). + // We create phis eagerly for all the names we find, see dup(). + + // Save the current scope as the loop head + ScopeNode head = _scope.keep(); + // Clone the head Scope to create a new Scope for the body. + // Create phis eagerly as part of cloning + _xScopes.push(_scope = _scope.dup(true)); // The true argument triggers creating phis + + // Parse predicate + var pred = peek(';') ? con(1) : parseAsgn(); + require( doFor ? ";" : ")" ); + + // IfNode takes current control and predicate + Node ifNode = new IfNode(ctrl(), pred.keep()).peephole(); + // Setup projection nodes + Node ifT = new CProjNode(ifNode. keep(), 0, "True" ).peephole().keep(); + Node ifF = new CProjNode(ifNode.unkeep(), 1, "False").peephole(); + + // for( ;;next ) body + int nextPos = -1, nextEnd = -1; + if( doFor ) { + // Skip the next expression and parse it later + nextPos = pos(); + skipAsgn(); + nextEnd = pos(); + require(")"); + } + + // Clone the body Scope to create the break/exit Scope which accounts for any + // side effects in the predicate. The break/exit Scope will be the final + // scope after the loop, and its control input is the False branch of + // the loop predicate. Note that body Scope is still our current scope. + ctrl(ifF); + _xScopes.push(_breakScope = _scope.dup()); + _breakScope.addGuards(ifF,pred,true); // Up-cast predicate + + // No continues yet + _continueScope = null; + + // Parse the true side, which corresponds to loop body + // Our current scope is the body Scope + ctrl(ifT.unkeep()); // set ctrl token to ifTrue projection + _scope.addGuards(ifT,pred.unkeep(),false); // Up-cast predicate + parseStatement().isKill(); // Parse loop body + _scope.removeGuards(ifT); + + // Merge the loop bottom into other continue statements + if (_continueScope != null) { + _continueScope = jumpTo(_continueScope); + _scope.kill(); + _scope = _continueScope; + } + + // Now append the next code onto the body code + if( doFor ) { + int old = pos(nextPos); + if( !peek(')') ) + parseAsgn(); + if( pos() != nextEnd ) + throw errorSyntax( "Unexpected code after expression" ); + pos(old); + } + + // The true branch loops back, so whatever is current _scope.ctrl gets + // added to head loop as input. endLoop() updates the head scope, and + // goes through all the phis that were created earlier. For each phi, + // it sets the second input to the corresponding input from the back + // edge. If the phi is redundant, it is replaced by its sole input. + var exit = _breakScope; + head.endLoop(_scope, exit); + head.unkeep().kill(); + + _xScopes.pop(); // Cleanup + _xScopes.pop(); // Cleanup + + _continueScope = savedContinueScope; + _breakScope = savedBreakScope; + + // At exit the false control is the current control, and + // the scope is the exit scope after the exit test. + // During sys parsing, there is no xscope here. + if( !_xScopes.isEmpty() ) { + _xScopes.pop(); + _xScopes.push( exit ); + } + _scope = exit; + return ZERO; + } + + private ScopeNode jumpTo(ScopeNode toScope) { + ScopeNode cur = _scope.dup(); + ctrl(XCTRL); // Kill current scope + // Prune nested lexical scopes that have depth > than the loop head + // We use _breakScope as a proxy for the loop head scope to obtain the depth + while( cur.depth() > _breakScope.depth() ) + cur.pop(); + // If this is a continue then first time the target is null + // So we just use the pruned current scope as the base for the + // "continue" + if( toScope == null ) + return cur; + // toScope is either the break scope, or a scope that was created here + assert toScope.depth() <= _breakScope.depth(); + toScope.ctrl(toScope.mergeScopes(cur,loc()).peephole()); + return toScope; + } + + private void checkLoopActive() { if (_breakScope == null) throw error("No active loop for a break or continue"); } + + private Node parseContinue() { checkLoopActive(); _continueScope = require(jumpTo( _continueScope ),";"); return ZERO; } + private Node parseBreak () { + checkLoopActive(); + // At the time of the break, and loop-exit conditions are only valid if + // they are ALSO valid at the break. It is the intersection of + // conditions here, not the union. + _breakScope.removeGuards(_breakScope.ctrl()); + _breakScope = require(jumpTo(_breakScope ),";"); + _breakScope.addGuards(_breakScope.ctrl(), null, false); + return ZERO; + } + + // Look for an unbalanced `)`, skipping balanced + private void skipAsgn() { + int paren=0; + while( true ) + // Next X char handles skipping complex comments + switch( _lexer.nextXChar() ) { + case Character.MAX_VALUE: + throw Utils.TODO(); + case ')': + if( --paren<0 ) { + posT( pos() - 1 ); + return; // Leave the `)` behind + } + break; + case '(': paren ++; break; + default: break; + } + } + + + /** + * Parses a statement + * + * <pre> + * if ( expression ) statement [else statement] + * </pre> + * @return a {@link Node}, never {@code null} + */ + private Node parseIf() { + // Parse predicate + require("("); + var pred = require(parseAsgn(), ")"); + return parseTrinary(pred,"else"); + } + + /** + * Handles a conditional expression needed for chaining operators. + * a < x < b the bounded var is x here</> + * @return a {@link Node}, never {@code null} + */ + private Node make_and_conditional(Node lhs, Node ext,boolean swap, Node bounded_var) { + lhs.keep(); + ext.keep(); + + Node ifNode = new IfNode(ctrl(), lhs).peephole(); + + Node ifT = new CProjNode(ifNode. keep(), 0, "True" ).peephole().keep(); + Node ifF = new CProjNode(ifNode.unkeep(), 1, "False").peephole().keep(); + + ScopeNode fScope = _scope.dup(); + + // true + ctrl(ifT.unkeep()); + _scope.addGuards(ifT,lhs,false); + Node rhs = parseShift(); + _scope.removeGuards(ifT); + fScope.balanceIf(_scope); + ScopeNode tScope = _scope; + _scope = fScope; + ctrl(ifF.unkeep()); + _scope.addGuards(ifF,lhs,true); + _scope.removeGuards(ifF); + + _scope = tScope; + tScope.balanceIf(fScope); + ext.setDef(swap ? 2: 1, bounded_var); + ext.setDef(swap ? 1 :2, rhs); + ext.peephole(); + + RegionNode r = ctrl(tScope.mergeScopes(fScope, loc())); + Node ret = peep(new PhiNode("",ext._type.meet(lhs._type).glb(false),r,ext.unkeep(),lhs.unkeep())); + + r.peephole(); + return ret; + } + + // Parse a conditional expression, merging results. + private Node parseTrinary( Node pred, String fside ) { + // IfNode takes current control and predicate + pred.keep(); + Node ifNode = new IfNode(ctrl(), pred).peephole(); + // Setup projection nodes + Node ifT = new CProjNode(ifNode. keep(), 0, "True" ).peephole().keep(); + Node ifF = new CProjNode(ifNode.unkeep(), 1, "False").peephole().keep(); + // In if true branch, the ifT proj node becomes the ctrl + // But first clone the scope and set it as current + ScopeNode fScope = _scope.dup(); // Duplicate current scope + _xScopes.push(fScope); // For graph visualization we need all scopes + + // Parse the true side + ctrl(ifT.unkeep()); // set ctrl token to ifTrue projection + _scope.addGuards(ifT,pred,false); // Up-cast predicate + // Parse true-side flavor + Node lhs = switch( fside ) { + case "else" -> parseStatement(); // if( pred ) stmts; + case ":" -> parseAsgn(); // pred ? asgn; + case "&&" -> parseLogical(); // pred && expr + case "||" -> pred; // pred || expr_is_ignored + default -> throw Utils.TODO(); + }; + lhs.keep(); + _scope.removeGuards(ifT); + + // See if a one-sided def was made: "if(pred) int x = 1;" and throw. + // See if any forward-refs were made, and copy them to the other side: + // "pred ? n*fact(n-1) : 1" + fScope.balanceIf(_scope); + + ScopeNode tScope = _scope; + + // Parse the false side + _scope = fScope; // Restore scope, then parse else block if any + ctrl(ifF.unkeep()); // Ctrl token is now set to ifFalse projection + // Up-cast predicate, even if not else clause, because predicate can + // remain true if the true clause exits: `if( !ptr ) return 0; return ptr.fld;` + _scope.addGuards(ifF,pred,true); + // Parse false-side flavor + boolean doRHS = false; // RHS is optional for if/else and trinary + Node rhs = switch( fside ) { + case "else" -> (doRHS=match(fside)) ? parseStatement() : con(lhs._type.makeZero()); + case ":" -> (doRHS=match(fside)) ? parseAsgn() : con(lhs._type.makeZero()); + case "&&" -> rhs = pred; + case "||" -> rhs = parseLogical(); + default -> throw Utils.TODO(); + }; + rhs.keep(); + _scope.removeGuards(ifF); + if( doRHS ) + fScope = _scope; + pred.unkeep(); + + // Check the trinary widening int/flt + if( !fside.equals("else") ) { + rhs = widenInt( rhs.unkeep(), lhs._type ).keep(); + lhs = widenInt( lhs.unkeep(), rhs._type ).keep(); + } + + _scope = tScope; + _xScopes.pop(); // Discard pushed from graph display + // See if a one-sided def was made: "if(pred) int x = 1;" and throw. + // See if any forward-refs were made, and copy them to the other side: + // "pred ? n*fact(n-1) : 1" + tScope.balanceIf(fScope); + + // Merge results + RegionNode r = ctrl(tScope.mergeScopes(fScope,loc())); + Node ret = peep(new PhiNode("",lhs._type.meet(rhs._type).glb(false),r,lhs.unkeep(),rhs.unkeep())); + // Immediately fail e.g. `arg ? 7 : ptr` + ParseException err; + if( !fside.equals("else") && (err=ret.err()) !=null ) throw err; + r.peephole(); + return ret; + } + + /** + * Parses a return statement; "return" already parsed. + * The $ctrl edge is killed. + * + * <pre> + * 'return' expr ; + * </pre> + * @return an expression {@link Node}, never {@code null} + */ + private Node parseReturn() { + var expr = require(parseAsgn(), ";"); + // Need default memory, since it can be lazy, need to force + // a non-lazy Phi + _fun.addReturn(ctrl(), _scope.mem().merge(), expr); + ctrl(XCTRL); // Kill control + return expr; + } + + /** + * Dumps out the node graph + * @return {@code null} + */ + Node showGraph() { + System.out.println(new GraphVisualizer().generateDotOutput(_code._stop,_scope,_xScopes)); + return null; + } + + /** Parse: [name '='] expr + */ + private Node parseAsgn() { + int old = pos(); + String name = _lexer.matchId(); + int old_pre_equals = pos(); + // Just a plain expression, no assignment. + // Distinguish `var==expr` from `var=expr` + if( name==null || KEYWORDS.contains(name) || !matchOpx('=','=') ) + { pos(old); return parseExpression(); } + + // Find variable to update + Var def = _scope.lookup(name); + if( def==null ) + throw error("Undefined name '" + name + "'"); + + // If a method var, allow nested blocks and methods, but not fcns or other structs. + // Else safety check for accessing fields out of function scope. + if( instance(def) ) { + pos(old_pre_equals); // setup for `self.name = expr` + Node self = _scope.in(_scope.lookup("self")); // Insert self reference + return parsePostfixName(self,name); + } + + // TOP fields are for late-initialized fields; these have never + // been written to, and this must be the final write. Other writes + // outside the constructor need to check the final bit. + if( _scope.in(def._idx)._type!=Type.TOP && def._final && + // Inside an allocation, final assign is OK, outside nope. + // The alloc() call added the allocation scope + !(_scope.inAllocation() && def._idx >= _scope._kinds.last(-1)._lexSize) ) + throw error("Cannot reassign final '"+name+"'"); + + // Parse assignment expression + Node expr = parseAsgn(); + + // Lift expression, based on type + Node lift = liftExpr(expr.keep(), def.type(), def._final, true); + // Update + _scope.update(name,lift); + // Return un-lifted expr + return expr.unkeep(); + } + + // Make finals deep; widen ints to floats; narrow wide int types. + // Early error if types do not match variable. + private Node liftExpr( Node expr, Type t, boolean xfinal, boolean isLoad ) { + if( expr._type instanceof TypeMemPtr tmp && TYPES.get(tmp._obj._name).isFRef() ) + throw error("Must define forward ref "+tmp._obj._name); + // Final is deep on ptrs + if( xfinal && t instanceof TypeMemPtr tmp ) { + t = tmp.makeRO(); + expr = peep(new ReadOnlyNode(expr)); + } + // Auto-widen array to i64 (cast ptr to raw int bits) + if( t == TypeInteger.BOT && expr._type instanceof TypeMemPtr tmp && tmp._obj.isAry() ) + expr = peep(new AddNode(peep(new CastNode(t,ctrl(),expr)),off(tmp._obj,"[]"))); + // Auto-widen int to float + expr = widenInt( expr, t ); + // Auto-narrow wide ints to narrow ints. For loads, emit code to force + // the loaded value to match the declared sign/zero bits. For stores, + // just force the type, acting "as if" the store silently truncates. + Type et = expr._type; + if( isLoad ) { expr = zsMask(expr,t); et = expr._type; } + else if( et instanceof TypeInteger && t instanceof TypeInteger ) et=t; + + // Type is sane + if( et!=Type.BOTTOM && !et.shallowISA(t) ) + expr = peep(new CastNode(t,null,expr)); + return expr; + } + + private Node widenInt( Node expr, Type t ) { + return (expr._type instanceof TypeInteger || expr._type==Type.NIL) && t instanceof TypeFloat + ? peep(new ToFloatNode(expr)) : expr; + } + + /** + * Parse declaration or expression statement + * declStmt = type var['=' exprAsgn][, var['=' exprAsgn]]* ';' | exprAsgn ';' + * <p> + * exprAsgn = var '=' exprAsgn | expr + */ + private Node parseDeclarationStatement() { + int old = pos(); + Type t = type(); + if( peek('.') ) // Ambiguity static vars: "type.var", parse as expression + { pos(old); t=null; } + if( t == null ) + return require(parseAsgn(),";"); + + // now parse var['=' asgnexpr] in a loop + Node n = parseDeclaration(t); + while( match(",") ) + n = parseDeclaration(t); + return require(n,";"); + } + + /** Parse final: [!]var['=' asgn] + */ + private Node parseDeclaration(Type t) { + assert t!=null; + // Has var/val instead of a user-declared type + boolean inferType = t==Type.TOP || t==Type.BOTTOM; + boolean hasBang = match("!"); + Lexer loc = loc(); + String name = requireId(); + // Optional initializing expression follows + boolean xfinal = false; + boolean fld_final = false; // Field is final, but not deeply final + Node expr; + if( match("=") ) { + expr = isExternDecl() + ? externDecl(name,t) + : parseAsgn(); + // TOP means val and val is always final + xfinal = (t==Type.TOP) || + expr instanceof ExternNode || + // BOTTOM is var and var is always not-final + (t!=Type.BOTTOM && + // no Bang AND + !hasBang && + // Locals are not-final by default + !_scope.inFunction() && + // not-null (expecting null to be set to not-null) + expr._type != Type.NIL && + // Pointers are final by default; int/flt are not-final by default. + (t instanceof TypeNil)); + + // var/val, then type comes from expression + if( inferType ) { + if( expr._type==Type.NIL ) + throw error("a not-null/non-zero expression"); + t = expr._type; + if( !xfinal ) t = t.glb(false); // Widen if not final + } + // expr is a constant function + if( t instanceof TypeFunPtr && expr._type instanceof TypeFunPtr tfp && tfp.isConstant() ) { + if( expr instanceof ExternNode ) t = expr._type; // Upgrade declared type to exact function + else _code.link(tfp).setName(name); // Assign debug name to Simple function + } + + } else { + // Need an expression to infer the type. + // Also, if not-null then need an initializing expression. + // Allowed in a class def, because type/init will happen in the constructor. + if( (inferType || (t instanceof TypeNil tn && !tn.nullable() )) && !_scope.inConstructor() ) + throw errorSyntax("=expression"); + // Initial value for uninitialized struct fields. + expr = switch( t ) { + // Nullable pointers get a NIL; not-null get a TOP which + // signals that they *must* be initialized in the constructor. + case TypeNil tn -> tn.nullable() ? NIL : con(Type.TOP); + case TypeInteger ti -> ZERO; + case TypeFloat tf -> con(TypeFloat.FZERO); + // Bottom signals type inference: they must be initialized in + // the constructor and that's when we'll discover the type. + case Type tt -> { assert tt==Type.BOTTOM; yield con(tt); } + }; + // Nullable fields are set in the constructor, but remain shallow final. + // e.g. final pointer to a r/w array + if( t instanceof TypeNil tn && !tn.nullable() && !hasBang ) + fld_final = true; + } + + // Lift expression, based on type + Node lift = liftExpr(expr, t, xfinal, true); + // Rebuild the deep RO 't', not returned from liftExpr + if( xfinal && t instanceof TypeMemPtr tmp ) + t = tmp.makeRO(); + + // Lift type to the declaration. This will report as an error later if + // we cannot lift the type. + if( !lift._type.isa(t) ) + lift = peep(new CastNode(t,null,lift)); + // Define a new name + if( !_scope.define(name,t,xfinal || fld_final,lift, loc) ) + throw error("Redefining name '" + name + "'", loc); + return lift; + } + + + + /** + * Parse a struct declaration, and return the following statement. + * Structs cannot be redefined, but can be nested. + * + * @return zero + */ + private String _nestedType; + private Node parseStruct() { + // "struct" already parsed, so expect the struct name next. + String old = _nestedType; + String typeName = requireId(); + if( old!=null ) typeName = old+"."+typeName; + _nestedType = typeName; + // New declared or forward-ref type + TypeStruct ts = TYPES.get(typeName) instanceof TypeMemPtr tmp ? tmp._obj : TypeStruct.open(typeName); + TYPES.put(typeName,TypeMemPtr.make(ts)); + + // A Block scope parse, and inspect the scope afterward for fields. + _scope.push(new Kind.Define(TypeMemPtr.make(ts))); + require("{"); + int lexlen = _scope._kinds.last()._lexSize, nvar=lexlen; + while (!peek('}') && !_lexer.isEOF()) { + parseStatement().isKill(); + while( nvar < _scope._vars._len ) { + Var v = _scope.var(nvar++); + if( !v.isFRef() ) { + ts = ts.add( Field.make( v._name, v.type(), _code.getALIAS(), v._final, v._final && _scope.in( v._idx )._type != Type.TOP ) ); + TYPES.put( typeName, TypeMemPtr.make( ts ) ); + } + } + } + + // Count struct declarations + int varlen = _scope._vars._len; + ts = ts.close(); + TYPES.put(typeName,TypeMemPtr.make(ts)); + + // Generate an initializing struct + StructNode s = new StructNode(ts); + for( int i=lexlen; i<varlen; i++ ) + if( !_scope.var(i).isFRef() ) // Promote to outer scope, not defined here + s.addDef(_scope.in(i)); // Keep the program code to generate instance + + // Save instance default constructor + s.setType(s.compute()); // Do not call peephole, in case the entire struct is a big plain constant + INITS.put(typeName,s.keep()); + + // Having finalized the struct, upgrade all the 'self' pointers + for( Node n : s._inputs ) + if( n._type instanceof TypeFunPtr tfp && _code.link(tfp) instanceof FunNode fun ) + _code.addAll( fun._outputs ); + + + // Done with struct/block scope + _nestedType = old; + require("}"); + require(";"); + _scope.pop(); + return ZERO; + } + + + // Parse and return a type or null. Valid types always are followed by an + // 'id' which the caller must parse. This lets us distinguish forward ref + // types (which ARE valid here) from local vars in an (optional) forward + // ref type position. + + // t = int|i8|i16|i32|i64|u8|u16|u32|u64|byte|bool | flt|f32|f64 | val | var | struct[?] + private Type type() { + int old1 = pos(); + // Only type with a leading `{` is a function pointer... + if( peek('{') ) return typeFunPtr(); + + // Otherwise you get a type name + String tname = _lexer.matchId(); + if( tname==null ) return null; + + // Convert the type name to a type. + Type t0 = TYPES.get(tname); + // No new types as keywords + if( t0 == null && KEYWORDS.contains(tname) ) + return posT(old1); + if( t0 == Type.BOTTOM || t0 == Type.TOP ) return t0; // var/val type inference + + // Check for subtype. + while( true ) { + int old2 = pos(); + if( !match(".") ) break; + String sname = _lexer.matchId(); + if( sname==null ) { pos(old2); break; } + String tsname = tname+"."+sname; + t0 = TYPES.get(tsname); + if( t0==null ) { pos(old2); t0 = TYPES.get(tname); break; } + tname = tsname; + } + + // Still no type found? Assume forward reference + Type t1 = t0 == null ? TypeMemPtr.make(TypeStruct.open(tname)) :t0; // Null: assume a forward ref type + // Nest arrays and '?' as needed + Type t2 = t1; + while( true ) { + if( match("?") ) { + if( !(t2 instanceof TypeMemPtr tmp) ) + throw error("Type "+t0+" cannot be null"); + if( tmp.nullable() ) throw error("Type "+t2+" already allows null"); + t2 = tmp.makeNullable(); + } else if( match("[~]") ) { + t2 = typeAry(t2,true); + } else if( match("[]") ) { + t2 = typeAry(t2,false); + } else + break; + } + + // Check no forward ref + if( t0 != null ) return t2; + // Check valid forward ref, after parsing all the type extra bits. + // Cannot check earlier, because cannot find required 'id' until after "[]?" syntax + int old2 = pos(); + match("!"); + String id = _lexer.matchId(); + if( !(peek(',') || peek(';') || match("->")) || id==null ) + return posT(old1); // Reset lexer to reparse + pos(old2); // Reset lexer to reparse + // Yes a forward ref, so declare it + TYPES.put(tname,t1); + // Return the (array, final) type + return t2; + } + + // Make an array type of t + private TypeMemPtr typeAry( Type t, boolean efinal ) { + if( t instanceof TypeMemPtr tmp && tmp.notNull() ) + throw error("Arrays of reference types must always be nullable"); + String tname = "[]"+t.str(); + TypeMemPtr ta = (TypeMemPtr)TYPES.get(tname); + if( ta==null ) + // Remember final version + TYPES.put(tname, ta = TypeMemPtr.make( TypeStruct.makeAry(tname,TypeInteger.U32,_code.getALIAS(),t,_code.getALIAS(),true) )); + Field elem = ta._obj.field("[]"); + if( elem._final == efinal ) + return ta; + return TypeMemPtr.make( ta._obj.replace(elem.makeFrom(efinal))); + } + + // A function type is `{ type... -> type }` or `{ type }`. + private Type typeFunPtr() { + int old = pos(); // Record lexer position + match("{"); // Skip already-peeked '{' + Type t0 = type(); // Either return or first arg + if( t0==null ) return posT(old); // Not a function + if( match("}") ) // No-arg function { -> type } + return TypeFunPtr.make(match("?"),false,TypeFunPtr.TEMPTY,t0); + Ary<Type> ts = new Ary<>(Type.class); + ts.push(t0); // First argument + while( true ) { + if( match("->") ) { // End of arguments, parse return + Type ret = type(); + if( ret==null || !match("}") ) + return posT(old); // Not a function + return TypeFunPtr.make(match("?"),false,ts.asAry(),ret); + } + Type t1 = type(); + if( t1==null ) return posT(old); // Not a function + ts.push(t1); + } + } + + // True if a TypeFunPtr, without advancing parser + private boolean isTypeFun() { + int old = pos(); + if( typeFunPtr()==null ) return false; + pos(old); + return true; + } + + /** + * Parse an expression of the form: + * + * <pre> + * expr : bitwise [? expr [: expr]] + * </pre> + * @return an expression {@link Node}, never {@code null} + */ + private Node parseExpression() { + Node expr = parseLogical(); + return match("?") ? parseTrinary(expr,":") : expr; + } + + /** + * Parse an bitwise expression + * + * <pre> + * bitwise : compareExpr (('&' | '|' | '^') compareExpr)* + * </pre> + * @return a bitwise expression {@link Node}, never {@code null} + */ + + private Node parseLogical() { + Node lhs = parseBitwise(); + while (true) { + if( false ) ; + else if( match("&&") ) lhs = parseTrinary(lhs, "&&"); + else if( match("||") ) lhs = parseTrinary(lhs, "||"); + else break; + } + return lhs; + } + + private Node parseBitwise() { + Node lhs = parseComparison(); + while( true ) { + if( false ) ; + else if( matchOp('&') ) lhs = new AndNode(loc(),lhs,null); + else if( matchOp('|') ) lhs = new OrNode(loc(),lhs,null); + else if( match ("^") ) lhs = new XorNode(loc(),lhs,null); + else break; + lhs.setDef(2,parseComparison()); + lhs = peep(lhs); + } + return lhs; + } + + /** + * Parse an expression of the form: + * + * <pre> + * expr : additiveExpr op additiveExpr + * </pre> + * @return an comparator expression {@link Node}, never {@code null} + */ + private Node parseComparison() { + var lhs = parseShift(); + Node bound_var = null; + boolean found_bl = false; + + while( true ) { + int idx=0; boolean negate=false; + // Test for any local nodes made, and "keep" lhs during peepholes + // chain operators + if( false ) ; + else if( match("==") ) { + if(found_bl) { + return make_and_conditional(lhs, new BoolNode.EQ(null, null), false, bound_var); + } + idx=2; lhs = new BoolNode.EQ(lhs, null); + } + else if( match("!=") ) { + if(found_bl) { + return make_and_conditional(lhs, peep(new NotNode(new BoolNode.EQ(null, null))), false, bound_var); + } + idx=2; lhs = new BoolNode.EQ(lhs, null); negate=true; + } + else if( match("<=") ) { + if(found_bl) { + return make_and_conditional(lhs, new BoolNode.LE(null, null), false, bound_var); + } + idx=2; lhs = new BoolNode.LE(lhs, null); + } + else if( match("<" ) ) { + if(found_bl) { + return make_and_conditional(lhs, new BoolNode.LT(null, null), false, bound_var); + } + idx=2; lhs = new BoolNode.LT(lhs, null); + } + else if( match(">=") ) { + if(found_bl) { + return make_and_conditional(lhs, new BoolNode.LE(null, null), true, bound_var); + } + idx=1; lhs = new BoolNode.LE(null, lhs); + } + else if( match(">" ) ) { + if(found_bl) { + return make_and_conditional(lhs, new BoolNode.LT(null, null), true, bound_var); + } + idx=1; lhs = new BoolNode.LT(null, lhs); + } + else break; + // Peepholes can fire, but lhs is already "hooked", kept alive + lhs.setDef(idx,parseShift()); + found_bl = true; + bound_var = lhs.in(idx); + lhs = peep(lhs.widen()); + if( negate ) // Extra negate for != + lhs = peep(new NotNode(lhs)); + } + found_bl = false; + return lhs; + } + + /** + * Parse an additive expression + * + * <pre> + * shiftExpr : additiveExpr (('<<' | '>>' | '>>>') additiveExpr)* + * </pre> + * @return a shift expression {@link Node}, never {@code null} + */ + private Node parseShift() { + Node lhs = parseAddition(); + while( true ) { + if( false ) ; + else if( match("<<") ) lhs = new ShlNode(loc(),lhs,null); + else if( match(">>>")) lhs = new ShrNode(loc(),lhs,null); + else if( match(">>") ) lhs = new SarNode(loc(),lhs,null); + else break; + lhs.setDef(2,parseAddition()); + ParseException err; + if( (err=lhs.err()) != null ) + throw err; + lhs = peep(lhs.widen()); + } + return lhs; + } + + /** + * Parse an additive expression + * + * <pre> + * additiveExpr : multiplicativeExpr (('+' | '-') multiplicativeExpr)* + * </pre> + * @return an add expression {@link Node}, never {@code null} + */ + private Node parseAddition() { + Node lhs = parseMultiplication(); + while( true ) { + if( false ) ; + else if( match("+") ) lhs = new AddNode(lhs,null); + else if( match("-") ) lhs = new SubNode(lhs,null); + else break; + lhs.setDef(2,parseMultiplication()); + lhs = peep(lhs.widen()); + } + return lhs; + } + + /** + * Parse an multiplicativeExpr expression + * + * <pre> + * multiplicativeExpr : unaryExpr (('*' | '/') unaryExpr)* + * </pre> + * @return a multiply expression {@link Node}, never {@code null} + */ + private Node parseMultiplication() { + var lhs = parseUnary(); + while( true ) { + if( false ) ; + else if( match("*") ) lhs = new MulNode(lhs,null); + else if( match("/") ) lhs = new DivNode(lhs,null); + else break; + lhs.setDef(2,parseUnary()); + lhs = peep(lhs.widen()); + } + return lhs; + } + + /** + * Parse a unary minus expression. + * + * <pre> + * unaryExpr : ('-') unaryExpr | '!') unaryExpr | postfixExpr | primaryExpr | '--' Id | '++' Id + * </pre> + * @return a unary expression {@link Node}, never {@code null} + */ + private Node parseUnary() { + // Pre-dec/pre-inc + int old = pos(); + if( match("--") || match("++") ) { + int delta = _lexer.peek(-1)=='+' ? 1 : -1; // Pre vs post + String name = _lexer.matchId(); + if( name!=null ) { + Var n = _scope.lookup(name); + if( n != null && !(n.type() instanceof TypeMemPtr) ) { + if( n._final ) + throw error("Cannot reassign final '"+n._name+"'"); + Node expr = n.type() instanceof TypeFloat + ? peep(new AddFNode(_scope.in(n),con(TypeFloat.constant(delta)))) + : zsMask(peep(new AddNode(_scope.in(n),con(delta))),n.type()); + _scope.update(n,expr); + return expr; + } + } + // Reset, try again + pos(old); + } + if (match("-")) return peep(new MinusNode(parseUnary()).widen()); + if (match("!")) return peep(new NotNode(parseUnary())); + // Else be a primary expression + return parsePrimary(); + } + + /** + * Parse a primary expression: + * + * <pre> + * primaryExpr : integerLiteral | "string" | 'char' | true | false | null | + * new Type | '(' expression ')' | Id['++','--'] | + * [static.]* Id + * </pre> + * @return a primary {@link Node}, never {@code null} + */ + private Node parsePrimary() { + if( _lexer.isNumber(_lexer.peek()) ) return parseLiteral(); + if( _lexer.peek('"') ) return newString(parseString()); + if( matchx("true" ) ) return con(1); + if( matchx("false") ) return ZERO; + if( matchx("null" ) ) return NIL; + if( match ("'" ) ) return parseChar(); + if( match ("(" ) ) return parsePostfix(require(parseAsgn(), ")")); + if( matchx("new" ) ) return parsePostfix(alloc()); + if( match ("{" ) ) return parsePostfix(require(func(),"}")); + + // Parse static variable lookup: `type.fld` in the type namespace + // CNC: not a full type parse, just a typename parse + int pos = pos(); + Type t = type(); + if( t!=null ) { + if( peek('.') ) + return parsePostfix(con(t)); + //pos(pos); // TODO: not a `type.fld` + //return null; + throw Utils.TODO(); + } + + // Expect an identifier now + + // - if null, make fref, normal var handling + // - if final constant, normal var handling + // - if method var, scan skipping blocks & methods, must hit correct struct no fcns + // - if normal var, scan skipping blocks, allowing last fcn + // - NO fcns nested in methods, NO methods nested in fcns + + String id = _lexer.matchId(); + if( id == null || KEYWORDS.contains(id) ) + throw errorSyntax("an identifier or expression"); + Var var = _scope.lookup(id); + + if( var==null ) { + // If missing, assume a forward reference + _scope.define(id, FRefNode.FREF_TYPE, true, XCTRL, loc()); + var = _scope.lookup(id); + } + + // If a method var, allow nested blocks and methods, but not fcns or other structs. + // Else safety check for accessing fields out of function scope. + if( instance(var) ) { + Node self = _scope.in(_scope.lookup("self")); // Insert self reference + return parsePostfixName(self,id); + } + + // Load local value + Node rvalue = _scope.in(var); + if( rvalue._type == Type.BOTTOM ) + if( rvalue instanceof FRefNode ) + return parsePostfix(rvalue); + else throw error("Cannot read uninitialized field '"+id+"'"); + + // Check for assign-update, x += e0; + char ch = _lexer.matchOperAssign(); + if( ch==0 ) // Normal primary, check for postfix updates + return parsePostfix(rvalue); + // Assign-update direct into Scope + Node op = opAssign(ch,rvalue, var.type() ); + _scope.update(var,op); + return postfix(ch) ? rvalue.unkeep() : op; + } + + // true if instance variable lookup (var is in any number of nested blocks, + // then an instance function then inside a struct declaration). + private boolean instance(Var var ) { + // If a method var, allow nested blocks and methods, but not fcns or other structs + Kind kind = _scope.kind(var); + if( kind instanceof Kind.Define ) { + for( int i = _scope.depth()-1; i>=0 && var._idx < _scope._kinds.at(i)._lexSize; i-- ) { + Kind xkind = _scope._kinds.at(i); + if( xkind instanceof Kind.Block ) continue; + if( xkind instanceof Kind.Func ) { + if( _scope._kinds.at(i-1)==kind ) + return true; // Instance variable: lookup in a method in a decl + } + throw Utils.TODO(); + } + } else { + // If a normal var, allow any nested blocks, and a last fcn - + // but not functions further out (which involves capture). + Node def = _scope.in(var._idx); + for( int i = _scope.depth()-1; i>=0 && var._idx < _scope._kinds.at(i)._lexSize; i-- ) + if( _scope._kinds.at(i) instanceof Kind.Func && + !(def instanceof FRefNode) && !(var._final && def._type.isConstant()) ) + throw error("Variable '"+var._name+"' is out of function scope and must be a final constant"); + } + return false; + } + + // Check for assign-update, "x += e0". + // Returns "x + e0"; the caller assigns value. + // if ch is postfix, then lhs is kept and caller will unkeep and return it. + private Node opAssign( char ch, Node lhs, Type t ) { + // RHS of the update. + lhs.keep(); // Alive across parseAsgn + Node rhs = + (byte)ch == 1 ? con( 1) : // var++ + (byte)ch == -1 ? con(-1) : // var-- + parseAsgn(); // var op= rhs + if( !postfix(ch) ) lhs.unkeep(); // Allow to die in next peep + // 4 cases: + // int + int ==>> narrow int + // int + flt ==>> error, caller must fail assigning flt into int + // flt + int ==>> use float op, wrap toFloat() + // flt + flt ==>> use float op + Node op = switch(ch) { + case 1, (char)-1, + '+' -> new AddNode(lhs,rhs); + case '-' -> new SubNode(lhs,rhs); + case '*' -> new MulNode(lhs,rhs); + case '/' -> new DivNode(lhs,rhs); + default -> throw Utils.TODO(); + }; + // Convert to float ops, or narrow int types; error if not declared type. + // Also, if postfix LHS is still keep() + return liftExpr(peep(op.widen()),t,false,true); + } + + + /** + Parse an allocation + */ + private Node alloc() { + Type t = type(); + if( t==null ) throw error("Expected a type"); + // Parse ary[ length_expr ] + if( match("[") ) { + if( !t.makeZero().isa(t) ) + throw error("Cannot allocate a non-nullable, since arrays always zero/null fill"); + Node len = parseAsgn(); + if( !(len._type instanceof TypeInteger) ) + throw error("Cannot allocate an array with length "+len._type); + require("]"); + TypeMemPtr tmp = typeAry(t,false); + return newArray(tmp._obj,len); + } + + if( !(t instanceof TypeMemPtr tmp) ) + throw error("Cannot allocate a "+t.str()); + + // Parse new struct { default_initialization } + StructNode s = INITS.get(tmp._obj._name); + if( s==null ) throw error("Unknown struct type '" + tmp._obj._name + "'"); + + Field[] fs = s._ts._fields; + // if the object is fully initialized, we can skip a block here. + // Check for constructor block: + boolean hasConstructor = match("{"); + Ary<Node> init=s._inputs; int idx=0; + if( hasConstructor ) { + idx = _scope.nIns(); + // Push a scope, and pre-assign all struct fields. + _scope.push(new Kind.Block()); + Lexer loc = loc(); + for( int i=0; i<fs.length; i++ ) + // An initial TOP means the field needs to be initialized. We + // store a BOT initially; any partial init will fall to BOT + // (merge BOT and the partial) and be obviously only a partial + // init. To be initialized the field needs a full clobber. + _scope.define(fs[i]._fname, fs[i]._t, fs[i]._final, s.in(i)._type==Type.TOP ? con(Type.BOTTOM) : s.in(i), loc); + // Parse the constructor body + require(parseBlock(new Kind.Alloc(tmp)),"}"); + init = _scope._inputs; + } + // Check that all fields are initialized + for( int i=idx; i<init.size(); i++ ) + if( init.at(i)._type == Type.TOP || init.at(i)._type == Type.BOTTOM ) + throw error("'"+tmp._obj._name+"' is not fully initialized, field '" + fs[i-idx]._fname + "' needs to be set in a constructor"); + Node ptr = newStruct(tmp._obj, off(tmp._obj, " len"), idx, init ); + if( hasConstructor ) + _scope.pop(); + return ptr; + } + + + /** + * Return a NewNode initialized memory. + * @param obj is the declared type, with GLB fields + * @param init is a collection of initialized fields + */ + private Node newStruct( TypeStruct obj, Node size, int idx, Ary<Node> init ) { + Field[] fs = obj._fields; + if( fs==null ) + throw error("Unknown struct type '" + obj._name + "'"); + int len = fs.length; + Node[] ns = new Node[2+len]; + ns[0] = ctrl(); // Control in slot 0 + // Total allocated length in bytes + ns[1] = size; + // Memory aliases for every field + for( int i = 0; i < len; i++ ) + if( !fs[i]._one ) + ns[2+i] = memAlias(fs[i]._alias); + Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole().keep(); + for( int i = 0; i < len; i++ ) + if( !fs[i]._one ) + memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole()); + Node ptr = new ProjNode(nnn.unkeep(),1,obj._name).peephole().keep(); + + // Initial nonzero values for every field + for( int i = 0; i < len; i++ ) { + Node val = init.get( i + idx ); + if( !fs[i]._one && val._type != val._type.makeZero() ) { + Node mem = memAlias(fs[i]._alias); + Node st = new StoreNode(loc(),fs[i]._fname,fs[i]._alias,fs[i]._t,mem,ptr,off(obj,fs[i]._fname),val,true).peephole(); + memAlias(fs[i]._alias,st); + } + } + + return ptr.unkeep(); + } + + private static final Ary<Node> ALTMP = new Ary<>(Node.class); + private Node newArray(TypeStruct ary, Node len) { + ConFldOffNode base = off(ary, "[]"); + int scale= ary.aryScale(); + Node size = peep(new AddNode(base,peep(new ShlNode(null,len.keep(),con(scale))))); + ALTMP.clear(); ALTMP.add(len.unkeep()); ALTMP.add(con(ary._fields[1]._t.makeZero())); + return newStruct(ary,size,0,ALTMP); + } + private Node newString(String s) { + TypeMemPtr tmp = typeAry(TypeInteger.U8,true); + int lenAlias = tmp._obj.field("#" )._alias; + int elemAlias = tmp._obj.field("[]")._alias; + TypeConAryB con = TypeConAryB.make(s); + Type elem = con.elem(); + // Make a TMP, not-null (byte)2, singleton (true) (requires text + // strings are hash-interned), with a TypeStruct having a constant + // array body. + TypeMemPtr str = TypeMemPtr.make((byte)2,TypeStruct.makeAry("[]u8", TypeInteger.constant(s.length()), lenAlias, con, elemAlias, true),true); + assert str.isConstant(); + return con(str); + } + + // We set up memory aliases by inserting special vars in the scope these + // variables are prefixed by $ so they cannot be referenced in Simple code. + // Using vars has the benefit that all the existing machinery of scoping + // and phis work as expected + private Node memAlias(int alias ) { return _scope.mem(alias ); } + private void memAlias(int alias, Node st) { _scope.mem(alias, st); } + public static String memName(int alias) { return ("$"+alias).intern(); } + + /** + * Parse postfix expression; this can be a field expression, an array + * lookup or a postfix operator like '#' + * + * <pre> + * expr ('.' FIELD)* [ = expr ] // Field reference + * expr '#' // Postfix unary read operator + * expr ['++' | '--' ] // Postfix unary write operator + * expr ('[' expr ']')* = [ = expr ] // Array reference + * expr '(' [args,]* ')' // Function call + * </pre> + */ + private Node parsePostfix(Node expr) { + String name; + if( match(".") ) name = requireId(); + else if( match("#") ) name = "#"; + else if( match("[") ) name = "[]"; + else if( match("(") ) return parsePostfix(require(functionCall(expr,null),")")); + else return expr; // No postfix + + return parsePostfixName(expr,name); + } + + /** + * Parse postfix expression; this can be a field expression, an array + * lookup or a postfix operator like '#' + * + * <pre> + * expr ['++' | '--' ] // Postfix unary write operator + * expr [ [op]= expr ] // Field reference + * expr ('[' expr ']')* [ [op]= expr ] // Array reference + * </pre> + */ + private Node parsePostfixName(Node expr, String name) { + + if( expr._type==Type.NIL ) + throw error("Accessing unknown field '" + name + "' from 'null'"); + + // Sanity check expr for being a reference + if( !(expr._type instanceof TypeMemPtr ptr) ) + throw error( "Expected "+(name=="#" || name=="[]" ? "array" : "reference")+" but found " + expr._type.str() ); + + // Find the field from the Type. Lookup in the base object field names. + TypeMemPtr ptr2 = (TypeMemPtr)TYPES.get(ptr._obj._name); + ptr = (TypeMemPtr)ptr.join(ptr2);// Upgrade to latest TYPES + TypeStruct base = ptr._obj; + int fidx = base.find(name); + if( fidx == -1 ) + throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'"); + + // Get field type and layout offset from base type and field index fidx + Field f = base._fields[fidx]; // Field from field index + Type tf = f._t; + if( tf instanceof TypeMemPtr ftmp && ftmp.isFRef() ) + tf = ftmp.makeFrom(((TypeMemPtr)(TYPES.get(ftmp._obj._name)))._obj); + + // Field offset; fixed for structs, computed for arrays + Node off = (name.equals("[]") // If field is an array body + // Array index math + ? peep(new AddNode(off(base,"[]"),peep(new ShlNode(null,require(parseAsgn(),"]"),con(base.aryScale()))))) + // Struct field offsets are hardwired + : off(base,name)).keep(); + + // Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment + if( matchOpx('=','=') ) { + Node val = parseAsgn().keep(); + Node lift = liftExpr( val, tf, f._final, false ); + + Node st = new StoreNode(loc(), name, f._alias, tf, memAlias(f._alias), expr, off.unkeep(), lift, false); + // Arrays include control, as a proxy for a safety range check. + // Structs don't need this; they only need a NPE check which is + // done via the type system. + if( base.isAry() ) st.setDef(0,ctrl()); + memAlias(f._alias, st.peephole()); + return val.unkeep(); // "obj.a = expr" returns the expression while updating memory + } + + // Keep expr for possible store update + expr.keep(); + // Load field + Node load = f._one && INITS.containsKey( base._name ) + ? INITS.get(base._name).in(base.find(name)) + : new LoadNode(loc(),name, f._alias, tf, memAlias(f._alias), expr, off); + // Arrays include control, as a proxy for a safety range check + // Structs don't need this; they only need a NPE check which is + // done via the type system. + if( base.isAry() && !name.equals("#") ) load.setDef(0,ctrl()); + load = peep(load); + + // Check for assign-update, "ptr.fld += expr" or "ary[idx]++" + char ch = _lexer.matchOperAssign(); + if( ch!=0 ) { + Node op = opAssign(ch,load, tf ); + Node st = new StoreNode(loc(), name, f._alias, tf, memAlias(f._alias), expr.unkeep(), off.unkeep(), op, false); + // Arrays include control, as a proxy for a safety range check. + // Structs don't need this; they only need a NPE check which is + // done via the type system. + if( base.isAry() ) st.setDef(0,ctrl()); + memAlias(f._alias, peep(st)); + load = postfix(ch) ? load.unkeep() : op; + // And use the original loaded value as the result + return load; + //throw Utils.TODO(); // NO POSTFIX AFTER STORE, JUST RETURN + } else { + off.unkill(); + // Method call: Loaded a function from a named field, AND the base + // field type is final. + if( load._type instanceof TypeFunPtr && name!="[]" && + !(load instanceof ExternNode) && + ((TypeMemPtr)TYPES.get(base._name))._obj.field(name)._final && + // And calling a function + match("(") ) { + return parsePostfix(require(functionCall(load,expr),")")); + } + + // Drop expr, keeping load alive + load.keep(); + expr.unkill(); + load.unkeep(); + } + + return parsePostfix(load); + } + + + // zero/sign extend. "i" is limited to either classic unsigned (min==0) or + // classic signed (min=minus-power-of-2); max=power-of-2-minus-1. + private Node zsMask(Node val, Type t ) { + if( !(val._type instanceof TypeInteger tval && t instanceof TypeInteger t0 && !tval.isa(t0)) ) { + if( !(val._type instanceof TypeFloat tval && t instanceof TypeFloat t0 && !tval.isa(t0)) ) + return val; + // Float rounding + return peep(new RoundF32Node(val)); + } + if( t0._min==0 ) // Unsigned + return peep(new AndNode(null,val,con(t0._max))); + // Signed extension + int shift = Long.numberOfLeadingZeros(t0._max)-1; + Node shf = con(shift); + if( shf._type==TypeInteger.ZERO ) + return val; + return peep(new SarNode(null,peep(new ShlNode(null,val,shf.keep())),shf.unkeep())); + } + + /** + * Parse a function body; the caller will parse the surrounding "{}" + * + * <pre> + * { [type arg,]* -> expr } + * { expr } // The no-argument function + * </pre> + */ + private Node func() { + Ary<Type> ts = new Ary<>(Type.class); + Ary<String> ids = new Ary<>(String.class); + + // Defined in constructor? Add `self` argument. "static" calls still + // add a `self` they just ignore it. + if( _scope._kinds.last() instanceof Kind.Define define ) { + // Upgrade defined struct to latest fields + TypeMemPtr tmp = (TypeMemPtr)TYPES.get(define._tmp._obj._name); + ts .push(tmp); + ids.push("self"); + } + + // Parse other arguments + _lexer.skipWhiteSpace(); + Lexer loc = loc(); // First argument location + while( true ) { + Type t = type(); // Arg type + if( t==null ) break; + String id = requireId(); + ts .push(t ); // Push type/arg pairs + ids.push(id); + match(","); + } + require("->"); + // Make a concrete function type, with a fidx + TypeFunPtr tfp = _code.makeFun(TypeFunPtr.make(false,false,ts.asAry(),Type.BOTTOM)); + ReturnNode ret = parseFunctionBody(tfp,loc,ids.asAry()); + return con(ret._fun.sig()); + } + + /** + * Parse function call arguments; caller will parse the surrounding "()" + * <pre> + * ( arg* ) + * </pre> + */ + private Node functionCall(Node fcn, Node self) { + if( fcn._type == Type.NIL ) + throw error("Calling a null function pointer"); + if( !(fcn instanceof FRefNode) && !fcn._type.isa(TypeFunPtr.BOT) ) + throw error("Expected a function but got "+fcn._type.glb(false).str()); + fcn.keep(); // Keep while parsing args + + Ary<Node> args = new Ary<>( Node.class ); + args.push(null); // Space for ctrl,mem + args.push(null); + if( self != null ) // Method call has a self + args.push(self); + while( !peek(')') ) { + Node arg = parseAsgn(); + if( arg==null ) break; + args.push(arg.keep()); + if( !match(",") ) break; + } + // Control & memory after parsing args + args.set(0,ctrl().keep()); + args.set(1,_scope.mem().merge().keep()); + args.push(fcn); // Function pointer + // Unkeep them all + for( Node arg : args ) + arg.unkeep(); + // Dead into the call? Skip all the node gen + if( ctrl()._type == Type.XCONTROL ) { + for( Node arg : args ) + if( arg.isUnused() ) + arg.kill(); + return con(Type.TOP); + } + + // Into the call + CallNode call = (CallNode)new CallNode(loc(), args.asAry()).peephole(); + + // Post-call setup + CallEndNode cend = (CallEndNode)new CallEndNode(call).peephole(); + call.peephole(); // Rerun peeps after CallEnd, allows early inlining + // Control from CallEnd + ctrl(new CProjNode(cend,0,ScopeNode.CTRL).peephole()); + // Memory from CallEnd + MemMergeNode mem = new MemMergeNode(true); + mem.addDef(null); // Alias#0 + mem.addDef(new ProjNode(cend,1,ScopeNode.MEM0).peephole()); + _scope.mem(mem); + // Call result + return new ProjNode(cend,2,"#2").peephole(); + } + + // Just after parsing "type foo = " can parse `"C"` + private boolean isExternDecl( ) { + int old = pos(); + String s = parseString(); + if( "C".equals(s) ) return true; + pos(old); + return false; + } + // External linked constant + private Node externDecl( String ex, Type t ) { + if( t instanceof TypeFunPtr tfp ) // Generic TFP from type parse + t = _code.makeFun(tfp); // Get a FIDX, becomes a constant + return new ExternNode(t,ex).peephole(); + } + + /** + * Parse integer literal + * + * <pre> + * integerLiteral: [1-9][0-9]* | [0] + * floatLiteral: [digits].[digits]?[e [digits]]? + * </pre> + */ + private ConstantNode parseLiteral() { return con(_lexer.parseNumber()); } + public static Node con( long con ) { return con==0 ? ZERO : con(TypeInteger.constant(con)); } + public static ConstantNode con( Type t ) { return (ConstantNode)new ConstantNode(t).peephole(); } + public static ConFldOffNode off( TypeStruct base, String fname ) { return (ConFldOffNode)(new ConFldOffNode(base._name,fname).peephole()); } + public Node peep( Node n ) { + // Peephole, then improve with lexically scoped guards + return _scope.upcastGuard(n.peephole()); + } + + // Parse a string or null + private String parseString() { + if( !peek('"') ) return null; + _lexer.inc(); + int start = pos(); + while( !_lexer.isEOF() && _lexer.nextChar()!= '"' ) ; + if( _lexer.isEOF() ) + throw error("Unclosed string"); + return new String(_lexer._input,start,pos()-start-1); + } + + // Already parsed "'" + private Node parseChar() { + return require(con(TypeInteger.constant(_lexer.nextChar())),"'"); + } + + ////////////////////////////////// + // Utilities for lexical analysis + + // Return true and skip if "syntax" is next in the stream. + private boolean match (String syntax) { return _lexer.match (syntax); } + // Match must be "exact", not be followed by more id letters + private boolean matchx(String syntax) { return _lexer.matchx(syntax); } + private boolean matchOp(char c0 ) { return _lexer.matchOp(c0); } + private boolean matchOpx(char c0, char c1) { return _lexer.matchOpx(c0,c1); } + // Return true and do NOT skip if 'ch' is next + private boolean peek(char ch) { return _lexer.peek(ch); } + private boolean peekIsId() { return _lexer.peekIsId(); } + + // ch is +/- 1, means oper++ or oper-- means postfix + private static boolean postfix(char ch) { + return (byte)ch== 1 || (byte)ch== -1; + } + + public int pos() { return _lexer._position; } + private int pos(int pos) { + int old = _lexer._position; + _lexer._position = pos; + return old; + } + private Type posT(int pos) { _lexer._position = pos; return null; } + // Source code location + Lexer loc() { return new Lexer(_lexer); } + + + // Require and return an identifier + private String requireId() { + String id = _lexer.matchId(); + if (id != null && !KEYWORDS.contains(id) ) return id.intern(); + throw error("Expected an identifier, found '"+id+"'"); + } + + private String matchId() { + int old = pos(); + String id = _lexer.matchId(); + if( id==null ) return null; + if( !KEYWORDS.contains(id) ) return id; + pos(old); + return null; + } + + // Require an exact match + private Parser require(String syntax) { require(null, syntax); return this; } + private <N> N require(N n, String syntax) { + if (match(syntax)) return n; + throw errorSyntax(syntax); + } + + //////////////////////////////////// + // Lexer components + + // Lexer provides low level access to the raw file bytes, peeks and matches + // short strings, parses numbers, skips comments and whitespace, tracks + // line numbers, allows the parse position to be saved and restored, and + // serves as a location indicator for errors. + + public static class Lexer { + + // Input buffer; an array of text bytes read from a file or a string + private final byte[] _input; + // Tracks current position in input buffer + private int _position = 0; + + // + private int _line_number = 1; + // Start of current line + private int _line_start = 0; + + /** + * Record the source text for lexing + */ + public Lexer(String source) { + this(source.getBytes()); + } + + /** + * Direct from disk file source + */ + public Lexer(byte[] buf) { + _input = buf; + } + + /** + * Copy a lexer from a lexer + */ + private Lexer(Lexer l) { + _input = l._input; + _position = l._position; + _line_number = l._line_number; + _line_start = l._line_start; + } + + // Very handy in the debugger, shows the unparsed program + @Override + public String toString() { + return new String(_input, _position, _input.length - _position); + } + + // True if at EOF + private boolean isEOF() { + return _position >= _input.length; + } + + // Peek next character, or report EOF + private char peek() { + return isEOF() ? Character.MAX_VALUE // Special value that causes parsing to terminate + : (char) _input[_position]; + } + // Just crash if misused + public byte peek(int off) { return _input[_position+off]; } + + private void inc() { + if( _position++ < _input.length && _input[_position-1] == '\n' ) { + _line_number++; + _line_start = _position; + } + } + // Does not honor LF, so caller must roll back position on a LF + private char nextChar() { + char ch = peek(); + inc(); + return ch; + } + + // True if a white space + private boolean isWhiteSpace() { + return peek() <= ' '; // Includes all the use space, tab, newline, CR + } + + /** + * Return the next non-white-space character + */ + private void skipWhiteSpace() { + while( true ) { + if( isWhiteSpace() ) inc(); + // Skip // to end of line + else if( _position+2 < _input.length && + _input[_position ] == '/' && + _input[_position+1] == '/') { + inc(); inc(); + while( !isEOF() && _input[_position] != '\n' ) + inc(); + } else if( _position+2 < _input.length && + _input[_position ] == '/' && + _input[_position+1] == '*') { + // Skip /*comment*/ + while( !isEOF() && !(_input[_position-1] == '*' && _input[_position] == '/')) + inc(); + inc(); + } else break; + } + } + + // Next non-white-space character, or EOF + public char nextXChar() { skipWhiteSpace(); return nextChar(); } + + // Return true, if we find "syntax" after skipping white space; also + // then advance the cursor past syntax. + // Return false otherwise, and do not advance the cursor. + boolean match(String syntax) { + assert syntax.indexOf('\n')==-1; // No newlines in match + skipWhiteSpace(); + int len = syntax.length(); + if (_position + len > _input.length) return false; + for (int i = 0; i < len; i++) + if ((char) _input[_position + i] != syntax.charAt(i)) + return false; + _position += len; + return true; + } + + // Match must be exact and not followed by more ID characters. + // Prevents identifier "ifxy" from matching an "if" statement. + boolean matchx(String syntax) { + if( !match(syntax) ) return false; + if( !isIdLetter(peek()) ) return true; + _position -= syntax.length(); + return false; + } + // Match this char, and the next char must be different. + // Handles '&&' vs '&' + boolean matchOp( char c0 ) { + skipWhiteSpace(); + if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c0 ) + return false; + inc(); + return true; + } + // Match these two characters in a row + boolean matchOpx(char c0, char c1) { + skipWhiteSpace(); + if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c1 ) + return false; + inc(); + return true; + } + + private boolean peek(char ch) { + skipWhiteSpace(); + return peek()==ch; + } + + boolean peekIsId() { + skipWhiteSpace(); + return isIdStart(peek()); + } + + // Return an identifier or null + String matchId() { + return peekIsId() ? parseId() : null; + } + + // Used for errors + String getAnyNextToken() { + if (isEOF()) return ""; + if (isIdStart(peek())) return parseId(); + if (isNumber(peek())) return parseNumberString(); + if (isPunctuation(peek())) return parsePunctuation(); + return String.valueOf(peek()); + } + + + boolean isNumber(char ch) {return Character.isDigit(ch);} + + // Return a constant Type, either TypeInteger or TypeFloat + private Type parseNumber() { + int old = _position; + int len = isLongOrDouble(); + if( len > 0 ) { + if( len > 1 && _input[old]=='0' ) + throw error("Syntax error: integer values cannot start with '0'",this); + long i = Long.parseLong(new String(_input,old,len)); + return TypeInteger.constant(i); + } + return TypeFloat.constant(Double.parseDouble(new String(_input,old,-len))); + } + private String parseNumberString() { + int old = _position; + int len = Math.abs(isLongOrDouble()); + return new String(_input,old,len); + } + + // Return +len that ends a long + // Return -len that ends a double + private int isLongOrDouble() { + int old = _position; + char c; + while( Character.isDigit(c=nextChar()) ) ; + if( !(c=='e' || c=='.') ) + return --_position - old; + if( peek() == '-' ) nextChar(); + while( Character.isDigit(c=nextChar()) || c=='e' || c=='.' ) ; + return -(--_position - old); + } + + // First letter of an identifier + private boolean isIdStart(char ch) { + return Character.isAlphabetic(ch) || ch == '_'; + } + + // All characters of an identifier, e.g. "_x123" + private boolean isIdLetter(char ch) { + return Character.isLetterOrDigit(ch) || ch == '_'; + } + + private String parseId() { + int start = _position; + while (isIdLetter(nextChar())) ; + return new String(_input, start, --_position - start); + } + + // + private boolean isPunctuation(char ch) { + return "=;[]<>()+-/*&|^".indexOf(ch) != -1; + } + + private String parsePunctuation() { + int start = _position; + return new String(_input, start, 1); + } + + // Next oper= character, or 0. + // As a convenience, mark "++" as a char 1 and "--" as char -1 (65535) + public char matchOperAssign() { + skipWhiteSpace(); + if( _position+2 >= _input.length ) return 0; + char ch0 = (char)_input[_position]; + if( "+-/*&|^".indexOf(ch0) == -1 ) return 0; + char ch1 = (char)_input[_position+1]; + if( ch1 == '=' ) { _position += 2; return ch0; } + if( isIdLetter((char)_input[_position+2]) ) return 0; + if( ch0 == '+' && ch1 == '+' ) { _position += 2; return (char) 1; } + if( ch0 == '-' && ch1 == '-' ) { _position += 2; return (char)-1; } + return 0; + } + } + + ParseException errorSyntax(String syntax) { return _errorSyntax("expected "+syntax); } + private ParseException _errorSyntax(String msg) { + return error("Syntax error, "+msg+": " + _lexer.getAnyNextToken()); + } + ParseException error(String msg) { return error(msg,_lexer); } + public static ParseException error(String msg, Lexer loc) { return new ParseException(msg,loc); } + + public static class ParseException extends RuntimeException { + public final Lexer _loc; + // file:line:charoff err + //String msg = "src:"+_line_number+":"+(_position-_line_start)+" "+errorMessage; + ParseException( String msg, Lexer loc ) { super(msg); _loc = loc; } + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/Var.java b/chapter24/src/main/java/com/seaofnodes/simple/Var.java new file mode 100644 index 00000000..cf549cd6 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/Var.java @@ -0,0 +1,53 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.type.*; + + +/** + * The tracked fields are now complex enough to deserve a array-of-structs layout + */ +public class Var { + + public final String _name; // Declared name + // These fields are not final for forward reference late updates or + // promotions. + public int _idx; // index in containing scope + private Type _type; // Declared type + public boolean _final; // Final field + public boolean _fref; // Forward ref + public Parser.Lexer _loc; // Source location + + public Var(int idx, String name, Type type, boolean xfinal, Parser.Lexer loc ) { + this(idx,name,type,xfinal,loc,false); + } + public Var(int idx, String name, Type type, boolean xfinal, Parser.Lexer loc, boolean fref) { + _idx = idx; + _name = name; + _type = type; + _final = xfinal; + _fref = fref; + _loc = loc; + } + public Type type() { + if( !_type.isFRef() ) return _type; + // Update self to no longer use the forward ref type + Type def = Parser.TYPES.get(((TypeMemPtr)_type)._obj._name); + return (_type=_type.meet(def)); + } + + // Forward reference variables (not types) must be BOTTOM and + // distinct from inferred variables + public boolean isFRef() { return _fref; } + + public void defFRef( Type type, boolean xfinal, Parser.Lexer loc ) { + assert isFRef() && xfinal; + _type = type; + _final = true; + _fref = false; + _loc = loc; + } + + @Override public String toString() { + return _type.toString()+(_final ? " ": " !")+_name; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java new file mode 100644 index 00000000..e9b5eb2e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java @@ -0,0 +1,90 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeMem; + +abstract public class BuildLRG { + // Compute live ranges in a single forwards pass. Every def is a new live + // range except live ranges are joined at Phi. Also, gather the + // intersection of register masks in each live range. Example: "free + // always zero" register forces register zero, and calling conventions + // typically force registers. + + // Sets FAILED to the set of hard-conflicts (means no need for an IFG, + // since it will not color, just split the conflicted ranges now). Returns + // true if no hard-conflicts, although we still might not color. + public static boolean run(int round, RegAlloc alloc) { + for( Node bb : alloc._code._cfg ) + for( Node n : bb.outs() ) { + if( n instanceof PhiNode phi && !(phi._type instanceof TypeMem) ) { + // All Phi inputs end up with the same LRG. + // Pass 1: find any pre-existing LRG, to avoid make-then-Union a LRG + LRG lrg = alloc.lrg(phi); + if( lrg == null ) + for( int i=1; i<phi.nIns(); i++ ) + if( (lrg = alloc.lrg(phi.in(i))) != null ) + break; + // If none, make one. + if( lrg==null ) lrg = alloc.newLRG(n); + if( phi instanceof MachNode ) defLRG(alloc,n); + // Pass 2: everybody uses the same LRG + lrg=alloc.union(lrg,phi); + for( int i=phi instanceof ParmNode ? 2 : 1; i<n.nIns(); i++ ) + lrg=alloc.union(lrg,n.in(i)); + if( lrg._mask!=null && lrg._mask.isEmpty() ) + alloc.fail(lrg); + + } else if( n instanceof MachNode mach ) { + // Attempt to commute ops to keep live ranges compatible. + if( mach.commutes() && n.nOuts()==1 ) { + int uidx = n.out(0)._inputs.find(n); + RegMask mask1 = n.in (1) instanceof MachNode machx ? machx.outregmap() : alloc.lrg(n.in(1))._mask; + RegMask mask2 = n.in (2) instanceof MachNode machx ? machx.outregmap() : alloc.lrg(n.in(2))._mask; + RegMask masko = n.out(0) instanceof MachNode machx ? machx.regmap(uidx): alloc.lrg(n )._mask; + if( !mask1.overlap(masko) && mask2.overlap(masko) ) + n.swap12(); + } + + // Define live range + defLRG(alloc,n); + + // Now, look in the opposite direction. How are incoming + // LRGs affected by this node: For all uses, make live lrgs + for( int i=1; i<n.nIns(); i++ ) + if( n.in(i)!=null ) { + LRG lrg2 = alloc.lrg(n.in(i)); + if( lrg2 != null ) { // Anti-dep or other, no LRG + RegMask use_mask = mach.regmap(i); // use_mask is also null for anti-dep + if( use_mask!=null && !lrg2.machUse(mach,(short)i,use_mask.size1()).and(use_mask) ) + alloc.fail(lrg2); // Empty register mask, must split + } + } + + } + + // MultiNodes have projections which set registers + if( n instanceof MultiNode && !(n instanceof CFGNode) ) + for( Node proj : n.outs() ) + if( proj instanceof MachNode ) + defLRG(alloc,proj); + } + + // Collect live ranges + alloc.unify(); + + return alloc.success(); + } + + private static void defLRG( RegAlloc alloc, Node n ) { + MachNode mach = (MachNode)n; + RegMask def_mask = mach.outregmap(); + if( def_mask == null ) return; + LRG lrg = mach.twoAddress() == 0 + ? alloc.newLRG(n) // Define a new LRG for N + : alloc.lrg2(n,mach.twoAddress()); // Use the matching 2-adr input + // Record mask and mach + if( !lrg.machDef(mach,def_mask.size1()).and(def_mask) ) + alloc.fail(lrg); // Empty register mask, must split + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java new file mode 100644 index 00000000..689ceceb --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java @@ -0,0 +1,105 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; +import java.util.IdentityHashMap; + +// Coalesce copies +abstract public class Coalesce { + + public static boolean coalesce( int round, RegAlloc alloc ) { + + // Walk all the splits, looking for coalesce chances + boolean progress = false; + for( CFGNode bb : alloc._code._cfg ) { + outer: + for( int j=0; j<bb.nOuts(); j++ ) { + Node n = bb.out(j); + if( !(n instanceof SplitNode) ) continue; + LRG v1 = alloc.lrg(n); + LRG v2 = alloc.lrg(n.in(1)); + if( v1 != v2 ) { + LRG ov1 = v1, ov2 = v2; + // Get the smaller neighbor count in v1 + if( v1.nadj() > v2.nadj() ) + { v1 = v2; v2 = alloc.lrg(n); } + int v2len = v2._adj==null ? 0 : v2._adj._len; + // See that they do not conflict (coalescing would make a self-conflict) + if( v1._adj!=null && v2._adj!=null && v1._mask.overlap(v2._mask) ) { + // Walk the smaller neighbors, and add to the larger. + // Check for direct conflicts along the way. + for( LRG v3 : v1._adj ) { + if( v3==v2 ) { + // Direct conflict, skip this LRG pair + v2._adj.setLen(v2len); + continue outer; + } + // Add missing LRGs from V1 to V2 + if( v2._adj.find(v3)== -1 ) + v2._adj.push(v3); + } + } + // Most constrained mask + RegMask mask = v1._mask==v2._mask ? v1._mask : v1._mask.copy().and(v2._mask); + // Check for capacity + if( v2.nadj() >= mask.size() ) { + // Fails capacity, will not be trivial colorable + if( v2._adj!=null ) v2._adj.setLen(v2len); + continue; + } + + // Union lrgs. + progress = true; + + // Since `n` is dying, remove from the LRGS BEFORE doing + // the union; this will let the union code keep the + // matching bits from the other side, preserving some + // info for biased coloring + if( ov1. _machDef==n ) ov1. _machDef = null; + if( ov1._splitDef==n ) ov1._splitDef = null; + if( ov2. _machUse==n ) ov2. _machUse = null; + if( ov2._splitUse==n ) ov2._splitUse = null; + // Keep larger adjacency list. + Ary<LRG> larger = v2._adj; + v2._adj = null; + + // Union lrgs. Swaps again, based on small lrg + LRG vWin = v1.union(v2); + vWin._adj = larger; + LRG vLose = v1.leader() ? v2 : v1; + + // LRGs below v2len were always in v2, but maybe not in v1. + // LRGs above v2len are in v1 but were not in v2. + + // Walk v2's neighbors, replacing vLose with vWin. + if( larger != null ) + for( LRG vn : larger ) { + int idx = vn._adj.find(vLose); + if( idx != -1 ) + vn._adj.del(idx); + if( vn._adj.find(vWin) == -1 ) + vn._adj.add(vWin); + } + } else { + + // Since `n` is dying, remove from the LRGS + if( v1. _machDef==n ) v1. _machDef=null; + if( v1. _machUse==n ) v1. _machUse=null; + if( v1._splitDef==n ) v1._splitDef=null; + if( v1._splitUse==n ) v1._splitUse=null; + } + + // Remove junk split + n.removeSplit(); + j--; + } + } + + if( progress ) + alloc.unify(); + + return true; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java new file mode 100644 index 00000000..3e5d656f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java @@ -0,0 +1,526 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.IterPeeps; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.print.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import java.io.IOException; +import java.util.*; + +@SuppressWarnings("unchecked") +public class CodeGen { + public static final String PORTS = "com.seaofnodes.simple.node.cpus"; + // Last created CodeGen as a global; used all over to avoid passing about a + // "context". + public static CodeGen CODE; + + public enum Phase { + Parse, // Parse ASCII text into Sea-of-Nodes IR + Opto, // Run ideal optimizations + TypeCheck, // Last check for bad programs + LoopTree, // Build a loop tree; break infinite loops + Select, // Convert to target hardware nodes + Schedule, // Global schedule (code motion) nodes + LocalSched, // Local schedule + RegAlloc, // Register allocation + Encoding, // Encoding + Export, // Export + } + public Phase _phase; + + // --------------------------- + // Compilation source code + public final String _src; + // Compile-time known initial argument type + public final TypeInteger _arg; + + // --------------------------- + public CodeGen( String src ) { this(src, TypeInteger.BOT, 123L, true ); } + public CodeGen( String src, TypeInteger arg) { this(src, arg==null ? TypeInteger.BOT : arg, 123L, true ); } + + public CodeGen( String src, TypeInteger arg, long workListSeed, boolean reset ) { + CODE = this; + if( reset ) Type.reset(); + _main = makeFun(TypeFunPtr.MAIN); + _phase = null; + _callingConv = null; + _start = new StartNode(arg); + _stop = new StopNode(src); + _src = src; + _arg = arg; + _iter = new IterPeeps(workListSeed); + P = new Parser(this,arg); + } + + + // All passes up to Phase, except ELF + public CodeGen driver( Phase phase ) { return driver(phase,null,null); } + public CodeGen driver( Phase phase, String cpu, String callingConv ) { + if( _phase==null ) parse(); + int p1 = phase.ordinal(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Opto .ordinal() ) opto(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.TypeCheck .ordinal() ) typeCheck(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LoopTree .ordinal() ) loopTree(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Select .ordinal() && cpu != null ) instSelect(cpu,callingConv); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Schedule .ordinal() ) GCM(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LocalSched.ordinal() ) localSched(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.RegAlloc .ordinal() ) regAlloc(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Encoding .ordinal() ) encode(); + return this; + } + + // Run all the phases through final ELF emission + public CodeGen driver( String cpu, String callingConv, String obj ) throws IOException { + return driver(Phase.Encoding,cpu,callingConv).exportELF(obj); + } + + + // --------------------------- + /** + * A counter, for unique node id generation. Starting with value 1, to + * avoid bugs confusing node ID 0 with uninitialized values. + */ + public int _uid = 1; + public int UID() { return _uid; } + public int getUID() { + return _uid++; + } + + // Next available memory alias number + private int _alias = 2; // 0 is for control, 1 for memory + public int getALIAS() { return _alias++; } + + + // idepths are cached and valid until *inserting* CFG edges (deleting is + // OK). This happens with inlining, which bumps the version to bulk + // invalidate the idepth caches. + private int _iDepthVersion = 0; + public void invalidateIDepthCaches() { _iDepthVersion++; } + public boolean validIDepth(int idepth) { + if( idepth==0 ) return false; + if( _iDepthVersion==0 ) return true; + return (idepth%100)==_iDepthVersion; + } + public int iDepthAt(int idepth) { + return 100*idepth+_iDepthVersion; + } + public int iDepthFrom(int idepth) { + assert idepth==0 || validIDepth(idepth); + return idepth+100; + } + + // Popular visit bitset, declared here, so it gets reused all over + public final BitSet _visit = new BitSet(); + public BitSet visit() { assert _visit.isEmpty(); return _visit; } + + // Start and stop; end points of the generated IR + public StartNode _start; + public StopNode _stop; + + // Global Value Numbering. Hash over opcode and inputs; hits in this table + // are structurally equal. + public final HashMap<Node,Node> _gvn = new HashMap<>(); + + // + private int _fidx =0; + public TypeFunPtr makeFun( TypeFunPtr fun ) { + int fidx = _fidx++; + assert fidx<64; // TODO: need a larger FIDX space + return fun.makeFrom(fidx); + } + // Signature for MAIN + public final TypeFunPtr _main; + // Reverse from a constant function pointer to the IR function being called + public FunNode link( TypeFunPtr tfp ) { + assert tfp.isConstant(); + TypeFunPtr tfp_generic = tfp.makeFrom(Type.BOTTOM); + FunNode fun =_linker.get(tfp_generic); + if( fun!=null && fun.isDead() ) { _linker.remove(tfp_generic); fun = null; } + return fun; + } + + // Insert linker mapping from constant function signature to the function + // being called. + public void link(FunNode fun) { + _linker.put(fun.sig().makeFrom(Type.BOTTOM),fun); + } + + // "Linker" mapping from constant TypeFunPtrs to heads of function. These + // TFPs all have exact single fidxs and their return is wiped to BOTTOM (so + // the return is not part of the match). + private final HashMap<TypeFunPtr,FunNode> _linker = new HashMap<>(); + + // Parser object + public final Parser P; + + // Parse ASCII text into Sea-of-Nodes IR + public int _tParse; + public CodeGen parse() { + assert _phase == null; + _phase = Phase.Parse; + long t0 = System.currentTimeMillis(); + + P.parse(); + _tParse = (int)(System.currentTimeMillis() - t0); + JSViewer.show(); + return this; + } + + + // --------------------------- + // Iterator peepholes. + public final IterPeeps _iter; + // Stop tracking deps while assertin + public boolean _midAssert; + // Statistics on peepholes + public int _iter_cnt, _iter_nop_cnt; + // Stat gathering + public void iterCnt() { if( !_midAssert ) _iter_cnt++; } + public void iterNop() { if( !_midAssert ) _iter_nop_cnt++; } + + // Run ideal optimizations + public int _tOpto; + public CodeGen opto() { + assert _phase == Phase.Parse; + _phase = Phase.Opto; + long t0 = System.currentTimeMillis(); + + // Pessimistic peephole optimization on a worklist + _iter.iterate(this); + + // OPTIMISTIC PASS GOES HERE + + // Not really a true optimistic pass, but look for unlinked functions. + // This can be removed, which may trigger another round of pessimistic. + // This is the point where we flip from a virtual Call Graph (any call + // can call any function) to having a correct (but conservative) CG. + int progress = 0; + while( progress != _start.nOuts() ) { + progress = _start.nOuts(); + FunNode main = link(_main); + for( int i=0; i<_start.nOuts(); i++ ) { + Node use = _start.out(i); + if( use instanceof FunNode fun && + fun.nIns()==2 && fun.in(1)==_start && fun != main && + (fun._name==null || fun._name.startsWith("sys.")) ) { + add(fun).setDef(1,Parser.XCTRL); + addAll(fun._outputs); + i--; + } + } + _iter.iterate(this); + } + + // Freeze field sizes; do struct layouts; convert field offsets into + // constants. + for( int i=0; i<_start.nOuts(); i++ ) { + Node use = _start.out(i); + if( use instanceof ConFldOffNode off ) { + TypeMemPtr tmp = (TypeMemPtr) Parser.TYPES.get(off._name); + off.subsume( off.asOffset(tmp._obj) ); + i--; + } + } + _iter.iterate(this); + + // To help with testing, sort StopNode returns by NID + Arrays.sort(_stop._inputs._es,0,_stop.nIns(),(x,y) -> x._nid - y._nid ); + + _tOpto = (int)(System.currentTimeMillis() - t0); + + // TODO: + // Optimistic + // TODO: + // loop unroll, peel, RCE, etc + return this; + } + public <N extends Node> N add( N n ) { return _iter.add(n); } + public void addAll( Ary<Node> ary ) { _iter.addAll(ary); } + + + // --------------------------- + // Last check for bad programs + public int _tTypeCheck; + public CodeGen typeCheck() { + // Demand phase Opto for cleaning up dead control flow at least, + // required for the following GCM. + assert _phase.ordinal() <= Phase.Opto.ordinal(); + _phase = Phase.TypeCheck; + long t0 = System.currentTimeMillis(); + + Parser.ParseException err = _stop.walk( Node::err ); + _tTypeCheck = (int)(System.currentTimeMillis() - t0); + if( err != null ) + throw err; + return this; + } + + // --------------------------- + // Build the loop tree; break never-exit loops + public int _tLoopTree; + public CodeGen loopTree() { + assert _phase.ordinal() <= Phase.TypeCheck.ordinal(); + _phase = Phase.LoopTree; + long t0 = System.currentTimeMillis(); + // Build the loop tree, fix never-exit loops + _start.buildLoopTree(_start,_stop); + _tLoopTree = (int)(System.currentTimeMillis() - t0); + return this; + } + + // --------------------------- + // Code generation CPU target + public Machine _mach; + // Chosen calling convention (usually either Win64 or SystemV) + public String _callingConv; + // Callee save registers + public RegMask _callerSave; + + // All returns have the following inputs: + // 0 - ctrl + // 1 - memory + // 2 - varies with returning GPR,FPR + // 3 - RPC + // 4+- Caller save registers + public RegMask[] _retMasks; + // Return Program Counter + public RegMask _rpcMask; + + // Convert to target hardware nodes + public int _tInsSel; + public CodeGen instSelect( String cpu, String callingConv ) { return instSelect(cpu,callingConv,PORTS); } + public CodeGen instSelect( String cpu, String callingConv, String base ) { + assert _phase.ordinal() == Phase.LoopTree.ordinal(); + _phase = Phase.Select; + + _callingConv = callingConv; + + // Not timing the class load... + // Look for CPU in fixed named place: + // com.seaofnodes.simple.node.cpus."cpu"."cpu.class" + String clzFile = base+"."+cpu+"."+cpu; + try { _mach = ((Class<Machine>) Class.forName( clzFile )).getDeclaredConstructor(new Class[]{CodeGen.class}).newInstance(this); } + catch( Exception e ) { throw new RuntimeException(e); } + + // Build global copies of common register masks. + long callerSave = _mach.callerSave(); + long neverSave = _mach. neverSave(); + int maxReg = Math.min(64,_mach.regs().length); + assert maxReg>=64 || (-1L << maxReg & callerSave)==0; // No stack slots in callerSave + _callerSave = new RegMask(callerSave); + + // Build a Return RegMask array. All returns have the following inputs: + // 0 - ctrl + // 1 - memory + // 2 - varies with returning GPR,FPR + // 3 - RPC + // 4+- Caller save registers + _retMasks = new RegMask[(maxReg-_callerSave.size()-Long.bitCount( neverSave ))+4]; + for( int reg=0, i=4; reg<maxReg; reg++ ) + if( !_callerSave.test(reg) && ((1L<<reg)&neverSave)==0 ) + _retMasks[i++] = new RegMask(reg); + _rpcMask = new RegMask(_mach.rpc()); + _retMasks[3] = _rpcMask; + + // Convert to machine ops + long t0 = System.currentTimeMillis(); + _uid = 1; // All new machine nodes reset numbering + var map = new IdentityHashMap<Node,Node>(); + _instSelect( _stop, map ); + _stop = ( StopNode)map.get(_stop ); + StartNode start = (StartNode)map.get(_start); + _start = start==null ? new StartNode(_start) : start; + _instOuts(_stop,visit()); + _visit.clear(); + _tInsSel = (int)(System.currentTimeMillis() - t0); + return this; + } + + // Walk all ideal nodes, recursively mapping ideal to machine nodes, then + // make a machine node for "this". + private Node _instSelect( Node n, IdentityHashMap<Node,Node> map ) { + if( n==null ) return null; + Node x = map.get(n); + if( x !=null ) return x; // Been there, done that + + // If n is a MachNode already, then its part of a multi-node expansion. + // It does not need instruction selection (already selected!) + // but it does need its inputs walked. + if( n instanceof MachNode ) { + for( int i=0; i < n.nIns(); i++ ) + n._inputs.set(i, _instSelect(n.in(i),map) ); + return n; + } + + // Produce a machine node from n; map it to flag as done so stops cycles. + map.put(n, x=_mach.instSelect(n) ); + // Walk machine op and replace inputs with mapped inputs + for( int i=0; i < x.nIns(); i++ ) + x._inputs.set(i, _instSelect(x.in(i),map) ); + if( x instanceof MachNode mach ) + mach.postSelect(this); // Post selection action + + return x; + } + + // Walk all machine Nodes, and set their output edges + private void _instOuts( Node n, BitSet visit ) { + if( visit.get(n._nid) ) return; + visit.set(n._nid); + for( Node in : n._inputs ) + if( in!=null ) { + in._outputs.push(n); + _instOuts(in,visit); + } + } + + + // --------------------------- + // Control Flow Graph in Reverse Post Order. + public int _tGCM; + public Ary<CFGNode> _cfg = new Ary<>(CFGNode.class); + + // Global schedule (code motion) nodes + public CodeGen GCM() { return GCM(false); } + public CodeGen GCM( boolean show) { + assert _phase.ordinal() <= Phase.Select.ordinal(); + _phase = Phase.Schedule; + long t0 = System.currentTimeMillis(); + + GlobalCodeMotion.buildCFG(this); + _tGCM = (int)(System.currentTimeMillis() - t0); + if( show ) + System.out.println(new GraphVisualizer().generateDotOutput(_stop,null,null)); + return this; + } + + // --------------------------- + // Local (basic block) scheduler phase, a classic list scheduler + public int _tLocal; + public CodeGen localSched() { + assert _phase == Phase.Schedule; + _phase = Phase.LocalSched; + long t0 = System.currentTimeMillis(); + ListScheduler.sched(this); + _tLocal = (int)(System.currentTimeMillis() - t0); + return this; + } + + + // --------------------------- + // Register Allocation + public int _tRegAlloc; + public RegAlloc _regAlloc; + public CodeGen regAlloc() { + assert _phase == Phase.LocalSched; + _phase = Phase.RegAlloc; + long t0 = System.currentTimeMillis(); + _regAlloc = new RegAlloc(this); + _regAlloc.regAlloc(); + _tRegAlloc = (int)(System.currentTimeMillis() - t0); + return this; + } + + // Human readable register name + public String reg(Node n) { return reg(n,null); } + public String reg(Node n, FunNode fun) { + if( _phase.ordinal() >= Phase.RegAlloc.ordinal() ) { + String s = _regAlloc.reg(n,fun); + if( s!=null ) return s; + } + return "N"+ n._nid; + } + + + // --------------------------- + // Encoding + public int _tEncode; + public Encoding _encoding; // Encoding object + public void preEncode() { } // overridden by alternative ports + public CodeGen encode() { + assert _phase == Phase.RegAlloc; + _phase = Phase.Encoding; + long t0 = System.currentTimeMillis(); + _encoding = new Encoding(this); + preEncode(); + _encoding.encode(); + _tEncode = (int)(System.currentTimeMillis() - t0); + return this; + } + + // --------------------------- + // Exporting to external formats + public CodeGen exportELF(String fname) throws IOException { + assert _phase == Phase.Encoding; + _phase = Phase.Export; + if( fname == null ) new LinkMem(this).link(); // In memory patching + else new ElfFile(this).export(fname); // External ELF file + return this; + } + + // --------------------------- + public boolean _asmLittle=true; + SB asm(SB sb) { return ASMPrinter.print(sb,this); } + public String asm() { return asm(new SB()).toString(); } + + + // Testing shortcuts + public Node ctrl() { return _stop.ret().ctrl(); } + public Node expr() { return _stop.ret().expr(); } + public String print() { return _stop.print(); } + + // Debugging helper + @Override public String toString() { + return _phase.ordinal() > Phase.Schedule.ordinal() + ? IRPrinter._prettyPrint( this ) + : _stop.p(9999); + } + + // Debugging helper + public Node f(int idx) { return _stop.find(idx); } + + + String printCFG() { + if( _cfg==null ) return "no CFG"; + SB sb = new SB(); + for( CFGNode cfg : _cfg ) { + sb.fix(8,""+cfg._idepth); + IRPrinter.printLine( cfg, sb ); + } + return sb.toString(); + } + + public static void print_as_hex(Encoding enc) { + for (byte b : enc._bits.toByteArray()) { + System.out.print(String.format("%02X", b)); + } + System.out.println(); + } + + public void print_as_hex() { + for (byte b : _encoding._bits.toByteArray()) { + System.out.print(String.format("%02X", b)); + } + System.out.println(); + } + + //// Debug purposes for now +// public CodeGen printENCODING() { +// ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); +// +// for(Node bb : CodeGen.CODE._cfg) { +// for(Node n: bb.outs()) { +// if(n instanceof MachNode) { +// ((MachNode) n).encoding(E); +// } +// } +// } +// +// print_as_hex(outputStream); +// // Get the raw bytes from the output stream +// return this; +// } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/ElfExpr.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/ElfExpr.java new file mode 100644 index 00000000..9d9b8a1c --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/ElfExpr.java @@ -0,0 +1,87 @@ +package com.seaofnodes.simple.codegen; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class ElfExpr { + public static void main(String[] args) { + try (FileOutputStream fos = new FileOutputStream("hello.o")) { + ByteBuffer buffer = ByteBuffer.allocate(512); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // === ELF HEADER (64 bytes) === + buffer.put(new byte[]{ + 0x7F, 'E', 'L', 'F', // ELF Magic + 2, 1, 1, 0, // 64-bit, little-endian, version + 0, 0, 0, 0, 0, 0, 0, // ABI padding + 2, 0, // Type: Executable (ET_EXEC) + 0x3E, 0x00, // Machine: x86-64 + 1, 0, 0, 0, // ELF version + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Entry point + 0, 0, 0, 0, 0, 0, 0, 0, // Program header offset + 64, 0, 0, 0, 0, 0, 0, 0, // Section header offset + 0, 0, 0, 0, // Flags + 64, 0, // ELF header size + 0, 0, // Program header entry size + 0, 0, // Number of program header entries + 40, 0, // Section header entry size + 2, 0, // Number of section headers + 1, 0 // Section header string table index + }); + + // === .TEXT SECTION (Executable Code) === + byte[] textSection = { + // sys_write (write(1, message, 13)) + (byte) 0x48, (byte) 0xC7, (byte) 0xC0, 0x01, 0x00, 0x00, 0x00, // mov rax, 1 + (byte) 0x48, (byte) 0xC7, (byte) 0xC7, 0x01, 0x00, 0x00, 0x00, // mov rdi, 1 + (byte) 0x48, (byte) 0xBE, (byte)0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rsi, message + (byte) 0x48, (byte) 0xC7, (byte) 0xC2, 0x0D, 0x00, 0x00, 0x00, // mov rdx, 13 + (byte) 0x0F, (byte) 0x05, // syscall + + // sys_exit (exit(0)) + (byte) 0x48, (byte) 0xC7, (byte) 0xC0, 0x3C, 0x00, 0x00, 0x00, // mov rax, 60 + (byte) 0x48, (byte) 0x31, (byte) 0xFF, // xor rdi, rdi + (byte) 0x0F, (byte) 0x05 // syscall + }; + + // Append section data + buffer.position(256); + buffer.put(textSection); + + // === STRING MESSAGE (.data Section) === + byte[] message = "Hello, World!\n".getBytes(); + buffer.position(400); + buffer.put(message); + + // === SECTION HEADERS === + buffer.position(64); + + // Null Section (required as first entry) + buffer.put(new byte[40]); + + // .text Section + buffer.putInt(1); // Offset in section string table (".text") + buffer.putInt(1); // Type: SHT_PROGBITS + buffer.putLong(6); // Flags: Executable | Allocatable + buffer.putLong(0); // Virtual address + buffer.putLong(256); // Offset to section data + buffer.putLong(textSection.length); // Section size + buffer.putInt(0); // Link + buffer.putInt(0); // Info + buffer.putLong(4); // Address alignment + buffer.putLong(0); // No extra entries + + // === SECTION HEADER STRING TABLE === + buffer.position(500); + buffer.put(".text".getBytes()); + buffer.put((byte) 0x00); // Null terminator + + fos.write(buffer.array()); + System.out.println("ELF object file 'hello.o' created."); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java new file mode 100644 index 00000000..8f9e2981 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java @@ -0,0 +1,381 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.Encoding.BAOS; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.Map; + +public class ElfFile { + + final CodeGen _code; + Ary<Section> _sections = new Ary<>(Section.class); + + ElfFile( CodeGen code ) { _code = code; } + + public static int writeCString(DataSection strtab, String name) { + // place name in the string table + int pos = strtab._contents.size(); + byte[] name_bytes = name.getBytes(); + strtab._contents.write(name_bytes, 0, name_bytes.length); + // the strings are null terminated + strtab._contents.write(0); + return pos; + } + + public static void write4( ByteArrayOutputStream bits, int op ) { + bits.write(op ); + bits.write(op>> 8); + bits.write(op>>16); + bits.write(op>>24); + } + public static void write8( ByteArrayOutputStream bits, long i64 ) { + write4(bits, (int) i64 ); + write4(bits, (int)(i64>>32)); + } + + public static final int SYMBOL_SIZE = 4+1+1+2+8+8; + + public static final int SYM_BIND_LOCAL = 0; + public static final int SYM_BIND_GLOBAL = 1; + public static final int SYM_BIND_WEAK = 2; + + public static final int SYM_TYPE_NOTYPE = 0; + public static final int SYM_TYPE_OBJECT = 1; + public static final int SYM_TYPE_FUNC = 2; + public static final int SYM_TYPE_SECTION = 3; + + public static class Symbol { + String _name; + int _name_pos; + + // index in the symbol table + int _index; + + // which section is it in + int _parent; + + // depends on the symbol type + // TODO + int _value, _size; + + // top 4bits are the "bind", bottom 4 are "type" + int _info; + + // bind 1011 + // 00001111 + // 10110000 + + Symbol(String name, int parent, int bind, int type) { + _name = name; + _parent = parent; + _info = (bind << 4) | (type & 0xF); + } + + void writeHeader(ByteBuffer out) { + out.putInt(_name_pos); // name + out.put((byte) _info); // info + // default visibility + out.put((byte) 0); // other + out.putShort((short) _parent); // shndx + out.putLong(_value); // value + out.putLong(_size); // size + } + } + + public static final int SHF_WRITE = 1; + public static final int SHF_ALLOC = 2; + public static final int SHF_EXECINSTR = 4; + public static final int SHF_STRINGS = 32; + public static final int SHF_INFO_LINK = 64; + + public static final int SECTION_HDR_SIZE = 64; + abstract public static class Section { + String _name; + int _index; + + int _type, _flags; + int _link, _info; + + // where's the name in the string table + int _name_pos; + int _file_offset; + + Section(String name, int type) { + _name = name; + _type = type; + } + + void writeHeader(ByteBuffer out) { + out.putInt(_name_pos); // name + out.putInt(_type); // type + out.putLong(_flags); // flags + out.putLong(0); // addr + out.putLong(_file_offset); // offset + out.putLong(size()); // size + out.putInt(_link); // link + out.putInt(_info); // info + out.putLong(16); // addralign + if (_type == 2) { + out.putLong(SYMBOL_SIZE);// entsize + } else if (_type == 4) { + out.putLong(24); // entsize + } else { + out.putLong(0); // entsize + } + } + + abstract void write(ByteBuffer out); + abstract int size(); + } + + public static class SymbolSection extends Section { + Ary<Symbol> _symbols = new Ary<>(Symbol.class); + Ary<Symbol> _loc = new Ary<>(Symbol.class); + + SymbolSection(String name, int type) { + super(name, type); + } + + @Override + void writeHeader(ByteBuffer out) { + // points to string table section + _link = 1; + + // number of non-local symbols + _info = _loc.len() + 1; + + super.writeHeader(out); + } + + void push(Symbol s) { + if ((s._info >> 4) != SYM_BIND_LOCAL) { + _symbols.push(s); + } else { + _loc.push(s); + } + } + + @Override + void write(ByteBuffer out) { + // Index 0 both designates the first entry in the table and serves as the undefined symbol index + for( int i = 0; i < SYMBOL_SIZE/4; i++ ) { + out.putInt(0); + } + // index is already set + for( Symbol s : _loc ) { + s.writeHeader(out); + } + for( Symbol s : _symbols ) { + s.writeHeader(out); + } + } + + @Override + int size() { + return (1 + _symbols.len() + _loc.len()) * SYMBOL_SIZE; + } + } + + public static class DataSection extends Section { + ByteArrayOutputStream _contents; + + DataSection(String name, int type) { + super(name, type); + _contents = new ByteArrayOutputStream(); + } + + DataSection(String name, int type, ByteArrayOutputStream contents) { + super(name, type); + _contents = contents; + } + + @Override + void write(ByteBuffer out) { + out.put(_contents.toByteArray()); + } + + @Override + int size() { + return _contents.size(); + } + } + + private void pushSection(Section s) { + _sections.push(s); + // ELF is effectively "1-based", due to the NULL section + s._index = _sections._len; + } + + /* creates function and stores where it starts*/ + private final HashMap<TypeFunPtr,Symbol> _funcs = new HashMap<>(); + private void encodeFunctions(SymbolSection symbols, DataSection text) { + for( int i=0; i<_code._cfg._len; i++ ) { + if( !(_code._cfg.at(i) instanceof FunNode fun) ) continue; + // skip until the function ends + while( !(_code._cfg.at(i) instanceof ReturnNode ret) ) + i++; + int end = _code._encoding._opStart[ret._nid] + _code._encoding._opLen[ret._nid]; + + Symbol func = new Symbol(fun._name, text._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); + func._value = _code._encoding._opStart[fun._nid]; + func._size = end - func._value; + symbols.push(func); + _funcs.put(fun.sig(), func); + } + } + + public void export(String fname) throws IOException { + DataSection strtab = new DataSection(".strtab", 3 /* SHT_SYMTAB */); + // first byte is reserved for an empty string + strtab._contents.write(0); + pushSection(strtab); + + // place all the symbols + SymbolSection symbols = new SymbolSection(".symtab", 2 /* SHT_STRTAB */); + pushSection(symbols); + + // zero flag by default + // we've already constructed this entire section in the encoding phase + DataSection text = new DataSection(".text", 1 /* SHT_PROGBITS */, _code._encoding._bits); + text._flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR; + pushSection(text); + + // Build and write constant pool + BAOS cpool = new BAOS(); + Encoding enc = _code._encoding; + enc.writeConstantPool(cpool,false); + DataSection rdata = new DataSection(".rodata", 1 /* SHT_PROGBITS */, cpool); + rdata._flags = SHF_ALLOC; + pushSection(rdata); + + // populate function symbols + encodeFunctions(symbols, text); + + int idx = 1; + for( Section s : _sections ) { + Symbol sym = new Symbol(s._name, idx++, SYM_BIND_LOCAL, SYM_TYPE_SECTION); + // we can reuse the same name pos from the actual section + sym._name_pos = s._name_pos; + sym._size = s.size(); + symbols.push(sym); + } + + // calculate local index + int num = 1; + for( Symbol s : symbols._loc ) + s._index = num++; + // extra space for .rela.text + int start_global = num+1; // Add one to skip the final .rela.text local symbol + for( Symbol a: symbols._symbols ) + a._index = start_global++; + + // create .text relocations + DataSection text_rela = new DataSection(".rela.text", 4 /* SHT_RELA */); + for( Node n : enc._externals.keySet()) { + int nid = n._nid; + String extern = enc._externals.get(n); + + Symbol sym = new Symbol(extern, 0, SYM_BIND_GLOBAL, SYM_TYPE_NOTYPE); + sym._index = start_global++; + symbols.push(sym); + + int offset = enc._opStart[nid] + enc._opLen[nid] - 4; + + // u64 offset + write8(text_rela._contents, offset); + // u64 info + write8(text_rela._contents, ((long)sym._index << 32L) | 4L /* PLT32 */); + // i64 addend + write8(text_rela._contents, -4); + } + + // Write relocations for the constant pool + for( Encoding.Relo relo : enc._bigCons.values() ) { + Symbol glob = new Symbol("CPOOL$"+start_global, rdata._index, SYM_BIND_GLOBAL, SYM_TYPE_FUNC); + glob._value = relo._target; + glob._size = relo._t.size(); + glob._index = start_global++; + symbols.push(glob); + write8(text_rela._contents, relo._opStart+relo._off); + write8(text_rela._contents, ((long)glob._index << 32L) | relo._elf ); + write8(text_rela._contents, -4); + } + + text_rela._flags = SHF_INFO_LINK; + text_rela._link = 2; + text_rela._info = text._index; + pushSection(text_rela); + + // Final .rela.text symbol + Symbol sym = new Symbol(text_rela._name, num++, SYM_BIND_LOCAL, SYM_TYPE_SECTION); + sym._name_pos = text_rela._name_pos; + sym._size = text_rela.size(); + symbols.push(sym); + + // populate string table + for( Section s : _sections ) { s._name_pos = writeCString(strtab, s._name); } + for( Symbol s : symbols._symbols ) { s._name_pos = writeCString(strtab, s._name); } + for( Symbol s : symbols._loc ) { s._name_pos = writeCString(strtab, s._name); } + + int size = 64; // ELF header + // size of all section data + for( Section s : _sections ) { + s._file_offset = size; + size += s.size(); + } + // headers go at the very end + int shdr_offset = size; + // there's a "null" section at the start of the section headers + size += SECTION_HDR_SIZE*(1 + _sections.len()); + + // System.out.printf("Hello %d, %d, %s\n", size, shdr_offset); + ByteBuffer out = ByteBuffer.allocate(size); + out.order(ByteOrder.LITTLE_ENDIAN); + + // ELF header + out.put(new byte[]{ 0x7F, 'E', 'L', 'F', 2, 1, 1, 0 }); + out.put(new byte[8]); + out.putShort((short)1 /* ET_REL */); // type + out.putShort((short)62 /* AMD64 */); // machine + out.putInt(1); // version + out.putLong(0); // entry + out.putLong(0); // phoff + out.putLong(shdr_offset); // shoff + out.putInt(0); // flags + out.putShort((short)64); // ehsize + out.putShort((short)0); // phentsize + out.putShort((short)0); // phnum + out.putShort((short)64); // shentsize + out.putShort((short) (1 + _sections.len())); // shnum + out.putShort((short)1); // shstrndx + + // raw section data + for( Section s : _sections ) { + s.write(out); + } + + // "null" section + for( int i = 0; i < 16; i++ ) { + out.putInt(0); + } + + for( Section s : _sections ) { + s.writeHeader(out); + } + assert out.position() == size; + + File file = new File(fname); + if( file.getParentFile()!=null ) + file.getParentFile().mkdirs(); + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); + bos.write(out.array()); + bos.close(); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/Encoding.java new file mode 100644 index 00000000..e3684445 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/Encoding.java @@ -0,0 +1,535 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.print.IRPrinter; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.io.ByteArrayOutputStream; +import java.util.*; + + +/** + * Instruction encodings + * <p> + * This class holds the encoding bits, plus the relocation information needed + * to move the code to a non-zero offset, or write to an external file (ELF). + * <p> + * There are also a bunch of generic utilities for managing bits and bytes + * common in all encodings. + */ +public class Encoding { + + // Top-level program graph structure + public final CodeGen _code; + + // Instruction bytes. The registers are encoded already. Relocatable data + // is in a fixed format depending on the kind of relocation. + + // - RIP-relative offsets into the same chunk are just encoded with their + // check relative offsets; no relocation info is required. + + // - Fixed address targets in the same encoding will be correct for a zero + // base; moving the entire encoding requires adding the new base address. + + // - RIP-relative to external chunks have a zero offset; the matching + // relocation info will be used to patch the correct value. + + public static class BAOS extends ByteArrayOutputStream { + public byte[] buf() { return buf; } + void set( byte[] buf0, int count0 ) { buf=buf0; count=count0; } + }; + final public BAOS _bits = new BAOS(); + + public int [] _opStart; // Start of opcodes, by _nid + public byte[] _opLen; // Length of opcodes, by _nid + + // Function headers now padded when printing + public boolean _padFunHeads; + + // Big Constant relocation info. + public static class Relo { + public final Node _op; + public final Type _t; // Constant type + public final byte _off; // Offset from start of opcode + public final byte _elf; // ELF relocation type, e.g. 2/PC32 + public int _target; // Where constant is finally placed + public int _opStart; // Opcode start + Relo( Node op, Type t, byte off, byte elf ) { + _op=op; _t=t; _off=off; _elf=elf; + } + } + public final HashMap<Node,Relo> _bigCons = new HashMap<>(); + + Encoding( CodeGen code ) { _code = code; } + + // Shortcut to the defining register + public short reg(Node n) { + return _code._regAlloc.regnum(n); + } + + public int read1(int idx) { + byte[] buf = _bits.buf(); + return (buf[idx]&0xFF); + } + public int read2(int idx) { + byte[] buf = _bits.buf(); + return (buf[idx]&0xFF) | (buf[idx+1]&0xFF) <<8; + } + public int read4(int idx) { + byte[] buf = _bits.buf(); + return (buf[idx]&0xFF) | (buf[idx+1]&0xFF) <<8 | (buf[idx+2]&0xFF)<<16 | (buf[idx+3]&0xFF)<<24; + } + public long read8(int idx) { + return (read4(idx) & 0xFFFFFFFFL) | read4(idx+4); + } + + // This buffer is invalid/moving until after all encodings are written + public byte[] bits() { return _bits.buf(); } + + // 4 byte little-endian write + public void patch4( int idx, int val ) { + byte[] buf = _bits.buf(); + buf[idx ] = (byte)(val ); + buf[idx+1] = (byte)(val>> 8); + buf[idx+2] = (byte)(val>>16); + buf[idx+3] = (byte)(val>>24); + } + + static void padN(int n, BAOS bits) { + while( (bits.size()+n-1 & -n) > bits.size() ) + bits.write(0); + } + + // Convenience for writing log-N + static void addN( int log, Type t, BAOS bits ) { + long x = t instanceof TypeInteger ti + ? ti.value() + : log==3 + ? Double.doubleToRawLongBits( ((TypeFloat)t).value()) + : Float.floatToRawIntBits((float)((TypeFloat)t).value()); + addN(log,x,bits); + } + static void addN( int log, long x, BAOS bits ) { + for( int i=0; i < 1<<log; i++ ) { + bits.write((int)x); + x >>= 8; + } + } + + public Encoding add1( int op ) { addN(0,op,_bits); return this; } + public Encoding add2( int op ) { addN(1,op,_bits); return this; } + public Encoding add4( int op ) { addN(2,op,_bits); return this; } + public Encoding add8(long op ) { addN(3,op,_bits); return this; } + + + // Nodes need "relocation" patching; things done after code is placed. + // Record src and dst Nodes. + private final HashMap<Node,CFGNode> _internals = new HashMap<>(); + // Source is a Call, destination in the Fun. + public Encoding relo( CallNode call ) { + _internals.put(call,_code.link(call.tfp())); + return this; + } + public Encoding relo( ConstantNode con ) { + TypeFunPtr tfp = (TypeFunPtr)con._con; + _internals.put(con,_code.link(tfp)); + return this; + } + public void jump( CFGNode jmp, CFGNode dst ) { + _internals.put(jmp,dst.uctrlSkipEmpty()); + } + + + final HashMap<Node,String> _externals = new HashMap<>(); + public Encoding external( Node n, String extern ) { + _externals.put(n,extern); + return this; + } + + // Store t as a 32/64 bit constant in the code space; generate RIP-relative + // addressing to load it + public void largeConstant( Node relo, Type t, int off, int elf ) { + assert t.isConstant(); + assert (byte)off == off; + assert (byte)elf == elf; + _bigCons.put(relo,new Relo(relo,t,(byte)off,(byte)elf)); + } + + // -------------------------------------------------- + void encode() { + // Basic block layout: negate branches to keep blocks in-order; insert + // unconditional jumps. Attempt to keep backwards branches taken, + // forwards not-taken (this is the default prediction on most + // hardware). Layout is still Reverse Post Order but with more + // restrictions. + basicBlockLayout(); + + // Write encoding bits in order into a big byte array. + // Record opcode start and length. + writeEncodings(); + + // Short-form RIP-relative support: replace long encodings with short + // encodings and compact the code, changing all the offsets. + compactShortForm(); + + // Patch RIP-relative and local encodings now. + patchLocalRelocations(); + } + + // -------------------------------------------------- + // Basic block layout: negate branches to keep blocks in-order; insert + // unconditional jumps. Attempt to keep backwards branches taken, forwards + // not-taken (this is the default prediction on most hardware). Layout is + // still Reverse Post Order but with more restrictions. + private void basicBlockLayout() { + IdentityHashMap<LoopNode,Ary<CFGNode>> rpos = new IdentityHashMap<>(); + Ary<CFGNode> rpo = new Ary<>(CFGNode.class); + rpos.put(_code._start.loop(),rpo); + BitSet visit = _code.visit(); + rpo.add(_code._stop); + FunNode main = _code.link(_code._main); + for( Node n : _code._start._outputs ) + if( n instanceof FunNode fun && fun != main ) { + int x = rpo._len; + _rpo_cfg(fun, visit, rpos ); + assert rpo.at(x) instanceof ReturnNode; + } + // Do any main function last... so it lands at offset 0 in the RPO + if( main!=null ) + _rpo_cfg(main, visit, rpos ); + rpo.add(_code._start); + + // Reverse in-place + for( int i=0; i< rpo.size()>>1; i++ ) + rpo.swap(i,rpo.size()-1-i); + visit.clear(); + _code._cfg = rpo; // Save the new ordering + } + + + private void _rpo_cfg(CFGNode bb, BitSet visit, IdentityHashMap<LoopNode,Ary<CFGNode>> rpos ) { + if( bb==null || visit.get(bb._nid) ) return; + visit.set(bb._nid); + CFGNode next = bb.uctrl(); + + // Loops run an inner "rpo_cfg", then append the entire loop body in + // place. This keeps loop bodies completely contained, although if + // Some Day Later we have real profile data we ought to arrange the + // branch orderings based on frequency. + if( bb instanceof LoopNode loop ) { + Ary<CFGNode> body = new Ary<>(CFGNode.class); // Private RPO for the loop + rpos.put(loop.loop(),body); // Find it via loop tree + _rpo_cfg(next,visit,rpos); // RPO the loop + body.add(loop); // Include loop last (first in RPO) + Ary<CFGNode> outer = rpos.get(loop.cfg(1).loop()); + outer.addAll(body); // Append to original CFG + return; + } + + // IfNodes visit 2 sides, and may choose to reorder them in the RPO + if( bb instanceof IfNode iff ) { + // Pick out the T/F projections + CProjNode t = iff.cproj(0); + CProjNode f = iff.cproj(1); + // Invert the branch or not + if( shouldInvert(t,f,iff.loopDepth()) ) { + iff.negate(); + t.invert(); + f.invert(); + CProjNode tmp=f; f=t; t=tmp; // Swap t/f + } + + // Whichever side is visited first becomes last in the RPO. With + // no loops, visit the False side last (so True side first) so that + // when the False RPO visit returns, the IF is immediately next. + // When the RPO is reversed, the fall-through path will always be + // following the IF. + _rpo_cfg(t,visit,rpos); // True side first + next = f; // False side last + } + + // If the *next* BB has already been visited, and we are not already a + // jump, we may need an unconditional forwards jump here + Ary<CFGNode> rpo = rpos.get(bb.loop()); + if( next!=null && visit.get(next._nid) && !(bb instanceof IfNode) ) { + boolean needJump = next instanceof LoopNode + // Empty blocks from an IF will invert the IF and backwards + // branch to the loop head. If not empty, or not an IF + // will need a jump. + ? (bb.nOuts()>1 || !(bb.cfg0() instanceof IfNode) ) + // Forwards jump. If all the blocks, in RPO order, to our + // target are empty, we will fall in and not need a jump. + : !backwardsEmptyScan(rpo,next); + if( needJump ) { + CFGNode jmp = _code._mach.jump(); + jmp._ltree = bb._ltree; + jmp.setDefX(0,bb); + next.setDef(next._inputs.find(bb),jmp); + rpo.add(jmp); + } + } + + _rpo_cfg(next,visit,rpos); + rpo.add(bb); + } + + // Should this test be inverted? + private static boolean shouldInvert(CFGNode t, CFGNode f, int bld) { + int tld = t.loopDepth(), fld = f.loopDepth(); + // These next two are symmetric and can happen in any order; if `tld < + // bld` is true, the `fld < bld` must be false, or else both directions + // exit the loop... and the IF test would not be in the loop. + + // true to exit a loop usually (and false falls into Yet Another Loop + // Block), invert if false is taking an empty backwards branch. + if( tld < bld ) return forwardsEmptyScan(f,bld); + // false to exit a loop, normally invert to true (except empty back) + if( fld < bld ) return !forwardsEmptyScan(t,bld); + + // Not exiting the loop; staying at this depth (or going deeper loop). + + // Jump/true to an empty backwards block + if( forwardsEmptyScan(t,bld) ) return false; + if( forwardsEmptyScan(f,bld) ) return true ; + + // Fall/false into a full block, Jump/true to an empty block. + if( f.nOuts()>1 && t.nOuts()==1 ) return false; + if( t.nOuts()>1 && f.nOuts()==1 ) return true ; + // Jump to a merge point, assuming other things are jumping there as well + if( f.out(0) instanceof RegionNode ) return true ; + if( t.out(0) instanceof RegionNode ) return false; + // Everything else equal, use pre-order + return t._pre > f._pre; + } + + // Do we continue forwards from 'c' to the Loop back edge, without doing + // anything else? Then this branch can directly jump to the loop head. + private static boolean forwardsEmptyScan( CFGNode c, int bld ) { + if( c.nOuts()!=1 || c.loopDepth()!=bld ) return false; + return c.uctrl() instanceof RegionNode cfg && + ((cfg instanceof LoopNode && cfg._ltree==c._ltree) || forwardsEmptyScan(cfg,bld)); + } + + // Is the CFG from "next" to the end empty? This means jumping to "next" + // will naturally fall into the end. + private static boolean backwardsEmptyScan(Ary<CFGNode> rpo, CFGNode next) { + for( int i=rpo._len-1; rpo.at(i)!=next; i-- ) + if( rpo.at(i).nOuts()!=1 ) + return false; + return true; + } + + // -------------------------------------------------- + // Write encoding bits in order into a big byte array. + // Record opcode start and length. + public FunNode _fun; // Currently encoding function + private void writeEncodings() { + _opStart= new int [_code.UID()]; + _opLen = new byte[_code.UID()]; + for( CFGNode bb : _code._cfg ) { + if( !(bb instanceof MachNode mach0) ) + _opStart[bb._nid] = _bits.size(); + else if( bb instanceof FunNode fun ) { + _fun = fun; // Currently encoding function + _opStart[bb._nid] = _bits.size(); + mach0.encoding( this ); + _opLen[bb._nid] = (byte) (_bits.size() - _opStart[bb._nid]); + } + for( Node n : bb._outputs ) { + if( n instanceof MachNode mach && !(n instanceof FunNode) ) { + _opStart[n._nid] = _bits.size(); + mach.encoding( this ); + _opLen[n._nid] = (byte) (_bits.size() - _opStart[n._nid]); + } + } + } + } + + // -------------------------------------------------- + // Short-form RIP-relative support: replace short encodings with long + // encodings and expand the code, changing all the offsets. + private void compactShortForm() { + int len = _code._cfg._len; + int[] oldStarts = new int[len]; + for( int i=0; i<len; i++ ) + oldStarts[i] = _opStart[_code._cfg.at(i)._nid]; + + // TODO: Rewrite this algo to use the small "_jmps" list of just the + // jumps instead of walking all blocks. + // TODO2: Allow short encodings on non-jumps. This algo doesn't + // really care jumps vs other rip-relative things. + + // Check the size of short jumps, adjust the block starts for a whole + // pass over all blocks. If some jumps go long, they might stretch the + // distance for other jumps, so another pass is needed. + int slide = -1; + while( slide != 0) { // While no fails + slide = 0; + for( int i=0; i<len; i++ ) { + CFGNode bb = _code._cfg.at(i); + _opStart[bb._nid] += slide; + // Slide down all other (non-CFG) ops in the block + for( Node n : bb._outputs ) + if( n instanceof MachNode && !(n instanceof CFGNode) ) + _opStart[n._nid] += slide; + if( bb instanceof RIPRelSize riprel ) { + CFGNode target = (bb instanceof IfNode iff ? iff.cproj(0) : (CFGNode)bb.out(0)).uctrlSkipEmpty(); + // Delta is from opStart to opStart. X86 at least counts + // the delta from the opEnd, but we don't have the end until + // we decide the size - so the encSize has to deal + int delta = _opStart[target._nid] - _opStart[bb._nid]; + byte opLen = riprel.encSize(delta); + // Recorded size is smaller than the current size? + if( _opLen[bb._nid] < opLen ) { + // Start sliding the code down; record slide amount and new size + slide += opLen - _opLen[bb._nid]; + _opLen[bb._nid] = opLen; + } + } + } + } + + + // Go again, inserting padding on function headers. Since no + // short-jumps span function headers, the padding will not make any + // short jumps fail. + for( int i=0; i<len; i++ ) { + CFGNode bb = _code._cfg.at(i); + // Functions pad to align 16 + if( bb instanceof FunNode ) { + int newStart = _opStart[bb._nid]+slide; + slide += (newStart+15 & -16)-newStart; + } + _opStart[bb._nid] += slide; + for( Node n : bb._outputs ) + if( n instanceof MachNode && !(n instanceof CFGNode) ) + _opStart[n._nid] += slide; + } + _padFunHeads = true; + + // Copy/slide the bits to make space for all the longer branches + int grow = _opStart[_code._cfg.at(len-1)._nid] - oldStarts[len-1]; + if( grow > 0 ) { // If no short-form ops, nothing to do here + int end = _bits.size(); + byte[] bits = new byte[end+grow]; + for( int i=len-1; i>=0; i-- ) { + int start = oldStarts[i]; + if( start==0 && i>1 ) continue; + int oldStart = oldStarts[i]; + int newStart = _opStart[_code._cfg.at(i)._nid]; + System.arraycopy(_bits.buf(),oldStart,bits,newStart,end-start); + end = start; + } + _bits.set(bits,bits.length); + } + + } + + + // -------------------------------------------------- + // Patch local encodings now + void patchLocalRelocations() { + // Walk the local code-address relocations + for( Node src : _internals.keySet() ) { + int start = _opStart[src._nid]; + Node dst = _internals.get(src); + int target = _opStart[dst._nid]; + ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start); + } + } + + // -------------------------------------------------- + // Write the constant pool into the BAOS and optionally patch locally + void writeConstantPool( BAOS bits, boolean patch ) { + padN(16,bits); + + // radix sort the big constants by alignment + Ary<Relo>[] raligns = new Ary[5]; + for( Node op : _bigCons.keySet() ) { + Relo relo = _bigCons.get(op); + int align = relo._t.alignment(); + Ary<Relo> relos = raligns[align]==null ? (raligns[align]=new Ary<>(Relo.class)) : raligns[align]; + relos.add(relo); + } + + + // Types can be used more than once; collapse the dups + HashMap<Type,Integer> targets = new HashMap<>(); + + // By alignment + for( int align = 4; align >= 0; align-- ) { + Ary<Relo> relos = raligns[align]; + if( relos == null ) continue; + for( Relo relo : relos ) { + // Map from relo to constant start and patch + Integer target = targets.get(relo._t); + if( target==null ) { + targets.put(relo._t,target = bits.size()); + // Write constant into constant pool + switch( relo._t ) { + case TypeTuple tt -> cpool(align,bits,tt); + case TypeStruct ts -> cpool(bits,ts); + // Simple primitive (e.g. larger int, float) + default -> addN(align,relo._t,bits); + } + } + // Record target address and opcode start + relo._target = target; + relo._opStart= _opStart[relo._op._nid]; + // Go ahead and locally patch in-memory + if( patch ) + ((RIPRelSize)relo._op).patch(this, relo._opStart, _opLen[relo._op._nid], relo._target - relo._opStart); + } + } + } + + // Constant tuples put all entries at same alignment + private void cpool(int align, BAOS bits, TypeTuple tt) { + for( Type tx : tt._types ) + addN(align,tx,bits); + } + + // Structs use internal field layout + private void cpool( BAOS bits, TypeStruct ts ) { + // Field order by offset + int[] layout = ts.layout(); + int off=0; // offset in the struct + for( int fn=0; fn<ts._fields.length; fn++ ) { + Field f = ts._fields[layout[fn]]; + int foff = ts. offset(layout[fn]); + // Pad up to field + while( off < foff ) { bits.write(0); off++; }; + // Constant array fields are special + if( f._fname=="[]" ) { // Must be a constant array + ((TypeConAry)f._t).write(bits); + off += ((TypeConAry)f._t).len(); + } else { + int log = f._t.log_size(); + addN(log,f._t,bits); + off += 1<<log; + } + } + } + + + // A series of libc/external calls that Simple can link against in a JIT. + // Since no runtime in the JVM process, using magic numbers for the CPU + // emulators to pick up on. + public static int SENTINEL_CALLOC = -4; + public static int SENTINEL_WRITE = -8; + + void patchGlobalRelocations() { + for( Node src : _externals.keySet() ) { + int start = _opStart[src._nid]; + String dst = _externals.get(src); + int target = switch( dst ) { + case "calloc" -> SENTINEL_CALLOC; + case "write" -> SENTINEL_WRITE ; + default -> throw Utils.TODO(); + }; + ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start); + } + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java new file mode 100644 index 00000000..520a18a3 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java @@ -0,0 +1,322 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.IterPeeps.WorkList; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import java.util.*; + +public abstract class GlobalCodeMotion { + + // Arrange that the existing isCFG() Nodes form a valid CFG. The + // Node.use(0) is always a block tail (either IfNode or head of the + // following block). There are no unreachable infinite loops. + public static void buildCFG( CodeGen code ) { + Ary<CFGNode> rpo = new Ary<>(CFGNode.class); + _rpo_cfg(null, code._start, code.visit(), rpo); + // Reverse in-place + for( int i=0; i< rpo.size()>>1; i++ ) + rpo.swap(i,rpo.size()-1-i); + // Set global CFG + code._cfg = rpo; + + schedEarly(code); + + // Break up shared global constants by functions + breakUpGlobalConstants(code._start); + + code._visit.clear(); + schedLate (code); + } + + // Post-Order of CFG + private static void _rpo_cfg(CFGNode def, Node use, BitSet visit, Ary<CFGNode> rpo) { + if( !(use instanceof CFGNode cfg) || visit.get(cfg._nid) ) + return; // Been there, done that + if( def instanceof ReturnNode && use instanceof CallEndNode ) + return; + assert !( def instanceof CallNode && use instanceof FunNode ); + visit.set(cfg._nid); + for( Node useuse : cfg._outputs ) + _rpo_cfg(cfg,useuse,visit,rpo); + rpo.add(cfg); + } + + // Break up shared global constants by functions + private static void breakUpGlobalConstants( Node start ) { + // For all global constants + for( int i=0; i< start.nOuts(); i++ ) { + Node con = start.out(i); + if( con instanceof MachNode mach && mach.isClone() ) { + breakUpGlobalConstants(con); + // While constant has users in different functions + while( true ) { + // Find a function user, and another function + FunNode fun = null; + boolean done=true; + for( Node use : con.outs() ) { + FunNode fun2 = use instanceof ReturnNode ret ? ret.fun() : use.cfg0().fun(); + if( fun==null || fun==fun2 ) fun=fun2; + else { done=false; break; } + } + // Single function user, so this constant is not shared + if( done ) { + if( con.in(0)==start ) i--; + con.setDef(0,fun); + break; + } + // Move function users to a private constant + Node con2 = mach.copy(); // Private constant clone + con2._inputs.set(0,null); // Preserve edge invariants from clone + con2.setDef(0,fun); + // Move function users to this private constant + for( int j=0; j<con._outputs._len; j++ ) { + Node use = con.out(j); + FunNode fun2 = use.cfg0().fun(); + if( fun2==fun ) { + use.setDef(use._inputs.find(con),con2); + j--; + } + } + } + } + } + } + + // ------------------------------------------------------------------------ + // Visit all nodes in CFG Reverse Post-Order, essentially defs before uses + // (except at loops). Since defs are visited first - and hoisted as early + // as possible, when we come to a use we place it just after its deepest + // input. + private static void schedEarly(CodeGen code) { + // Reverse Post-Order on CFG + for( CFGNode cfg : code._cfg ) { + cfg.loopDepth(); + for( Node n : cfg._inputs ) + _schedEarly(n,code ); + if( cfg instanceof RegionNode ) + for( Node phi : cfg._outputs ) + if( phi instanceof PhiNode ) + _schedEarly(phi,code ); + } + } + + private static void _schedEarly(Node n, CodeGen code) { + if( n==null || code._visit.get(n._nid) ) return; // Been there, done that + assert !(n instanceof CFGNode); + code._visit.set(n._nid); + // Schedule not-pinned not-CFG inputs before self. Since skipping + // Pinned, this never walks the backedge of Phis (and thus spins around + // a data-only loop), eventually attempting relying on some pre-visited- + // not-post-visited data op with no scheduled control. + for( Node def : n._inputs ) + if( def!=null && !(def instanceof PhiNode) ) + _schedEarly(def,code); + + // If not-pinned (e.g. constants, projections, phi) and not-CFG + if( !n.isPinned() ) { + // Schedule at deepest input + CFGNode early = code._start; // Maximally early, lowest idepth + if( n.in(0) instanceof CFGNode cfg ) early = cfg; + for( int i=1; i<n.nIns(); i++ ) + if( n.in(i)!=null && n.in(i).cfg0().idepth() > early.idepth() ) + early = n.in(i).cfg0(); // Latest/deepest input + n.setDef(0,early); + } + } + + // ------------------------------------------------------------------------ + private static void schedLate( CodeGen code ) { + CFGNode[] late = new CFGNode[code.UID()]; + Node[] ns = new Node[code.UID()]; + // Breadth-first scheduling + breadth(code._stop,ns,late); + + // Copy the best placement choice into the control slot + for( int i=0; i<late.length; i++ ) + if( ns[i] != null && !(ns[i] instanceof ProjNode) ) + ns[i].setDef(0,late[i]); + } + + private static void breadth(Node stop, Node[] ns, CFGNode[] late) { + // Things on the worklist have some (but perhaps not all) uses done. + WorkList<Node> work = new WorkList<>(); + work.push(stop); + Node n; + outer: + while( (n = work.pop()) != null ) { + assert late[n._nid]==null; // No double visit + // These I know the late schedule of, and need to set early for loops + if( n instanceof CFGNode cfg ) late[n._nid] = cfg.blockHead() ? cfg : cfg.cfg(0); + else if( n instanceof PhiNode phi ) late[n._nid] = phi.region(); + else if( n instanceof ProjNode && n.in(0) instanceof CFGNode cfg ) late[n._nid] = cfg; + else { + + // All uses done? + for( Node use : n._outputs ) + if( use!=null && late[use._nid]==null ) + continue outer; // Nope, await all uses done + + // Loads need their memory inputs' uses also done + if( n instanceof MemOpNode ld && ld._isLoad ) + for( Node memuse : ld.mem()._outputs ) + if( late[memuse._nid]==null && + // New makes new memory, never crushes load memory + !(memuse instanceof NewNode) && + // Load-use directly defines memory + (memuse._type instanceof TypeMem || + // Load-use directly defines memory + memuse instanceof CallNode || + // Load-use indirectly defines memory + (memuse._type instanceof TypeTuple tt && tt._types[ld._alias] instanceof TypeMem)) ) + continue outer; + + // All uses done, schedule + _doSchedLate(n,ns,late); + } + + // Walk all inputs and put on worklist, as their last-use might now be done + for( Node def : n._inputs ) { + if( def!=null && late[def._nid]==null ) + work.push(def); + // if the def has a load use, maybe the load can fire + if( def!=null ) + for( Node out : def._outputs ) + if( out instanceof MemOpNode ld && ld._isLoad && late[ld._nid]==null ) + work.push(ld); + } + + if( n instanceof LoopNode loop ) { + for( Node phi : loop._outputs ) { + if( phi instanceof PhiNode && late[phi._nid]==null ) + work.push(phi); + } + } + } + } + + private static void _doSchedLate(Node n, Node[] ns, CFGNode[] late) { + // Walk uses, gathering the LCA (Least Common Ancestor) of uses + CFGNode early = n.in(0) instanceof CFGNode cfg ? cfg : n.in(0).cfg0(); + assert early != null; + CFGNode lca = null; + for( Node use : n._outputs ) + if( use != null ) + lca = use_block(n,use, late)._idom(lca,null); + + // Loads may need anti-dependencies, raising their LCA + if( n instanceof MemOpNode load && load._isLoad ) + lca = find_anti_dep(lca,load,early,late); + + + // Nodes setting a single register and getting killed will stay close + // to the uses, since they will be forced to spill anyway. The kill + // check is very weak, and some may be hoisted only to spill in the RA. + if( n instanceof MachNode mach ) { + RegMask out = mach.outregmap(); + if( out!=null && out.size1() ) { + int reg = mach.outregmap().firstReg(); + // Look for kills + outer: + for( CFGNode lca2=lca; lca2 != early; lca2 = lca2.idom() ) { + if( lca2 instanceof MachNode mach2 ) { + for( int i=1; i<lca2.nIns(); i++ ) { + RegMask mask = mach2.regmap(i); + if( mask!=null && mask.test(reg) ) { + early = lca2 instanceof IfNode ? lca2.idom() : lca2; + break outer; + } + } + RegMask kill = mach2.killmap(); + if( kill != null ) + throw Utils.TODO(); + } + } + } + } + + // Walk up from the LCA to the early, looking for best place. This is + // the lowest execution frequency, approximated by least loop depth and + // deepest control flow. + CFGNode best = lca; + lca = lca.idom(); // Already found best for starting LCA + for( ; lca != early.idom(); lca = lca.idom() ) + if( better(lca,best) ) + best = lca; + assert !(best instanceof IfNode); + ns [n._nid] = n; + late[n._nid] = best; + } + + // Block of use. Normally from late[] schedule, except for Phis, which go + // to the matching Region input. + private static CFGNode use_block(Node n, Node use, CFGNode[] late) { + if( !(use instanceof PhiNode phi) ) + return late[use._nid]; + CFGNode found=null; + for( int i=1; i<phi.nIns(); i++ ) + if( phi.in(i)==n ) + found = phi.region().cfg(i)._idom(found,null); + + assert found!=null; + return found; + } + + + // Least loop depth first, then largest idepth + private static boolean better( CFGNode lca, CFGNode best ) { + return lca.loopDepth() < best.loopDepth() || + lca instanceof NeverNode || + lca.idepth() > best.idepth() || + best instanceof IfNode; + } + + private static CFGNode find_anti_dep(CFGNode lca, MemOpNode load, CFGNode early, CFGNode[] late) { + // We could skip final-field loads here. + // Walk LCA->early, flagging Load's block location choices + for( CFGNode cfg=lca; early!=null && cfg!=early.idom(); cfg = cfg.idom() ) + cfg._anti = load._nid; + // Walk load->mem uses, looking for Stores causing an anti-dep + for( Node mem : load.mem()._outputs ) { + switch( mem ) { + case MemOpNode st: + if( !st._isLoad && load._alias == st._alias ) { + assert late[mem._nid] != null; + lca = anti_dep( load, late[mem._nid], mem.cfg0(), lca, st ); + } + break; // Loads do not cause anti-deps on other loads + case CallNode call: + assert late[call._nid]!=null; + lca = anti_dep(load,late[call._nid],call.cfg0(),lca,call); + break; + case PhiNode phi: + // Repeat anti-dep for matching Phi inputs. + // No anti-dep edges but may raise the LCA. + for( int i=1; i<phi.nIns(); i++ ) + if( phi.in(i)==load.mem() ) + lca = anti_dep(load,phi.region().cfg(i),load.mem().cfg0(),lca,null); + break; + case NewNode st: break; + case ReturnNode ret: break; // Load must already be ahead of Return + case MemMergeNode ret: break; // Mem uses now on ScopeMin + case NeverNode never: break; + default: throw Utils.TODO(); + } + } + return lca; + } + + // + private static CFGNode anti_dep( MemOpNode load, CFGNode stblk, CFGNode defblk, CFGNode lca, Node st ) { + // Store and Load overlap, need anti-dependence + if( stblk._anti==load._nid ) { + lca = stblk._idom(lca,null); // Raise Loads LCA + if( lca == stblk && st != null && st._inputs.find(load) == -1 ) // And if something moved, + st.addDef(load); // Add anti-dep as well + return lca; // Cap this stores' anti-dep to here + } + return lca; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/IFG.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/IFG.java new file mode 100644 index 00000000..6dd6fbf1 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/IFG.java @@ -0,0 +1,549 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; +import java.util.IdentityHashMap; + +// Interference Graph +abstract public class IFG { + // Interference Graph Support + + // Map from a Basic Block to Live-Out: {a map from a Live Range to a Def} + private static final IdentityHashMap<CFGNode,IdentityHashMap<LRG,Node>> BBOUTS = new IdentityHashMap<>(); + static void resetBBLiveOut() { + for( IdentityHashMap<LRG,Node> bbout : BBOUTS.values() ) + bbout.clear(); + } + static final IdentityHashMap<LRG,Node> TMP = new IdentityHashMap<>(); + + // Inteference Graph: Array of Bitsets + static final Ary<BitSet> IFG = new Ary<>(BitSet.class); + static void resetIFG() { + for( BitSet bs : IFG ) + if( bs!=null ) bs.clear(); + } + + // Set matching bit + private static void addIFG( LRG lrg0, LRG lrg1 ) { + short x0 = lrg0._lrg, x1 = lrg1._lrg; + // Triangulate + if( x0 < x1 ) _addIFG(x0,x1); + else _addIFG(x1,x0); + } + // Add lrg1 to lrg0's conflict set + private static void _addIFG( short x0, short x1 ) { + BitSet ifg = IFG.atX(x0); + if( ifg==null ) + IFG.setX(x0,ifg = new BitSet()); + ifg.set(x1); + } + + + private static final Ary<CFGNode> WORK = new Ary<>(CFGNode.class); + static void pushWork(CFGNode bb) { + if( WORK.find(bb) == -1 ) + WORK.push(bb); + } + + // ------------------------------------------------------------------------ + // Visit all blocks, using the live-out LRGs per-block and doing a backwards + // walk over each block. At the end of the walk, push the live-out sets to + // prior blocks. Due to loops, no single visitation order suffices. This + // problem can be fairly efficiently solved with a proper LIVE calculation + // and bitsets. In the interests of simplicity (and assumption of smaller + // programs) I am skipping LIVE and directly computing it during the IFG + // building. + + // Start by setting the live-out of the exit block (to empty), and putting + // it on a worklist. + + // - Pull from worklist a block who's live-out has changed + // - Walk backwards, adding interferences and computing live. + // - At block head, "push" the new live-out to prior blocks. + // - - If they pick up new live-outs, put them on the worklist. + + public static boolean build( int round, RegAlloc alloc ) { + // Reset all to empty + resetBBLiveOut(); + resetIFG(); + + // Last block has nothing live out + assert WORK.isEmpty(); + for( CFGNode bb : alloc._code._cfg ) + if( bb.blockHead()) + WORK.push( bb ); + + // Process blocks until no more changes + while( !WORK.isEmpty() ) + do_block(round,alloc,WORK.pop()); + + if( alloc.success() ) + convert2DAdjacency(alloc); + return alloc.success(); + } + + // Walk one block backwards, compute live-in from live-out, and build IFG + static void do_block( int round, RegAlloc alloc, CFGNode bb ) { + assert bb.blockHead(); + IdentityHashMap<LRG,Node> live_out = BBOUTS.get(bb); + TMP.clear(); + if( live_out != null ) + TMP.putAll(live_out); // Copy bits to temp + + // A backwards walk over instructions in the basic block + for( int inum = bb.nOuts()-1; inum >= 0; inum-- ) { + Node n = bb.out(inum); + if( n.in(0) != bb ) continue; + // In a backwards walk, proj users come before the node itself + if( n instanceof MultiNode ) + for( Node proj : n.outs() ) + if( proj instanceof ProjNode ) + do_node(alloc,proj); + if( n instanceof MachNode ) + do_node(alloc,n); + } + + // The bb head kills register, e.g. a CallEnd and caller-save registers + if( bb instanceof MachNode mach ) + kills(alloc,mach); + + // Push live-sets backwards to priors in CFG. + if( bb instanceof RegionNode ) + for( int i=1; i<bb.nIns(); i++ ) + mergeLiveOut(alloc,bb,i); + else + mergeLiveOut(alloc,bb,0); + } + + private static void do_node(RegAlloc alloc, Node n) { + // Defining means killing live LRG + LRG lrg = alloc.lrg(n); + if( lrg != null ) { + // Check for def-side self-conflict live ranges. These must split, + // and only happens during the first round a particular LRG splits. + selfConflict(alloc,n,lrg); + TMP.remove(lrg); // Kill def + } + + // Phis use and define the same live range, i.e. these LRGs already + // marked conflicted, no need to mark again + if( n instanceof PhiNode ) + return; + + // Kill any killed registers; milli-code routines like New can kill + // will not being a CFG. + if( n instanceof MachNode m ) + kills(alloc,m); + + // Interfere n with all live + if( lrg!=null ) { + // Interfere n with all live + for( LRG tlrg : TMP.keySet() ) { + assert tlrg.leader(); + // Skip self + if( lrg != tlrg && + // And register sets overlap + lrg._mask.overlap(tlrg._mask) ) + // Then tlrg and lrg interfere. If lrg needs the single + // last tlrg register at some point, either tlrg or lrg + // must fail. If *n* (a subset of lrg) needs the single + // last tlrg register then only tlrg must fail. + if( ((MachNode)n).outregmap().size1() ) { + if( !tlrg.clr(lrg._mask.firstReg()) ) // Clear bit, no interference + alloc.fail(tlrg); // Clearing drives mask to empty + } else addIFG(lrg,tlrg); // Add interference + } + } + + + // Check for self-conflict live ranges. These must split, and only + // happens during the first round when a particular LRG splits. + // Also record use-side spills for biased coloring. + // Then make all inputs live. + for( int i=1; i<n.nIns(); i++ ) { + Node def = n.in(i); + if( def==null ) continue; + LRG lrg1 = alloc.lrg(def); + if( lrg1==null ) continue; // Anti-dependence, etc, no register + + // Check use-side for self-conflict; if so we MUST split + selfConflict(alloc,def,lrg1); + + // Look for a must-use single register conflicting with some other must-def. + if( n instanceof MachNode m ) { + RegMask ni_mask = m.regmap(i); + if( ni_mask!=null && ni_mask.size1() ) { // Must-use single register + // Search all current live + for( LRG tlrg : TMP.keySet() ) { + assert tlrg.leader(); + Node live = TMP.get(tlrg); + if( live != def && live instanceof MachNode lmach && lmach.outregmap().overlap(ni_mask) ) { + // Deny the register, since it absolutely must be used here + if( !tlrg.clr(ni_mask.firstReg()) ) + // Then direct reg-reg conflict between use here (at n.in(i)) and def (of tlrg) there. + // Fail the older live range, it must move its register. + alloc.fail( tlrg ); + } + } + } + } + + // All inputs live - except in self conflicts, where we keep the prior def alive + // until it goes. + TMP.put(lrg1,def); + } + } + + // Single-register defines *must* have their register; other live ranges + // *must* avoid this register, so instead of interfering we remove the + // single register from the other rmask. + private static void kills( RegAlloc alloc, MachNode m ) { + RegMask killMask = m.killmap(); + if( killMask==null ) return; + // Kill registers with all live + for( LRG tlrg : TMP.keySet() ) { + assert tlrg.leader(); + // Always, tlrg cannot use kills + if( tlrg._mask.overlap(killMask) ) { + // Disallow clone-ables from killing registers. Just fail + // them and re-clone closer to target... so no kill. + // Special case for Intel XOR used to zero. + Node n = (Node)m; + CFGNode effUseBlk = n.out(0) instanceof PhiNode phi ? phi.region().cfg(phi._inputs.find(n)) : n.out(0).cfg0(); + if( m.isClone() && // Must be clonable + (n.nOuts()>1 || // Has many users OR + // Only 1 user but effective use is remote block + effUseBlk != n.cfg0() )) + // Then fail the clonable; it should split or move + alloc.fail(alloc.lrg((Node)m)); + // Else clonable cannot move + else if( !tlrg.sub(killMask) ) + alloc.fail(tlrg); + } + } + } + + // Check for self-conflict live ranges. These must split, and only happens + // during the first round a particular LRG splits. + private static void selfConflict(RegAlloc alloc, Node n, LRG lrg) { + selfConflict(alloc,n,lrg,TMP.get(lrg)); + } + private static void selfConflict(RegAlloc alloc, Node n, LRG lrg, Node prior) { + if( prior!=null && prior != n ) { + lrg.selfConflict(prior); + lrg.selfConflict(n); + alloc.fail(lrg); // 2 unrelated values live at once same live range; self-conflict + } + } + + // Merge TMP into bb's live-out set; if changes put bb on WORK + private static void mergeLiveOut( RegAlloc alloc, CFGNode priorbb, int i ) { + CFGNode bb = priorbb.cfg(i); + if( bb == null ) return; // Start has no prior + while( !bb.blockHead() ) bb = bb.cfg0(); + + // Lazy get live-out set for bb + IdentityHashMap<LRG, Node> lrgs = BBOUTS.computeIfAbsent( bb, k -> new IdentityHashMap<>() ); + + for( LRG lrg : TMP.keySet() ) { + Node def = TMP.get(lrg); + // Effective def comes from phi input from prior block + if( def instanceof PhiNode phi && phi.cfg0()==priorbb ) { + assert i!=0; + def = phi.in( i ); + } + Node def_bb = lrgs.get(lrg); + if( def_bb==null ) { + lrgs.put(lrg,def); + pushWork(bb); + } else { + // Alive twice with different definitions; self-conflict + selfConflict(alloc,def,lrg,def_bb); + } + } + } + + + static void convert2DAdjacency( RegAlloc alloc ) { + // Convert the 2-D array of bits (a 1-D array of BitSets) into an + // adjacency matrix. + int maxlrg = alloc._LRGS.length; + for( int i=1; i<maxlrg; i++ ) { + BitSet ifg = IFG.atX(i); + if( ifg != null ) { + LRG lrg0 = alloc._LRGS[i]; + for( int lrg = ifg.nextSetBit(0); lrg>=0; lrg=ifg.nextSetBit(lrg+1) ) { + LRG lrg1 = alloc._LRGS[lrg]; + lrg0.addNeighbor(lrg1); + lrg1.addNeighbor(lrg0); + } + } + } + } + + + // ------------------------------------------------------------------------ + // Color the inference graph. + + // Coloring works by removing "trivial" live ranges from the IFG - those + // live ranges with fewer neighbors than available colors (registers). + // These are trivial because even if every neighbor takes a unique color, + // there's at least one more available to color this live range. + + // If we hit a clique of non-trivial live ranges, we pick one to be "at + // risk" of not-coloring. Good choices include live ranges with a large + // area and few hot uses. + + // Then we reverse and put-back live ranges - picking a color as we go. + // If there's no spare color we'll have to spill this at-risk live range. + + public static boolean color(int round, RegAlloc alloc) { + int maxlrg = alloc._LRGS.length, nlrgs=0; + for( int i=1; i<maxlrg; i++ ) + if( alloc._LRGS[i] != null ) + nlrgs++; + + // Simplify + + // Walk all the LRGS looking for some trivial ones to start with. + // During this pass all LRGS are broken into 3 disjoint sets: + // - trivial, removed from IFG; color_stack[0 to sptr] + // - trivial, not (yet) removed from IFG; color_stack[sptr to swork] + // - unknown; color_stack[work to maxlrg] + + // Gather all not-unified (not-null); separate trivial and non-trivial set. + int sptr = 0, swork = 0; + LRG[] color_stack = new LRG[nlrgs]; + for( int i=0, j=0; i<maxlrg; i++ ) { + LRG lrg = alloc._LRGS[i]; + if( lrg==null ) continue; // Unified lrgs are null here + color_stack[j++] = lrg; + if( lrg.lowDegree() ) swap(color_stack, swork++, j-1); + } + + // Pull all lrgs from IFG, in trivial order if possible + while( sptr < color_stack.length ) { + // Swap best color up front + pickColor(color_stack,sptr,swork); + + // Pick a trivial lrg, and (temporarily) remove from the IFG. + LRG lrg = color_stack[sptr++]; + // If sptr was swork, then pulled an at-risk lrg + if( sptr > swork ) + swork = sptr; + + // Walk all neighbors and remove + if( lrg._adj != null ) { + for( LRG nlrg : lrg._adj ) { + // Remove and compress out neighbor + if( nlrg.removeCompress(lrg) ) { + // Neighbor is just exactly going trivial as 'lrg' is removed from IFG + // Find "j" position in the color_stack + int jx = swork; while( color_stack[jx] != nlrg ) jx++; + // Add trivial neighbor to trivial list. Pull lrg j out of + // unknown set, since its now in the trivial set + swap(color_stack, swork++, jx); + } + } + } + } + + // Reverse simplify (unstack the color stack), and set colors (registers) for live ranges + while( sptr > 0 ) { + LRG lrg = color_stack[--sptr]; + if( lrg==null ) continue; + RegMaskRW rmask = lrg._mask.copy(); + // Walk neighbors and remove adjacent colors + if( lrg._adj!=null ) { + for( LRG nlrg : lrg._adj ) { + nlrg.reinsert(lrg); + int reg = nlrg._reg; + if( reg!= -1 ) // Failed neighbors do not count + rmask.clr(reg); // Remove neighbor from my choices + } + } + // At-risk live-range did not color? + if( rmask.isEmpty() ) { + alloc.fail(lrg); + lrg._reg = -1; + } else { + // Pick first available register + short reg = rmask.firstReg(); + // Pick a "good" color from the choices. Typically, biased-coloring + // removes some over-spilling. + if( rmask.size() > 1 ) reg = biasColor(alloc,lrg,reg,rmask); + lrg._reg = reg; // Assign the register + } + } + + return alloc.success(); + } + + // Pick LRG from color stack + private static void pickColor(LRG[] color_stack, int sptr, int swork) { + // Out of trivial colorable, pick an at-risk to pull + if( sptr==swork ) + swap(color_stack,sptr,pickRisky(color_stack,sptr)); + // When coloring, we'd like to give more choices; so when coloring we'd + // like to see the single-def first (since no choices anyway), then + // non-split related (so more live ranges get colored), then + // split-related last, so they have more colors to bias towards. + + // Working in reverse, pick first split-related with many regs, then + // those with some regs, then single-def. + int bidx=sptr; + LRG best=color_stack[bidx]; + for( int idx = sptr+1; idx < swork; idx++ ) + if( betterLRG(best,color_stack[idx]) ) + best = color_stack[bidx=idx]; + if( bidx != sptr ) + swap(color_stack,sptr,bidx); // Pick best at sptr + } + + private static boolean betterLRG( LRG best, LRG lrg ) { + // If single-def varies, keep the not-single-def + if( best.size1() != lrg.size1() ) + return best.size1(); + // If hasSplit varies, keep the hasSplit + if( best.hasSplit() != lrg.hasSplit() ) + return lrg.hasSplit(); + // Keep large register count + return best.size() < lrg.size(); + } + + // Pick a live range that hasn't already spilled, or has a single-def- + // single-use that are not adjacent. + private static int pickRisky( LRG[] color_stack, int sptr ) { + int best=sptr; + int bestScore = pickRiskyScore(color_stack[best]); + for( int i=sptr+1; i<color_stack.length; i++ ) { + if( bestScore == 1000000 ) return best; // Already max score + int iScore = pickRiskyScore(color_stack[i]); + if( iScore > bestScore ) + { best = i; bestScore = iScore; } + } + return best; + } + + // Pick a live range to pull, that might not color. + // + // Picking a live range with a very large span, with defs and uses outside + // loops means spilling a relative cheap live range and getting that + // register over a large area. + // + // Picking a live range that is very close to coloring might allow it to + // color despite being risky. + private static int pickRiskyScore( LRG lrg ) { + // Pick single-def clonables that are not right next to their single-use. + // Failing to color these will clone them closer to their uses. + if( !lrg._multiDef && lrg._machDef.isClone() ) { + Node def = ((Node)lrg._machDef); + Node use = ((Node)lrg._machUse); + CFGNode cfg = def.cfg0(); + if( cfg != use.cfg0() || // Different blocks OR + // Same block, but not close + cfg._outputs.find(def) < cfg._outputs.find(use)+1 ) + return 1000000; + } + + // Always pick callee-save registers as being very large area recovered + // and very cheap to spill. + if( lrg._machDef instanceof CalleeSaveNode ) + return 1000000-2-lrg._mask.firstReg(); + if( lrg._splitDef != null && lrg._splitDef. in(1) instanceof CalleeSaveNode && + lrg._splitUse != null && lrg._splitUse.out(0) instanceof ReturnNode ) + return 1000000-1; + + // TODO: cost/benefit model. Perhaps counting loop-depth (freq) of def/use for cost + // and "area" for benefit + return 1000; + } + + private static short biasColor( RegAlloc alloc, LRG lrg, short reg, RegMask mask ) { + if( mask.size1() ) return reg; + // Check chain of splits up the def-chain. Take first allocated + // register, and if it's available in the mask, take it. + Node def = lrg._splitDef, use = lrg._splitUse; + int tidx=0, cnt=0; + + while( def != null || use != null ) { + if( cnt++ > 10 ) break; + + if( def != null ) { + short bias = biasColor( alloc, def, mask ); + if( bias >= 0 ) return bias; // Good bias + if( bias == -2 ) def = null; // Kill this side, no more searching + else if( (tidx=biasable(def)) == 0 ) def = null; + } + + if( use != null ) { + short bias = biasColor( alloc, use, mask ); + if( bias >= 0 ) return bias; // Good bias + if( bias == -2 ) use = null; // Kill this side, no more searching + else if( biasable(use)==0 ) use = null; + } + + if( def != null ) { + short bias = biasColorNeighbors( alloc, def, mask ); + if( bias >= 0 ) return bias; + // Advance def side + def = def.in(tidx); + if( alloc.lrg(def)==null ) def=null; + } + + if( use != null ) { + short bias = biasColorNeighbors( alloc, use, mask ); + if( bias >= 0 ) return bias; + use = use.out(0); + if( biasable(use)==0 ) use=null; + } + + } + return mask.firstReg(); + } + + private static int biasable(Node split) { + if( split instanceof SplitNode ) return 1; // Yes biasable, advance is slot 1 + if( split instanceof PhiNode phi ) return phi.region() instanceof LoopNode ? 2 : 1; // Yes biasable, advance is slot 1 + if( !(split instanceof MachNode mach) ) return 0; // Not biasable + return mach.twoAddress(); // Only biasable if 2-addr + } + + // 3-way return: + // - good bias reg, take it & exit + // - this path is cutoff; do not search here anymore + // - advance this side + private static short biasColor( RegAlloc alloc, Node split, RegMask mask ) { + short bias = alloc.lrg(split)._reg; + if( bias != -1 ) { + if( mask.test(bias) ) return bias; // Good bias + else return -2; // Kill this side + } else return -1; // Advance this side + } + + // Check if we can match "split" color, or else trim "mask" to colors + // "split" might get. + private static short biasColorNeighbors( RegAlloc alloc, Node split, RegMask mask ) { + LRG slrg = alloc.lrg(split); + if( slrg._adj == null ) return -1; // No trimming + + // Can I limit my own choices to valid neighbor choices? + for( LRG alrg : slrg._adj ) { + short reg = alrg._reg; + if( reg == -1 && alrg._mask.size1() ) + reg = alrg._mask.firstReg(); + if( reg != -1 ) { + mask.clr(alrg._reg); + if( mask.size1() ) + return mask.firstReg(); + } + } + return -1; // No obvious color choice, but mask got trimmed + } + + private static void swap( LRG[] ary, int x, int y ) { + LRG tmp = ary[x]; ary[x] = ary[y]; ary[y] = tmp; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/LRG.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/LRG.java new file mode 100644 index 00000000..009ddcdb --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/LRG.java @@ -0,0 +1,233 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.IdentityHashMap; + +/** A Live Range + * <p> + * A live range is a set of nodes and edges which must get the same register. + * Live ranges form an interconnected web with almost no limits on their + * shape. Live ranges also gather the set of register constraints from all + * their parts. + * <p> + * Most of the fields in this class are for spill heuristics, but there are a + * few key ones that define what a LRG is. LRGs have a unique dense integer + * `_lrg` number which names the LRG. New `_lrg` numbers come from the + * `RegAlloc._lrg_num` counter. LRGs can be unioned together - + * (<a href="https://en.wikipedia.org/wiki/Disjoint-set_data_structure">this is the Union-Find algorithm</a>) + * - and when this happens the lower numbered `_lrg` wins. Unioning only + * happens during `BuildLRG` and happens because either a `Phi` is forcing all + * its inputs and outputs into the same register, or because of a 2-address + * instruction. LRGs have matching `union` and `find` calls, and a set + * `_leader` field. + */ +public class LRG { + + // Dense live range numbers + final short _lrg; + + // U-F leader; null if leader + LRG _leader; + + // Choosen register + short _reg; + + // Count of single-register defs and uses + short _1regDefCnt, _1regUseCnt; + // Count of all defs, uses. Mostly interested 1 vs many + boolean _multiDef, _multiUse; + + // A sample MachNode def in the live range + public MachNode _machDef, _machUse; + short _uidx; // _machUse input + + // Some splits used in biased coloring + MachConcreteNode _splitDef, _splitUse; + + // All the self-conflicting defs for this live range + IdentityHashMap<Node,String> _selfConflicts; + + // AND of all masks involved; null if none have been applied yet + RegMask _mask; + + // Adjacent Live Range neighbors. Only valid during coloring + Ary<LRG> _adj; + + public int nadj() { return _adj==null ? 0 : _adj._len; } + + void addNeighbor(LRG lrg) { + if( _adj==null ) _adj = new Ary<>(LRG.class); + _adj.push(lrg); + } + + // Remove and compress neighbor list; store ex-neighbor past + // end for unwinding Simplify. True if exactly going low-degree + boolean removeCompress( LRG lrg ) { + _adj.swap(_adj.find(lrg),_adj._len-1); + return _adj._len-- == _mask.size(); + } + + void reinsert( LRG lrg ) { + assert _adj._es[_adj._len]==lrg; + _adj._len++; + } + + // More registers than neighbors + boolean lowDegree() { return nadj() < _mask.size(); } + + LRG( short lrg ) { _lrg = lrg; _reg = -1; } + + boolean leader() { return _leader == null; } + + // Fast-path Find from the Union-Find algorithm + LRG find() { + if( _leader==null ) return this; // I am the leader + if( _leader._leader==null ) // I point to the leader + return _leader; + return _rollup(); + } + // Slow-path rollup of U-F + private LRG _rollup() { + LRG ldr = _leader._leader; + // Roll-up + while( ldr._leader!=null ) ldr = ldr._leader; + LRG l2 = this; + while( l2 != ldr ) { + LRG l3 = l2._leader; + l2._leader = ldr; + l2 = l3; + } + return ldr; + } + + // Union `this` and `lrg`, keeping the lower numbered _lrg. + // Includes a number of fast-path cutouts. + LRG union( LRG lrg ) { + assert leader(); + if( lrg==null ) return this; + lrg = lrg.find(); + if( lrg==this ) return this; + return _lrg < lrg._lrg ? _union(lrg) : lrg._union(this); + } + // Union `this` and `lrg`, folding together all stats. + private LRG _union( LRG lrg ) { + // Set U-F leader + lrg._leader = this; + // Fold together stats + if( _machDef==null ) { + _machDef = lrg._machDef; + } else if( lrg._machDef!=null ) { + if( _machDef != lrg._machDef ) _multiDef=true; + if( _1regDefCnt==0 ) + _machDef = lrg._machDef; + else if( _machDef==lrg._machDef ) + _1regDefCnt--; + } + _1regDefCnt += lrg._1regDefCnt; + _multiDef |= lrg._multiDef; + + if( _machUse==null ) { + _machUse = lrg._machUse; + _uidx = lrg._uidx; + } else if( lrg._machUse!=null ) { + if( _machUse != lrg._machUse ) _multiUse=true; + if( _1regUseCnt==0 ) { + _machUse = lrg._machUse; + _uidx = lrg._uidx; + } + else if( _machUse==lrg._machUse ) + _1regUseCnt--; + } + _1regUseCnt += lrg._1regUseCnt; + _multiUse |= lrg._multiUse; + + // Fold deepest Split + _splitDef = deepSplit(_splitDef,lrg._splitDef); + _splitUse = deepSplit(_splitUse,lrg._splitUse); + + // Fold together masks + RegMask mask = _mask.and(lrg._mask); + if( mask==null ) + mask = _mask.copy().and(lrg._mask); + _mask = mask; + return this; + } + + private static MachConcreteNode deepSplit( MachConcreteNode s0, MachConcreteNode s1 ) { + return s0==null || (s1!=null && s0.cfg0().loopDepth() < s1.cfg0().loopDepth()) ? s1 : s0; + } + + // Record any Mach def for spilling heuristics + LRG machDef( MachNode def, boolean size1 ) { + if( _machDef!=null && _machDef!=def ) + _multiDef = true; + if( _machDef==null || size1 ) + _machDef = def; + if( size1 ) + _1regDefCnt++; + if( def instanceof SplitNode split ) + _splitDef = deepSplit(_splitDef,split); + return this; + } + + // Record any Mach use for spilling heuristics + LRG machUse( MachNode use, short uidx, boolean size1 ) { + if( _machUse!=null && _machUse!=use ) + _multiUse = true; + if( _machUse==null || size1 ) + { _machUse = use; _uidx = uidx; } + if( size1 ) + _1regUseCnt++; + if( use instanceof SplitNode split ) + _splitUse = deepSplit(_splitUse,split); + return this; + } + + boolean hasSplit() { return _splitDef != null || _splitUse != null; } + short size() { return _mask.size(); } + boolean size1() { return _mask.size1(); } + + + void selfConflict( Node def ) { + if( _selfConflicts == null ) _selfConflicts = new IdentityHashMap<>(); + _selfConflicts.put(def,""); + } + + + // Record intersection of all register masks. + // True if still has registers + boolean and( RegMask mask ) { + RegMask mask2 = mask.and(_mask); + if( mask2==null ) + mask2 = _mask.copy().and(mask); + _mask = mask2; + return !_mask.isEmpty(); + } + // Remove this singular register + // True if still has registers + boolean clr( int reg ) { + if( _mask.clr(reg) ) return true; + _mask = _mask.copy(); // Need a mutable copy + return _mask.clr(reg); + } + // Subtract mask (AND complement) + // True if still has registers + boolean sub( RegMask mask ) { + RegMask mask2 = _mask.sub(mask); + if( mask2==null ) + mask2 = _mask.copy().sub(mask); + _mask = mask2; + return !_mask.isEmpty(); + } + + @Override public String toString() { return toString(new SB()).toString(); } + + public SB toString( SB sb ) { + sb.p("V").p(_lrg); + if( _mask!=null ) _mask.toString(sb); + return sb; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java new file mode 100644 index 00000000..2415203d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java @@ -0,0 +1,23 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +// In-memory linking +public class LinkMem { + final CodeGen _code; + LinkMem( CodeGen code ) { _code = code; } + + public CodeGen link() { + Encoding enc = _code._encoding; + + // Patch external calls internally + enc.patchGlobalRelocations(); + + // Write any large constants into a constant pool; they + // are accessed by RIP-relative addressing. + enc.writeConstantPool(enc._bits,true); + + return _code; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java new file mode 100644 index 00000000..ddf5a679 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java @@ -0,0 +1,261 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.IterPeeps.WorkList; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import java.util.*; + +public abstract class ListScheduler { + + // eXtra per-node stuff for scheduling. + // Nodes are all block-local, and projections fold into their parent. + private static final IdentityHashMap<Node,XSched> XS = new IdentityHashMap<>(); + private static class XSched { + + Node _n; // Node this extra is for + int _bcnt; // Not-ready not-scheduled inputs + int _rcnt; // Ready not-scheduled inputs + boolean _ruse; // Node IS a "remote use", uses a other-block value + boolean _rdef; // Node IS a "remote def" of a value used in other block + boolean _single; // Defines a single register, likely to conflict + + static final Ary<XSched> FREE = new Ary<>(XSched.class); + static void alloc(CFGNode bb, Node n) { + XSched x = FREE.pop(); + XS.put(n, (x==null ? new XSched() : x).init(bb,n)); + } + void free() { _n = null; FREE.push(this); } + + static XSched get(Node n) { return n==null ? null : XS.get(n instanceof ProjNode && !(n.in(0) instanceof CallEndNode) ? n.in(0) : n); } + + private XSched init(CFGNode bb, Node n) { + _n = n; + _bcnt = 0; + _ruse = _rdef = _single = false; + + // Count block-locals and remote inputs + if( !(n instanceof PhiNode) ) + for( Node def : n._inputs ) + if( def != null && def != bb ) { + if( def.cfg0()==bb ) _bcnt++; // Raise block-local input count + else if( !def.isMem() ) _ruse = true; // Remote register user + } + // Count remote outputs and allowed registers + if( n instanceof MultiNode ) + for( Node use : n._outputs ) + computeSingleRDef(bb,use); + else + computeSingleRDef(bb,n); + + if( n instanceof NewNode || n instanceof CallNode ) + bb.fun()._hasCalls = true; + return this; + } + + private void computeSingleRDef(CFGNode bb, Node n) { + // See if this is 2-input, and that input is single-def + if( n instanceof MachNode mach && mach.twoAddress() != 0 ) { + XSched xs = XS.get(n.in(mach.twoAddress())); + if( xs != null ) + _single = xs._single; + } + // Visit all outputs + RegMaskRW rmask = !_single && n instanceof MachNode mach && mach.outregmap() != null ? mach.outregmap().copy() : null; + for( Node use : n._outputs ) { + // Remote use, so this is a remote def + if( use!=null && use.cfg0()!=bb ) _rdef = true; + // And mask between n's def mask and all n's users masks' + if( use instanceof MachNode mach && rmask != null ) + for( int i=1; i<use.nIns(); i++ ) + if( use.in(i)==n ) + rmask.and(mach.regmap(i)); + } + // Defines in a single register + _single |= rmask!=null && rmask.size1(); + } + + // If _bcnt==0, declare ready; move user bcnts into rcnts. + boolean isReady() { + if( _bcnt > 0 || _rcnt > 0 ) return false; + if( _n instanceof MultiNode ) + for( Node use : _n._outputs ) + if( use instanceof ProjNode ) readyUp(use); + // anti-dep from a multireg directly + else _readyUp(use); + else + readyUp(_n); + return true; + } + private static void readyUp(Node n) { + for( Node use : n._outputs ) + _readyUp(use); + } + private static void _readyUp(Node use) { + XSched xs = get(use); + if( xs!=null && !(use instanceof PhiNode) ) + { assert xs._bcnt>0; xs._bcnt--; xs._rcnt++; } + } + + boolean decIsReady() { + assert _rcnt > 0; + _rcnt--; + return isReady(); + } + } + + + // List schedule every block + public static void sched( CodeGen code ) { + XS.clear(); + for( CFGNode bb : code._cfg ) + if( bb.blockHead() ) + local(bb,false); + } + + // Classic list scheduler + private static void local( CFGNode bb, boolean trace ) { + assert XS.isEmpty(); + int len = bb.nOuts(); + + // Count block-locals, remote inputs and outputs + for( int i=0; i<len; i++ ) + XSched.alloc(bb,bb.out(i)); + + // Nodes are ready if they are not used by other nodes in this block. + // Move ready up front. + int ready = 0; + for( int i=0; i<len; i++ ) + if( XSched.get(bb.out(i)).isReady() ) // No block-local inputs? + bb._outputs.swap(ready++,i); // Move into ready set + assert len==0 || ready > 0; + + // Classic list scheduler. Behind sched is scheduled. Between sched + // and ready have zero counts and are ready to schedule. Ahead of + // ready is undefined. + // + // As nodes are scheduled, the nodes they use decrement their bcnts[]. Once + // that gets to 0, all the nodes using it are scheduled, so it's ready. + int sched = 0; + while( sched < len ) { + assert sched < ready; + int pick = best(bb._outputs,sched,ready,trace); // Pick best + Node best = bb._outputs.swap(pick,sched++); // Swap best to head of ready and move into the scheduled set + // Lower ready count of users, and since projections are ready as + // soon as their multi is ready, lower those now too. + for( Node use : best._outputs ) + if( use instanceof ProjNode ) + for( Node useuse : use._outputs ) + ready = ready(bb,useuse,ready); + else + ready = ready(bb,use,ready); + } + + // Reset for next block + for( XSched x : XS.values() ) + x.free(); + XS.clear(); + } + + private static int ready(CFGNode bb, Node use, int ready) { + if( use!=null && use.in(0)==bb && !(use instanceof PhiNode) && XSched.get(use).decIsReady() ) + bb._outputs.set(ready++, use); // Became ready, move into ready set + //bb._outputs.swap(ready++,use); // Became ready, move into ready set + return ready; + } + + + // Pick best between sched and ready. + private static int best( Ary<Node> blk, int sched, int ready, boolean trace ) { + int pick = sched; + Node p = blk.at(pick); + int score = score(p); + if( trace ) { System.out.printf("%4d N%d ",score,p._nid); System.out.println(p); } + for( int i=sched+1; i<ready; i++ ) { + Node n = blk.at(i); + int nscore = score(n); + if( trace ) { System.out.printf("%4d N%d ",nscore,n._nid); System.out.println(n); } + if( nscore > score ) + { score = nscore; pick = i; p = n; } + } + if( trace ) { System.out.printf("Pick: N%d %s\n\n",p._nid,p); } + return pick; + } + + // Highest score wins. Max at 1000, min at 10, except specials. + private static final int[] CNT = new int[3]; + static int score( Node n ) { + if( n instanceof ProjNode ) return 1001; // Pinned at block entry + if( n instanceof CProjNode ) return 1001; // Pinned at block entry + if( n instanceof PhiNode ) return 1000; + if( n instanceof CFGNode ) return 1; // Pinned at block exit + + int score = 500; + // Ideal nodes ignore register pressure scheduling + if( !(n instanceof MachNode) ) + return score; + + // Register pressure local scheduling: avoid overlapping specialized + // registers usages. + + // Subtract 10 (delay) if this op forces a live range to exist that + // cannot be resolved immediately; i.e., live count goes up. Scale to + // 20 if multi-def. + + // Subtract 100 if this op forces a single-def live range to exist + // which might conflict on the same register with other live ranges. + // Defines a single register based on def & uses, and the output is not + // ready. Scale to 200 for multi-def. + CNT[1]=CNT[2]=0; + XSched xn = XSched.get(n); + // If defining a remote value, just generically stall alot. Value is + // used in a later block, can we delay until the end of this block? + if( xn._rdef ) score = 200; // If defining a remote value, just generically stall alot + boolean flags = false; + if( n instanceof MultiNode ) { + for( Node use : n._outputs ) + flags |= singleUseNotReady( use, xn._single ); + } else + flags |= singleUseNotReady( n, xn._single ); + score += -10 * Math.min( CNT[1], 2 ); + score += -100 * Math.min( CNT[2], 2 ); + if( flags ) return 10; + + // Add 10 if this op ends a single-def live range, add 20 for 2 or more. + // Scale to 100,200 if the single-def is also single-register. + CNT[1]=CNT[2]=0; + for( int i=1; i<n.nIns(); i++ ) { + XSched xd = XSched.get( n.in(i) ); + if( xd != null && n.in(i).nOuts()==1 ) + CNT[xd._single || ((MachNode)n).regmap(i)!=null && ((MachNode)n).regmap(i).size1() ? 2 : 1]++; + } + score += 10 * Math.min( CNT[1], 2 ); + score += 100 * Math.min( CNT[2], 2 ); + + // Nothing special + assert 10 <= score && score <= 990; + return score; + } + + // Single use, and that use is not ready to fire once this one does. If + // true, stalling 'n' might reduce 'n's lifetime. Stall by 1 (2 if single) + // per not-ready. + + // If CFG user in this block, it must be last, so definitely stall + // single-def (which stalls flags on x86,arm until the jmp). + private static boolean singleUseNotReady( Node n, boolean single ) { + // If n can rematerialize, assume allocator will split into private uses + // as needed. No impact on local scheduling. + if( n.nOuts()>1 && n instanceof MachNode mach && mach.isClone() ) + return false; + for( Node use : n.outs() ) { + XSched xu = XSched.get(use); + if( xu != null && xu._n instanceof CFGNode ) return true; + if( xu != null && xu._bcnt > 0 ) + CNT[single ? 2 : 1]++; // Since bcnt>0 or CFG, stall until user is more ready + } + return false; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/Machine.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/Machine.java new file mode 100644 index 00000000..2766414f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/Machine.java @@ -0,0 +1,97 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeFunPtr; + +abstract public class Machine { + // Human readable machine name. Something like "x86-64" or "arm" or "risc5" + public abstract String name(); + // Default opcode size for printing; 4 bytes for most 32-bit risc chips + public int defaultOpSize() { return 4; } + // Human-readable name for a register number, e.g. "RAX" or "R0" + public abstract String[] regs(); + // Create a split op; any register to any register, including stack slots + public abstract SplitNode split( String kind, byte round, LRG lrg); + // List of caller-save registers, as a 64bit mask + public abstract long callerSave(); + // List of never-save registers, e.g. RSP or a ZERO register if you have one + public abstract long neverSave(); + // Call Argument Mask. Passed in the function signature and argument + // number (2-based; 0 is for control and 1 for memory). Also passed in a 0 + // for the function itself, or for *outgoing* calls, the maximum stack slot + // given to the incoming function arguments (stack slots reserved for + // incoming arguments). + public abstract RegMask callArgMask(TypeFunPtr tfp, int arg, int maxArgSlot); + // Return register mask, based on signature (GPR vs FPR) + public abstract RegMask retMask(TypeFunPtr tfp); + // Return PC register + public abstract int rpc(); + // Return a MachNode unconditional branch + public abstract CFGNode jump(); + // Instruction select from ideal nodes + public abstract Node instSelect( Node n ); + + /** Stack Slot Numbering + +RA gives all registers a number, starting at 0. Stack slots continue this +numbering going up from the last register number. Common register numbers are +0-15 for GPRs, 16-31 for FPRs, 32 for flags, and stack slots starting at +register#33 going up. These numbers are machine-specific, YMMV, etc; e.g. RPC +is only in stack slot 0 on X86; other cpus start with the rpc in a register +which may spill into any generic spill slot. + +For ease of reading and printing, stack slots start again at slot#0 - but +during RA they are actually biased by CPU.MAX_REG. + +Stack Layout during Reg Alloc: + + Slot Value Description + ---- ------- ----------- +MAXREG+ R+1 argR maxArgSlot(calleR tfp), can be 0 + ... +MAXREG+ 1 arg0 + ---- -- Caller ------ +MAXREG+ 0 RPC +MAXREG+ R+E+N PAD optional alignment + +MAXREG+ + Spills Caller Frame Space; N spills +MAXREG+ R+E+1 Spills + +MAXREG+ R+E argE maxArgSlot(calleE tfp), can be 0 + ... +MAXREG+ R+2 arg0 + ---- -- Callee ------- + ... + +Slots defined by maxArgSlot do not have to contain the actual passed argument; +they can be "shadow slots". If they exist, they are property of the frame / +FunNode where the TFP comes from. + +For a given calleR, there are generally many calleE's and they all share the +low-range stack slots. + +Example:, Win64, main(int arg) { calloc(1,size); } + + Post-Warp: SP+56 shadow-main-arg +Pre-alloc Post-Alloc SP+48 RPC +--- ------- ---------- ------------- +40 spill#3 SP+40 SP+40 spill#3 +39 spill#2 SP+32 "" +38 spill#1 SP+24 "" +37 spill#0 SP+16 "" spill#0 +36 shadow-calloc#size SP+ 8 SP+ 8 shadow-calloc#size +35 shadow-calloc#1 SP+ 0 SP+ 0 shadow-calloc#1 +--- --- FRAME BASE ---------- ---- FRAME BASE ------- +34 shadow-main-arg SP+56 +33 RPC SP+48 + + + */ + + + // Maximum stack slot (or 0) for the args in this TFP. This will include + // shadow slots if defined in the ABI, even if all arguments are passed in + // registers. + public abstract short maxArgSlot(TypeFunPtr tfp); + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/RIPRelSize.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/RIPRelSize.java new file mode 100644 index 00000000..777182dc --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/RIPRelSize.java @@ -0,0 +1,14 @@ +package com.seaofnodes.simple.codegen; + +// This Node rip-relative encodings has sizes that vary by delta +public interface RIPRelSize { + // delta is the distance from the opcode *start* to the target start. Each + // hardware target adjusts as needed, X86 measures from the opcode *end* + // and small jumps are 2 bytes, so they'll need to subtract 2. + byte encSize(int delta); + + // Patch full encoding in. Used for both short and long forms. delta + // again is from the opcode *start*. + void patch( Encoding enc, int opStart, int opLen, int delta ); + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java new file mode 100644 index 00000000..da521082 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java @@ -0,0 +1,639 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.node.*; +import java.util.Arrays; +import java.util.BitSet; +import java.util.IdentityHashMap; + +/** + * "Briggs/Chaitin/Click". + * Graph coloring. + * <p> + * Every def and every use have a bit-set of allowed registers. + * Fully general to bizarre chips. + * Multiple outputs fully supported, e.g. add-with-carry or combined div/rem or "xor rax,rax" setting both rax and flags. + * <p> + * Intel 2-address accumulator-style ops fully supported. + * Op-to-stack-spill supported. + * All addressing modes supported. + * Register pairs could be supported with some grief. + * <p> + * Splitting instead of spilling (simpler implementation). + * Stack slots are "just another register" (tiny stack frames, simpler implementation). + * Stack/unstack during coloring with a marvelous trick (simpler implementation). + * <p> + * Both bitset and adjacency list formats for the interference graph; one of + * the few times it's faster to change data structures mid-flight rather than + * just wrap one of the two. + * <p> + * Liveness computation and interference graph built in the same one pass (one + * fewer passes per round of coloring). + * <p> + * Single-register def or use live ranges deny neighbors their required + * register and thus do not interfere, vs interfering and denying the color + * and coloring time. Basically all function calls do this, but many oddball + * registers also, e.g. older div/mod/mul ops. (5x smaller IFG, the only + * O(n^2) part of this operation). + */ + +public class RegAlloc { + // Main Coloring Algorithm: + // Repeat until colored: + // Build Live Ranges (LRGs) + // - Intersect allowed registers + // If hard conflicts (LRGs with no allowed registers) + // - Pre-split conflicted LRGs, and repeat + // Build Interference Graph (IFG) + // - Self conflicts split now + // Color (remove trivial first then any until empty; reverse assign colors + // - If color fails: + // - - Split uncolorable LRGs + + // Top-level program graph structure + final CodeGen _code; + + public int _spills, _spillScaled; + + // ----------------------- + // Live ranges with self-conflicts or no allowed registers + private final IdentityHashMap<LRG,String> _failed = new IdentityHashMap<>(); + void fail( LRG lrg ) { + assert lrg.leader(); + _failed.put(lrg,""); + } + boolean success() { return _failed.isEmpty(); } + + + // ----------------------- + // Map from Nodes to Live Ranges + private final IdentityHashMap<Node,LRG> _lrgs = new IdentityHashMap<>(); + short _lrg_num; + + // Define a new LRG, and assign n + LRG newLRG( Node n ) { + LRG lrg = lrg(n); + if( lrg!=null ) return lrg; + lrg = new LRG(_lrg_num++); + LRG old = _lrgs.put(n,lrg); assert old==null; + return lrg; + } + + // LRG for n + LRG lrg( Node n ) { + LRG lrg = _lrgs.get(n); + if( lrg==null ) return null; + LRG lrg2 = lrg.find(); + if( lrg != lrg2 ) + _lrgs.put(n,lrg2); + return lrg2; + } + + // Find LRG for n.in(idx), and also map n to it + LRG lrg2( Node n, int idx ) { + LRG lrg = lrg(n.in(idx)); + return union(lrg,n); + } + + // Union any lrg for n with lrg and map to the union + LRG union( LRG lrg, Node n ) { + LRG lrgn = _lrgs.get(n); + LRG lrg3 = lrg.union(lrgn); + _lrgs.put(n,lrg3); + return lrg3; + } + + // Force all unified to roll up; collect live ranges + LRG[] _LRGS; + void unify() { + Ary<LRG> lrgs = new Ary<>(LRG.class); + for( Node n : _lrgs.keySet() ) { + LRG lrg = lrg(n); + lrgs.setX(lrg._lrg,lrg); + } + _LRGS = lrgs.asAry(); + // Remove unified lrgs from failed set also + for( LRG lrg : _failed.keySet().toArray(new LRG[0]) ) { + if( !lrg.leader() ) { + LRG lrg2 = lrg.find(); + _failed.remove(lrg); + _failed.put(lrg2,""); + } + } + } + + + public short regnum( Node n ) { + LRG lrg = lrg(n); + return lrg==null ? -1 : lrg._reg; + } + + // Printable register number for node n + String reg( Node n ) { return reg(n,null); } + String reg( Node n, FunNode fun ) { + LRG lrg = lrg(n); + if( lrg==null ) return null; + // No register yet, use LRG + if( lrg._reg == -1 ) return "V"+lrg._lrg; + // Chosen machine register unless stack-slot and past RA + String[] regs = _code._mach.regs(); + if( lrg._reg < regs.length || _code._phase.ordinal() <= CodeGen.Phase.RegAlloc.ordinal() || fun==null ) + return RegMask.reg(regs,lrg._reg); + // Stack-slot past RA uses the frame layout logic + return "[rsp+"+fun.computeStackOffset(_code,lrg._reg)+"]"; + } + + // ----------------------- + RegAlloc( CodeGen code ) { _code = code; } + + public void regAlloc() { + // Insert callee-save registers + String[] regs = _code._mach.regs(); + long neverSave= _code._mach.neverSave(); + for( CFGNode bb : _code._cfg ) + if( bb instanceof FunNode fun ) { + ReturnNode ret = fun.ret(); + int len = Math.min(regs.length,64); + for( int reg=0; reg<len; reg++ ) + if( !_code._callerSave.test(reg) && ((1L<<reg)&neverSave)==0 ) { + ret.addDef(new CalleeSaveNode(fun,reg,regs[reg])); + assert ret.regmap(ret.nIns()-1).firstReg()==reg; + } + } + // Cache reg masks for New and Call + for( CFGNode bb : _code._cfg ) { + if( bb instanceof CallEndMach cend ) cend.cacheRegs(_code); + for( Node n : bb._outputs ) + if( n instanceof NewNode nnn ) nnn.cacheRegs(_code); + } + + // Top driver: repeated rounds of coloring and splitting. + byte round=0; + while( !graphColor(round) ) { + split(round); + if( round >= 7 ) // Really expect to be done soon + throw Utils.TODO("Allocator taking too long"); + round++; + } + postColor(); // Remove no-op spills + } + + private boolean graphColor(byte round) { + _failed.clear(); + _lrgs.clear(); + _lrg_num = 1; + _LRGS=null; + + return + // Build Live Ranges + BuildLRG.run(round,this) && // if no hard register conflicts + // Build Interference Graph + IFG.build(round,this) && // If no self conflicts or uncolorable + // Conservative coalesce copies + Coalesce.coalesce(round,this) && + // Color attempt + IFG.color(round,this); // If colorable + } + + // ----------------------- + // Split conflicted live ranges. + void split(byte round) { + + // In C2, all splits are handling in one pass over the program. Here, + // in the name of clarity, we'll handle each failing live range + // independently... which generally requires a full pass over the + // program for each failing live range. i.e., might be a lot of + // passes. + + // Sort, to avoid non-deterministic HashMap ordering + LRG[] splits = _failed.keySet().toArray(new LRG[0]); + Arrays.sort(splits, (x,y) -> x._lrg - y._lrg ); + for( LRG lrg : splits ) + split(round,lrg); + } + + // Split this live range, top level heuristic + boolean split( byte round, LRG lrg ) { + assert lrg.leader(); // Already rolled up + + if( lrg._selfConflicts != null ) + return splitSelfConflict(round,lrg); + + // Register mask when empty; split around defs and uses with limited + // register masks. + if( lrg._mask.isEmpty() && (!lrg._multiDef || lrg._1regUseCnt==1) ) { + if( lrg._1regDefCnt <= 1 && + lrg._1regUseCnt <= 1 && + (lrg._1regDefCnt + lrg._1regUseCnt) > 0 ) + return splitEmptyMaskSimple(round,lrg); + // Repeated single-reg uses from a single def. Special for archs + // with more fixed regs. + if( !lrg._multiDef && lrg._1regDefCnt <= 1 && lrg._1regUseCnt > 2 ) + if( splitEmptyMaskByUse(round,lrg) ) + return true; + } + + // Generic split-by-loop depth. + return splitByLoop(round,lrg); + } + + // Split live range with an empty mask. Specifically forces splits at + // single-register defs or uses and not elsewhere. + boolean splitEmptyMaskSimple( byte round, LRG lrg ) { + // Live range has a single-def single-register, and/or a single-use + // single-register. Split after the def and before the use. Does not + // require a full pass. + + // Split just after def + if( lrg._1regDefCnt==1 && !lrg._machDef.isClone() ) + // Force must-split, even if a prior split same block because register + // conflicts. Example: + // alloc + // V1/rax - forced by alloc + // alloc + // V2/rax - kills prior RAX + // st4 [V1],len - No good, must split around + insertAfterAndReplace( makeSplit("def/empty1",round,lrg), (Node)lrg._machDef, false/*true*/); + // Split just before use + if( lrg._1regUseCnt==1 || (lrg._1regDefCnt==1 && ((Node)lrg._machDef).nOuts()==1) ) + insertBefore((Node)lrg._machUse,lrg._uidx,"use/empty1",round,lrg); + return true; + } + + // Single-def live range with an empty mask. There are many single-reg + // uses. Theory is there's many repeats of the same reg amongst the uses. + // In of splitting once per use, start by splitting into groups based on + // required input register. + boolean splitEmptyMaskByUse( byte round, LRG lrg ) { + Node def = (Node)lrg._machDef; + + // Look at each use, and break into non-overlapping register classes. + Ary<RegMask> rclass = new Ary<>(RegMask.class); + boolean done=false; + int ncalls=0; + while( !done ) { + done = true; + for( Node use : def._outputs ) + if( use instanceof MachNode mach ) { + if( mach instanceof CallNode ) ncalls++; + for( int i=1; i<use.nIns(); i++ ) + if( use.in(i)==def ) + done = putIntoRegClass( rclass, mach.regmap(i) ); + } + } + + // See how many register classes we split into. Generally not + // productive to split like this across calls, which are going to kill + // all registers anyways. + if( rclass._len <= 1 || ncalls > 1 ) return false; + + // Split by class + Ary<Node> ns = new Ary<>(Node.class); + for( RegMask rmask : rclass ) { + ns.addAll(def._outputs); + Node split = makeSplit(def,"popular",round,lrg,rmask); + split.insertAfter( def ); + if( split.nIns()>1 ) split.setDef(1,def); + // all uses by class to split + for( int j=0; j < def._outputs._len; j++ ) { + Node use = def._outputs.at(j); + if( use instanceof MachNode mach && use!=split ) { + // Check all use inputs for n, in case there's several + for( int i = 1; i < use.nIns(); i++ ) + // Find a def input, and check register class + if( use.in( i ) == def && mach.regmap( i ).overlap( rmask ) ) { + RegMask m = mach.regmap( i ); + if( m!=null && mach.regmap( i ).overlap( rmask ) ) + // Modify use to use the split version specialized to this rclass + { use.setDefOrdered( i, split ); j--; break; } + } + } + } + ns.clear(); + } + return true; + } + + + // Put use into a register class, perhaps adding a class or perhaps + // narrowing a class (and causing a repeat) + private static boolean putIntoRegClass( Ary<RegMask> rclass, RegMask rmask ) { + for( int i=0; i<rclass._len; i++ ) { + RegMask omask = rclass.at(i); + if( omask.and(rmask) == omask ) return true; // Within the same register class + if( omask.overlap(rmask) ) { + rclass.set(i,new RegMask(omask.copy().and(rmask))); + return false; // Need go again + } + } + // Add a new class, no need to go again + rclass.push(rmask); + return true; + } + + // Self conflicts require Phis (or two-address). + // Insert a split after every def. + boolean splitSelfConflict( byte round, LRG lrg ) { + // Sort conflict set, so we're deterministic + Node[] conflicts = lrg._selfConflicts.keySet().toArray(new Node[0]); + Arrays.sort(conflicts, (x,y) -> x._nid - y._nid ); + + // For all conflicts + for( Node def : conflicts ) { + assert lrg(def)==lrg; // Might be conflict use-side + // Split before each use that extends the live range; i.e. is a + // Phi or two-address + for( int i=0; i<def._outputs._len; i++ ) { + Node use = def.out(i); + if( (use instanceof PhiNode phi && + !(phi.region() instanceof LoopNode loop && phi.in(2)==def && def.cfg0().idepth() > loop.idepth() ) ) || + (use instanceof MachNode mach && mach.twoAddress()!=0 && use.in(mach.twoAddress())==def) ) + insertBefore( use, use._inputs.find(def), "use/self/use",round,lrg ); + } + // Split after the Phi which extends the LRG. Split also before + // Phi slot 1 (and not all inputs), because Phis extend the live range. + // TODO: split before all inputs (except the last; at least 1 split here must be extra) + if( def instanceof PhiNode phi && !(def instanceof ParmNode) ) { + SplitNode split = makeSplit("def/self",round,lrg); + insertAfterAndReplace(split,def,false); + if( split.nOuts()==0 ) + split.killOrdered(); + insertBefore(phi,1,"use/self/phi",round,lrg); + } + // Split before two-address ops which extend the live range + if( def instanceof MachNode mach && mach.twoAddress()!= 0 ) + insertBefore(def,mach.twoAddress(),"use/self/two",round,lrg); + } + return true; + } + + + // Generic: split around the outermost loop with non-split def/uses. This + // covers both self-conflicts (once we split deep enough) and register + // pressure issues. + boolean splitByLoop( byte round, LRG lrg ) { + findAllLRG(lrg); + + // Find min loop depth for all non-split defs and uses. + long ld = (-1L<<32) | 9999; + for( Node n : _ns ) { + if( lrg(n)==lrg ) // This is a LRG def + ld = ldepth(ld,n,n.cfg0()); + // PhiNodes check all CFG inputs + if( n instanceof PhiNode phi ) { + for( int i=1; i<n.nIns(); i++ ) + ld = ldepth(ld, phi.in(i), phi.region().cfg(i)); + } else { + // Others check uses + for( int i=1; i<n.nIns(); i++ ) + if( lrgSame(n.in(i),lrg) ) // This is a LRG use + ld = ldepth(ld,n,n.cfg0()); + } + } + int min = (int)ld; + int max = (int)(ld>>32); + + + // If the minLoopDepth is less than the maxLoopDepth: for-all defs and + // uses, if at minLoopDepth or lower, split after def and before use. + for( Node n : _ns ) { + if( n instanceof SplitNode && min!=max ) continue; // Ignoring splits; since spilling need to split in a deeper loop + if( n.isDead() ) continue; // Some Cloneable went dead by other spill changes + // If this is a 2-address commutable op (e.g. AddX86, MulX86) and the rhs has only a single user, + // commute the inputs... which chops the LHS live ranges' upper bound to just the RHS. + if( n instanceof MachNode mach && lrg(n)==lrg && mach.twoAddress()==1 && mach.commutes() && n.in(2).nOuts()==1 ) + n.swap12(); + + if( lrg(n)==lrg && // This is a LRG def + // At loop boundary, or splitting in inner loop + (min==max || n.cfg0().loopDepth() <= min) ) { + // Cloneable constants will be cloned at uses, not after def + if( !(n instanceof MachNode mach && mach.isClone()) && + // Single user is already a split adjacent + !(n.nOuts()==1 && n.out(0) instanceof SplitNode split && sameBlockNoClobber(split) ) ) + // Split after def in min loop nest + insertAfterAndReplace( makeSplit("def/loop",round,lrg), n,true); + } + + // PhiNodes check all CFG inputs + if( n instanceof PhiNode phi && !(n instanceof ParmNode)) { + for( int i=1; i<n.nIns(); i++ ) + // No split in front of a split + if( !(n.in(i) instanceof SplitNode) && + // splitting in inner loop or at loop border + (min==max || phi.region().cfg(i).loopDepth() <= min) && + // and not around the backedge of a loop (bad place to force a split, hard to remove) + !(phi.region() instanceof LoopNode && i==2 && (phi.in(i) instanceof PhiNode pp && pp.region()==phi.region())) ) + // Split before phi-use in prior block + insertBefore(phi,i, "use/loop/phi",round,lrg); + + } else { + // Others check uses + for( int i=1; i<n.nIns(); i++ ) { + // This is a LRG use + // splitting in inner loop or at loop border + if( lrgSame( n.in( i ), lrg ) && + (min == max || (n.in(i) instanceof MachNode mach && mach.isClone()) || n.cfg0().loopDepth() <= min) ) + // Split before in this block + insertBefore( n, i, "use/loop/use", round,lrg, false ); + } + } + } + return true; + } + + private boolean lrgSame(Node x, LRG lrg) { + LRG xlrg = lrg(x); + while( xlrg==null && x instanceof SplitNode ) + xlrg=lrg(x = x.in(1)); + return xlrg==lrg; + } + + private static long ldepth( long ld, Node n, CFGNode cfg ) { + // Do not count splits + if( n instanceof SplitNode ) return ld; + // Collect min/max loop depth + int min = (int)ld; + int max = (int)(ld>>32); + int d = cfg.loopDepth(); + // if n will lower the min loop and is in the tail end of the loop + // header, splitting "around" the loop will not help. Treat n as being + // in the loop. + if( d < min ) { + if( cfg.uctrl() instanceof LoopNode loop && loop.entry()==cfg ) { + for( int i=cfg.nOuts()-2; i>=0; i-- ) { + Node out = cfg.out(i); + if( n==out ) + { d = loop.loopDepth(); break; } // Treat n as being "in the loop" + if( !((out instanceof MachNode mach && mach.isClone()) || out instanceof SplitNode ) ) + break; // Treat b as "normal", out of loop + } + } + } + + // lower min, raise max, and re-fold + min = Math.min(min,d); + max = Math.max(max,d); + return ((long)max<<32) | min; + } + + // Find all members of a live range, both defs and uses + private final Ary<Node> _ns = new Ary<>(Node.class); + void findAllLRG( LRG lrg ) { + _ns.clear(); + int wd = 0; + _ns.push((Node)lrg._machDef); + _ns.push((Node)lrg._machUse); + while( wd < _ns._len ) { + Node n = _ns.at(wd++); + if( lrg(n)!=lrg ) continue; + for( Node def : n._inputs ) + if( lrg(def)==lrg && _ns.find(def)== -1 ) + _ns.push(def); + for( Node use : n._outputs ) + if( _ns.find(use)== -1 ) + _ns.push(use); + } + for( Node n : _ns ) assert !n.isDead(); + } + + void insertBefore(Node n, int i, String kind, byte round, LRG lrg, boolean skip) { + Node def = n.in(i); + // Effective block for use + CFGNode cfg = n instanceof PhiNode phi ? phi.region().cfg(i) : n.cfg0(); + // Use-side RegMask, if available + RegMask umask = n instanceof MachNode mach ? mach.regmap(i) : null; + // Def is a split ? + if( skip && def instanceof SplitNode ) { + boolean singleReg = umask!=null && umask.size1(); + // Same block, multiple registers, split is only used by n, + // assume this is good enough and do not split again. + if( cfg==def.cfg0() && def.nOuts()==1 && !singleReg ) + return; + } + makeSplit(def,kind,round,lrg,umask).insertBefore(n, i); + // Skip split-of-split same block + if( skip && def instanceof SplitNode && cfg==def.cfg0() ) + n.in(i).setDefOrdered(1,def.in(1)); + } + void insertBefore(Node n, int i, String kind, byte round, LRG lrg) { + insertBefore(n,i,kind,round,lrg,true); + } + + // Replace uses of `def` with `split`, and insert `split` immediately after + // `def` in the basic block. + public void insertAfterAndReplace( Node split, Node def, boolean must ) { + split.insertAfter(def); + if( split.nIns()>1 ) split.setDef(1,def); + for( int j=def.nOuts()-1; j>=0; j-- ) { + Node use = def.out(j); + if( use==split ) continue; // Skip self + // Can we avoid a split of a split? 'this' split is used by + // another split in the same block. + if( !must && use instanceof SplitNode split2 && sameBlockNoClobber(split2) ) + continue; + int idx = use._inputs.find(def); + use.setDefOrdered(idx,split); + if( j < def.nOuts() ) j++; + } + } + + private Node makeSplit( Node def, String kind, byte round, LRG lrg, RegMask umask ) { + // Clone simple constants if possible + Node split = def instanceof MachNode mach && mach.isClone() && (umask==null || mach.outregmap().overlap(umask)) + ? mach.copy() + : _code._mach.split(kind,round,lrg); + _lrgs.put(split,lrg); + return split; + } + private SplitNode makeSplit( String kind, byte round, LRG lrg ) { + SplitNode split = _code._mach.split(kind,round,lrg); + _lrgs.put(split,lrg); + return split; + } + + + // ----------------------- + // POST PASS: Remove empty spills that biased-coloring made + private void postColor() { + int maxReg = -1; + for( CFGNode bb : _code._cfg ) { // For all ops + if( bb instanceof FunNode ) + maxReg = -1; // Reset for new function + // Compute frame size, based on arguments and largest reg seen + if( bb instanceof ReturnNode ret ) + ret.fun().computeFrameAdjust(_code,maxReg); + // Raise frame size by max stack args passed, even if ignored + if( bb instanceof CallEndMach cend ) + maxReg = Math.max(maxReg,cend._xslot); + + for( int j=0; j<bb.nOuts(); j++ ) { + Node n = bb.out(j); + if( lrg(n)!=null ) + maxReg = Math.max(maxReg,lrg(n)._reg+1); + // Raise frame size by max stack args passed to New + if( n instanceof NewNode nnn ) + maxReg = Math.max(maxReg,nnn._xslot); + + if( !(n instanceof SplitNode ) ) continue; + int defreg = lrg(n )._reg; + int usereg = lrg(n.in(1))._reg; + // Attempt to bypass split + if( defreg != usereg && splitBypass(bb,j,n,defreg) ) + usereg = lrg(n.in(1))._reg; + + // Split has same reg? Useless! Can remove it! + if( defreg == usereg ) { + n.removeSplit(); + j--; + continue; + } + // Split is kept; count against split score + _spills++; + _spillScaled += (1<<bb.loopDepth()*3); + assert _spillScaled >= 0; + } + } + } + + private boolean splitBypass( CFGNode bb, int j, Node lo, int defreg ) { + // Attempt to bypass split + Node hi = lo.in(1); + while( true ) { + if( !(hi instanceof SplitNode && lo.cfg0() == hi.cfg0()) ) + return false; + if( lrg(hi.in(1))._reg==defreg ) + break; + hi = hi.in(1); + } + // Check no clobbers + for( int idx = j-1; bb.out(idx) != hi; idx++) { + Node n = bb.out(idx); + if( lrg(n)!=null && lrg(n)._reg == defreg ) + return false; // Clobbered + } + lo.setDefOrdered(1,hi.in(1)); + return true; + } + + + public boolean sameBlockNoClobber( SplitNode split ) { + Node def = split.in(1); + CFGNode cfg = def.cfg0(); + if( cfg != split.cfg0() ) return false; // Not same block + // Get multinode head + Node def0 = def instanceof ProjNode ? def.in(0) : def; + int defreg = lrg(def)._reg; + if( defreg == -1 ) defreg = lrg(def)._mask.firstReg(); + if( defreg == -1 ) return false; // no allowed registers -> clobbered + for( int idx = cfg._outputs.find(split) -1; idx >= 0; idx-- ) { + Node n = cfg.out(idx); + if( n==def0 ) return true; // No clobbers + if( lrg(n) == lrg(def) ) return false; // Self conflict + if( lrg(n)!=null && lrg(n)._reg == defreg ) + return false; // Clobbered + } + throw Utils.TODO(); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/RegMask.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/RegMask.java new file mode 100644 index 00000000..c7dda1da --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/RegMask.java @@ -0,0 +1,126 @@ +package com.seaofnodes.simple.codegen; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +/** RegMask + * A "register mask" - 1 bit set for each allowed register. In addition, + * "stack slot" registers may be allowed, effectively making the set infinite. + * <p> + * For smaller and simpler machines it suffices to make such masks an i64 or + * i128 (64- or 128-bit integers), and this presentation is by far the better + * way to go... if all register allocations can fit in this bit limitation. + * The allocator will need bits for stack-based parameters and for splits + * which cannot get a register. For a 32-register machine like the X86, add 1 + * for flags - gives 33 registers. Using a Java `long` has 64 bits, leaving + * 31 for spills and stack passing. This is adequate for nearly all + * allocations; only the largest allocations will run this out. However, if + * we move to a chip with 64 registers we'll immediately run out, and need at + * least a 128 bit mask. Since you cannot *return* a 128 bit value directly + * in Java, Simple will pick up a `RegMask` class object. +*/ +public class RegMask { + + long _bits0, _bits1; + + private static final RegMask EMPTY = new RegMask(0L); + public static final RegMask FULL = new RegMask(-1L); + + public RegMask(int bit) { + if( bit < 64 ) _bits0 = 1L<<bit; + else _bits1 = 1L<<(bit-64); + } + public RegMask(long bits ) { _bits0 = bits; } + public RegMask(long bits0, long bits1 ) { _bits0 = bits0; _bits1 = bits1; } + public RegMask(RegMask r) { _bits0 = r._bits0; _bits1 = r._bits1; } + private RegMask() { _bits0 = _bits1 = 0; } + + // AND, with copy-on-write if changing + RegMask and( RegMask mask ) { + if( mask==null ) return this; + long bits0 = _bits0 & mask._bits0; + long bits1 = _bits1 & mask._bits1; + if( bits0==_bits0 && bits1==_bits1 ) return this; + if( bits0==mask._bits0 && bits1==mask._bits1 ) return mask; + if( bits0==0 && bits1==0 ) return EMPTY; + // Update-in-place a mutable mask, or make a defensive copy + return null; + } + RegMask sub( RegMask mask ) { + if( mask==null ) return this; + long bits0 = _bits0 & ~mask._bits0; + long bits1 = _bits1 & ~mask._bits1; + if( bits0==_bits0 && bits1==_bits1 ) return this; + if( bits0==mask._bits0 && bits1==mask._bits1 ) return mask; + if( bits0==0 && bits1==0 ) return EMPTY; + // Update-in-place a mutable mask, or make a defensive copy + return null; + } + + // Fails if bit is set, because this is immutable + public boolean clr( int reg ) { + if( reg < 64 ) return ((_bits0 >> reg)&1)==0; + if( reg < 128 ) return ((_bits1 >> reg)&1)==0; + return true; + } + + + public short firstReg() { + if( isEmpty() ) return -1; + return (short)(_bits0 != 0 + ? Long.numberOfTrailingZeros(_bits0) + : Long.numberOfTrailingZeros(_bits1)+64); + } + public short nextReg(short reg) { + if( reg<64 ) { + long bits0 = _bits0 >> (reg+1); + if( bits0!=0 ) + return (short)(reg+1+Long.numberOfTrailingZeros(bits0)); + reg=64; + } + long bits1 = _bits1 >> (reg-64+1); + if( bits1!=0 ) + return (short)(reg+1+Long.numberOfTrailingZeros(bits1)); + return -1; + } + + boolean isEmpty() { return _bits0==0 && _bits1==0; } + + public boolean test( int reg ) { + return ((reg<64 ? (_bits0 >> reg) : (_bits1 >> (reg-64))) & 1) != 0; + } + + // checks if the 2 masks have at least 1 bit in common + public boolean overlap( RegMask mask ) { return (_bits0 & mask._bits0)!=0 || (_bits1 & mask._bits1)!=0; } + + // Defensive writable copy + public RegMaskRW copy() { return new RegMaskRW( _bits0, _bits1 ); } + + // Has exactly 1 bit set + public boolean size1() { + return ((_bits0 & -_bits0)==_bits0 && _bits1==0) || + ((_bits1 & -_bits1)==_bits1 && _bits0==0); + } + + // Cardinality + public short size() { return (short)(Long.bitCount(_bits0)+Long.bitCount(_bits1)); } + + @Override public String toString() { return toString(new SB()).toString(); } + public SB toString(SB sb) { + Machine mach = CodeGen.CODE._mach; + if( _bits0==0 && _bits1==0 ) return sb.p("[]"); + sb.p("["); + String[] regs = mach.regs(); + for( int i=0; i<64; i++ ) + if( ((_bits0 >> i)&1) != 0 ) + sb.p(reg(regs,i)).p(","); + for( int i=0; i<64; i++ ) + if( ((_bits1 >> i)&1) != 0 ) + sb.p(reg(regs,i+64)).p(","); + return sb.unchar().p("]"); + } + + public static String reg(String[] regs, int i) { + return i<regs.length ? regs[i] : "[stk#"+i+"]"; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/RegMaskRW.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/RegMaskRW.java new file mode 100644 index 00000000..1da9a3b1 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/RegMaskRW.java @@ -0,0 +1,36 @@ +package com.seaofnodes.simple.codegen; + +// Mutable regmask(writable) +public class RegMaskRW extends RegMask { + public RegMaskRW(long x, long y) { super(x,y); } + // clears bit at position r. Returns true if the mask is still not empty. + public boolean clr(int r) { + if( r < 64 ) _bits0 &= ~(1L<<(r )); + else _bits1 &= ~(1L<<(r-64)); + return _bits0!=0 || _bits1!=0; + } + // sets bit at position r. + public void set(int r) { + if( r < 64 ) _bits0 |= (1L<<(r )); + else _bits1 |= (1L<<(r-64)); + } + @Override RegMaskRW and( RegMask mask ) { + if( mask==null ) return this; + _bits0 &= mask._bits0; + _bits1 &= mask._bits1; + return this; + } + @Override RegMaskRW sub( RegMask mask ) { + if( mask==null ) return this; + _bits0 &= ~mask._bits0; + _bits1 &= ~mask._bits1; + return this; + } + public RegMaskRW or( RegMask mask ) { + if( mask!=null ) { + _bits0 |= mask._bits0; + _bits1 |= mask._bits1; + } + return this; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/AddFNode.java new file mode 100644 index 00000000..792da62e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/AddFNode.java @@ -0,0 +1,44 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; + +import java.util.BitSet; + +public class AddFNode extends Node { + public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "AddF"; } + + @Override public String glabel() { return "+"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("("), visited); + in(2)._print0(sb.append("+"), visited); + return sb.append(")"); + } + + @Override + public Type compute() { + if (in(1)._type instanceof TypeFloat i0 && + in(2)._type instanceof TypeFloat i1) { + if (i0.isConstant() && i1.isConstant()) + return TypeFloat.constant(i0.value()+i1.value()); + } + return in(1)._type.meet(in(2)._type); + } + + @Override + public Node idealize() { + Node lhs = in(1); + Type t2 = in(2)._type; + + // Add of 0. + if ( t2.isConstant() && t2 instanceof TypeFloat i && i.value()==0 ) + return lhs; + + return null; + } + @Override Node copy(Node lhs, Node rhs) { return new AddFNode(lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/AddNode.java new file mode 100644 index 00000000..c5ba14de --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/AddNode.java @@ -0,0 +1,169 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.*; + +import static com.seaofnodes.simple.Parser.con; + +public class AddNode extends ArithNode { + public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "Add"; } + @Override public String op() { return "+"; } + + @Override long doOp( long x, long y ) { return x + y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + // Fold ranges like {0-1} + {2-3} into {2-4}. + if( !overflow(x._min,y._min) && + !overflow(x._max,y._max) ) + return TypeInteger.make(x._min+y._min,x._max+y._max); + return TypeInteger.BOT; + } + + @Override + public Node idealize () { + Node lhs = in(1); + Node rhs = in(2); + if( rhs instanceof AddNode add && add.err()!=null ) + return null; + Type t2 = rhs._type; + + // Add of 0. We do not check for (0+x) because this will already + // canonicalize to (x+0) + if( t2 == TypeInteger.ZERO ) + return lhs; + + // Add of same to a multiply by 2 + if( lhs==rhs ) + return new ShlNode(null,lhs,con(1)); + + // Goal: a left-spine set of adds, with constants on the rhs (which then fold). + + // Move non-adds to RHS + if( !(lhs instanceof AddNode) && rhs instanceof AddNode ) + return swap12(); + + // x+(-y) becomes x-y + if( rhs instanceof MinusNode minus ) + return new SubNode(lhs,minus.in(1)); + + // Now we might see (add add non) or (add non non) or (add add add) but never (add non add) + + // Do we have x + (y + z) ? + // Swap to (x + y) + z + // Rotate (add add add) to remove the add on RHS + if( rhs instanceof AddNode add ) + return new AddNode(new AddNode(lhs,add.in(1)).peephole(), add.in(2)); + + // Now we might see (add add non) or (add non non) but never (add non add) nor (add add add) + if( !(lhs instanceof AddNode) ) + // Rotate; look for (add (phi cons) con/(phi cons)) + return spine_cmp(lhs,rhs,this) ? swap12() : phiCon(this,true); + + // Now we only see (add add non) + + // Dead data cycle; comes about from dead infinite loops. Do nothing, + // the loop will peep as dead after a bit. + if( lhs.in(1) == lhs ) + return null; + + // Do we have (x + con1) + con2? + // Replace with (x + (con1+con2) which then fold the constants + // lhs.in(2) is con1 here + // If lhs.in(2) is not a constant, we add ourselves as a dependency + // because if it later became a constant then we could make this + // transformation. + if( addDep(lhs.in(2))._type.isConstant() && rhs._type.isConstant() ) + return new AddNode(lhs.in(1),new AddNode(lhs.in(2),rhs).peephole()); + + + // Do we have ((x + (phi cons)) + con) ? + // Do we have ((x + (phi cons)) + (phi cons)) ? + // Push constant up through the phi: x + (phi con0+con0 con1+con1...) + Node phicon = phiCon(this,true); + if( phicon!=null ) return phicon; + + // Now we sort along the spine via rotates, to gather similar things together. + + // Do we rotate (x + y) + z + // into (x + z) + y ? + if( spine_cmp(lhs.in(2),rhs,this) ) + return new AddNode(new AddNode(lhs.in(1),rhs).peephole(),lhs.in(2)); + + return super.idealize(); + } + + // Rotation is only valid for associative ops, e.g. Add, Mul, And, Or, Xor. + // Do we have ((phi cons)|(x + (phi cons)) + con|(phi cons)) ? + // Push constant up through the phi: x + (phi con0+con0 con1+con1...) + static Node phiCon(Node op, boolean rotate) { + Node lhs = op.in(1); + Node rhs = op.in(2); + if( rhs._type==TypeInteger.TOP ) return null; + // LHS is either a Phi of constants, or another op with Phi of constants + PhiNode lphi = pcon(lhs,op); + if( rotate && lphi==null && lhs.nIns() > 2 ) { + // Only valid to rotate constants if both are same associative ops + if( lhs.getClass() != op.getClass() ) return null; + lphi = pcon(lhs.in(2),op); // Will rotate with the Phi push + } + if( lphi==null ) return null; + if( lphi.region().nIns() <=2 ) return null; // Phi is collapsing + + // RHS is a constant or a Phi of constants + if( !(rhs instanceof ConstantNode) && pcon(rhs,op)==null ) + return null; + + // If both are Phis, must be same Region + if( rhs instanceof PhiNode && lphi.in(0) != rhs.in(0) ) + return null; + + // Note that this is the exact reverse of Phi pulling a common op down + // to reduce total op-count. We don't get in an endless push-up + // push-down peephole cycle because the constants all fold first. + Node[] ns = new Node[lphi.nIns()]; + ns[0] = lphi.in(0); + // Push constant up through the phi: x + (phi con0+con0 con1+con1...) + for( int i=1; i<ns.length; i++ ) + ns[i] = op.copy(lphi.in(i), rhs instanceof PhiNode ? rhs.in(i) : rhs).peephole(); + String label = lphi._label + (rhs instanceof PhiNode rphi ? rphi._label : ""); + Node phi = new PhiNode(label,lphi._minType.meet(op._type),ns).peephole(); + // Rotate needs another op, otherwise just the phi + return lhs==lphi ? phi : op.copy(lhs.in(1),phi); + } + + /** + * Tests if the op is a phi and has all constant inputs. + * If not, returns null. + * If op is a phi, but its inputs are not all constants, then dep is added as + * a dependency to the phi's non-const input, because if later the input turn into a constant + * dep can make progress. + */ + static PhiNode pcon(Node op, Node dep) { + return op instanceof PhiNode phi && phi.allCons(dep) ? phi : null; + } + + // Compare two off-spine nodes and decide what order they should be in. + // Do we rotate ((x + hi) + lo) into ((x + lo) + hi) ? + // Generally constants always go right, then Phi-of-constants, then muls, then others. + // Ties with in a category sort by node ID. + // TRUE if swapping hi and lo. + static boolean spine_cmp( Node hi, Node lo, Node dep ) { + if( lo._type.isConstant() || lo instanceof ConFldOffNode ) return false; + if( hi._type.isConstant() || hi instanceof ConFldOffNode ) return true ; + + if( lo instanceof PhiNode lphi && lphi.region()._type==Type.XCONTROL ) return false; + if( hi instanceof PhiNode hphi && hphi.region()._type==Type.XCONTROL ) return false; + + if( lo instanceof PhiNode && lo.allCons(dep) ) return false; + if( hi instanceof PhiNode && hi.allCons(dep) ) return true ; + + if( lo instanceof PhiNode && !(hi instanceof PhiNode) ) return true; + if( hi instanceof PhiNode && !(lo instanceof PhiNode) ) return false; + + // Same category of "others" + return lo._nid > hi._nid; + } + + @Override Node copy(Node lhs, Node rhs) { return new AddNode(lhs,rhs); } + @Override Node copyF() { return new AddFNode(null,null); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/AndNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/AndNode.java new file mode 100644 index 00000000..70b57d6d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/AndNode.java @@ -0,0 +1,50 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; + +public class AndNode extends ArithNode { + public AndNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } + + @Override public String label() { return "And"; } + @Override public String op() { return "&"; } + @Override public String glabel() { return "&"; } + + @Override long doOp( long x, long y ) { return x & y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + // Sharpen allowed bits if either value is narrowed + long mask = x.mask() & y.mask(); + return mask < 0 ? TypeInteger.BOT : TypeInteger.make(0,mask); + } + + @Override + public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + if( !(t1 instanceof TypeInteger && t2 instanceof TypeInteger t2i) ) + return null; // Malformed, e.g. (17 & 3.14) + + // And of -1. We do not check for (-1&x) because this will already + // canonicalize to (x&-1). We do not check for zero, because + // the compute() call will return a zero already. + if( t2i.isConstant() && t2i.value()==-1 ) + return lhs; + + // Move constants to RHS: con*arg becomes arg*con + if( t1.isConstant() && !t2.isConstant() ) + return swap12(); + + // Do we have ((x & (phi cons)) & con) ? + // Do we have ((x & (phi cons)) & (phi cons)) ? + // Push constant up through the phi: x & (phi con0&con0 con1&con1...) + Node phicon = AddNode.phiCon(this,true); + if( phicon!=null ) + return phicon; + + return super.idealize(); + } + @Override Node copy(Node lhs, Node rhs) { return new AndNode(_loc,lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ArithNode.java new file mode 100644 index 00000000..96067c8e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ArithNode.java @@ -0,0 +1,101 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; + +import java.util.BitSet; + +public abstract class ArithNode extends Node { + // Source location for late reported errors + Parser.Lexer _loc; + + public ArithNode( Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; } + @Override public String glabel() { return op(); } + abstract String op(); + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("("), visited); + in(2)._print0(sb.append(op()), visited); + return sb.append(")"); + } + + abstract long doOp(long x, long y); + abstract TypeInteger doOp(TypeInteger x, TypeInteger y); + + // Generic airthmetic op math: high returns high; low returns low; 2 + // constants fold; only 2 non-constants call specialized math. + @Override + public final TypeInteger compute() { + Type t1 = in(1)._type, t2 = in(2)._type; + if( t1.isHigh() || t2.isHigh() ) + return TypeInteger.TOP; + if( t1 instanceof TypeInteger x && + t2 instanceof TypeInteger y ) + return x.isConstant() && y.isConstant() + ? con(x,y) + : doOp(x,y); + return TypeInteger.BOT; + } + + private TypeInteger con( Type t1, Type t2 ) { + return TypeInteger.constant( doOp( ((TypeInteger)t1).value(), ((TypeInteger)t2).value()) ); + } + + // Check for "op(Phi(con,x),Phi(con,y))" and push-up through the Phi. + // Note that this is the exact reverse of Phi pulling a common op down + // to reduce total op-count. We don't get in an endless push-up + // push-down peephole cycle because the constants all fold first. + // Returns "Phi(op(con,con),op(x,y))". + + // This check is slightly different from the + + // Expected to be called after other ideal checks are done. + @Override public Node idealize() { + if( in(1) instanceof PhiNode lhs && + in(2) instanceof PhiNode rhs && + lhs.nIns() >= 2 && !lhs.inProgress() && + lhs.region()==rhs.region() && + lhs.nIns()>2 && // A 1-input Phi will collapse already + // Disallow with self-looping phi; these will collapse + (lhs.in(2)!=lhs && rhs.in(2)!=rhs) ) { + // Profit check: only 1 instance of `this` will remain, all the + // others will fold to constants. + int cnt=0; + for( int i=1; i<lhs.nIns(); i++ ) + if( isCon(lhs,rhs,i) ) + cnt++; + if( lhs.nIns()-1 - cnt <= 1 ) { + // Profit! Push up-phi and fold + Node[] ns = new Node[lhs.nIns()]; + ns[0] = lhs.in(0); + for( int i=1; i<lhs.nIns(); i++ ) { + ns[i] = isCon(lhs,rhs,i) + ? new ConstantNode(con(lhs.in(i)._type, rhs.in(i)._type)).peephole() + : copy(lhs.in(i), rhs.in(i)).peephole(); + } + String label = lhs._label==rhs._label ? lhs._label : lhs._label + rhs._label; + return new PhiNode(label,lhs._minType,ns).peephole(); + } + } + return null; + } + + static boolean isCon( PhiNode lhs, PhiNode rhs, int i ) { + return lhs.in(i)._type.isConstant() && rhs.in(i)._type.isConstant(); + } + + + static boolean overflow( long x, long y ) { + if( (x ^ y ) < 0 ) return false; // unequal signs, never overflow + return (x ^ (x + y)) < 0; // sum has unequal signs, so overflow + } + + @Override public Parser.ParseException err() { + if( in(1)._type.isHigh() || in(2)._type.isHigh() ) return null; + if( !(in(1)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+op()+"' " + in(1)._type,_loc); + if( !(in(2)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+op()+"' " + in(2)._type,_loc); + return null; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/BoolNode.java new file mode 100644 index 00000000..2765c308 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/BoolNode.java @@ -0,0 +1,164 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; +import static com.seaofnodes.simple.type.TypeInteger.*; + +abstract public class BoolNode extends Node { + + public BoolNode(Node lhs, Node rhs) { + super(null, lhs, rhs); + } + + abstract public String op(); // String opcode name + + @Override + public String label() { return getClass().getSimpleName(); } + + @Override + public String glabel() { return op(); } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("("), visited); + in(2)._print0(sb.append(op()), visited); + return sb.append(")"); + } + + @Override + public TypeInteger compute() { + Type t1 = in(1)._type; + Type t2 = in(2)._type; + // Exactly equals? + if( t1.isHigh() || t2.isHigh() ) + return (TypeInteger)BOOL.dual(); + if( in(1)==in(2) ) + // LT fails, both EQ and LE succeed + return this instanceof LT ? FALSE : TRUE; + if( t1 instanceof TypeInteger i1 && + t2 instanceof TypeInteger i2 ) + return doOp(i1,i2); + if( t1 instanceof TypeFloat f1 && + t2 instanceof TypeFloat f2 && + f1.isConstant() && f2.isConstant() ) + return doOp(f1.value(), f2.value()) ? TRUE : FALSE; + return BOOL; + } + + TypeInteger doOp(TypeInteger t1, TypeInteger t2) { throw Utils.TODO(); } + boolean doOp(double lhs, double rhs) { throw Utils.TODO(); } + Node copyF(Node lhs, Node rhs) { return null; } + public boolean isFloat() { return false; } + + @Override + public Node idealize() { + // Compare of same + if( in(1)==in(2) ) + return this instanceof LT ? Parser.ZERO : new ConstantNode(TRUE); + + // Equals pushes constant to the right; 5==X becomes X==5. + if( this instanceof EQ ) { + if( !(in(2) instanceof ConstantNode) ) { + // con==noncon becomes noncon==con + if( in(1) instanceof ConstantNode || in(1)._nid > in(2)._nid ) + // Equals sorts by NID otherwise: non.high == non.low becomes non.low == non.high + return in(1)._type instanceof TypeFloat ? new EQF(in(2),in(1)) : new EQ(in(2),in(1)); + } + // Equals X==0 becomes a !X + if( (in(2)._type == ZERO || in(2)._type == Type.NIL) ) + return new NotNode(in(1)); + } + + // Do we have ((x * (phi cons)) * con) ? + // Do we have ((x * (phi cons)) * (phi cons)) ? + // Push constant up through the phi: x * (phi con0*con0 con1*con1...) + Node phicon = AddNode.phiCon(this,this instanceof EQ); + if( phicon!=null ) return phicon; + + return null; + } + + public static class EQ extends BoolNode { + public EQ(Node lhs, Node rhs) { super(lhs,rhs); } + public String op() { return "=="; } + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { + if( i1==i2 && i1.isConstant() ) return TRUE; + if( i1._max < i2._min || i1._min > i2._max ) return FALSE; + return BOOL; + } + Node copy(Node lhs, Node rhs) { return new EQ(lhs,rhs); } + Node copyF() { return new EQF(null,null); } + } + + public static class NE extends BoolNode { + public NE(Node lhs, Node rhs) { super(lhs,rhs); } + public String op() { return "!="; } + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { + if( i1==i2 && i1.isConstant() ) return TRUE; + if( i1._max < i2._min || i1._min > i2._max ) return FALSE; + return BOOL; + } + Node copy(Node lhs, Node rhs) { return new NE(lhs,rhs); } + Node copyF() { throw Utils.TODO(); } + } + + public static class LT extends BoolNode { + public LT(Node lhs, Node rhs) { super(lhs,rhs); } + public String op() { return "<" ; } + public String glabel() { return "<"; } + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { + if( i1._max < i2._min ) return TRUE; + if( i1._min >= i2._max ) return FALSE; + return BOOL; + } + Node copy(Node lhs, Node rhs) { return new LT(lhs,rhs); } + Node copyF() { return new LTF(null,null); } + } + + public static class LE extends BoolNode { + public LE(Node lhs, Node rhs) { super(lhs,rhs); } + public String op() { return "<="; } + public String glabel() { return "<="; } + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { + if( i1._max <= i2._min ) return TRUE; + if( i1._min > i2._max ) return FALSE; + return BOOL; + } + Node copy(Node lhs, Node rhs) { return new LE(lhs,rhs); } + Node copyF() { return new LEF(null,null); } + } + + public static class EQF extends EQ { + public EQF(Node lhs, Node rhs) { super(lhs,rhs); } + @Override boolean doOp(double lhs, double rhs) { return lhs == rhs; } + @Override public boolean isFloat() { return true; } + @Override Node copy(Node lhs, Node rhs) { return new EQF(lhs,rhs); } + } + public static class LTF extends LT { + public LTF(Node lhs, Node rhs) { super(lhs,rhs); } + @Override boolean doOp(double lhs, double rhs) { return lhs < rhs; } + @Override public boolean isFloat() { return true; } + @Override Node copy(Node lhs, Node rhs) { return new LTF(lhs,rhs); } + } + public static class LEF extends LE { + public LEF(Node lhs, Node rhs) { super(lhs,rhs); } + @Override boolean doOp(double lhs, double rhs) { return lhs <= rhs; } + @Override public boolean isFloat() { return true; } + @Override Node copy(Node lhs, Node rhs) { return new LEF(lhs,rhs); } + } + + // Unsigned less that, for range checks. Not directly user writable. + public static class ULT extends BoolNode { + public ULT(Node lhs, Node rhs) { super(lhs,rhs); } + public String op() { return "u<" ; } + public String glabel() { return "u<"; } + TypeInteger doOp(TypeInteger i1, TypeInteger i2) { + if( Long.compareUnsigned(i1._max,i2._min) < 0 ) return TRUE; + if( Long.compareUnsigned(i1._min,i2._max) >= 0 ) return FALSE; + return BOOL; + } + Node copy(Node lhs, Node rhs) { return new ULT(lhs,rhs); } + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CFGNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CFGNode.java new file mode 100644 index 00000000..b9c70e5f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CFGNode.java @@ -0,0 +1,208 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; +import java.util.HashMap; +import java.util.HashSet; + +/** Control Flow Graph Nodes + * <p> + * CFG nodes have a immediate dominator depth (idepth) and a loop nesting + * depth(loop_depth). + * <p> + * idepth is computed lazily upon first request, and is valid even in the + * Parser, and is used by peepholes during parsing and afterward. + * <p> + * loop_depth is computed after optimization as part of scheduling. + * + * Start - Block head; has constants and trailing Funs + * Region - Block head; has Phis. Includes Fun and Parms. + * CallEnd - Block head; followed by CProj and Proj; also linked RPC Parms + * CProj - Block head + * + * If - Block tail; followed by CProj same block + * Call - Block tail; followed by CallEnd and linked Funs + * New/intrinsic - If followed by CProj: block tail else mid-block; followed by Proj + * + */ +public abstract class CFGNode extends Node { + + public CFGNode(Node... nodes) { super(nodes); } + public CFGNode(CFGNode cfg) { + super(cfg); + if( cfg != null ) { + _idepth = cfg._idepth; + _ltree = cfg._ltree; + _pre = cfg._pre; + } + } + + public CFGNode cfg(int idx) { return (CFGNode)in(idx); } + + // Block head is Start, Region, CProj, but not e.g. If, Return, Stop + public boolean blockHead() { return false; } + + // Get the one control following; error to call with more than one e.g. an + // IfNode or other multi-way branch. + public CFGNode uctrl() { + CFGNode c = null; + for( Node n : _outputs ) + if( n instanceof CFGNode cfg ) + { assert c==null; c = cfg; } + return c; + } + + // Used by the encoding / final BB layout + public CFGNode uctrlSkipEmpty() { + CFGNode x = this, y; + while( x.nOuts() == 1 && (y=x.uctrl())!=null && !(y instanceof CallNode) ) // Skip empty blocks + x = y; + return x; + } + + // ------------------------------------------------------------------------ + /** + * Immediate dominator tree depth, used to approximate a real IDOM during + * parsing where we do not have the whole program, and also peepholes + * change the CFG incrementally. + * <p> + * See {@link <a href="https://en.wikipedia.org/wiki/Dominator_(graph_theory)">...</a>} + */ + public int _idepth; + public int idepth() { + return CodeGen.CODE.validIDepth(_idepth) ? _idepth : (_idepth=CodeGen.CODE.iDepthFrom(idom().idepth())); + } + + // Return the immediate dominator of this Node and compute dom tree depth. + public CFGNode idom(Node dep) { return cfg(0); } + public final CFGNode idom() { return idom(null); } + + // Return the LCA of two idoms + public CFGNode _idom(CFGNode rhs, Node dep) { + if( rhs==null ) return this; + CFGNode lhs = this; + while( lhs != rhs ) { + var comp = lhs.idepth() - rhs.idepth(); + if( comp >= 0 ) lhs = (dep==null ? lhs : dep.addDep(lhs)).idom(); + if( comp <= 0 ) rhs = (dep==null ? rhs : dep.addDep(rhs)).idom(); + if( lhs==null || rhs==null ) return null; + } + return lhs; + } + + // Anti-dependence field support + public int _anti; // Per-CFG field to help find anti-deps + + // Find nearest enclosing FunNode + public FunNode fun() { + CFGNode cfg = this; + while( !(cfg instanceof FunNode fun) ) + cfg = cfg.idom(); + return fun; + } + + // ------------------------------------------------------------------------ + // Loop nesting + public LoopNode loop() { return _ltree._head; } + public int loopDepth() { return _ltree==null ? 0 : _ltree.depth(); } + + public LoopTree _ltree; + public int _pre; // Pre-order numbers for loop tree finding + static class LoopTree { + LoopTree _par; + final LoopNode _head; + int _depth; + LoopTree(LoopNode head) { _head = head; } + @Override public String toString() { return "LOOP"+_head._nid; } + int depth() { + return _depth==0 ? (_par==null ? 0 : (_depth = _par.depth()+1)) : _depth; + } + } + + // ------------------------------------------------------------------------ + // Tag all CFG Nodes with their containing LoopNode; LoopNodes themselves + // also refer to *their* containing LoopNode, as well as have their depth. + // Start is a LoopNode which contains all at depth 1. + public void buildLoopTree(StartNode start, StopNode stop) { + // Unlink all linked calls. This can remove RPC constants which + // shuffled the StartNode outputs so requires a while loop. + boolean done=false; + while(!done) { + done = true; + for( Node use : start._outputs ) + if( use instanceof FunNode fun ) + for( Node c : fun._inputs ) + if( c instanceof CallNode call ) + { call.unlink_all(); done=false; } + } + + _ltree = stop._ltree = Parser.XCTRL._ltree = new LoopTree((StartNode)this); + _bltWalk(2,null,stop, new BitSet()); + } + int _bltWalk( int pre, FunNode fun, StopNode stop, BitSet post ) { + // Pre-walked? + if( _pre!=0 ) return pre; + _pre = pre++; + // Pre-walk + for( Node use : _outputs ) + if( use instanceof CFGNode usecfg && !skip( usecfg ) ) + pre = usecfg._bltWalk( pre, use instanceof FunNode fuse ? fuse : fun, stop, post ); + + // Post-order work: find innermost loop + LoopTree inner = null, ltree; + for( Node use : _outputs ) { + if( !(use instanceof CFGNode usecfg) ) continue; + if( skip(usecfg) ) continue; + if( usecfg._type == Type.XCONTROL || // Do not walk dead control + usecfg._type == TypeTuple.IF_NEITHER ) // Nor dead IFs + continue; + // Child visited but not post-visited? + if( !post.get(usecfg._nid) ) { + // Must be a backedge to a LoopNode then + ltree = usecfg._ltree = new LoopTree((LoopNode)usecfg); + } else { + // Take child's loop choice, which must exist + ltree = usecfg._ltree; + // If falling into a loop, use the target loop's parent instead + if( ltree._head == usecfg ) { + if( ltree._par == null ) + // This loop never had an If test choose to take its + // exit, i.e. it is a no-exit infinite loop. + ltree._par = ltree._head.forceExit(fun,stop)._ltree; + ltree = ltree._par; + } + } + // Sort inner loops. The decision point is some branch far removed + // from either loop head OR either backedge so requires pre-order + // numbers to figure out innermost. + if( inner == null ) { inner = ltree; continue; } + if( inner == ltree ) continue; // No change + LoopTree outer = ltree._head._pre > inner._head._pre ? inner : ltree; + inner = ltree._head._pre > inner._head._pre ? ltree : inner; + inner._par = outer; + } + // Set selected loop + if( inner!=null ) + _ltree = inner; + // Tag as post-walked + post.set(_nid); + return pre; + } + + private boolean skip(CFGNode usecfg) { + // Only walk control users that are alive. + // Do not walk from a Call to linked Fun's. + return usecfg instanceof XCtrlNode || + (this instanceof CallNode && usecfg instanceof FunNode) || + (this instanceof ReturnNode && usecfg instanceof CallEndNode); + } + + + public String label( CFGNode target ) { + return (target instanceof LoopNode ? "LOOP" : "L")+target._nid; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CProjNode.java new file mode 100644 index 00000000..a6e21ea0 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CProjNode.java @@ -0,0 +1,68 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeMem; +import com.seaofnodes.simple.type.TypeTuple; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +public class CProjNode extends CFGNode { + + // Which slice of the incoming multipart value + public int _idx; + + // Debugging label + public String _label; + + public CProjNode(Node ctrl, int idx, String label) { + super(ctrl); + _idx = idx; + _label = label; + } + public CProjNode(CProjNode c) { super(c); _idx = c._idx; _label = c._label; } + + @Override public String label() { return _label; } + + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); } + + @Override public boolean blockHead() { return true; } + + public CFGNode ctrl() { return cfg(0); } + + @Override + public Type compute() { + Type t = ctrl()._type; + return t instanceof TypeTuple tt ? tt._types[_idx] : Type.BOTTOM; + } + + @Override + public Node idealize() { + if( ctrl()._type instanceof TypeTuple tt ) { + if( tt._types[_idx]==Type.XCONTROL ) + return Parser.XCTRL; // We are dead + if( ctrl() instanceof IfNode && tt._types[1-_idx]==Type.XCONTROL ) // Only true for IfNodes + return ctrl().in(0); // We become our input control + } + + // Flip a negating if-test, to remove the not + if( ctrl() instanceof IfNode iff && addDep(iff.pred()) instanceof NotNode not ) + return new CProjNode(new IfNode(iff.ctrl(),not.in(1)).peephole(),1-_idx,_idx==0 ? "False" : "True"); + + // Copy of some other input + return ((MultiNode)ctrl()).pcopy(_idx); + } + + // Only called during basic-block layout, inverts a T/F CProj + public void invert() { + _label = _idx == 0 ? "False" : "True"; + _idx = 1-_idx; + } + + @Override + public boolean eq( Node n ) { return _idx == ((CProjNode)n)._idx; } + + @Override + int hash() { return _idx; } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndMach.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndMach.java new file mode 100644 index 00000000..d26ea33b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndMach.java @@ -0,0 +1,36 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.util.SB; + +public class CallEndMach extends CallEndNode implements MachNode { + public CallEndMach( CallEndNode n ) { super(n); } + // MachNode specifics, shared across all CPUs + public int _xslot; + private RegMask _retMask; + private RegMask _kills; + public void cacheRegs(CodeGen code) { + // Return mask depends on TFP (either GPR or FPR) + _retMask = code._mach.retMask(call().tfp()); + // Kill mask is all caller-saves, and any mirror stack slots for args + // in registers. + RegMaskRW kills = code._callerSave.copy(); + // Start of stack slots + int maxReg = code._mach.regs().length; + // Incoming function arg slots, all low numbered in the RA + int fslot = fun()._maxArgSlot; + // Killed slots for this calls outgoing args + int xslot = code._mach.maxArgSlot(call().tfp()); + _xslot = (maxReg+fslot)+xslot; + for( int i=0; i<xslot; i++ ) + kills.set((maxReg+fslot)+i); + _kills = kills; + } + public String op() { return "cend"; } + public RegMask regmap(int i) { return null; } + public RegMask outregmap() { return null; } + public RegMask outregmap(int idx) { return idx==2 ? _retMask : null; } + public RegMask killmap() { return _kills; } + public void encoding( Encoding enc ) { } + public void asm(CodeGen code, SB sb) { } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndNode.java new file mode 100644 index 00000000..d95af697 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndNode.java @@ -0,0 +1,113 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.type.*; +import java.util.BitSet; + +/** + * CallEnd + */ +public class CallEndNode extends CFGNode implements MultiNode { + + // When set true, this Call/CallEnd/Fun/Return is being trivially inlined + private boolean _folding; + public final TypeRPC _rpc; + + public CallEndNode(CallNode call) { super(new Node[]{call}); _rpc = TypeRPC.constant(_nid); } + public CallEndNode(CallEndNode cend) { super(cend); _rpc = cend._rpc; } + + @Override public String label() { return "CallEnd"; } + @Override public boolean blockHead() { return true; } + + public CallNode call() { return (CallNode)in(0); } + + @Override public CFGNode idom(Node dep) { + // Folding the idom is the one inlining Return + return _folding ? cfg(1) : super.idom(dep); + } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + sb.append("cend( "); + sb.append( in(0) instanceof CallNode ? "Call, " : "----, "); + for( int i=1; i<nIns()-1; i++ ) + in(i)._print0(sb,visited).append(","); + sb.setLength(sb.length()-1); + return sb.append(")"); + } + + @Override + public Type compute() { + if( !(in(0) instanceof CallNode call) ) + return TypeTuple.RET.dual(); + Type ret = Type.BOTTOM; + if( addDep(call.fptr())._type instanceof TypeFunPtr tfp ) { + ret = tfp.ret(); + // Here, if I can figure out I've found *all* callers, then I can meet + // across the linked returns and join with the function return type. + if( tfp.isConstant() && nIns()>1 ) { + assert nIns()==2; // Linked exactly once for a constant + ret = ((TypeTuple)in(1)._type).ret(); // Return type + } + } + return TypeTuple.make(call._type,TypeMem.BOT,ret); + } + + @Override + public Node idealize() { + + // Trivial inlining: call site calls a single function; single function + // is only called by this call site. + if( !_folding && nIns()==2 && in(0) instanceof CallNode call ) { + Node fptr = call.fptr(); + if( fptr.nOuts() == 1 && // Only user is this call + fptr instanceof ConstantNode && // We have an immediate call + // Function is being called, and its not-null + fptr._type instanceof TypeFunPtr tfp && tfp.notNull() && + // Arguments are correct + call.err()==null ) { + ReturnNode ret = (ReturnNode)in(1); + FunNode fun = ret.fun(); + // Expecting Start, and the Call + if( fun.nIns()==3 ) { + assert fun.in(1) instanceof StartNode && fun.in(2)==call; + // Disallow self-recursive inlining (loop unrolling by another name) + CFGNode idom = call; + while( !(idom instanceof FunNode) && idom!=null ) + idom = idom.idom(); + // Inline? + if( idom != fun && idom != null ) { + // Trivial inline: rewrite + _folding = true; + // Rewrite Fun so the normal RegionNode ideal collapses + fun._folding = true; + fun.setDef(1,Parser.XCTRL); // No default/unknown StartNode caller + fun.setDef(2,call.ctrl()); // Bypass the Call; + fun.ret().setDef(3,null); // Return is folding also + CodeGen.CODE.addAll(fun._outputs); + // Repeat defs 1 layer down, for users of Parm (Phis) + for( Node parm : fun._outputs ) + if( parm instanceof ParmNode ) + CodeGen.CODE.addAll(parm._outputs); + + // Inlining immediately blows all cache idepth fields past the inline point. + // Bump the global version number invalidating them en-masse. + CodeGen.CODE.invalidateIDepthCaches(); + return this; + } + } else { + addDep(fun); + } + } else { // Function ptr has multiple users (so maybe multiple call sites) + addDep(fptr); + } + } + + return null; + } + + @Override public Node pcopy(int idx) { + return _folding ? in(1).in(idx) : null; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CallNode.java new file mode 100644 index 00000000..ba08c87a --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CallNode.java @@ -0,0 +1,176 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.IterPeeps; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +/** + * Call + */ +public class CallNode extends CFGNode { + + // Source location for late reported errors + public final Parser.Lexer _loc; + + public CallNode(Parser.Lexer loc, Node... nodes) { super(nodes); _loc = loc; } + public CallNode(CallNode call) { super(call); _loc = call._loc; } + + @Override public String label() { return "Call"; } + + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { + String fname = name(); + if( fname == null ) fptr()._print0(sb,visited); + else sb.append(fname); + sb.append("( "); + for( int i=2; i<nIns()-1; i++ ) + in(i)._print0(sb,visited).append(","); + sb.setLength(sb.length()-1); + return sb.append(")"); + } + public String name() { + if( fptr()._type instanceof TypeFunPtr tfp && tfp.isConstant() ) { + FunNode fun = CodeGen.CODE.link(tfp); + if( fun !=null ) return fun._name; + if( fptr() instanceof ExternNode ex ) return ex._extern; + } + return null; + } + + + + Node ctrl() { return in(0); } + Node mem () { return in(1); } + // Args mapped 1-to-1 on inputs, so conceptually start at 2 + public Node arg(int idx) { return in(idx); } + // Same arg accounting as TFPs, although the numbering starts at 2 + public int nargs() { return nIns()-3; } // Minus control, memory, fptr + // args from input 2 to last; last is function input + public Node fptr() { return _inputs.last(); } + // Error if not a TFP + public TypeFunPtr tfp() { return (TypeFunPtr)fptr()._type; } + + // Call is to an externally supplied code + public boolean external() { return false; } + + + // Find the Call End from the Call + public CallEndNode cend() { + // Always in use slot 0 + if( nOuts()>0 && out(0) instanceof CallEndNode cend ) { + assert _cend()==cend; + return cend; + } else { + assert _cend()==null; + return null; + } + } + private CallEndNode _cend() { + CallEndNode cend=null; + for( Node n : _outputs ) + if( n instanceof CallEndNode cend0 ) + { assert cend == null; cend = cend0; } + return cend; + } + + // Get the one control following; error to call with more than one e.g. an + // IfNode or other multi-way branch. + @Override public CFGNode uctrl() { return cend(); } + + + @Override + public Type compute() { + return ctrl()._type; + } + + @Override + public Node idealize() { + CallEndNode cend = cend(); + if( cend==null ) return null; // Still building + + // Link: call calls target function. Linking makes the target FunNode + // point to this Call, and all his Parms point to the call arguments; + // also the CallEnd points to the Return. + Node progress = null; + if( fptr()._type instanceof TypeFunPtr tfp && tfp.nargs() == nargs() ) { + // If fidxs is negative, then infinite unknown functions + long fidxs = tfp.fidxs(); + if( fidxs > 0 ) { + // Wipe out the return which matching in the linker table + // Walk the (63 max) bits and link + for( ; fidxs!=0; fidxs = TypeFunPtr.nextFIDX(fidxs) ) { + int fidx = Long.numberOfTrailingZeros(fidxs); + TypeFunPtr tfp0 = tfp.makeFrom(fidx); + FunNode fun = CodeGen.CODE.link(tfp0); + if( fun!=null && !fun._folding && !linked(fun) ) + progress = link(fun); + } + } + } + + return progress; + } + + // True if Fun is linked to this Call + boolean linked( FunNode fun ) { + for( Node n : fun._inputs ) + if( n == this ) + return true; + return false; + } + + + // Link so this calls fun + private Node link( FunNode fun ) { + assert !linked(fun); + fun.addDef(this); + for( Node use : fun._outputs ) + if( use instanceof ParmNode parm ) + parm.addDef(parm._idx==0 ? new ConstantNode(cend()._rpc).peephole() : arg(parm._idx)); + // Call end points to function return + CodeGen.CODE.add(cend()).addDef(fun.ret()); + return this; + } + + // Unlink all linked functions + public void unlink_all() { + for( int i=0; i<_outputs._len; i++ ) + if( out(i) instanceof FunNode fun ) { + assert linked(fun); + int idx = fun._inputs.find(this); + for( Node use : fun._outputs ) + if( use instanceof ParmNode ) + use.delDef(idx); + fun.delDef(idx); + cend().delDef(cend()._inputs.find(fun.ret())); + assert !linked(fun); + i--; + } + } + + @Override + public Parser.ParseException err() { + if( !(fptr()._type instanceof TypeFunPtr tfp) ) + throw Utils.TODO(); + if( !tfp.notNull() ) + return Parser.error( "Might be null calling "+tfp, _loc); + if( nargs() != tfp.nargs() ) + return Parser.error( "Expecting "+tfp.nargs()+" arguments, but found "+nargs(), _loc); + + // Check for args + for( int i=0; i<tfp.nargs(); i++ ) + if( !arg(i+2)._type.isa(tfp.arg(i)) ) { + cend().addDep(arg(i+2)); // Upgrading arg type may allow inlining + return Parser.error( "Argument #" + i + " isa " + arg(i+2)._type + ", but must be a " + tfp.arg(i), _loc ); + } + + if( tfp.fidxs() < 0 ) + throw Utils.TODO(); // Infinite unknown TFPs? Should be fairly precise CG + + return null; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CalleeSaveNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CalleeSaveNode.java new file mode 100644 index 00000000..0afc5827 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CalleeSaveNode.java @@ -0,0 +1,23 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.type.Type; + +public class CalleeSaveNode extends ProjNode implements MachNode { + final RegMask _mask; + public CalleeSaveNode(FunNode fun, int reg, String label) { + super(fun,reg,label); + fun._outputs.pop(); + int i=0; + while( fun.out(i) instanceof PhiNode ) i++; + fun._outputs.insert(this,i); + _mask = new RegMask(reg); + } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return _mask; } + @Override public void encoding( Encoding enc ) { } + + @Override public Type compute() { return Type.BOTTOM; } + @Override public Node idealize() { return null; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CastMach.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CastMach.java new file mode 100644 index 00000000..e45898f5 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CastMach.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.util.SB; + +/** + * Cast a pointer to read-only + */ +public class CastMach extends CastNode implements MachNode { + public CastMach( CastNode n ) { super(n); } + @Override public String op() { return label(); } + @Override public RegMask regmap(int i) { assert i==1; return RegMask.FULL; } + @Override public RegMask outregmap() { return RegMask.FULL; } + @Override public int twoAddress( ) { return 1; } + @Override public void encoding( Encoding enc ) { } + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(in(1))); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CastNode.java new file mode 100644 index 00000000..6dc8e9fe --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CastNode.java @@ -0,0 +1,74 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +// Upcast (join) the input to a t. Used after guard test to lift an input. +// Can also be used to make a type-assertion if ctrl is null. +public class CastNode extends Node { + public Type _t; + public CastNode(Type t, Node ctrl, Node in) { + super(ctrl, in); + _t = t; + setType(compute()); + } + + public CastNode(CastNode c) { + super(c.in(0), c.in(1)); // Call parent constructor + this._t = c._t; // Copy the Type field + setType(compute()); // Ensure type is recomputed + } + + @Override public String label() { return "("+_t.str()+")"; } + + @Override + public String uniqueName() { return "Cast_" + _nid; } + + @Override public boolean isPinned() { return true; } + @Override public boolean isConst() { return true; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return in(1)._print0(sb.append(label()), visited); + } + + @Override + public Type compute() { + // Cast array to int + Type t1 = in(1)._type; + if( _t == TypeInteger.BOT && t1 instanceof TypeMemPtr tmp && tmp._obj.isAry() ) + return _t; + // Freeze if the join is high but both inputs are low + Type tj = t1.join(_t); + if( tj.isHigh() && !t1.isHigh() ) + return _type==null ? _t : _type; + + return tj; + } + + @Override + public Node idealize() { + return in(1)._type.isa(_t) ? in(1) : null; + } + + @Override + public boolean eq(Node n) { + CastNode cast = (CastNode)n; // Contract + return _t==cast._t; + } + + @Override + int hash() { return _t.hashCode(); } + + @Override + public Parser.ParseException err() { + // Has a condition to test, so OK + if( in(0) != null ) return null; + // No condition to test, so this must optimize away + return Parser.error( "Type " + in(1)._type.str() + " is not of declared type " + _t.str(), null ); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java new file mode 100644 index 00000000..3e1d3c69 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java @@ -0,0 +1,43 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.type.TypeStruct; +import com.seaofnodes.simple.util.SB; +import java.util.BitSet; + +/** + * A field offset. This becomes a constant *after* other optimizations which + * determine field sizes - some fields might be dead, or hold only zeros or + * small values. + */ + +public class ConFldOffNode extends ConstantNode { + public final String _name; // Struct name + public final String _fname; // Field name + public ConFldOffNode( String name, String fname ) { super(TypeInteger.BOT); _name = name; _fname = fname; } + + @Override public String label() { + return _fname == " len" ? "sizeof("+_name+")" : "#"+_fname; + } + @Override public String glabel() { return label(); } + @Override public String uniqueName() { return "Off_" + _nid; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return sb.append(label()); + } + + // Convert field offset to an integer + public Node asOffset(TypeStruct ts) { + return new ConstantNode(TypeInteger.constant(ts.offset(_fname==" len" ? ts._fields.length : ts.find(_fname)))).peephole(); + } + + + @Override public boolean eq(Node n) { + ConFldOffNode off = (ConFldOffNode)n; // Invariant + return _name==off._name && _fname==off._fname && super.eq(n); + } + @Override int hash() { return super.hash() * _name.hashCode() * _fname.hashCode(); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ConstantNode.java new file mode 100644 index 00000000..22bf03c4 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ConstantNode.java @@ -0,0 +1,52 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; +import java.util.BitSet; + +/** + * A Constant node represents a constant value. + * <p> + * Constants have no semantic inputs. However, we set Start as an input to + * Constants to enable a forward graph walk. This edge carries no semantic + * meaning, and it is present <em>solely</em> to allow visitation. + * <p> + * The Constant's value is the value stored in it. + */ + +public class ConstantNode extends Node { + public final Type _con; + public ConstantNode( Type type ) { + super(new Node[]{CodeGen.CODE._start}); + _con = _type = type; + } + public ConstantNode( ConstantNode con ) { super(con); _con = con._type; } + + public static Node make( Type type ) { + if( type==Type. CONTROL ) return new CtrlNode(); + if( type==Type.XCONTROL ) return new XCtrlNode(); + return new ConstantNode(type); + } + + @Override public String label() { return "#"+_con; } + @Override public String glabel() { return "#"+_con.gprint(); } + @Override public String uniqueName() { return "Con_" + _nid; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + if( _con instanceof TypeFunPtr tfp && tfp.isConstant() ) { + FunNode fun = CodeGen.CODE.link(tfp); + if( fun!=null && fun._name != null ) + return sb.append("{ ").append(fun._name).append("}"); + } + return sb.append(_con==null ? "---" : _con.toString()); + } + + @Override public boolean isConst() { return true; } + @Override public Type compute() { return _con; } + @Override public Node idealize() { return null; } + @Override public boolean eq(Node n) { return _con==((ConstantNode)n)._con; } + @Override int hash() { return _con.hashCode(); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CtrlNode.java new file mode 100644 index 00000000..eda7d684 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CtrlNode.java @@ -0,0 +1,15 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import java.util.BitSet; + +public class CtrlNode extends CFGNode { + public CtrlNode() { super(CodeGen.CODE._start); } + @Override public String label() { return "Ctrl"; } + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Cctrl"); } + @Override public boolean isConst() { return true; } + @Override public Type compute() { return Type.CONTROL; } + @Override public Node idealize() { return null; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/DivFNode.java new file mode 100644 index 00000000..633f3224 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/DivFNode.java @@ -0,0 +1,41 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; + +import java.util.BitSet; + +public class DivFNode extends Node { + public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "DivF"; } + + @Override public String glabel() { return "/"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("("), visited); + in(2)._print0(sb.append("/"), visited); + return sb.append(")"); + } + + @Override + public Type compute() { + if (in(1)._type instanceof TypeFloat i0 && + in(2)._type instanceof TypeFloat i1) { + if (i0.isConstant() && i1.isConstant()) + return TypeFloat.constant(i0.value()/i1.value()); + } + return in(1)._type.meet(in(2)._type); + } + + @Override + public Node idealize() { + // Div of constant + if( in(2)._type instanceof TypeFloat f && f.isConstant() ) + return new MulFNode(in(1),new ConstantNode(TypeFloat.constant(1.0/f.value())).peephole()); + + return null; + } + @Override Node copy(Node lhs, Node rhs) { return new DivFNode(lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/DivNode.java new file mode 100644 index 00000000..0de1c946 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/DivNode.java @@ -0,0 +1,28 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import java.util.BitSet; + +public class DivNode extends ArithNode { + public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "Div"; } + @Override public String op() { return "//"; } + + @Override long doOp( long x, long y ) { return y==0 ? 0 : x / y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + return TypeInteger.BOT; + } + + @Override + public Node idealize() { + // Div of 1. + if( in(2)._type == TypeInteger.TRUE ) + return in(1); + return super.idealize(); + } + + @Override Node copy(Node lhs, Node rhs) { return new DivNode(lhs,rhs); } + @Override Node copyF() { return new DivFNode(null,null); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ExternNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ExternNode.java new file mode 100644 index 00000000..a10bb84a --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ExternNode.java @@ -0,0 +1,23 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; +import java.util.BitSet; + +/** + A constant with external linkage. + */ + +public class ExternNode extends ConstantNode { + public final String _extern; + public ExternNode(Type t, String ex) { super(t); _extern = ex; } + + @Override public String label() { return "#"+_con+":"+_extern; } + @Override public String glabel() { return _con.print(new SB().p("#"), new BitSet(), true).p(":").p(_extern).toString(); } + @Override public String uniqueName() { return "Extern_" + _nid; } + + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/FRefNode.java new file mode 100644 index 00000000..6093b8a6 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/FRefNode.java @@ -0,0 +1,35 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.Var; +import com.seaofnodes.simple.type.Type; +import java.util.BitSet; + +/** + * A Forward Reference. Its any final constant, including functions. When + * the Def finally appears its plugged into the forward reference, which then + * peepholes to the Def. + */ +public class FRefNode extends ConstantNode { + public static final Type FREF_TYPE = Type.BOTTOM; + public final Var _n; + public FRefNode( Var n ) { super(FREF_TYPE); _n = n; } + + @Override public String label() { return "FRef"+_n; } + + @Override public String uniqueName() { return "FRef_" + _nid; } + + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return sb.append("FRef_").append(_n); + } + + @Override public Node idealize() { + // When FRef finds its definition, idealize to it + return nIns()==1 ? null : in(1); + } + + public Parser.ParseException err() { return Parser.error("Undefined name '"+_n._name+"'",_n._loc); } + + @Override public boolean eq(Node n) { return this==n; } + @Override int hash() { return _n._idx; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/FunNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/FunNode.java new file mode 100644 index 00000000..4bd0fd97 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/FunNode.java @@ -0,0 +1,227 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.type.TypeTuple; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; +import static com.seaofnodes.simple.codegen.CodeGen.CODE; + +public class FunNode extends RegionNode { + + // When set true, this Call/CallEnd/Fun/Return is being trivially inlined + boolean _folding; + + private TypeFunPtr _sig; // Initial signature + private ReturnNode _ret; // Return pointer + + public String _name; // Debug name + + public FunNode( Parser.Lexer loc, TypeFunPtr sig, String name, Node... nodes ) { super(loc,nodes); _name=name; _sig = sig; } + public FunNode( FunNode fun ) { + super( fun, fun==null ? null : fun._loc ); + if( fun!=null ) { + _sig = fun.sig(); + _name = fun._name; + } else { + _sig = TypeFunPtr.BOT; + _name = ""; + } + } + + @Override + public String label() { return _name == null ? "$fun"+_sig.fidx() : _name; } + + // Find the one CFG user from Fun. It's not always the Return, but always + // the Return *is* a CFG user of Fun. + @Override public CFGNode uctrl() { + for( Node n : _outputs ) + if( n instanceof CFGNode cfg && + (cfg instanceof RegionNode || cfg.cfg0()==this) ) + return cfg; + return null; + } + + public ParmNode rpc() { + ParmNode rpc = null; + for( Node n : _outputs ) + if( n instanceof ParmNode parm && parm._idx==0 ) + { assert rpc==null; rpc=parm; } + return rpc; + } + + // Cannot create the Return and Fun at the same time; one has to be first. + // So setting the return requires a second step. + public void setRet(ReturnNode ret) { _ret=ret; } + public ReturnNode ret() { assert _ret!=null; return _ret; } + + // Signature can improve over time + public TypeFunPtr sig() { return _sig; } + public void setSig( TypeFunPtr sig ) { + assert sig.isa(_sig); + if( _sig != sig ) { + CODE.add(this); + _sig = sig; + } + } + + public void setName( String name ) { + if( _name==null ) _name=name; + else _name += "."+name; + } + + @Override + public Type compute() { + // Only dead if no callers after SCCP + if( unknownCallers() ) + return Type.CONTROL; + return super.compute(); + } + + @Override + public Node idealize() { + + // Some linked path dies + Node progress = deadPath(); + if( progress!=null ) { + if( nIns()==3 && in(2) instanceof CallNode call ) + CODE.add(call.cend()); // If Start and one call, check for inline + return progress; + } + + // Upgrade inferred or user-written return type to actual + if( _ret!=null && _ret._type instanceof TypeTuple tt && tt.ret() != _sig.ret() ) + throw Utils.TODO(); + + // When can we assume no callers? Or no other callers (except main)? + // In a partial compilation, we assume Start gets access to any/all + // top-level public structures and recursively what they point to. + // This in turn is valid arguments to every callable function. + // + // In a total compilation, we can start from Start and keep things + // more contained. + + // If no default/unknown caller, use the normal RegionNode ideal rules + // to collapse + if( unknownCallers() ) return null; + + // If down to a single input, become that input + if( nIns()==2 && !hasPhi() ) { + CODE.add( CODE._stop ); // Stop will remove dead path + CODE.add( _ret ); // Return will compute to TOP control + return in(1); // Collapse if no Phis; 1-input Phis will collapse on their own + } + + return null; + } + + // Bypass Region idom, always assume depth == 1, one more than Start, + // unless folding then just a ID on input#1 + @Override public int idepth() { + return _folding ? super.idepth() : CodeGen.CODE.iDepthAt(1); + } + // Bypass Region idom, always assume idom is Start + @Override public CFGNode idom(Node dep) { return _folding && nIns()==3 ? cfg(2) : (nIns()>1 ? cfg(1) : null); } + + // Always in-progress until we run out of unknown callers + public boolean unknownCallers() { return nIns()>=2 && in(1) instanceof StartNode; } + + @Override public boolean inProgress() { return unknownCallers(); } + + // Add a new function exit point. + public void addReturn(Node ctrl, Node mem, Node rez) { _ret.addReturn(ctrl,mem,rez); } + + // Build the function body + public BitSet body() { + + // Reverse up (stop to start) CFG only, collect bitmap. + BitSet cfgs = new BitSet(); + cfgs.set(_nid); + walkUp(ret(),cfgs ); + + // Top down (start to stop) all flavors. CFG limit to bitmap. + // If data use bottoms out in wrong CFG, returns false - but tries all outputs. + // If any output hits an in-CFG use (e.g. phi), then keep node. + BitSet body = new BitSet(); + walkDown(this, cfgs, body, new BitSet()); + return body; + } + + private static void walkUp(CFGNode n, BitSet cfgs) { + if( cfgs.get(n._nid) ) return; + cfgs.set(n._nid); + if( n instanceof RegionNode r ) + for( int i=1; i<n.nIns(); i++ ) + walkUp(n.cfg(i),cfgs); + else walkUp(n.cfg0(),cfgs); + } + + private static boolean walkDown( Node n, BitSet cfgs, BitSet body, BitSet visit ) { + if( visit.get(n._nid) ) return body.get(n._nid); + visit.set(n._nid); + + if( n instanceof CFGNode && !cfgs.get(n._nid) ) + return false; + if( n.in(0)!=null && !cfgs.get(n.in(0)._nid) ) + return false; + boolean in = n.in(0)!=null || n instanceof CFGNode; + for( Node use : n._outputs ) + in |= walkDown(use,cfgs,body,visit); + if( in ) body.set(n._nid); + return in; + } + + + // ------------ + // MachNode specifics, shared across all CPUs + + // Function may call other functions? X86 requires 16b aligned SP on + // outbound calls, but not leaf. Set during an unrelated RA scan. + public boolean _hasCalls; + + // Maximum incoming argument slot, based on function type + public int _maxArgSlot; + + // Frame adjust, including padding, set during early Encoding + public int _frameAdjust; + + public String op() { return _frameAdjust==0 ? "entry" : "subi"; } + public void postSelect(CodeGen code) { + code.link(this); + // Max slot seen past space reserved for incoming arguments + _maxArgSlot = code._mach.maxArgSlot(sig()); + } + public RegMask regmap(int i) { return null; } + public RegMask outregmap() { return null; } + public void encoding( Encoding enc ) { throw Utils.TODO(); } + public void asm(CodeGen code, SB sb) { + if( _frameAdjust!=0 ) + sb.p("rsp -= #").p(_frameAdjust); + } + + public void computeFrameAdjust(CodeGen code, int maxReg) { + // Max slot seen, or 0. + int maxSlot = Math.max(maxReg - code._mach.regs().length,_maxArgSlot); + // Frame adjust before rounding, can be negative for no spills + int size = maxSlot - _maxArgSlot; + _frameAdjust = size*8; + } + + // Given a high register number and during encoding compute the stack + // pointer offset. Pre-RA we lack the fun._frameAdjust. We also need a + // FunNode. + public int computeStackOffset(CodeGen code, int reg) { + String[] regs = code._mach.regs(); + int stackSlot = reg - regs.length; + int slotRotate = stackSlot < _maxArgSlot + ? stackSlot + (_frameAdjust>>3) + : stackSlot - _maxArgSlot; + return slotRotate*8; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/IfNode.java new file mode 100644 index 00000000..c5d687e5 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/IfNode.java @@ -0,0 +1,97 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +public class IfNode extends CFGNode implements MultiNode { + + public IfNode(Node ctrl, Node pred) { + super(ctrl, pred); + CodeGen.CODE.add(this); // Because idoms are complex, just add it + } + public IfNode(IfNode iff) { super(iff); } + + @Override + public String label() { return "If"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + sb.append("if( "); + if( in(1)==null ) sb.append("never"); + else in(1)._print0(sb, visited); + return sb.append(" )"); + } + + public Node ctrl() { return in(0); } + public Node pred() { return in(1); } + + // No one unique control follows + @Override public CFGNode uctrl() { return null; } + + @Override + public Type compute() { + // If the If node is not reachable then neither is any following Proj + if (ctrl()._type != Type.CONTROL && ctrl()._type != Type.BOTTOM ) + return TypeTuple.IF_NEITHER; + Node pred = pred(); + Type t = pred._type; + // High types mean NEITHER side is reachable. + // Wait until the type falls to decide which way to go. + if( t.isHigh() ) + return TypeTuple.IF_NEITHER; + // If constant is 0 then false branch is reachable + // Else true branch is reachable + if( t.isConstant() ) + return (t==Type.NIL || t==TypeInteger.ZERO || (t instanceof TypeFunPtr tfp && tfp._fidxs==0) ) ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE; + // If adding a zero makes a difference, the predicate must not have a zero/null + if( !t.makeZero().isa(t) ) + return TypeTuple.IF_TRUE; + + return TypeTuple.IF_BOTH; + } + + @Override + public Node idealize() { + // Hunt up the immediate dominator tree. If we find an identical if + // test on either the true or false branch, that side wins. + if( !pred()._type.isHighOrConst() ) + for( CFGNode dom = idom(), prior=this; dom!=null; prior = dom, dom = dom.idom() ) + if( addDep(dom) instanceof IfNode iff && addDep(iff.pred())==pred() && prior instanceof CProjNode prj ) { + setDef(1,con( prj._idx==0 ? 1 : 0 )); + return this; + } + return null; + } + + // MachNode variants need to support this and negate the conditional test. + // The following CProjs will be inverted by the caller. + public void negate() { throw Utils.TODO(); } + + // Negate the sense of a test + public static String negate( String bop ) { + return switch( bop ) { + case "<" -> ">="; + case "<=" -> ">" ; + case "==" -> "!="; + case "!=" -> "=="; + case ">" -> "<="; + case ">=" -> "<" ; + default -> throw Utils.TODO(); + }; + } + + // Swap compare operands + public static String swap( String bop ) { + return switch( bop ) { + case "<" -> ">" ; + case "<=" -> ">="; + case "==" -> "=="; + case "!=" -> "!="; + case ">" -> "<" ; + case ">=" -> "<="; + default -> throw Utils.TODO(); + }; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/LoadNode.java new file mode 100644 index 00000000..b58ea498 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/LoadNode.java @@ -0,0 +1,233 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +/** + * Load represents extracting a value from inside a memory object, + * in chapter 10 this means Struct fields. + */ +public class LoadNode extends MemOpNode { + + /** + * Load a value from a ptr.field. + * + * @param name The field we are loading + * @param mem The memory alias node - this is updated after a Store + * @param ptr The ptr to the struct base from where we load a field + * @param off The offset inside the struct base + */ + public LoadNode(Parser.Lexer loc, String name, int alias, Type glb, Node mem, Node ptr, Node off) { + super(loc, name, alias, true, glb, mem, ptr, off); + } + + // GraphVis DOT code (must be valid Java identifiers) and debugger labels + @Override public String label() { return "ld_"+mlabel(); } + // GraphVis node-internal labels + @Override public String glabel() { return "." +_name; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); } + + @Override + public Type compute() { + if( !(mem()._type instanceof TypeMem mem) ) + return _declaredType; // No memory yet? Declared type + assert !_declaredType.isFRef(); + // No lifting if ptr might null-check + if( err()!=null || !(ptr()._type instanceof TypeMemPtr tmp) ) + return _declaredType; // No pointer yet? Declared type + Type t = tmp._obj.field(_name)._t; + if( t instanceof TypeConAry ary ) { + t = ary.elem(); // TODO: if offset is known, can peek the constant + } + // Lift from declared type and memory input + t = t.join(_declaredType).join(mem._t); + if( _declaredType.isFinal() ) + t = t.makeRO(); // Deep final applied + return t; + } + + @Override + public Node idealize() { + Node ptr = ptr(); + Node mem = mem(); + + if( mem instanceof CastNode cast ) { + setDef(1,cast.in(1)); + return this; + } + + // Simple Load-after-Store on same address. + if( mem instanceof StoreNode st && + ptr == st.ptr() && off() == st.off() ) { // Must check same object + assert _name.equals(st._name); // Equiv class aliasing is perfect + return extend(st.val()); + } + + // Simple load-after-MemMerge to a known alias can bypass. Happens when inlining. + if( mem instanceof MemMergeNode mem2 ) { + Node memA = mem2.alias(_alias); + for( Node ld : memA._outputs ) + if( ld instanceof LoadNode ) + CodeGen.CODE.add(ld); + setDef(1,memA); + return this; + } + + // Simple Load-after-New on same address. + if( mem instanceof ProjNode p && p.in(0) instanceof NewNode nnn && + ptr == nnn.proj(1) ) // Must check same object + return zero(nnn); // Load zero from new + + // Uplift control to a prior dominating load. + for( Node memuse : mem._outputs ) + // Find a prior load, has same mem,ptr,off but higher ctrl + if( memuse != this && memuse instanceof LoadNode ld && ptr==ld.ptr() && off()==ld.off() && + cfg0()!=null && cfg0()._idom(ld.cfg0(),this) == ld.cfg0() ) // Higher control means load is legal earlier + return ld; + + // Load-after-Store on same address, but bypassing provably unrelated + // stores. This is a more complex superset of the above two peeps. + // "Provably unrelated" is really weak. + if( ptr instanceof ReadOnlyNode ro ) + ptr = ro.in(1); + outer: + while( true ) { + switch( mem ) { + case StoreNode st: + if( ptr == addDep(st.ptr()) && off() == st.off() ) + return extend(castRO(st.val())); // Proved equal + // Can we prove unequal? Offsets do not overlap? + if( !off()._type.join(st.off()._type).isHigh() && // Offsets overlap + !neverAlias(ptr,st.ptr()) ) // And might alias + break outer; // Cannot tell, stop trying + // Pointers cannot overlap + mem = st.mem(); // Proved never equal + break; + case PhiNode phi: + // Assume related + addDep(phi); + break outer; + case ConstantNode top: break outer; // Assume shortly dead + case ProjNode mproj: // Memory projection + switch( mproj.in(0) ) { + case NewNode nnn1: + if( ptr instanceof ProjNode pproj && pproj.in(0) == mproj.in(0) ) + return zero(nnn1); + if( !(ptr instanceof ProjNode pproj && pproj.in(0) instanceof NewNode) ) + break outer; // Cannot tell, ptr not related to New + mem = nnn1.in(nnn1.findAlias(_alias));// Bypass unrelated New + break; + case StartNode start: break outer; + case CallEndNode cend: break outer; // TODO: Bypass no-alias call + default: throw Utils.TODO(); + } + break; + case CastNode cast: mem = cast.in(1); break; + case MemMergeNode merge: mem = merge.alias(_alias); break; + + default: + throw Utils.TODO(); + } + } + + // Push a Load up through a Phi, as long as it collapses on at least + // one arm. If at a Loop, the backedge MUST collapse - else we risk + // spinning the same transform around the loop indefinitely. + // BEFORE (2 Sts, 1 Ld): AFTER (1 St, 0 Ld): + // if( pred ) ptr.x = e0; val = pred ? e0 + // else ptr.x = e1; : e1; + // val = ptr.x; ptr.x = val; + if( mem() instanceof PhiNode memphi && memphi.region()._type == Type.CONTROL && memphi.nIns()== 3 && + // Offset can be hoisted + off() instanceof ConstantNode && + // Pointer can be hoisted + hoistPtr(ptr,memphi) ) { + + // Profit on RHS/Loop backedge + if( profit(memphi,2) || + // Else must not be a loop to count profit on LHS. + (!(memphi.region() instanceof LoopNode) && profit(memphi,1)) ) { + Node ld1 = ld(1); + Node ld2 = ld(2); + return new PhiNode(_name,_declaredType,memphi.region(),ld1,ld2); + } + } + + return null; + } + + // Load a flavored zero from a New + private Node zero(NewNode nnn) { + TypeStruct ts = nnn._ptr._obj; + Type zero = ts._fields[ts.findAlias(_alias)]._t.makeZero(); + return castRO(new ConstantNode(zero).peephole()); + } + + private Node ld( int idx ) { + Node mem = mem(), ptr = ptr(); + return new LoadNode(_loc,_name,_alias,_declaredType,mem.in(idx),ptr instanceof PhiNode && ptr.in(0)==mem.in(0) ? ptr.in(idx) : ptr, off()).peephole(); + } + + private static boolean neverAlias( Node ptr1, Node ptr2 ) { + return ptr1.in(0) != ptr2.in(0) && + // Unrelated allocations + ptr1 instanceof ProjNode && ptr1.in(0) instanceof NewNode && + ptr2 instanceof ProjNode && ptr2.in(0) instanceof NewNode; + } + + private static boolean hoistPtr(Node ptr, PhiNode memphi ) { + // Can I hoist ptr above the Region? + if( !(memphi.region() instanceof RegionNode r) ) + return false; // Dead or dying Region/Phi + // If ptr from same Region, then yes, just use hoisted split pointers + if( ptr instanceof PhiNode pphi && pphi.region() == r ) + return true; + + // No, so can we lift this ptr? + CFGNode cptr = ptr.cfg0(); + if( cptr != null ) + // Pointer is controlled high + // TODO: Really needs to be the LCA of all inputs is high + return cptr.idepth() <= r.idepth(); + + // Dunno without a longer walk + return false; + } + + // Profitable if we find a matching Store on this Phi arm. + private boolean profit(PhiNode phi, int idx) { + Node px = phi.in(idx); + if( px==null ) return false; + if( px._type instanceof TypeMem mem && mem._t.isHighOrConst() ) return true; + if( px instanceof StoreNode st1 && ptr()==addDep(st1.ptr() )&& off()==st1.off() ) return true; + addDep(px); + return false; + } + + // Read-Only is a deep property, and cannot be cast-away + private Node castRO(Node rez) { + if( ptr()._type.isFinal() && !rez._type.isFinal() ) + return new ReadOnlyNode(rez).peephole(); + return rez; + } + + // When a load bypasses a store, the store might truncate bits - and the + // load will need to zero/sign-extend. + private Node extend(Node val) { + if( !(_declaredType instanceof TypeInteger ti) ) return val; + if( ti._min==0 ) // Unsigned + return new AndNode(null,val,con(ti._max)); + // Signed extension + int shift = Long.numberOfLeadingZeros(ti._max)-1; + Node shf = con(shift); + if( shf._type==TypeInteger.ZERO ) + return val; + Node shl = new ShlNode(null,val,shf.keep()).peephole(); + return new SarNode(null,shl,shf.unkeep()); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/LoopNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/LoopNode.java new file mode 100644 index 00000000..fc50e17f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/LoopNode.java @@ -0,0 +1,105 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.type.TypeMem; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; +import java.util.HashSet; + +public class LoopNode extends RegionNode { + public LoopNode( Parser.Lexer loc, Node entry ) { super(loc,null,entry,null); } + public LoopNode( LoopNode loop ) { super(loop); } + + public CFGNode entry() { return cfg(1); } + public CFGNode back () { return cfg(2); } + + @Override + public String label() { return "Loop"; } + + @Override + public Type compute() { + if( inProgress() ) return Type.CONTROL; + return entry()._type; + } + + // Bypass Region idom, same as the default idom() using use in(1) instead of in(0) + @Override public int idepth() { + return CodeGen.CODE.validIDepth(_idepth) ? _idepth : (_idepth=CodeGen.CODE.iDepthFrom(idom().idepth())); + } + // Bypass Region idom, same as the default idom() using use in(1) instead of in(0) + @Override public CFGNode idom(Node dep) { return entry(); } + + // If this is an unreachable loop, it may not have an exit. If it does not + // (i.e., infinite loop), force an exit to make it reachable. + public StopNode forceExit( FunNode fun, StopNode stop ) { + // Walk the backedge, then immediate dominator tree util we hit this + // Loop again. If we ever hit a CProj from an If (as opposed to + // directly on the If) we found our exit. + CFGNode x = back(); + while( x != this ) { + if( x instanceof CProjNode exit && exit.in(0) instanceof IfNode iff ) { + CFGNode other = iff.cproj(1-exit._idx); + if( other!=null && other._ltree != _ltree && nested(_ltree,other._ltree) ) + return stop; // Found an exit, not an infinite loop + } + x = x.idom(); + } + // Found a no-exit loop. Insert an exit + NeverNode iff = (NeverNode)new NeverNode(back()).peephole(); // Ideal never-branch + CProjNode t = new CProjNode(iff,0,"True" ).init(); + CProjNode f = new CProjNode(iff,1,"False").init(); + setDef(2,t); // True continues loop, False (never) exits loop + ReturnNode ret = fun.ret(); + iff._ltree = t._ltree = _ltree; + ret._ltree = f._ltree = stop._ltree; + + // Now fold control into the exit. Might have 1 valid exit, or an + // XCtrl or a bunch of prior NeverNode exits. + Node top = new ConstantNode(Type.TOP).peephole(); + Node memout = new MemMergeNode(false); + memout.addDef(f); // placeholder for control + for( Node u : _outputs ) + if( u instanceof PhiNode phi && phi._type.isa(TypeMem.BOT) ) + memout.addDef(phi); + + Node ctrl = ret.ctrl(), mem = ret.mem(), expr = ret.expr(); + if( ctrl!=null && ctrl._type != Type.XCONTROL ) { + // Perfect aligned exit? + if( !(ctrl instanceof RegionNode r && + mem instanceof PhiNode pmem && pmem.region()==r && + expr instanceof PhiNode prez && prez.region()==r ) ) { + // Nope, insert an aligned exit layer + RegionNode r = new RegionNode(_loc,null,ctrl).init(); + ctrl = r; r._ltree = stop._ltree; + mem = new PhiNode(r,mem ).init(); + expr = new PhiNode(r,expr).init(); + } + // Append new Never exit + ctrl.keep().addDef(f ); + mem .keep().addDef(memout); + expr.keep().addDef(top); + } else { + ctrl = f .keep(); + mem = memout.keep(); + expr = top .keep(); + } + ret.setDef(0,ctrl.unkeep()); + ret.setDef(1,mem .unkeep()); + ret.setDef(2,expr.unkeep()); + ret._type = null; // This may LIFT the Return type, from [XCtrl,mem,expr] to [Ctrl,mem,expr] + ret.setType(ret.compute()); + + return stop; + } + + private static boolean nested(LoopTree inner, LoopTree outer) { + for( ; inner!=null; inner = inner._par ) + if( inner == outer ) + return true; + return false; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java new file mode 100644 index 00000000..9440a7ea --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java @@ -0,0 +1,27 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.Utils; +import java.io.ByteArrayOutputStream; +import java.util.BitSet; + +// Generic machine-specific class, has a few Node implementations that have to +// exist (abstract) but are not useful past the optimizer. +public abstract class MachConcreteNode extends Node implements MachNode { + + public MachConcreteNode(Node node) { super(node); } + public MachConcreteNode(Node[]nodes) { super(nodes); } + + @Override public String label() { return op(); } + @Override public Type compute () { throw Utils.TODO(); } + @Override public Node idealize() { throw Utils.TODO(); } + + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { + sb.append("(").append(op()).append(","); + for( int i=1; i<nIns(); i++ ) + (in(i)==null ? sb.append(" ---") : in(i)._print0(sb, visited)).append(","); + sb.setLength(sb.length()-1); + return sb.append(")"); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MachNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MachNode.java new file mode 100644 index 00000000..c0b3af66 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MachNode.java @@ -0,0 +1,60 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public interface MachNode { + + // Easy access to the abstract Machine + default Machine machine() { return CodeGen.CODE._mach; } + + // Run a post-instruction-selection action + default void postSelect( CodeGen code ) { } + + // Register mask allowed on input i. 0 for no register. + RegMask regmap( int i ); + // Register mask allowed as a result. 0 for no register. + RegMask outregmap(); + // Multi-reg-defining machine op; idx comes from Proj. + // Sometimes these Projs have no uses, and just exist to kill a register. + default RegMask outregmap(int idx) { throw Utils.TODO(); } + + // Set of killed registers + default RegMask killmap() { return null; } + + // If this op updates the same register as input 'idx', e.g. many X86 "R1 += + // R2" style ops. This forces the output live range to equal the input live + // range, so they both get the same register. + + // This can hold true for projections, if the instruction updates many + // registers that it also takes in. Note that ops also use the same + // registers for both inputs and outputs but these are pinned and without any + // choices (e.g. always RCX for both an input and output) and are better + // served with just declaring as a fixed register. + + // Returns either 0 for not-two-adr or the updated input; for projections + // this is their Multi's updated input. + default int twoAddress( ) { return 0; } + // Ok to switch arguments + default boolean commutes() { return false; } + + // Instructions cheaper to recreate than to spill, such as loading small constants + default boolean isClone() { return false; } + + // Make a clone of a cheap instruction + default Node copy() { return null; } + + // Encoding is appended, relocations gathered. + void encoding( Encoding enc ); + + // Human-readable form appended to the SB. Things like the encoding, + // indentation, leading address or block labels not printed here. + // Just something like "R17=[R18+12] // Load array base". + // General form: "dst=src+src". + default void asm(CodeGen code, SB sb) { throw Utils.TODO(); } + + // Human readable opcode; e.g. "ld4" or "call". + default String op() { throw Utils.TODO(); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java new file mode 100644 index 00000000..19acc5b9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java @@ -0,0 +1,180 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.*; +import java.util.*; + +/** + * Memory Merge - a merge of many aliases into a "fat memory". All aliases + * are here, but most will be lazy - take the default fat memory. + */ +public class MemMergeNode extends Node { + + /* + * In-Progress means this is being used by the Parser to track memory + * aliases. No optimizations are allowed. When no longer "in progress" + * normal peeps work. + */ + public final boolean _inProgress; + + public MemMergeNode( boolean inProgress) { _type = TypeMem.BOT; _inProgress = inProgress; } + public MemMergeNode(MemMergeNode mem) { super(mem); _inProgress = false; } + + + // If being used by a Scope, this is "in progress" from the Parser. + // Otherwise, it's a memory merge + boolean inProgress() { return _inProgress; } + + @Override public String label() { return "ALLMEM"; } + @Override public boolean isMem() { return true; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + sb.append(_inProgress ? "Merge[" : "MEM[ "); + for( int j=2; j<nIns(); j++ ) { + sb.append(j); + sb.append(":"); + Node n = in(j); + while( n instanceof ScopeNode loop ) { + sb.append("Lazy_"); + n = loop.mem(j); + } + if( n==null ) sb.append("___ "); + else n._print0(sb, visited).append(" "); + } + sb.setLength(sb.length()-1); + return sb.append("]"); + } + + // Make a memory merge: no longer a Scope really, tracking memory state but + // not related to the parser in any way. + public Node merge() { + // Force default memory to not be lazy + MemMergeNode merge = new MemMergeNode(false); + for( Node n : _inputs ) + merge.addDef(n); + for( int i=1; i<nIns(); i++ ) + merge._mem(i,null); + return merge.peephole(); + } + + + @Override public Type compute() { return TypeMem.BOT; } + + @Override public Node idealize() { + if( inProgress() ) return null; + + // Fold defaults into the default + boolean progress=false, allDefault=true; + for( int i=2; i<nIns(); i++ ) { + if( in(i) instanceof CastNode cast ) + { setDef(i,cast.in(1)); progress=true; } + if( in(1) == in(i) ) { setDef(i,null); progress=true; } + else { allDefault=false; } + } + + // If not merging any memory (all memory is just the default) + if( allDefault ) + return in(1); // Become default memory + + // Collapse stacked all-mem + if( in(1) instanceof MemMergeNode mem ) { + // Goal is to swap my default mem with mem's default mem + for( int i=2; i<mem.nIns(); i++ ) { + if( mem.in(i) != null ) { + // deeper default mem has a non-default + if( i>=nIns() || in(i)==null ) + setDefX(i,mem.in(i)); + } + } + setDef(1,mem.in(1)); + return this; + } + + return progress ? this : null; + } + + + public Node in( Var v ) { return in(v._idx); } + + public Node alias( int alias ) { + return alias < nIns() && in(alias)!=null ? in(alias) : in(1); + } + + Node alias( int alias, Node st ) { + while( alias >= nIns() ) addDef(null); + return setDef(alias,st); + } + + // Read or update from memory. + // A shared implementation allows us to create lazy phis both during + // lookups and updates; the lazy phi creation is part of chapter 8. + Node _mem( int alias, Node st ) { + // Memory projections are made lazily; if one does not exist + // then it must be START.proj(1) + Node old = alias(alias); + if( old instanceof ScopeNode loop ) { + MemMergeNode loopmem = loop.mem(); + Node memdef = loopmem.alias(alias); + // Lazy phi! + old = memdef instanceof PhiNode phi && loop.ctrl()==phi.region() + // Loop already has a real Phi, use it + ? memdef + // Set real Phi in the loop head + // The phi takes its one input (no backedge yet) from a recursive + // lookup, which might have insert a Phi in every loop nest. + : loopmem.alias(alias, new PhiNode(Parser.memName(alias), TypeMem.make(alias,Type.BOTTOM),loop.ctrl(),loopmem._mem(alias,null),null).peephole() ); + alias(alias,old); + } + // Memory projections are made lazily; expand as needed + return st==null ? old : alias(alias,st); // Not lazy, so this is the answer + } + + + void _merge( MemMergeNode that, RegionNode r) { + int len = Math.max(nIns(),that.nIns()); + for( int i = 1; i < len; i++) + if( alias(i) != that.alias(i) ) { // No need for redundant Phis + // If we are in lazy phi mode we need to a lookup + // by alias as it will trigger a phi creation + Node lhs = this._mem(i,null); + Node rhs = that._mem(i,null); + alias(i, new PhiNode(Parser.memName(i), lhs._type.meet(rhs._type).glb(true), r, lhs, rhs).peephole()); + } + } + + // Fill in the backedge of any inserted Phis + void _endLoopMem( ScopeNode scope, MemMergeNode back, MemMergeNode exit ) { + Node exit_def = exit.alias(1); + for( int i=1; i<nIns(); i++ ) { + if( in(i) instanceof PhiNode phi && phi.region()==scope.ctrl() ) { + assert phi.in(2)==null; + phi.setDef(2,back.alias(i)==scope ? phi : back.alias(i)); // Fill backedge + } + if( exit_def == scope ) // Replace a lazy-phi on the exit path also + exit.alias(i,in(i)); + } + } + + // Now one-time do a useless-phi removal + void _useless( ) { + for( int i=2; i<nIns(); i++ ) { + if( in(i) instanceof PhiNode phi ) { + // Do an eager useless-phi removal + Node in = phi.peephole(); + CodeGen.CODE.addAll(phi._outputs); + phi.moveDepsToWorklist(); + if( in != phi ) { + if( !phi.iskeep() ) // Keeping phi around for parser elsewhere + phi.subsume(in); + setDef(i,in); // Set the update back into Scope + } + } + } + } + + @Override public boolean eq( Node n ) { + return this==n || !_inProgress; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MemOpNode.java new file mode 100644 index 00000000..ead82322 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MemOpNode.java @@ -0,0 +1,109 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.util.Utils; +import java.lang.StringBuilder; +import java.util.BitSet; + +/** + * Convenience common base for Load and Store. + * + * 0 - Control + * 1 - Memory + * 2 - Base of object, OOP + * 3 - Offset, integer types + * 4 - Value, for Stores only + */ +public abstract class MemOpNode extends Node { + + // The equivalence alias class + public final int _alias; + + // True if load-like, false if store-like. + // + // Stores produce memory (maybe as part of a tuple with other things), + // loads do not. + // + // Loads might pick up anti-dependences on prior Stores, and never cause an + // anti-dependence themselves. + // + // Stores must maximally sink to the least dominator use. Loads can be + // opportunistically hoisted. + public final boolean _isLoad; + + // Declared type; not final because it might be a forward-reference + // which will be lazily improved when the reference is declared. + public Type _declaredType; + + // A debug name, no semantic meaning + public final String _name; + // Source location for late reported errors + public final Parser.Lexer _loc; + + public MemOpNode(Parser.Lexer loc, String name, int alias, boolean isLoad, Type glb, Node mem, Node ptr, Node off) { + super(null, mem, ptr, off); + _name = name; + _alias = alias; + _declaredType = glb; + _loc = loc; + _isLoad = isLoad; + } + public MemOpNode(Parser.Lexer loc, String name, int alias, boolean isLoad, Type glb, Node mem, Node ptr, Node off, Node value) { + this(loc,name, alias, isLoad, glb, mem, ptr, off); + addDef(value); + } + public MemOpNode( Node mach, MemOpNode mop ) { + super(mach); + _name = mop==null ? null : mop._name; + _alias = mop==null ? 0 : mop._alias; + _loc = mop==null ? null : mop._loc; + _isLoad= mop==null ? true : mop._isLoad; + _declaredType = mop==null ? Type.BOTTOM : mop._declaredType; + if( mop==null ) + throw Utils.TODO("Load or not"); + } + + // Used by M2 when translating graph to Simple + public MemOpNode( boolean isLoad ) { + super((Node)null); + _name = null; + _alias = 0; + _loc = null; + _isLoad = isLoad; + _declaredType = Type.BOTTOM; + } + + static String mlabel(String name) { return "[]".equals(name) ? "ary" : ("#".equals(name) ? "len" : name); } + String mlabel() { return mlabel(_name); } + + public Node mem() { return in(1); } + public Node ptr() { return in(2); } + public Node off() { return in(3); } + + @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return _printMach(sb,visited); } + public StringBuilder _printMach( StringBuilder sb, BitSet visited ) { throw Utils.TODO(); } + public int log_size() { return _declaredType.log_size(); } + + @Override + public boolean eq(Node n) { + MemOpNode mem = (MemOpNode)n; // Invariant + return _alias==mem._alias; // When comparing types error to use "equals"; always use "==" + } + + @Override + int hash() { return _alias; } + + @Override + public Parser.ParseException err() { + Type ptr = ptr()._type; + // Already an error, but better error messages come from elsewhere + if( ptr == Type.BOTTOM ) return null; + if( ptr.isHigh() ) return null; // Assume it will fall to not-null + // Better be a not-nil TMP + if( ptr instanceof TypeMemPtr tmp && tmp.notNull() ) + return null; + return Parser.error( "Might be null accessing '" + _name + "'",_loc); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MinusFNode.java new file mode 100644 index 00000000..99fc3144 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MinusFNode.java @@ -0,0 +1,36 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; + +import java.util.BitSet; + +public class MinusFNode extends Node { + public MinusFNode(Node in) { super(null, in); } + + @Override public String label() { return "MinusF"; } + + @Override public String glabel() { return "-"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("(-"), visited); + return sb.append(")"); + } + + @Override + public Type compute() { + if (in(1)._type instanceof TypeFloat i0) + return i0.isConstant() ? TypeFloat.constant(-i0.value()) : i0; + return TypeFloat.F64; + } + + @Override + public Node idealize() { + // -(-x) is x + if( in(1) instanceof MinusFNode minus ) + return minus.in(1); + + return null; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MinusNode.java new file mode 100644 index 00000000..f26ce37e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -0,0 +1,39 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +public class MinusNode extends Node { + public MinusNode(Node in) { super(null, in); } + + @Override public String label() { return "Minus"; } + + @Override public String glabel() { return "-"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("(-"), visited); + return sb.append(")"); + } + + @Override + public Type compute() { + if( in(1)._type.isHigh() ) return TypeInteger.TOP; + if( in(1)._type instanceof TypeInteger i0 && + i0._min != Long.MIN_VALUE && i0._max != Long.MIN_VALUE ) + return TypeInteger.make(-i0._max,-i0._min); + return TypeInteger.BOT; + } + + @Override + public Node idealize() { + // -(-x) is x + if( in(1) instanceof MinusNode minus ) + return minus.in(1); + + return null; + } + @Override Node copyF() { return new MinusFNode(null); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MulFNode.java new file mode 100644 index 00000000..6fbf4bbb --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MulFNode.java @@ -0,0 +1,51 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; + +import java.util.BitSet; + +public class MulFNode extends Node { + public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "MulF"; } + + @Override public String glabel() { return "*"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("("), visited); + in(2)._print0(sb.append("*"), visited); + return sb.append(")"); + } + + @Override + public Type compute() { + if (in(1)._type instanceof TypeFloat i0 && + in(2)._type instanceof TypeFloat i1) { + if (i0.isConstant() && i1.isConstant()) + return TypeFloat.constant(i0.value()*i1.value()); + } + return in(1)._type.meet(in(2)._type); + } + + @Override + public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Mul of 1. We do not check for (1*x) because this will already + // canonicalize to (x*1) + if ( t2.isConstant() && t2 instanceof TypeFloat i && i.value()==1 ) + return lhs; + + // Move constants to RHS: con*arg becomes arg*con + if ( t1.isConstant() && !t2.isConstant() ) + return swap12(); + + return null; + } + @Override Node copy(Node lhs, Node rhs) { return new MulFNode(lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MulNode.java new file mode 100644 index 00000000..debc2c56 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MulNode.java @@ -0,0 +1,63 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import java.util.BitSet; + +public class MulNode extends ArithNode { + public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "Mul"; } + @Override public String op() { return "*"; } + + @Override long doOp( long x, long y ) { return x * y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + return TypeInteger.BOT; + } + + @Override + public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Move constants to RHS: con*arg becomes arg*con + if ( t1.isConstant() && !t2.isConstant() ) + return swap12(); + + // Multiply by constant + if ( t2.isConstant() && t2 instanceof TypeInteger i ) { + // Mul of 1. We do not check for (1*x) because this will already + // canonicalize to (x*1) + long c = i.value(); + if( c==1 ) return lhs; + if( c==0 ) return Parser.ZERO; + // Mul by a power of 2, +/-1. Bit patterns more complex than this + // are unlikely to win on an X86 vs the normal "imul", and so + // become machine-specific. + if( (c & (c-1)) == 0 ) + return new ShlNode(null,lhs,con(Long.numberOfTrailingZeros(c))); + // 2**n + 1, e.g. 9 + long d = c-1; + if( (d & (d-1)) == 0 ) + return new AddNode(new ShlNode(null,lhs,con(Long.numberOfTrailingZeros(d))).peephole(),lhs); + // 2**n - 1, e.g. 31 + long e = c+1; + if( (e & (e-1)) == 0 ) + return new SubNode(new ShlNode(null,lhs,con(Long.numberOfTrailingZeros(e))).peephole(),lhs); + + } + + // Do we have ((x * (phi cons)) * con) ? + // Do we have ((x * (phi cons)) * (phi cons)) ? + // Push constant up through the phi: x * (phi con0*con0 con1*con1...) + Node phicon = AddNode.phiCon(this,true); + if( phicon!=null ) return phicon; + + return super.idealize(); + } + @Override Node copy(Node lhs, Node rhs) { return new MulNode(lhs,rhs); } + @Override Node copyF() { return new MulFNode(null,null); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MultiNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MultiNode.java new file mode 100644 index 00000000..b4d6d78e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MultiNode.java @@ -0,0 +1,29 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.util.Ary; + + +public interface MultiNode { + + abstract Ary<Node> outs(); + + // Find a projection by index + default ProjNode proj( int idx ) { + for( Node out : outs() ) + if( out instanceof ProjNode prj && prj._idx==idx ) + return prj; + return null; + } + + // Find a projection by index + default CProjNode cproj( int idx ) { + for( Node out : outs() ) + if( out instanceof CProjNode prj && prj._idx==idx ) + return prj; + return null; + } + + // Return not-null if this projection index is a ideal copy. + // Called by ProjNode ideal and used to collapse Multis. + default Node pcopy(int idx) { return null; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/NeverNode.java new file mode 100644 index 00000000..516f218b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/NeverNode.java @@ -0,0 +1,22 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeTuple; + +import java.util.BitSet; + +// "Never true" for infinite loop exits +public class NeverNode extends IfNode { + public NeverNode(NeverNode ctrl) { super(ctrl); } + public NeverNode(Node ctrl) { super(ctrl,null); } + + @Override public String label() { return "Never"; } + + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Never"); } + + @Override public Type compute() { return TypeTuple.IF_BOTH; } + + @Override public Node idealize() { return null; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/NewNode.java new file mode 100644 index 00000000..1785af4e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/NewNode.java @@ -0,0 +1,131 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; + +import java.util.BitSet; + +/** + * Allocation! Allocate a chunk of memory, and pre-zero it. + * The inputs include control and size, and ALL aliases being set. + * The output is large tuple, one for every alias plus the created pointer. + * New is expected to be followed by projections for every alias. + */ +public class NewNode extends Node implements MultiNode { + + public final TypeMemPtr _ptr; + public final int _len; + + public NewNode(TypeMemPtr ptr, Node... nodes) { + super(nodes); + assert !ptr.nullable(); + _ptr = ptr; + _len = ptr._obj._fields.length; + // Control in slot 0 + assert nodes[0]._type==Type.CONTROL || nodes[0]._type == Type.XCONTROL; + // Malloc-length in slot 1 + assert nodes[1]._type instanceof TypeInteger || nodes[1]._type==Type.NIL; + for( int i=0; i<_len; i++ ) + assert ptr._obj._fields[i]._one || nodes[2 + i]._type.isa( TypeMem.BOT ); + } + + public NewNode(NewNode nnn) { super(nnn); _ptr = nnn._ptr; _len = nnn._len; } + + public Node mem (int idx) { return in(idx+2); } + + @Override public String label() { return "new_"+glabel(); } + @Override public String glabel() { + return _ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._t.str() : _ptr._obj.str(); + } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + sb.append("new "); + return sb.append(_ptr._obj.str()); + } + + int findAlias(int alias) { + int idx = _ptr._obj.findAlias(alias); + assert idx!= -1; // Error, caller should be calling + return idx+2; // Skip ctrl, size + } + + // 0 - ctrl + // 1 - byte size + // 2-len+2 - aliases, one per field + // len+2 - 2*len+2 - initial values, one per field + public Node size() { return in(1); } + + @Override + public TypeTuple compute() { + Field[] fs = _ptr._obj._fields; + Type[] ts = new Type[fs.length+2]; + ts[0] = Type.CONTROL; + ts[1] = _ptr; + for( int i=0; i<fs.length; i++ ) { + if( _ptr._obj._fields[i]._one ) { + // Once-only fields use the declared type + ts[i+2] = _ptr._obj._fields[i]._t; + } else { + // Others take from the inputs + Type mt = in(i+2)._type; + TypeMem mem = mt==Type.TOP ? TypeMem.TOP : (TypeMem)mt; + Type tfld = mem._t.meet(mem._t.makeZero()); + Type tfld2 = tfld.join(fs[i]._t ); + ts[i+2] = TypeMem.make(fs[i]._alias,tfld2); + } + } + return TypeTuple.make(ts); + } + + @Override + public Node idealize() { + Node progress=null; + for( int i=1; i<nIns(); i++ ) { + if( in(i) instanceof CastNode cast ) + progress = setDef(i,cast.in(1)); + } + return progress == null ? null : this; + } + + @Override + public boolean eq(Node n) { return this == n; } + + @Override + int hash() { return _ptr.hashCode(); } + + // ------------ + // MachNode specifics, shared across all CPUs + public int _arg2Reg, _xslot; + private RegMask _arg3Mask; + private RegMask _retMask; + private RegMask _kills; + public void cacheRegs(CodeGen code) { + _arg2Reg = code._mach.callArgMask(TypeFunPtr.CALLOC,2,0).firstReg(); + _arg3Mask = code._mach.callArgMask(TypeFunPtr.CALLOC,3,0); + // Return mask depends on TFP (either GPR or FPR) + _retMask = code._mach.retMask(TypeFunPtr.CALLOC); + // Kill mask is all caller-saves, and any mirror stack slots for args + // in registers. + RegMaskRW kills = code._callerSave.copy(); + // Start of stack slots + int maxReg = code._mach.regs().length; + // Incoming function arg slots, all low numbered in the RA + int fslot = cfg0().fun()._maxArgSlot; + // Killed slots for this calls outgoing args + int xslot = code._mach.maxArgSlot(TypeFunPtr.CALLOC); + _xslot = (maxReg+fslot)+xslot; + for( int i=0; i<xslot; i++ ) + kills.set((maxReg+fslot)+i); + _kills = kills; + } + public String op() { return "alloc"; } + public RegMask regmap(int i) { return i==1 ? _arg3Mask : null; } + public RegMask outregmap() { return null; } + public RegMask outregmap(int idx) { return idx==1 ? _retMask : null; } + public RegMask killmap() { return _kills; } + public void asm(CodeGen code, SB sb) { + sb.p("#calloc, ").p(code.reg(size())); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter24/src/main/java/com/seaofnodes/simple/node/Node.java new file mode 100644 index 00000000..5e5be196 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/Node.java @@ -0,0 +1,738 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.print.IRPrinter; +import com.seaofnodes.simple.print.JSViewer; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.type.TypeInteger; +import java.util.*; +import java.util.function.Function; +import static com.seaofnodes.simple.codegen.CodeGen.CODE; + +/** + * All Nodes in the Sea of Nodes IR inherit from the Node class. + * The Node class provides common functionality used by all subtypes. + * Subtypes of Node specialize by overriding methods. + */ +public abstract class Node implements Cloneable { + + /** + * Each node has a unique dense Node ID within a compilation context + * The ID is useful for debugging, for using as an offset in a bitvector, + * as well as for computing equality of nodes (to be implemented later). + */ + public int _nid; + + /** + * Inputs to the node. These are use-def references to Nodes. + * <p> + * Generally fixed length, ordered, nulls allowed, no unused trailing space. + * Ordering is required because e.g. "a/b" is different from "b/a". + * The first input (offset 0) is often a {@link CFGNode} node. + */ + public Ary<Node> _inputs; + + /** + * Outputs reference Nodes that are not null and have this Node as an + * input. These nodes are users of this node, thus these are def-use + * references to Nodes. + * <p> + * Outputs directly match inputs, making a directed graph that can be + * walked in either direction. These outputs are typically used for + * efficient optimizations but otherwise have no semantics meaning. + */ + public Ary<Node> _outputs; + + + /** + * Current computed type for this Node. This value changes as the graph + * changes and more knowledge is gained about the program. + */ + public Type _type; + + + Node(Node... inputs) { + _nid = CODE.getUID(); // allocate unique dense ID + _inputs = new Ary<>(Node.class); + Collections.addAll(_inputs,inputs); + _outputs = new Ary<>(Node.class); + for( Node n : _inputs ) + if( n != null ) + n.addUse( this ); + } + + // Make a Node using the existing arrays of nodes. + // Used by any pass rewriting all Node classes but not the edges. + Node( Node n ) { + assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.Select.ordinal(); + _nid = CODE.getUID(); // allocate unique dense ID + _inputs = new Ary<>(n==null ? new Node[0] : n._inputs.asAry()); + _outputs = new Ary<>(Node.class); + _type = n==null ? Type.BOTTOM : n._type; + _deps = null; + _hash = 0; + } + + // Easy reading label for debugger, e.g. "Add" or "Region" or "EQ" + public abstract String label(); + + // Unique label for graph visualization, e.g. "Add12" or "Region30" or "EQ99" + public String uniqueName() { + // Get rid of $ as graphviz doesn't like it + String label = label().replaceAll("\\$", ""); + return label + _nid; + } + + // Graphical label, e.g. "+" or "Region" or "==" + public String glabel() { return label(); } + + // Extra fun stuff, for assembly printing. Jump labels, parser locations, + // variable types, etc. + public String comment() { return null; } + + // ------------------------------------------------------------------------ + + // Debugger Printing. + + // {@code toString} is what you get in the debugger. It has to print 1 + // line (because this is what a debugger typically displays by default) and + // has to be robust with broken graph/nodes. + @Override + public final String toString() { return print(); } + + // This is a *deep* print. We print with a mutually recursive tik-tok + // style; the common _print0 calls the per-Node _print1, which calls back + // to _print0; + public final String print() { + return _print0(new StringBuilder(), new BitSet()).toString(); + } + + // This is the common print: check for repeats, check for DEAD and print + // "DEAD" else call the per-Node print1. + public final StringBuilder _print0(StringBuilder sb, BitSet visited) { + if (visited.get(_nid) && !(this instanceof ConstantNode) ) + return sb.append(label()); + visited.set(_nid); + return isDead() + ? sb.append(uniqueName()).append(":DEAD") + : _print1(sb, visited); + } + // Every Node implements this; a partial-line recursive print + abstract public StringBuilder _print1(StringBuilder sb, BitSet visited); + + public String p(int depth) { return IRPrinter.prettyPrint(this,depth); } + + public boolean isConst() { return false; } + + // ------------------------------------------------------------------------ + // Graph Node & Edge manipulation + + /** + * Gets the ith input node + * @param i Offset of the input node + * @return Input node or null + */ + public Node in(int i) { return _inputs.get(i); } + public Node out(int i) { return _outputs.get(i); } + public final Ary<Node> outs() { return _outputs; } + + public int nIns() { return _inputs.size(); } + + public int nOuts() { return _outputs.size(); } + + public boolean isUnused() { return nOuts() == 0; } + + public CFGNode cfg0() { return (CFGNode)in(0); } + + /** + * Change a <em>def</em> into a Node. Keeps the edges correct, by removing + * the corresponding <em>use->def</em> edge. This may make the original + * <em>def</em> go dead. This function is co-recursive with {@link #kill}. + * <p> + + * This method is the normal path for altering a Node, because it does the + * proper default edge maintenance. It also <em>immediately</em> kills + * Nodes that lose their last use; at times care must be taken to avoid + * killing Nodes that are being used without having an output Node. This + * definitely happens in the middle of recursive {@link #peephole} calls. + * + * @param idx which def to set + * @param new_def the new definition + * @return new_def for flow coding + */ + public <N extends Node> N setDef(int idx, N new_def ) { + unlock(); + Node old_def = in(idx); + if( old_def == new_def ) return new_def; // No change + // If new def is not null, add the corresponding def->use edge + // This needs to happen before removing the old node's def->use edge as + // the new_def might get killed if the old node kills it recursively. + if( new_def != null ) + new_def.addUse(this); + // Set the new_def over the old (killed) edge + _inputs.set(idx,new_def); + if( old_def != null ) { // If the old def exists, remove a def->use edge + if( old_def.delUse(this) ) // If we removed the last use, the old def is now dead + old_def.kill(); // Kill old def + else CODE.add(old_def); // Else old lost a use, so onto worklist + } + moveDepsToWorklist(); + // Return new_def for easy flow-coding + return new_def; + } + public <N extends Node> N setDefX(int idx, N new_def ) { + while( nIns() <= idx ) addDef(null); + return setDef(idx,new_def); + } + + // Remove the numbered input, compressing the inputs in-place. This + // shuffles the order deterministically - which is suitable for Region and + // Phi, but not for every Node. If the def goes dead, it is recursively + // killed, which may include 'this' Node. + public Node delDef(int idx) { + unlock(); + Node old_def = in(idx); + _inputs.del(idx); + if( old_def.delUse(this) ) // If we removed the last use, the old def is now dead + old_def.kill(); // Kill old def + old_def.moveDepsToWorklist(); + return this; + } + + // Insert the numbered input, sliding other inputs to the right + Node insertDef(int idx, Node new_def) { + _inputs.add(idx,null); + return setDef(idx,new_def); + } + + + /** + * Add a new def to an existing Node. Keep the edges correct by + * adding the corresponding <em>def->use</em> edge. + * + * @param new_def the new definition, appended to the end of existing definitions + * @return new_def for flow coding + */ + public Node addDef(Node new_def) { + unlock(); + // Add use->def edge + _inputs.add(new_def); + // If new def is not null, add the corresponding def->use edge + if( new_def != null ) + new_def.addUse(this); + return new_def; + } + + // Breaks the edge invariants, used temporarily + @SuppressWarnings("unchecked") + protected <N extends Node> N addUse(Node n) { _outputs.add(n); return (N)this; } + + // Remove node 'use' from 'def's (i.e. our) output list, by compressing the list in-place. + // Return true if the output list is empty afterward. + // Error is 'use' does not exist; ok for 'use' to be null. + protected boolean delUse( Node use ) { + _outputs.del(_outputs.find(use)); + return _outputs.isEmpty(); + } + + // Shortcut for "popping" until n nodes. A "pop" is basically a + // setDef(last,null) followed by lowering the nIns() count. + public void popUntil(int n) { + unlock(); + while( nIns() > n ) { + Node old_def = _inputs.pop(); + if( old_def != null && // If it exists and + old_def.delUse(this) ) // If we removed the last use, the old def is now dead + old_def.kill(); // Kill old def + } + } + + /** + * Kill a Node with no <em>uses</em>, by setting all of its <em>defs</em> + * to null. This may recursively kill more Nodes, and is basically dead + * code elimination. + */ + public void kill( ) { + assert isUnused(); // Has no uses, so it is dead + unlock(); + moveDepsToWorklist(); + _type=null; // Flag as dead + while( nIns()>0 ) { // Set all inputs to null, recursively killing unused Nodes + Node old_def = _inputs.removeLast(); + // Revisit neighbor because removed use + if( old_def != null && CODE.add(old_def).delUse(this) ) + old_def.kill(); // If we removed the last use, the old def is now dead + } + assert isDead(); // Really dead now + } + + // Preserve CFG use-ordering when killing + public void killOrdered() { + CFGNode cfg = cfg0(); + cfg._outputs.remove(cfg._outputs.find(this)); + _inputs.set(0,null); + kill(); + } + + + // Mostly used for asserts and printing. + public boolean isDead() { return isUnused() && nIns()==0 && _type==null; } + + // Shortcuts to stop DCE mid-parse + // Add bogus null use to keep node alive + public <N extends Node> N keep() { return addUse(null); } + // Remove bogus null. + @SuppressWarnings("unchecked") + public <N extends Node> N unkeep() { + delUse(null); + return (N)this; + } + // Test "keep" status + public boolean iskeep() { return _outputs.find(null) != -1; } + public void unkill() { + if( unkeep().isUnused() ) + kill(); + } + public void isKill() { + if( isUnused() ) + kill(); + } + + + // Replace self with nnn in the graph, making 'this' go dead + public void subsume( Node nnn ) { + assert nnn!=this; + while( nOuts() > 0 ) { + Node n = _outputs.removeLast(); + n.unlock(); + int idx = n._inputs.find(this); + n._inputs.set(idx,nnn); + nnn.addUse(n); + CODE.add(n); + CODE.addAll(n._outputs); + } + kill(); + } + + // insert `this` immediately after `def` in the same basic block. + public void insertAfter( Node def ) { + CFGNode cfg = def.cfg0(); + int i = cfg._outputs.find(def)+1; + if( cfg instanceof CallEndNode ) { + cfg = cfg.uctrl(); i=0; + } else if( def.in(0) instanceof MultiNode ) { + assert i==0; + i = cfg._outputs.find(def.in(0))+1; + } + + while( cfg.out(i) instanceof PhiNode || cfg.out(i) instanceof CalleeSaveNode ) i++; + cfg._outputs.insert(this,i); + _inputs.set(0,cfg); + } + + // Insert this in front of use.in(uidx) with this, and insert this + // immediately before use in the basic block. + public void insertBefore( Node use, int uidx ) { + CFGNode cfg = use.cfg0(); + int i; + if( use instanceof PhiNode phi ) { + cfg = phi.region().cfg(uidx); + if( cfg instanceof CProjNode && cfg.in(0) instanceof NeverNode nvr ) + cfg = nvr.cfg0(); + i = cfg.nOuts()-1; + } else { + i = cfg._outputs.find(use); + } + cfg._outputs.insert(this,i); + _inputs.set(0,cfg); + if( _inputs._len > 1 && this instanceof SplitNode ) + setDefOrdered(1,use.in(uidx)); + use.setDefOrdered(uidx,this); + } + + public void setDefOrdered( int idx, Node def) { + // If old is dying, remove from CFG ordered + Node old = in(idx); + if( old!=null && old.nOuts()==1 ) { + CFGNode cfg = old.cfg0(); + if( cfg!=null ) { + cfg._outputs.remove(cfg._outputs.find(old)); + old._inputs.set(0,null); + } + } + setDef(idx,def); + } + + public void removeSplit() { + CFGNode cfg = cfg0(); + cfg._outputs.remove(cfg._outputs.find(this)); + _inputs.set(0,null); + if( _inputs._len > 1 ) subsume(in(1)); + } + + // ------------------------------------------------------------------------ + // Graph-based optimizations + + /** + * Try to peephole at this node and return a better replacement Node. + * Always returns some not-null Node (often this). + */ + public final Node peephole( ) { + if( _type==null ) // Brand-new node, never peeped before + JSViewer.show(); + Node n = peepholeOpt(); + if( n!=null ) // Made progress? + JSViewer.show(); // Show again + return n==null ? this : deadCodeElim(n._nid >= _nid ? n.peephole() : n); // Cannot return null for no-progress + } + + /** + * Try to peephole at this node and return a better replacement Node if + * possible. We compute a {@link Type} and then check and replace: + * <ul> + * <li>if the Type {@link Type#isConstant}, we replace with a {@link ConstantNode}</li> + * <li>in a future chapter we will look for a + * <a href="https://en.wikipedia.org/wiki/Common_subexpression_elimination">Common Subexpression</a> + * to eliminate.</li> + * <li>we ask the Node for a better replacement. The "better replacement" + * is things like {@code (1+2)} becomes {@code 3} and {@code (1+(x+2))} becomes + * {@code (x+(1+2))}. By canonicalizing expressions we fold common addressing + * math constants, remove algebraic identities and generally simplify the + * code. </li> + * + * Unlike peephole above, this explicitly returns null for no-change, or not-null + * for a better replacement (which can be this). + * </ul> + */ + public final Node peepholeOpt( ) { + CODE.iterCnt(); + // Compute initial or improved Type + Type old = setType(compute()); + + // Replace constant computations from non-constants with a constant + // node. If peeps are disabled, still allow high Phis to collapse; + // they typically come from dead Regions, and we want the Region to + // collapse, which requires the Phis to die first. + if( !isConst() && _type.isHighOrConst() ) + return ConstantNode.make(_type).peephole(); + + // Global Value Numbering + if( _hash==0 ) { + Node n = CODE._gvn.get(this); // Will set _hash as a side effect + if( n==null ) + CODE._gvn.put(this,this); // Put in table now + else { + // Because of random worklist ordering, the two equal nodes + // might have different types. Because of monotonicity, both + // types are valid. To preserve monotonicity, the resulting + // shared Node has to have the best of both types. + n.setType(n._type.join(_type)); + _hash = 0; // Clear, since it never went in the table + return deadCodeElim(n);// Return previous; does Common Subexpression Elimination + } + } + + // Ask each node for a better replacement + Node n = idealize(); + if( n != null ) // Something changed + return n; // Report progress + + if( old!=_type ) return this; // Report progress; + CODE.iterNop(); + return null; // No progress + } + + // m is the new Node, self is the old. + // Return 'm', which may have zero uses but is alive nonetheless. + // If self has zero uses (and is not 'm'), {@link #kill} self. + private Node deadCodeElim(Node m) { + // If self is going dead and not being returned here (Nodes returned + // from peephole commonly have no uses (yet)), then kill self. + if( m != this && isUnused() && !isDead() ) { + // Killing self - and since self recursively kills self's inputs we + // might end up killing 'm', which we are returning as a live Node. + // So we add a bogus extra null output edge to stop kill(). + m.keep(); // Keep m alive + kill(); // Kill self because replacing with 'm' + m.unkeep(); // Okay to peephole m + } + return m; + } + + /** + * This function needs to be + * <a href="https://en.wikipedia.org/wiki/Monotonic_function">Monotonic</a> + * as it is part of a Monotone Analysis Framework. + * <a href="https://www.cse.psu.edu/~gxt29/teaching/cse597s21/slides/08monotoneFramework.pdf">See for example this set of slides</a>. + * <p> + * For Chapter 2, all our Types are really integer constants, and so all + * the needed properties are trivially true, and we can ignore the high + * theory. Much later on, this will become important and allow us to do + * many fancy complex optimizations trivially... because theory. + * <p> + * {@link #compute()} needs to be stand-alone, and cannot recursively call compute + * on its inputs, because programs are cyclic (have loops!) and this will just + * infinitely recurse until stack overflow. Instead, compute typically + * computes a new type from the {@link #_type} field of its inputs. + */ + public abstract Type compute(); + + // Set the type. Assert monotonic progress. + // If changing, add users to worklist. + public Type setType(Type type) { + Type old = _type; + assert old==null || type.isa(old); // Since _type not set, can just re-run this in assert in the debugger + if( old == type ) return old; + _type = type; // Set _type late for easier assert debugging + CODE.addAll(_outputs); + moveDepsToWorklist(); + return old; + } + + @SuppressWarnings("unchecked") + public <N extends Node> N init() { _type = compute(); return (N)this; } + + /** + * This function rewrites the current Node into a more "idealized" form. + * This is the bulk of our peephole rewrite rules, and we use this to + * e.g. turn arbitrary collections of adds and multiplies with mixed + * constants into a normal form that's easy for hardware to implement. + * Example: An array addressing expression: + * <pre> ary[idx+1]</pre> + * might turn into Sea-of-Nodes IR: + * <pre> (ary+12)+((idx+1) * 4)</pre> + * This expression can then be idealized into: + * <pre> ary + ((idx*4) + (12 + (1*4)))</pre> + * And more folding: + * <pre> ary + ((idx<<2) + 16)</pre> + * And during code-gen: + * <pre> MOV4 Rary,[Ridx<<2 +16] // or some such hardware-specific notation </pre> + * <p> + * {@link #idealize} has a very specific calling convention: + * <ul> + * <li>If NO change is made, return {@code null} + * <li>If ANY change is made, return not-null; this can be {@code this} + * <li>The returned Node does NOT call {@link #peephole} on itself; the {@link #peephole} call will recursively peephole it. + * <li>Any NEW nodes that are not directly returned DO call {@link #peephole}. + * </ul> + * <p> + * Examples: + * <table border="3"> + * <tr><th> before </th><th> after </th><th>return </th><th>comment </th></tr> + * <tr><td>{@code (x+5) }</td><td>{@code (x+5) }</td><td>{@code null }</td><td>No change</td></tr> + * <tr><td>{@code (5+x) }</td><td>{@code (x+5) }</td><td>{@code this }</td><td>Swapped arguments</td></tr> + * <tr><td>{@code ((x+1)+2)}</td><td>{@code (x+(1+2))}</td><td>{@code (x+_) }</td><td>Returns 2 new Nodes</td></tr> + * </table> + * + * The last entry deserves more discussion. The new Node {@code (1+2)} + * created in {@link #idealize} calls {@link #peephole} (which then folds + * into a constant). The other new Node {@code (x+3)} does not call + * peephole, because it is returned and peephole itself will recursively + * call peephole. + * <p> + * Since idealize calls peephole and peephole calls idealize, you must be + * careful that all idealizations are <em>monotonic</em>: all transforms + * remove some feature, so that the set of available transforms always + * shrinks. If you don't, you risk an infinite peephole loop! + * + * @return Either a new or changed node, or null for no changes. + */ + public abstract Node idealize(); + + + // Some of the peephole rules get complex, and search further afield than + // just the nearest neighbor. These peepholes can fail the pattern match + // on a node some distance away, and if that node ever changes we should + // retry the peephole. Track a set of Nodes dependent on `this`, and + // revisit them if `this` changes. + Ary<Node> _deps; + + /** + * Add a node to the list of dependencies. Only add it if its not an input + * or output of this node, that is, it is at least one step away. The node + * being added must benefit from this node being peepholed. + */ + <N extends Node> N addDep( N dep ) { + // Running peepholes during the big assert cannot have side effects + // like adding dependencies. + if( CODE._midAssert ) return dep; + if( dep._deps==null ) dep._deps = new Ary<>(Node.class); + if( dep._deps .find(this) != -1 ) return dep; // Already on list + if( dep._inputs .find(this) != -1 ) return dep; // No need for deps on immediate neighbors + if( dep._outputs.find(this) != -1 ) return dep; + dep._deps.add(this); + return dep; + } + + // Move the dependents onto a worklist, and clear for future dependents. + public void moveDepsToWorklist( ) { + if( _deps==null ) return; + CODE.addAll(_deps); + _deps.clear(); + } + + + // Two nodes are equal if they have the same inputs and the same "opcode" + // which means the same Java class, plus same internal parts. + @Override public final boolean equals( Object o ) { + if( o==this ) return true; + if( o.getClass() != getClass() ) return false; + Node n = (Node)o; + int len = _inputs.size(); + if( len != n._inputs.size() ) return false; + for( int i=0; i<len; i++ ) + if( in(i) != n.in(i) ) + return false; + return eq(n); + } + // Subclasses add extra checks (such as ConstantNodes have same constant), + // and can assume "this!=n" and has the same Java class. + public boolean eq( Node n ) { return true; } + + + // Cached hash. If zero, then not computed AND this Node is NOT in the GVN + // table - and can have its edges hacked (which will change his hash + // anyway). If Non-Zero then this Node is IN the GVN table, or is being + // probed to see if it can be inserted. His edges are "locked", because + // hacking his edges will change his hash. + int _hash; + + // If the _hash is set, then the Node is in the GVN table; remove it. + void unlock() { + if( _hash==0 ) return; + Node old = CODE._gvn.remove(this); // Pull from table + assert old==this; + _hash=0; // Out of table now + } + + + // Hash of opcode and inputs + @Override public final int hashCode() { + if( _hash != 0 ) return _hash; + int hash = hash(); + for( Node n : _inputs ) + if( n != null ) + hash = hash ^ (hash<<17) ^ (hash>>13) ^ n._nid; + if( hash==0 ) hash = 0xDEADBEEF; // Bad hash, so use some junky thing + return (_hash=hash); + } + // Subclasses add extra hash info (such as ConstantNodes constant) + int hash() { return 0; } + + // ------------------------------------------------------------------------ + // + + /** Is this Node Memory related */ + public boolean isMem() { return false; } + + /** Pinned in the schedule; these are data nodes whose input#0 is not allowed to change */ + public boolean isPinned() { return false; } + + // Semantic change to the graph (so NOT a peephole), used by the Parser. + // If any input is a float, flip to a float-flavored opcode and widen any + // non-float input. + public final Node widen() { + if( !hasFloatInput() ) return this; + Node flt = copyF(); + if( flt==null ) return this; + for( int i=1; i<nIns(); i++ ) + flt.setDef(i, in(i)._type instanceof TypeFloat ? in(i) : new ToFloatNode(in(i)).peephole()); + kill(); + return flt; + } + private boolean hasFloatInput() { + for( int i=1; i<nIns(); i++ ) + if( in(i)._type instanceof TypeFloat ) + return true; + return false; + } + Node copyF() { return null; } + + + // ------------------------------------------------------------------------ + // Peephole utilities + + // Swap inputs without letting either input go dead during the swap. + public Node swap12() { + unlock(); // Hash is order dependent + _inputs.swap(1,2); + return this; + } + + /** + * Does this node contain all constants? Ignores in(0), as is usually + * control. In an input is not a constant, we add dep as a dependency to + * it because dep can make progress if the input becomes a constant later. + * It is sufficient for one of the non-const inputs to have the dependency, + * so we don't bother checking the rest. + */ + boolean allCons(Node dep) { + for( int i=1; i<nIns(); i++ ) + if( !(in(i)._type.isConstant()) ) { + dep.addDep(in(i)); // If in(i) becomes a constant later, will trigger some peephole + return false; + } + return true; + } + + + // Make a shallow copy (same class) of this Node, with given inputs and + // empty outputs and a new Node ID. The original inputs are ignored. + // Does not need to be implemented in isCFG() nodes. + Node copy(Node lhs, Node rhs) { throw Utils.TODO("Binary ops need to implement copy"); } + + public Node copy() { + Node n; + try { n = (Node)clone(); } + catch( Exception e ) { throw new RuntimeException(e); } + n._nid = CODE.getUID(); // allocate unique dense ID + n._inputs = new Ary<>(Node.class); + n._outputs = new Ary<>(Node.class); + n._deps = null; + n._hash = 0; + return n; + } + + // Report any post-optimize errors + public Parser.ParseException err() { return null; } + + // Common integer constants + public static ConstantNode con(long x) { return (ConstantNode)(new ConstantNode(TypeInteger.constant(x)).peephole()); } + + // Utility to walk the entire graph applying a function; return the first + // not-null result. + final public <E> E walk( Function<Node,E> pred ) { + assert CODE._visit.isEmpty(); + E rez = _walk(pred); + CODE._visit.clear(); + return rez; + } + + private <E> E _walk( Function<Node,E> pred ) { + if( CODE._visit.get(_nid) ) return null; // Been there, done that + CODE._visit.set(_nid); + E x = pred.apply(this); + if( x != null ) return x; + for( Node def : _inputs ) if( def != null && (x = def._walk(pred)) != null ) return x; + for( Node use : _outputs ) if( use != null && (x = use._walk(pred)) != null ) return x; + return null; + } + + /** + * Debugging utility to find a Node by index + */ + public Node find(int nid) { return _find(nid, new BitSet()); } + private Node _find(int nid, BitSet bs) { + if( bs.get(_nid) ) return null; // Been there, done that + bs.set(_nid); + if( _nid==nid ) return this; + Node x; + for( Node def : _inputs ) if( def != null && (x = def._find(nid,bs)) != null ) return x; + for( Node use : _outputs ) if( use != null && (x = use._find(nid,bs)) != null ) return x; + return null; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/NotNode.java new file mode 100644 index 00000000..4b80e61c --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/NotNode.java @@ -0,0 +1,32 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +public class NotNode extends Node { + public NotNode(Node in) { super(null, in); } + + @Override public String label() { return "Not"; } + + @Override public String glabel() { return "!"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("(!"), visited); + return sb.append(")"); + } + + @Override + public TypeInteger compute() { + Type t0 = in(1)._type; + if( t0.isHigh() ) return (TypeInteger)TypeInteger.BOOL.dual(); + if( t0 == Type.NIL || t0 == TypeInteger.ZERO ) return TypeInteger.TRUE; + if( t0 instanceof TypeNil tn && tn.notNull() ) return TypeInteger.FALSE; + if( t0 instanceof TypeInteger i && (i._min > 0 || i._max < 0) ) return TypeInteger.FALSE; + return TypeInteger.BOOL; + } + + @Override + public Node idealize() { return null; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/OrNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/OrNode.java new file mode 100644 index 00000000..ac0d8454 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/OrNode.java @@ -0,0 +1,45 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; + +public class OrNode extends ArithNode { + public OrNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } + + @Override public String label() { return "Or"; } + @Override public String op() { return "|"; } + @Override public String glabel() { return "|"; } + + + @Override long doOp( long x, long y ) { return x | y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + return TypeInteger.BOT; + } + + @Override + public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Or of 0. We do not check for (0|x) because this will already + // canonicalize to (x|0) + if( t2.isConstant() && t2 instanceof TypeInteger i && i.value()==0 ) + return lhs; + + // Move constants to RHS: con*arg becomes arg*con + if ( t1.isConstant() && !t2.isConstant() ) + return swap12(); + + // Do we have ((x | (phi cons)) | con) ? + // Do we have ((x | (phi cons)) | (phi cons)) ? + // Push constant up through the phi: x | (phi con0|con0 con1|con1...) + Node phicon = AddNode.phiCon(this,true); + if( phicon!=null ) return phicon; + + return super.idealize(); + } + @Override Node copy(Node lhs, Node rhs) { return new OrNode(_loc,lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ParmNode.java new file mode 100644 index 00000000..a14a4fb9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ParmNode.java @@ -0,0 +1,45 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import java.util.BitSet; + +public class ParmNode extends PhiNode { + + // Argument indices are mapped one-to-one on CallNode inputs + public final int _idx; // Argument index + + public ParmNode(String label, int idx, Type declaredType, Node... inputs) { + super(label,declaredType,inputs); + _idx = idx; + } + public ParmNode(ParmNode parm) { super(parm, parm._label, parm._minType ); _idx = parm._idx; } + + @Override public String label() { return MemOpNode.mlabel(_label); } + + @Override public String glabel() { return _label; } + + public FunNode fun() { return (FunNode)in(0); } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + if( "main".equals(fun()._name) && _label.equals("arg") ) + return sb.append("arg"); + sb.append("Parm_").append(_label).append("("); + for( Node in : _inputs ) { + if (in == null) sb.append("____"); + else in._print0(sb, visited); + sb.append(","); + } + sb.setLength(sb.length()-1); + sb.append(")"); + return sb; + } + + + // Always in-progress until we run out of unknown callers + @Override public boolean inProgress() { return in(0) instanceof FunNode fun && fun.inProgress(); } + + @Override public boolean eq( Node n ) { + return ((ParmNode)n)._idx==_idx && super.eq(n); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/PhiNode.java new file mode 100644 index 00000000..fcbacbc9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/PhiNode.java @@ -0,0 +1,271 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +public class PhiNode extends Node { + + public final String _label; + + // The Phi type we compute must stay within the domain of the Phi. Example + // Int stays Int, Ptr stays Ptr, Control stays Control, Mem stays Mem. + Type _minType; + + public PhiNode(String label, Type minType, Node... inputs) { + super(inputs); + _label = label; + assert minType!=null; + _minType = minType; + } + // Used by ParmNode + public PhiNode(PhiNode phi, String label, Type minType) { super(phi); _label = label; _type = _minType = minType; } + // Used by instruction Selection + public PhiNode(PhiNode phi) { this(phi,phi._label,phi._minType ); } + // Used by the infinite-loop exit breaker + public PhiNode(RegionNode r, Node sample) { + super(new Node[]{r}); + _label = ""; + _minType = sample._type; + while( nIns() < r.nIns() ) + addDef(sample); + } + + @Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); } + + @Override public String glabel() { return "φ_"+_label; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + if( !(region() instanceof RegionNode r) || r.inProgress() ) + sb.append("Z"); + sb.append("Phi("); + for( Node in : _inputs ) { + if (in == null) sb.append("____"); + else in._print0(sb, visited); + sb.append(","); + } + sb.setLength(sb.length()-1); + sb.append(")"); + return sb; + } + + public CFGNode region() { return (CFGNode)in(0); } + @Override public boolean isMem() { return _minType instanceof TypeMem; } + @Override public boolean isPinned() { return true; } + + @Override + public Type compute() { + if( !(region() instanceof RegionNode r) ) + return region()._type==Type.XCONTROL ? (_type instanceof TypeMem ? TypeMem.TOP : Type.TOP) : _type; + // During parsing Phis have to be computed type pessimistically. + if( r.inProgress() ) return _minType; + // Set type to local top of the starting type + //Type t = _minType.dual(); + Type t = Type.TOP; + for (int i = 1; i < nIns(); i++) + // If the region's control input is live, add this as a dependency + // to the control because we can be peeped should it become dead. + if( addDep(r.in(i))._type != Type.XCONTROL ) { + if( in(i)._type==Type.BOTTOM ) + return Type.BOTTOM; + t = t.meet(in(i)._type); + } + t = t.join( _minType ); + return t; + } + + @Override + public Node idealize() { + if( !(region() instanceof RegionNode r ) ) + return in(1); // Input has collapse to e.g. starting control. + // Can upgrade minType even while in-progress + if( _minType instanceof TypeMemPtr tmp && _minType.isFRef() ) { + TypeMemPtr tmp2 = (TypeMemPtr)CodeGen.CODE.P.TYPES.get(tmp._obj._name); + if( tmp2!=null && tmp2 != _minType ) { + _minType = tmp2; + return this; + } + } + if( r.inProgress() || r.nIns()<=1 ) + return null; // Input is in-progress + + // If we have only a single unique input, become it. + Node live = singleUniqueInput(); + if( live != null ) { + if( live._type.isa(_type) ) + return live; + // Keep the Phi upcast + return new CastNode(_type,null,live); + } + + // No bother if region is going to fold dead paths soon + for( int i=1; i<nIns(); i++ ) + if( r.in(i)._type == Type.XCONTROL ) + return null; + + // Simple Phi-after-MemMerge to a known alias can bypass. Happens when inlining. + if( _type instanceof TypeMem tmem && tmem._alias!=1 ) { + for( int i=1; i<nIns(); i++ ) + if( in(i) instanceof MemMergeNode mem ) { + setDef(i,mem.alias(tmem._alias)); + return this; + } + } + + // Generic "pull down op" + Node progress; + if( same_op() && (progress = drop_same_op()) != null ) + return progress; + + // If merging Phi(N, cast(N)) - we are losing the cast JOIN effects, so just remove. + if( nIns()==3 ) { + if( in(1) instanceof CastNode cast && addDep(cast.in(1))==in(2) ) return in(2); + if( in(2) instanceof CastNode cast && addDep(cast.in(1))==in(1) ) return in(1); + } + // If merging a null-checked null and the checked value, just use the value. + // if( val ) ..; phi(Region,False=0/null,True=val); + // then replace with plain val. + if( nIns()==3 ) { + int nullx = -1; + if( in(1)._type == in(1)._type.makeZero() ) nullx = 1; + if( in(2)._type == in(2)._type.makeZero() ) nullx = 2; + if( nullx != -1 ) { + Node val = in(3-nullx); + if( val instanceof CastNode cast ) + val = cast.in(1); + if( addDep(r.idom(this)) instanceof IfNode iff && addDep(iff.pred())==val ) { + // Must walk the idom on the null side to make sure we hit False. + CFGNode idom = (CFGNode)r.in(nullx); + while( idom != null && idom.nIns() > 0 && idom.in(0) != iff ) idom = idom.idom(); + if( idom instanceof CProjNode proj && proj._idx==1 ) + return val; + } + } + } + + return null; + } + + // Same op on all Phi paths; all ops have only the Phi as a use. + // None have a control input. + private boolean same_op() { + for( int i=1; i<nIns(); i++ ) { + Node op = in(i); + if( in(1).getClass() != op.getClass() || op.in(0)!=null || in(1).nIns() != op.nIns() ) + return false; // Wrong class or CFG bound or mismatched inputs + if( in(1) instanceof MemOpNode mem && mem._alias != ((MemOpNode)op)._alias ) + return false; + if( op.nOuts() > 1 ) { // Too many users, but addDep in case lose users + for( Node out : op._outputs ) + if( out!=null && out!=this ) + addDep(out); + return false; + } + for( int j=1; j<in(1).nIns(); j++ ) + if( op.in(j) instanceof ScopeNode || (op.in(j)==null ^ in(1).in(j)==null) ) + return false; // Lazy Phi input + } + return true; + } + + private Node drop_same_op() { + assert !(in(1) instanceof CFGNode); + Node op = in(1); + Node cp = op.copy(); + cp._type = null; // Fresh type + cp.addDef(null); // No control + + for( int j=1; j<op.nIns(); j++ ) { + boolean needsPhi = false; + Node x = op.in(j); // Jth input from sample #1 + for( int i=2; i<nIns(); i++ ) + if( in(i).in(j) != x ) + { needsPhi=true; break; } + if( needsPhi ) { + x = new PhiNode(_label,op.in(j)._type.glb(false)); + x.addDef(region()); + for( int i=1; i<nIns(); i++ ) + x.addDef(in(i).in(j)); + x = x.peephole(); + } + cp.addDef(x); + } + // Test not running backwards, which can happen for e.g. And's + if( cp.compute().isa(compute()) ) + return cp; + cp.kill(); + return null; + } + + /** + * If only single unique input, return it + */ + private Node singleUniqueInput() { + if( region() instanceof LoopNode loop && loop.entry()._type == Type.XCONTROL ) + return null; // Dead entry loops just ignore and let the loop collapse + Node live = null; + for( int i=1; i<nIns(); i++ ) { + // If the region's control input is live, add this as a dependency + // to the control because we can be peeped should it become dead. + if( addDep(region().in(i))._type != Type.XCONTROL && in(i) != this ) + if( live == null || live == in(i) ) live = in(i); + else return null; + } + return live; + } + + @Override + boolean allCons(Node dep) { + if( !(region() instanceof RegionNode r) ) return false; + // When the region completes (is no longer in progress) the Phi can + // become a "all constants" Phi, and the "dep" might make progress. + dep.addDep(this); + if( r.inProgress() ) return false; + return super.allCons(dep); + } + + // True if last input is null + public boolean inProgress() { + return in(nIns()-1) == null; + } + + // Never equal if inProgress. + // Also, joins + @Override public boolean eq( Node n ) { + if( inProgress() ) return false; + Type min = ((PhiNode)n)._minType; + if( _minType==min ) return true; + Type mt = min.meet(_minType); + if( min!=mt && _minType!=mt ) return false; + //// Theory says these 2 Phis CAN be merged/GVNd, but I need to pick the + //// most general minType. + //_minType = ((PhiNode)n)._minType = mt; + //return true; + return false; + } + + @Override + public Parser.ParseException err() { + if( _type != Type.BOTTOM ) return null; + + // BOTTOM means we mixed e.g. int and ptr + for( int i=1; i<nIns(); i++ ) + // Already an error, but better error messages come from elsewhere + if( in(i)._type == Type.BOTTOM ) + return null; + + // Gather a minimal set of types that "cover" all the rest + boolean ti=false, tf=false, tp=false, tn=false; + for( int i=1; i<nIns(); i++ ) { + Type t = in(i)._type; + ti |= t instanceof TypeInteger x; + tf |= t instanceof TypeFloat x; + tp |= t instanceof TypeMemPtr x; + tn |= t==Type.NIL; + } + return ReturnNode.mixerr(ti,tf,tp,tn, ((RegionNode)region())._loc); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ProjNode.java new file mode 100644 index 00000000..a0394e5b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ProjNode.java @@ -0,0 +1,54 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeMem; +import com.seaofnodes.simple.type.TypeTuple; + +import java.util.BitSet; + +public class ProjNode extends Node { + + // Which slice of the incoming multipart value + public final int _idx; + + // Debugging label + public final String _label; + + public ProjNode(Node ctrl, int idx, String label) { + super(new Node[]{ctrl}); + _idx = idx; + _label = label; + } + public ProjNode(ProjNode p) { super(p); _idx = p._idx; _label = p._label; } + + @Override public String label() { return _label; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + if( _label != null ) return sb.append(_label); + if( in(0) instanceof CallEndNode cend && cend.call()!=null ) + return cend.call()._print0(sb,visited); + return sb.append("LONELY PROJ"); + } + + @Override public CFGNode cfg0() { + return in(0) instanceof CFGNode cfg ? cfg : in(0).cfg0(); + } + + @Override public boolean isMem() { return _type instanceof TypeMem; } + @Override public boolean isPinned() { return true; } + + @Override + public Type compute() { + Type t = in(0)._type; + return t instanceof TypeTuple tt ? tt._types[_idx] : Type.BOTTOM; + } + + @Override public Node idealize() { return ((MultiNode)in(0)).pcopy(_idx); } + + @Override + public boolean eq( Node n ) { return _idx == ((ProjNode)n)._idx; } + + @Override + int hash() { return _idx; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java new file mode 100644 index 00000000..a35f5a1d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.util.SB; + +/** + * Cast a pointer to read-only + */ +public class ReadOnlyMach extends ReadOnlyNode implements MachNode { + public ReadOnlyMach( ReadOnlyNode n ) { super(n); } + @Override public String op() { return label(); } + @Override public RegMask regmap(int i) { assert i==1; return RegMask.FULL; } + @Override public RegMask outregmap() { return RegMask.FULL; } + @Override public int twoAddress( ) { return 1; } + @Override public void encoding( Encoding enc ) { } + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(in(1))); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java new file mode 100644 index 00000000..d8fe6286 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java @@ -0,0 +1,30 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeMemPtr; +import java.util.BitSet; + +/** + * Cast a pointer to read-only + */ +public class ReadOnlyNode extends Node { + public ReadOnlyNode( Node n ) { super(null,n); } + public ReadOnlyNode( ReadOnlyNode n ) { super(n); } + @Override public String label() { return "ReadOnly"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return in(1)._print0(sb.append("(const)"),visited); + } + @Override public Type compute() { + Type t = in(1)._type; + return t instanceof TypeMemPtr tmp ? tmp.makeRO() : t; + } + + @Override public Node idealize() { + if( in(1)._type instanceof TypeMemPtr tmp && tmp.isFinal() ) + return in(1); + return null; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/RegionNode.java new file mode 100644 index 00000000..f6d96410 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/RegionNode.java @@ -0,0 +1,168 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.Type; +import java.util.*; + +public class RegionNode extends CFGNode { + // Source location for late discovered errors + public Parser.Lexer _loc; + + public RegionNode(Parser.Lexer loc, Node... nodes) { super(nodes); _loc = loc; } + public RegionNode(RegionNode r, Parser.Lexer loc) { super(r); _loc = loc; } + public RegionNode(RegionNode r) { super(r); if( r!=null ) _loc = r._loc; } + + @Override + public String label() { return "Region"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return sb.append(label()); + } + + @Override public boolean blockHead() { return true; } + + @Override + public Type compute() { + if( inProgress() ) return Type.CONTROL; + Type t = Type.XCONTROL; + for (int i = 1; i < nIns(); i++) + t = t.meet(in(i)._type); + return t; + } + + @Override + public Node idealize() { + if( inProgress() ) return null; + + Node progress = deadPath(); + if( progress!=null ) return progress; + + // If down to a single input, become that input + if( nIns()==2 && !hasPhi() ) + return in(1); // Collapse if no Phis; 1-input Phis will collapse on their own + + // If a CFG diamond with no merging, delete: "if( pred ) {} else {};" + if( !hasPhi() && nIns()>3 && // No Phi users, just a control user + in(1) instanceof CProjNode p1 && + in(2) instanceof CProjNode p2 && + addDep(p1.in(0))==addDep(p2.in(0)) && + p1.in(0) instanceof IfNode iff ) { + // Replace with the iff.ctrl directly + if( nIns()==3 ) return iff.ctrl(); + // Just delete the path for fat Regions + setDef(1,iff.ctrl()); + return delDef(2); + } + + // Flatten stacked regions (no loops involved) + if( getClass() == RegionNode.class && nIns()>2 ) { + for( int i=1; i<nIns(); i++ ) + if( cfg(i) instanceof RegionNode region && region.getClass() == RegionNode.class && region.nIns()>2 && !hasMidUser(region) ) { + assert !region.inProgress(); + // Fold Phis + for( Node use : _outputs ) { + if( use instanceof PhiNode phi ) { + PhiNode phi2 = phi.in(i) instanceof PhiNode phi2x && phi2x.region()==region ? phi2x : null; + for( int j=1; j<region.nIns(); j++ ) + phi.addDef(phi2==null ? phi.in(i) : phi2.in(j)); + CodeGen.CODE.add(phi); + } + } + + // Fold Region + for( int j=1; j<region.nIns(); j++ ) + addDef(region.in(j)); + setDef(i,Parser.XCTRL); + return this; + } + } + + return null; + } + + Node deadPath() { + // Delete dead paths into a Region + int path = findDeadInput(); + if( path==0 ) return null; + // Do not delete the entry path of a loop (ok to remove the back edge + // and make the loop a single-entry Region which folds away the Loop). + // Folding the entry path confused the loop structure, moving the + // backedge to the entry point. + if( this instanceof LoopNode loop && loop.entry()==in(path) ) + return null; + // Cannot use the obvious output iterator here, because a Phi deleting + // an input might recursively delete *itself*. This shuffles the + // output array, and we might miss iterating an unrelated Phi. So on + // rare occasions we repeat the loop to get all the Phis. + int nouts = 0; + while( nouts != nOuts() ) { + nouts = nOuts(); + for( int i=0; i<nOuts(); i++ ) + if( out(i) instanceof PhiNode phi && phi.nIns()==nIns() ) + CodeGen.CODE.addAll(phi.delDef(path)._outputs); + } + return isDead() ? Parser.XCTRL : delDef(path); + } + + + private int findDeadInput() { + for( int i=1; i<nIns(); i++ ) + if( in(i)._type==Type.XCONTROL ) + return i; + return 0; // All inputs alive + } + + boolean hasPhi() { + for( Node phi : _outputs ) + if( phi instanceof PhiNode ) + return true; + return false; + } + + // Is there a value in-between 2 Regions? Difficult to correctly fuse + // without extensive testing, so just ignore. + boolean hasMidUser(RegionNode r) { + for( Node use : r._outputs ) { + if( use==this ) continue; + if( use instanceof PhiNode ) { + for( Node data : use._outputs ) { + if( !(data instanceof PhiNode phi2) || phi2.region()!=this ) + { addDep(use); if( data!=null ) addDep(data); return true; } + } + } else + { addDep(use); return true; } // Control user + } + return false; + } + + + // Immediate dominator of Region is a little more complicated. + @Override public int idepth() { + if( CodeGen.CODE.validIDepth(_idepth) ) + return _idepth; + int d=0; + for( Node n : _inputs ) + if( n!=null ) + d = Math.max(d,CodeGen.CODE.iDepthFrom(((CFGNode)n).idepth())); + return _idepth = d; + } + + @Override public CFGNode idom(Node dep) { + CFGNode lca = null; + // Walk the LHS & RHS idom trees in parallel until they match, or either fails. + // Because this does not cache, it can be linear in the size of the program. + for( int i=1; i<nIns(); i++ ) + lca = cfg(i)._idom(lca,dep); + return lca; + } + + // True if last input is null + public boolean inProgress() { return nIns()>1 && in(nIns()-1) == null; } + + // Never equal if inProgress + @Override public boolean eq( Node n ) { return !inProgress(); } + +}
\ No newline at end of file diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ReturnNode.java new file mode 100644 index 00000000..7971733a --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ReturnNode.java @@ -0,0 +1,166 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +/** + * The Return node has two inputs. The first input is a control node and the + * second is the data node that supplies the return value. + * <p> + * In this presentation, Return functions as a Stop node, since multiple <code>return</code> statements are not possible. + * The Stop node will be introduced in Chapter 6 when we implement <code>if</code> statements. + * <p> + * The Return's output is the value from the data node. + */ +public class ReturnNode extends CFGNode { + + public FunNode _fun; + + public ReturnNode(Node ctrl, Node mem, Node data, Node rpc, FunNode fun ) { + super(ctrl, mem, data, rpc); + _fun = fun; + } + public ReturnNode( ReturnNode ret, FunNode fun ) { super(ret); _fun = fun; } + + public Node ctrl() { return in(0); } + public Node mem () { return in(1); } + public Node expr() { return in(2); } + public Node rpc () { return in(3); } + @Override public FunNode fun() { return _fun; } + + @Override + public String label() { return "Return"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + sb.append("return "); + if( expr()==null ) sb.append("----"); + else expr()._print0(sb, visited); + return sb.append(";"); + } + + // No one unique control follows; can be many call end sites + @Override public CFGNode uctrl() { return null; } + + @Override + public Type compute() { + if( inProgress () ) return TypeTuple.RET; // In progress + return TypeTuple.make(ctrl()._type,mem()._type,expr()._type); + } + + @Override public Node idealize() { + if( inProgress () ) return null; + if( _fun.isDead() ) return null; + + // Upgrade signature based on return type + Type ret = expr()._type; + TypeFunPtr fcn = _fun.sig(); + if( ret != fcn.ret() && ret.isa(fcn.ret()) ) + _fun.setSig(fcn.makeFrom(ret)); + + // If dead (cannot be reached; infinite loop), kill the exit values + if( ctrl()._type==Type.XCONTROL && + !(mem() instanceof ConstantNode && expr() instanceof ConstantNode) ) { + Node top = new ConstantNode(Type.TOP).peephole(); + setDef(1,top); + setDef(2,top); + return this; + } + + return null; + } + + public boolean inProgress() { + return ctrl().getClass() == RegionNode.class && ((RegionNode)ctrl()).inProgress(); + } + + // Gather parse-time return types for error reporting + private Type mt = Type.TOP; + private boolean ti=false, tf=false, tp=false, tn=false; + + // Add a return exit to the current parsing function + void addReturn( Node ctrl, Node rmem, Node expr ) { + assert inProgress(); + + // Gather parse-time return types for error reporting + Type t = expr._type; + mt = mt.meet(t); + ti |= t instanceof TypeInteger x; + tf |= t instanceof TypeFloat x; + tp |= t instanceof TypeMemPtr x; + tn |= t==Type.NIL; + + // Merge path into the One True Return + RegionNode r = (RegionNode)ctrl(); + // Assert that the Phis are in particular outputs; not reordered or shuffled + PhiNode mem = (PhiNode)r.out(0); assert mem._minType == TypeMem.BOT; + PhiNode rez = (PhiNode)r.out(1); assert rez._minType == Type.BOTTOM; + // Pop "inProgress" null off + r ._inputs.pop(); + mem._inputs.pop(); + rez._inputs.pop(); + // Add new return point + r .addDef(ctrl); + mem.addDef(rmem); + rez.addDef(expr); + // Back to being inProgress + r .addDef(null); + mem.addDef(null); + rez.addDef(null); + } + + @Override public Parser.ParseException err() { + return expr()._type/*mt*/==Type.BOTTOM ? mixerr(ti,tf,tp,tn,_fun._loc) : null; + } + + static Parser.ParseException mixerr( boolean ti, boolean tf, boolean tp, boolean tn, Parser.Lexer loc ) { + if( !ti && !tf && !tp && !tn ) + return Parser.error("No defined return type", loc); + SB sb = new SB().p("No common type amongst "); + if( ti ) sb.p("int and "); + if( tf ) sb.p("f64 and "); + if( tp || tn ) sb.p("reference and "); + return Parser.error(sb.unchar(5).toString(),loc); + } + + + // ------------ + // MachNode specifics, shared across all CPUs + public String op() { + return _fun._frameAdjust > 0 ? "addi" : "ret"; + } + // Correct Nodes outside the normal edges + public void postSelect(CodeGen code) { + FunNode fun = (FunNode)rpc().in(0); + _fun = fun; + fun.setRet(this); + } + public RegMask regmap(int i) { + return i==2 + ? CodeGen.CODE._mach.retMask(_fun.sig()) + : CodeGen.CODE._retMasks[i]; + } + public RegMask outregmap() { return null; } + public void encoding( Encoding enc ) { throw Utils.TODO(); } + public void asm(CodeGen code, SB sb) { + int frameAdjust = fun()._frameAdjust; + if( frameAdjust>0 ) + sb.p("rsp += #").p(frameAdjust).p("\nret"); + // Post code-gen, just print the "ret" + if( code._phase.ordinal() <= CodeGen.Phase.RegAlloc.ordinal() ) + // Prints return reg (either RAX or XMM0), RPC and then the + // callee-save registers. + for( int i=2; i<nIns(); i++ ) + sb.p(code.reg(in(i),fun())).p(" "); + // If we did not get the expected rpc, print which one we got + else if( code._regAlloc.regnum(rpc()) != code._mach.rpc() ) + sb.p("[").p(code.reg(rpc())).p("]"); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter24/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java new file mode 100644 index 00000000..7936086d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java @@ -0,0 +1,38 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; + +import java.util.BitSet; + +public class RoundF32Node extends Node { + public RoundF32Node(Node lhs) { super(null, lhs); } + + @Override public String label() { return "RoundF32"; } + + @Override public String glabel() { return "(f32)"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return in(1)._print0(sb.append("((f32)"), visited).append(")"); + } + + @Override + public Type compute() { + if (in(1)._type instanceof TypeFloat i0 && i0.isConstant() ) + return TypeFloat.constant((float)i0.value()); + return in(1)._type; + } + + @Override + public Node idealize() { + Node lhs = in(1); + Type t1 = lhs._type; + + // RoundF32 of float + if( t1 instanceof TypeFloat tf && tf._sz==32 ) + return lhs; + + return null; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/SarNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/SarNode.java new file mode 100644 index 00000000..ee15fa65 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/SarNode.java @@ -0,0 +1,38 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; + +public class SarNode extends ArithNode { + public SarNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } + + @Override public String label() { return "Sar"; } + @Override public String op() { return ">>"; } + @Override public String glabel() { return ">>"; } + + @Override long doOp( long x, long y ) { return x >> y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { + if( y.isConstant() ) { + int log = (int)y.value(); + return TypeInteger.make(-1L<<(63-log),(1L<<(63-log))-1); + } + return TypeInteger.BOT; + } + + @Override + public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t2 = rhs._type; + + // Sar of 0. + if( t2.isConstant() && t2 instanceof TypeInteger i && (i.value()&63)==0 ) + return lhs; + + // TODO: x >> 3 >> (y ? 1 : 2) ==> x >> (y ? 4 : 5) + + return super.idealize(); + } + @Override Node copy(Node lhs, Node rhs) { return new SarNode(_loc,lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ScopeNode.java new file mode 100644 index 00000000..36746a81 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ScopeNode.java @@ -0,0 +1,468 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.Var; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.AryInt; +import com.seaofnodes.simple.util.Utils; + +import java.util.*; + +/** + * The Scope node is purely a parser helper - it tracks names to nodes with a + * stack of variables. + */ +public class ScopeNode extends MemMergeNode { + + /** + * The control is a name that binds to the currently active control + * node in the graph + */ + public static final String CTRL = "$ctrl"; + public static final String ARG0 = "arg"; + public static final String MEM0 = "$mem"; + + // All active/live variables in all nested scopes, all run together. + // Maps 1-to-1 to the _inputs array. + public final Ary<Var> _vars; + + // Lexical scope is typed: + public static class Kind { + // Basic block scoping + public static class Block extends Kind { } + // Function scope + public static class Func extends Kind { } + // Struct definition, mapping types to fields + public static class Define extends Kind { public Define(TypeMemPtr tmp) { _tmp=tmp; } public final TypeMemPtr _tmp; } + // Struct allocation, mapping values to fields + public static class Alloc extends Kind { public Alloc (TypeMemPtr tmp) { _tmp=tmp; } public final TypeMemPtr _tmp; } + + public int _lexSize; // Number of Vars in this scope + } + public final Ary<Kind> _kinds; + // Lexical scope nesting depth + public int depth() { return _kinds._len; } + + // Extra guards; tested predicates and casted results + private final Ary<Node> _guards; + + // A new ScopeNode + public ScopeNode() { + super(true); + _vars = new Ary<>(Var .class); + _kinds = new Ary<>(Kind.class); + _guards = new Ary<>(Node.class); + } + + @Override public String label() { return "Scope"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + sb.append("Scope[ "); + int j=1; + for( int i=0; i<nIns(); i++ ) { + if( j < depth() && i == _kinds.at(j)._lexSize ) { sb.append("| "); j++; } + Var v = _vars.at(i); + sb.append(v.type()); + sb.append(" "); + if( v._final ) sb.append("!"); + sb.append(v._name); + sb.append("="); + Node n = in(i); + while( n instanceof ScopeNode loop ) { + sb.append("Lazy_"); + n = loop.in(i); + } + if( n==null ) sb.append("___"); + else n._print0(sb, visited); + sb.append(", "); + } + sb.setLength(sb.length()-2); + return sb.append("]"); + } + + + public Node ctrl() { return in(0); } + public MemMergeNode mem() { return (MemMergeNode)in(1); } + public Var var(int i) { return _vars.at(i); } + + /** + * The ctrl of a ScopeNode is always bound to the currently active + * control node in the graph, via a special name '$ctrl' that is not + * a valid identifier in the language grammar and hence cannot be + * referenced in Simple code. + * + * @param n The node to be bound to '$ctrl' + * + * @return Node that was bound + */ + public <N extends Node> N ctrl(N n) { return setDef(0,n); } + public Node mem(Node n) { return setDef(1,n); } + + public void push( Kind kind ) { + kind._lexSize = _vars.size(); + _kinds.push(kind); + } + + // Pop a lexical scope + public void pop() { + promote(); // Promote forward references to the next outer scope + int n = _kinds.pop()._lexSize; + popUntil(n); // Pop off inputs going out of scope + _vars.setLen(n); // Pop off variables going out of scope + } + + + // Look for forward references in the last lexical scope and promote to the + // next outer lexical scope. At the last scope declare them an error. + public void promote() { + Kind kind = _kinds.last(); + int n = kind._lexSize; + for( int i=n; i<nIns(); i++ ) { + Var v = var(i); + if( !v.isFRef() ) continue; + if( depth()==1 ) + throw Parser.error("Undefined name '" + v._name + "'",v._loc); + _vars .swap(n,i); + _inputs.swap(n,i); + v._idx = n; + kind._lexSize = ++n; + } + } + + + public boolean inConstructor() { return _kinds.last() instanceof Kind.Define; } + public boolean inAllocation () { return _kinds.last() instanceof Kind.Alloc ; } + public boolean inFunction () { return _kinds.last() instanceof Kind.Func ; } + + public Kind kind( Var v ) { + for( int i=depth()-1; i>=0; i-- ) + if( v._idx >= _kinds.at(i)._lexSize ) + return _kinds.at(i); + throw Utils.TODO(); + } + + // Return the kind for the defining scope, or a function scope if found + // first. Block scopes means the variable can be r/w directly in the + // scope, Function scopes require final constants (no capture), and + // Constructor scopes mean an instance variable reference. + + // Walk up-lexical scope looking for defining lexical Kind. + // - Skip any amount of nested block scopes + // - Walking out of a function requires v be a final constant (for now) - + // and we can stop walking. + + // - Walking out of a method and (skipping Blocks) into the matching struct + // is OK, and this is a instance var load. + + // - Walking out of a method and into the wrong struct is an error; + // including nested structs containing (no nested classes yet) + + // Returns error, forward-ref, ok containing struct, ok containing function/block. + + public String outOfFunction( Var v ) { + //if( v==null ) return null; // Prolly forward reference + //int i; for( i=_lexSize._len-1; i>=0 && v._idx<_lexSize.at(i); i-- ) + // if( _kinds.at(i)=="{->}" ) return "{->}"; + //return _kinds.at(i); + throw Utils.TODO(); + } + + + // Find name in reverse, return an index into _vars or -1. Linear scan + // instead of hashtable, but probably doesn't matter until the scan + // typically hits many dozens of variables. + public int find( String name ) { + for( int i=_vars.size()-1; i>=0; i-- ) + if( var(i)._name.equals(name) ) + return i; + return -1; + } + + /** + * Create a new variable name in the current scope + */ + public boolean define( String name, Type declaredType, boolean xfinal, Node init, Parser.Lexer loc ) { + assert _kinds.isEmpty() || name.charAt(0)!='$' ; // Later scopes do not define memory + if( depth() > 0 ) + for( int i=_vars.size()-1; i>=_kinds.last()._lexSize; i-- ) { + Var n = var(i); + if( n._name.equals(name) ) { + if( !n.isFRef() ) return false; // Double define + FRefNode fref = (FRefNode)in(n._idx); // Get forward ref + if( !xfinal || !declaredType.isConstant() ) throw fref.err(); // Must be a final constant + n.defFRef(declaredType,xfinal,loc); // Declare full correct type, final, source location + setDef(n._idx,fref.addDef(init)); // Set FRef to defined; tell parser also + } + } + Var v = new Var(nIns(),name,declaredType,xfinal,loc,init==Parser.XCTRL); + _vars.add(v); + // Creating a forward reference + if( init==Parser.XCTRL ) + init = new FRefNode(v).init(); + addDef(init); + return true; + } + + // Read from memory + public Node mem( int alias ) { return mem()._mem(alias,null); } + // Write to memory + public void mem( int alias, Node st ) { mem()._mem(alias,st); } + + + /** + * Lookup a name in all scopes starting from most deeply nested. + * + * @param name Name to be looked up + * @return null if not found, or the implementing Node + */ + public Var lookup( String name ) { + int idx = find(name); + // -1 is missed in all scopes, not found + return idx == -1 ? null : update(var(idx),null); + } + + /** + * Redefine an existing name + * + * @param name Name being redefined + * @param n The node to bind to the name + */ + public void update( String name, Node n ) { + int idx = find(name); + assert idx>=0; + update(var(idx),n); + } + + public Var update( Var v, Node st ) { + Node old = in(v._idx); + if( old instanceof ScopeNode loop ) { + // Lazy Phi! + Node def = loop.in(v._idx); + old = def instanceof PhiNode phi && loop.ctrl()==phi.region() + // Loop already has a real Phi, use it + ? def + // Set real Phi in the loop head + // The phi takes its one input (no backedge yet) from a recursive + // lookup, which might have insert a Phi in every loop nest. + : loop.setDef(v._idx,new PhiNode(v._name, v.type(), loop.ctrl(), loop.in(loop.update(v,null)._idx),null).peephole()); + setDef(v._idx,old); + } + //assert !v._final || st==null; + if( st!=null ) setDef(v._idx,st); // Set new value + return v; + } + + /** + * Duplicate a ScopeNode; including all levels, up to Nodes. So this is + * neither shallow (would dup the Scope but not the internal HashMap + * tables), nor deep (would dup the Scope, the HashMap tables, but then + * also the program Nodes). + * <p> + * If the {@code loop} flag is set, the edges are filled in as the original + * Scope, as an indication of Lazy Phis at loop heads. The goal here is to + * not make Phis at loop heads for variables which are never touched in the + * loop body. + * <p> + * The new Scope is a full-fledged Node with proper use<->def edges. + */ + public ScopeNode dup() { return dup(false); } + public ScopeNode dup(boolean loop) { + ScopeNode dup = new ScopeNode(); + // Our goals are: + // 1) duplicate the name bindings of the ScopeNode across all stack levels + // 2) Make the new ScopeNode a user of all the nodes bound + // 3) Ensure that the order of defs is the same to allow easy merging + dup._vars .addAll(_vars ); + dup._kinds .addAll(_kinds ); + dup._guards .addAll(_guards ); + // The dup'd guards all need dup'd keepers, to keep proper accounting + // when later removing all guards + for( Node n : _guards ) + if( !(n instanceof CFGNode) ) + n.keep(); + dup.addDef(ctrl()); // Control input is just copied + + // Memory input is a shallow copy + MemMergeNode memdup = new MemMergeNode(true), mem = mem(); + memdup.addDef(null); + memdup.addDef(loop ? this : mem.in(1)); + for( int i=2; i<mem.nIns(); i++ ) + // For lazy phis on loops we use a sentinel + // that will trigger phi creation on update + memdup.addDef(loop ? this : mem.in(i)); + dup.addDef(memdup); + + // Copy of other inputs + for( int i=2; i<nIns(); i++ ) + // For lazy phis on loops we use a sentinel + // that will trigger phi creation on update + dup.addDef(loop && !var(i)._final ? this : in(i)); + return dup; + } + + /** + * Merges the names whose node bindings differ, by creating Phi node for such names + * The names could occur at all stack levels, but a given name can only differ in the + * innermost stack level where the name is bound. + * + * @param that The ScopeNode to be merged into this + * @return A new node representing the merge point + */ + public RegionNode mergeScopes(ScopeNode that, Parser.Lexer loc) { + RegionNode r = ctrl(new RegionNode(loc,null,ctrl(), that.ctrl()).keep()); + mem()._merge(that.mem(),r); + this ._merge(that ,r); + that.kill(); // Kill merged scope + CodeGen.CODE.add(r); + return r.unkeep(); + } + + private void _merge(ScopeNode that, RegionNode r) { + for( int i = 2; i < nIns(); i++) + if( in(i) != that.in(i) ) { // No need for redundant Phis + // If we are in lazy phi mode we need to a lookup + // by name as it will trigger a phi creation + Var v = var(i); + Node lhs = this.in(this.update(v,null)); + Node rhs = that.in(that.update(v,null)); + setDef(i, new PhiNode(v._name, v.type(), r, lhs, rhs).peephole()); + } + } + + // Balance arms of an IF. Extra lonely defs are thrown: "if(pred) int x;". + // Forward refs are copied to the other side, "as if" they were there all along. + public void balanceIf( ScopeNode scope ) { + for( int i = nIns(); i < scope.nIns(); i++ ) { + Var n = scope.var(i); + if( n.isFRef() ) { // RHS has forward refs + _vars.add(n); // Copy to LHS + addDef(scope.in(i)); + } else + throw Parser.error("Cannot define a '"+n._name+"' on one arm of an if",n._loc); + } + } + + + // peephole the backedge scope into this loop head scope + // We set the second input to the phi from the back edge (i.e. loop body) + public void endLoop(ScopeNode back, ScopeNode exit ) { + Node ctrl = ctrl(); + assert ctrl instanceof LoopNode loop && loop.inProgress(); + ctrl.setDef(2,back.ctrl()); + + mem()._endLoopMem( this, back.mem(), exit.mem() ); + this ._endLoop ( this, back , exit ); + back.kill(); // Loop backedge is dead + // Now one-time do a useless-phi removal + mem()._useless(); + this ._useless(); + + // The exit mem's lazy default value had been the loop top, + // now it goes back to predating the loop. + exit.mem().setDef(1,mem().in(1)); + } + + // Fill in the backedge of any inserted Phis + void _endLoop( ScopeNode scope, Node back, Node exit ) { + for( int i=2; i<nIns(); i++ ) { + if( var(i)._final ) continue; // Final vars did not get modified in the loop + if( var(i).type().isHighOrConst() ) continue; // Cannot lift higher than a constant, so no Phi + if( back.in(i) != scope ) { + PhiNode phi = (PhiNode)in(i); + assert phi.region()==scope.ctrl() && phi.in(2)==null; + phi.setDef(2,back.in(i)); // Fill backedge + } + if( exit.in(i) == scope ) // Replace a lazy-phi on the exit path also + exit.setDef(i,in(i)); + } + } + + + // Up-casting: using the results of an If to improve a value. + // E.g. "if( ptr ) ptr.field;" is legal because ptr is known not-null. + public void addGuards( Node ctrl, Node pred, boolean invert ) { + assert ctrl instanceof CFGNode; + _guards.add(ctrl); // Marker to distinguish 0,1,2 guards + // add pred & its cast to the normal input list, with special Vars + if( pred==null || pred.isDead() ) + return; // Dead, do not add any guards + // Invert the If conditional + if( invert ) + pred = pred instanceof NotNode not ? not.in(1) : CodeGen.CODE.add(new NotNode(pred).peephole()); + // This is a zero/null test. + // Compute the positive test type. + Type tnz = pred._type.nonZero(); + if( tnz!=null ) + _addGuard(tnz,ctrl,pred); + + // Compute the negative test type. + if( pred instanceof NotNode not ) { + Node npred = not.in(1); + Type tzero = npred._type.makeZero(); + _addGuard(tzero,ctrl,npred); + } + } + + private void _addGuard(Type guard, Node ctrl, Node pred) { + Type tcast = guard.join(pred._type); + if( tcast != pred._type && !tcast.isHigh() ) { + Node cast = new CastNode(tcast,ctrl,pred.keep()).peephole().keep(); + _guards.add(pred); + _guards.add(cast); + replace(pred,cast); + } + } + + + // Remove matching pred/cast pairs from this guarded region. + public ScopeNode removeGuards( Node ctrl ) { + assert ctrl instanceof CFGNode; + // 0,1 or 2 guards + while( true ) { + Node g = _guards.pop(); + if( g == ctrl ) break; + if( g instanceof CFGNode ) continue; + g .unkill(); // Pop/kill cast + _guards.pop().unkill(); // Pop/kill pred + } + return this; + } + + // If we find a guarded instance of pred, replace with the upcasted version + public Node upcastGuard( Node pred ) { + // If finding an instanceof pred, replace with cast. + // Otherwise, just pred itself. + int i = _guards._len; + while( i > 0 ) { + Node cast = _guards.at(--i); + if( cast instanceof CFGNode ) continue; // Marker between guard sets + Node xpred = _guards.at(--i); + if( xpred == pred ) + return cast; + } + return pred; + } + + // Kill guards also + @Override public void kill() { + for( Node n : _guards ) + if( !(n instanceof CFGNode) ) + n.unkill(); + _guards.clear(); + // Can have lazy uses remaining + if( isUnused() ) + super.kill(); + } + + + private void replace( Node old, Node cast ) { + assert old!=null && old!=cast; + for( int i=0; i<nIns(); i++ ) + if( in(i)==old ) + setDef(i,cast); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ShlNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ShlNode.java new file mode 100644 index 00000000..2557bf6b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ShlNode.java @@ -0,0 +1,50 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; + +public class ShlNode extends ArithNode { + public ShlNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } + + @Override public String label() { return "Shl"; } + @Override public String op() { return "<<"; } + @Override public String glabel() { return "<<"; } + + @Override long doOp( long x, long y ) { return x << y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { + if( x == TypeInteger.ZERO ) + return TypeInteger.ZERO; + if( y.isConstant() ) { + int shf = (int)y.value(); + // If no overflow, shift endpoints + if( !(((x._min<<shf)>>shf) != x._min || + ((x._max<<shf)>>shf) != x._max ) ) + return TypeInteger.make(x._min<<shf,x._max<<shf); + } + return TypeInteger.BOT; + } + + @Override + public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + + if( rhs._type instanceof TypeInteger shl && shl.isConstant() ) { + // Shl of 0. + if( (shl.value()&63)==0 ) + return lhs; + // (x + c) << i => (x << i) + (c << i) + if( lhs instanceof AddNode add && addDep(add).in(2)._type instanceof TypeInteger c && c.isConstant() ) { + long sum = c.value() << shl.value(); + if( Integer.MIN_VALUE <= sum && sum <= Integer.MAX_VALUE ) + return new AddNode(new ShlNode(_loc,add.in(1),rhs).peephole(), Parser.con(sum) ); + } + } + + // TODO: x << 3 << (y ? 1 : 2) ==> x << (y ? 4 : 5) + + return super.idealize(); + } + @Override Node copy(Node lhs, Node rhs) { return new ShlNode(_loc,lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ShrNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ShrNode.java new file mode 100644 index 00000000..269f6b7f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ShrNode.java @@ -0,0 +1,34 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; + +public class ShrNode extends ArithNode { + public ShrNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } + + @Override public String label() { return "Shr"; } + @Override public String op() { return ">>>"; } + @Override public String glabel() { return ">>>"; } + + @Override long doOp( long x, long y ) { return x >>> y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { + return x == TypeInteger.ZERO ? x : TypeInteger.BOT; + } + + @Override + public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t2 = rhs._type; + + // Shr of 0. + if( t2.isConstant() && t2 instanceof TypeInteger i && (i.value()&63)==0 ) + return lhs; + + // TODO: x >>> 3 >>> (y ? 1 : 2) ==> x >>> (y ? 4 : 5) + + return super.idealize(); + } + @Override Node copy(Node lhs, Node rhs) { return new ShrNode(_loc,lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/SplitNode.java new file mode 100644 index 00000000..d061cdbd --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/SplitNode.java @@ -0,0 +1,25 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; +import java.util.BitSet; + +public abstract class SplitNode extends MachConcreteNode { + public final String _kind; // Kind of split + public final byte _round; + public SplitNode(String kind, byte round, Node[] nodes) { super(nodes); _kind = kind; _round = round; } + @Override public String op() { return "mov"; } + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { + sb.append("mov("); + if( in(1) == null ) sb.append("---"); + else in(1)._print0(sb,visited); + return sb.append(")"); + } + @Override public Type compute() { return in(0)._type; } + @Override public Node idealize() { return null; } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))); + } + @Override public String comment() { return _kind + " #"+ _round; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/StartNode.java new file mode 100644 index 00000000..e3806de7 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/StartNode.java @@ -0,0 +1,56 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.*; +import java.util.Arrays; +import java.util.BitSet; +import java.util.HashSet; +import static com.seaofnodes.simple.util.Utils.TODO; + +/** + * The Start node represents the start of the function. + * <p> + * Start initially has 1 input (arg) from outside and the initial control. + * In ch10 we also add mem aliases as structs get defined; each field in struct + * adds a distinct alias to Start's tuple. + */ +public class StartNode extends LoopNode implements MultiNode { + + final Type _arg; + + public StartNode(Type arg) { super(null,null); _arg = arg; _type = compute(); } + public StartNode(StartNode start) { super(start); _arg = start==null ? null : start._arg; } + + @Override public String label() { return "Start"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return sb.append(label()); + } + + @Override public CFGNode cfg0() { return null; } + + // Get the one control following; error to call with more than one e.g. an + // IfNode or other multi-way branch. For Start, its "main" + @Override public CFGNode uctrl() { + // Find "main", it's the start. + CFGNode C = null; + for( Node use : _outputs ) + if( use instanceof FunNode fun && fun.sig().isa(CodeGen.CODE._main) ) + { assert C==null; C = fun; } + return C; + } + + + @Override public TypeTuple compute() { + return TypeTuple.make(Type.CONTROL,TypeMem.TOP,_arg); + } + + @Override public Node idealize() { return null; } + + // No immediate dominator, and idepth==0 + @Override public int idepth() { return CodeGen.CODE.iDepthAt(0); } + @Override public CFGNode idom(Node dep) { return null; } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/StopNode.java new file mode 100644 index 00000000..4b03bf4e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/StopNode.java @@ -0,0 +1,75 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +public class StopNode extends CFGNode { + + public final String _src; + + public StopNode(String src) { + super(); + _src = src; + _type = compute(); + } + public StopNode(StopNode stop) { super(stop); _src = stop==null ? null : stop._src; } + + @Override + public String label() { + return "Stop"; + } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + // For the sake of many old tests, and single value prints as "return val" + ReturnNode ret1 = ret(); + if( ret1!=null ) return ret1._print0(sb,visited); + sb.append("Stop[ "); + for( Node ret : _inputs ) + if( ret!=null ) { + String name = ((ReturnNode)ret).fun()._name; + if( name== null || !name.startsWith("sys.") ) + ret._print0(sb, visited).append(" "); + } + return sb.append("]"); + } + + @Override public boolean blockHead() { return true; } + + + // If a single Return, return it. + // Otherwise, null because ambiguous. + public ReturnNode ret() { + Node ret1 = this; + for( Node ret : _inputs ) { + String name = ((ReturnNode)ret).fun()._name; + if( name==null || !name.startsWith("sys.") ) + ret1 = ret1==this ? ((ReturnNode)ret) : null; + } + return ret1==this ? null : (ReturnNode)ret1; + } + + @Override + public Type compute() { + return Type.BOTTOM; + } + + @Override + public Node idealize() { + int len = nIns(); + for( int i=0; i<nIns(); i++ ) + if( addDep(((ReturnNode)in(i)).fun()).isDead() ) + delDef(i--); + if( len != nIns() ) return this; + return null; + } + + @Override public int idepth() { + if( _idepth!=0 ) return _idepth; + int d=0; + for( Node ret : _inputs ) + d = Math.max(d,((ReturnNode)ret).idepth()+1); + return _idepth=d; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java new file mode 100644 index 00000000..5fb274db --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java @@ -0,0 +1,140 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.type.*; +import java.util.BitSet; + +/** + * Store represents setting a value to a memory based object, in chapter 10 + * this means a field inside a struct. + */ +public class StoreNode extends MemOpNode { + + private final boolean _init; // Initializing writes are allowed to write null + + /** + * @param name The struct field we are assigning to + * @param mem The memory alias node - this is updated after a Store + * @param ptr The ptr to the struct base where we will store a value + * @param off The offset inside the struct base + * @param value Value to be stored + */ + public StoreNode(Parser.Lexer loc, String name, int alias, Type glb, Node mem, Node ptr, Node off, Node value, boolean init) { + super(loc, name, alias, false, glb, mem, ptr, off, value); + _init = init; + } + + // GraphVis DOT code and debugger labels + @Override public String label() { return "st_"+mlabel(); } + // GraphVis node-internal labels + @Override public String glabel() { return "." +_name+"="; } + @Override public boolean isMem() { return true; } + + public Node val() { return in(4); } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return sb.append(".").append(_name).append("=").append( val()).append(";"); + } + + @Override + public Type compute() { + Type val = val()._type; + Type mem0 = mem()._type; + if( mem0 == Type.TOP ) return TypeMem.TOP; + TypeMem mem = (TypeMem)mem0; // Invariant + if( mem == TypeMem.TOP ) return TypeMem.TOP; + Type t = Type.BOTTOM; // No idea on field contents + // Same alias, lift val to the declared type and then meet into other fields + if( mem._alias == _alias ) { + assert !_declaredType.isFRef(); + // Sharpen memory value; required for narrowing stores where the parser inserts + // zero/sign masking and somebody reads the TypeMem type. + val = val.join(_declaredType); + t = val.meet(mem._t); + } + return TypeMem.make(_alias,t); + } + + @Override + public Node idealize() { + + if( mem() instanceof CastNode cast ) { + setDef(1,cast.in(1)); + return this; + } + + // Simple store-after-store on same address. Should pick up the + // required init-store being stomped by a first user store. + if( mem() instanceof StoreNode st && + ptr()==st.ptr() && // Must check same object + off()==st.off() && // And same offset (could be "same alias" but this handles arrays to same index) + ptr()._type instanceof TypeMemPtr && // No bother if weird dead pointers + // Must have exactly one use of "this" or you get weird + // non-serializable memory effects in the worse case. + checkOnlyUse(st) ) { + assert _name.equals(st._name); // Equiv class aliasing is perfect + setDef(1,st.mem()); + return this; + } + + // Simple store-after-MemMerge to a known alias can bypass. Happens when inlining. + if( mem() instanceof MemMergeNode mem ) { + setDef(1,mem.alias(_alias)); + return this; + } + + // Value is automatically truncated by narrow store + if( val() instanceof AndNode and && and.in(2)._type.isConstant() ) { + int log = _declaredType.log_size(); + if( log<3 ) { // And-mask vs narrow store + long mask = ((TypeInteger)and.in(2)._type).value(); + long bits = (1L<<(8<<log))-1; + // Mask does not mask any of the stored bits + if( (bits&mask)==bits ) + // So and-mask is already covered by the store + { setDef(4,and.in(1)); return this; } + } + } + + // Store will chop high order bits off; math to change those bits can be dropped. + if( val() instanceof SarNode shr && + shr.in(1) instanceof ShlNode shl && + shr.in(2)._type.isConstant() && + shl.in(2)._type.isConstant() ) { + TypeInteger shrC = (TypeInteger) shr.in(2)._type; + + // size of the thing that sign-extends + int base_size = (1 << shr.in(1)._type.log_size()) << 3; + int not_affected_bits = base_size - (int) shrC.value(); + int store_size = (1 << log_size()) << 3; + // if the store is unrelated to the shift amount, then get rid of the shift + if( shl.in(2)._type == shr.in(2)._type && shrC.value() >= store_size && not_affected_bits >= store_size) { + setDef(4, shl.in(1)); + return this; + } + } + return null; + } + + // Check that "mem" has no uses except "this" + private boolean checkOnlyUse(Node mem) { + if( mem.nOuts()==1 ) return true; + // Add deps on the other uses (can be e.g. ScopeNode mid-parse) so that + // when the other uses go away we can retry. + for( Node use : mem._outputs ) + if( use != this ) + addDep(use); + return false; + } + + @Override + public Parser.ParseException err() { + Parser.ParseException err = super.err(); + if( err != null ) return err; + TypeMemPtr tmp = (TypeMemPtr)ptr()._type; + if( tmp._obj.field(_name)._final && !_init ) + return Parser.error("Cannot modify final field '"+_name+"'",_loc); + return null; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/StructNode.java new file mode 100644 index 00000000..b5b59b81 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/StructNode.java @@ -0,0 +1,47 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import java.util.BitSet; + +/** + * Build a compound object + */ +public class StructNode extends Node { + + public final TypeStruct _ts; + public StructNode(TypeStruct ts) { _ts=ts; assert !ts._open; } + + @Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + if( _ts==null ) return sb.append("STRUCT?"); + sb.append(_ts._name).append(" {"); + for( int i=0; i<nIns(); i++ ) { + sb.append(_ts._fields[i]._fname).append(":"); + sb.append(in(i)==null ? Type.BOTTOM : in(i)._type); + sb.append("; "); + } + sb.setLength(sb.length()-2); + return sb.append("}"); + } + + @Override + public TypeStruct compute() { + if( _ts==null ) return TypeStruct.BOT; + Field[] fs = new Field[_ts._fields.length]; + for( int i=0; i<fs.length; i++ ) + fs[i] = _ts._fields[i].makeFrom(in(i)==null ? Type.TOP : in(i)._type); + return TypeStruct.make(_ts._name,false,fs); + } + + @Override + public Node idealize() { return null; } + + @Override + public boolean eq(Node n) { return _ts == ((StructNode)n)._ts; } + + @Override + int hash() { return _ts==null ? 0 : _ts.hashCode(); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/SubFNode.java new file mode 100644 index 00000000..5c7e969f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/SubFNode.java @@ -0,0 +1,44 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; + +import java.util.BitSet; + +public class SubFNode extends Node { + public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "SubF"; } + + @Override public String glabel() { return "-"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("("), visited); + in(2)._print0(sb.append("-"), visited); + return sb.append(")"); + } + + @Override + public Type compute() { + if (in(1)._type instanceof TypeFloat i0 && + in(2)._type instanceof TypeFloat i1) { + if (i0.isConstant() && i1.isConstant()) + return TypeFloat.constant(i0.value()-i1.value()); + } + return in(1)._type.meet(in(2)._type); + } + + @Override + public Node idealize() { + Node lhs = in(1); + Type t2 = in(2)._type; + + // Sub of 0. + if ( t2.isConstant() && t2 instanceof TypeFloat i && i.value()==0 ) + return lhs; + + return null; + } + @Override Node copy(Node lhs, Node rhs) { return new SubFNode(lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/SubNode.java new file mode 100644 index 00000000..8e4f6f79 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -0,0 +1,43 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import java.util.BitSet; + +public class SubNode extends ArithNode { + public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "Sub"; } + @Override public String op() { return "-"; } + + @Override long doOp( long x, long y ) { return x - y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + // Sub of same is 0 + if( in(1)==in(2) ) + return TypeInteger.ZERO; + // Fold ranges like {2-3} - {0-1} into {1-3}. + if( !AddNode.overflow(x._min,-y._max) && + !AddNode.overflow(x._max,-y._min) && + y._min != Long.MIN_VALUE ) + return TypeInteger.make(x._min-y._max,x._max-y._min); + + return TypeInteger.BOT; + } + + @Override + public Node idealize() { + // x - (-y) is x+y + if( in(2) instanceof MinusNode minus ) + return new AddNode(in(1),minus.in(1)); + + // (-x) - y is -(x+y) + if( in(1) instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + + return super.idealize(); + } + + @Override Node copy(Node lhs, Node rhs) { return new SubNode(lhs,rhs); } + @Override Node copyF() { return new SubFNode(null,null); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java new file mode 100644 index 00000000..c098ad99 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java @@ -0,0 +1,34 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.type.TypeInteger; + +import java.util.BitSet; + +public class ToFloatNode extends Node { + public ToFloatNode(Node lhs) { super(null, lhs); } + + @Override public String label() { return "ToFloat"; } + + @Override public String glabel() { return "(flt)"; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return in(1)._print0(sb.append("(flt)"), visited); + } + + @Override + public Type compute() { + if( in(1)._type == Type.NIL ) return TypeFloat.FZERO; + if (in(1)._type instanceof TypeInteger i0 ) { + if( i0.isHigh() ) return TypeFloat.F64.dual(); + if( i0.isConstant() ) + return TypeFloat.constant(i0.value()); + } + return TypeFloat.F64; + } + + @Override public Node idealize() { return null; } + @Override Node copy(Node lhs, Node rhs) { return new ToFloatNode(lhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java new file mode 100644 index 00000000..8c620a04 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java @@ -0,0 +1,15 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import java.util.BitSet; + +public class XCtrlNode extends CFGNode { + public XCtrlNode() { super(new Node[]{CodeGen.CODE._start}); } + @Override public String label() { return "Xctrl"; } + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); } + @Override public boolean isConst() { return true; } + @Override public Type compute() { return Type.XCONTROL; } + @Override public Node idealize() { return null; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/XorNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/XorNode.java new file mode 100644 index 00000000..fdb4863e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/XorNode.java @@ -0,0 +1,44 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; + +public class XorNode extends ArithNode { + public XorNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } + + @Override public String label() { return "Xor"; } + @Override public String op() { return "^"; } + @Override public String glabel() { return "^"; } + + @Override long doOp( long x, long y ) { return x ^ y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { + return TypeInteger.BOT; + } + + @Override + public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Xor of 0. We do not check for (0^x) because this will already + // canonicalize to (x^0) + if( t2.isConstant() && t2 instanceof TypeInteger i && i.value()==0 ) + return lhs; + + // Move constants to RHS: con*arg becomes arg*con + if ( t1.isConstant() && !t2.isConstant() ) + return swap12(); + + // Do we have ((x ^ (phi cons)) ^ con) ? + // Do we have ((x ^ (phi cons)) ^ (phi cons)) ? + // Push constant up through the phi: x ^ (phi con0^con0 con1^con1...) + Node phicon = AddNode.phiCon(this,true); + if( phicon!=null ) return phicon; + + return super.idealize(); + } + @Override Node copy(Node lhs, Node rhs) { return new XorNode(_loc,lhs,rhs); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java new file mode 100644 index 00000000..1c865254 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java @@ -0,0 +1,20 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class AddARM extends MachConcreteNode implements MachNode { + AddARM( Node add) { super(add); } + @Override public String op() { return "add"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + + // ADD (shifted register) + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_ADD); } + // General form: "rd = rs1 + rs2" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java new file mode 100644 index 00000000..eb75c1a0 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java @@ -0,0 +1,22 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class AddFARM extends MachConcreteNode implements MachNode { + AddFARM(Node addf) { super(addf); } + @Override public String op() { return "addf"; } + @Override public RegMask regmap(int i) { return arm.DMASK; } + @Override public RegMask outregmap() { return arm.DMASK; } + + //FADD (scalar) + @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,arm.OPF_OP_ADD);} + + // Default on double precision for now(64 bits) + // General form: "addf rd = src1 + src2 + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java new file mode 100644 index 00000000..93c9e8c3 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java @@ -0,0 +1,27 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; + +public class AddIARM extends MachConcreteNode implements MachNode { + final int _imm; + AddIARM(Node add, int imm) { + super(add); + _inputs.pop(); + _imm = imm; + } + @Override public String op() { + return _imm == 1 ? "inc" : (_imm == -1 ? "dec" : "addi"); + } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + //ADD (immediate) + @Override public void encoding( Encoding enc ) { + arm.imm_inst(enc,this, in(1), arm.OPI_ADD,_imm); + } + // General form: "addi rd = rs1 + imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java new file mode 100644 index 00000000..77115d54 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java @@ -0,0 +1,21 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; + +public class AndARM extends MachConcreteNode implements MachNode { + AndARM(Node and) { super(and); } + @Override public String op() { return "and"; } + @Override public String glabel() { return "&"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + // AND (shifted register) + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_AND); } + // General form: #rd = rs1 & rs2 + @Override public void asm(CodeGen code, SB sb){ + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java new file mode 100644 index 00000000..5b739cd3 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java @@ -0,0 +1,24 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class AndIARM extends MachConcreteNode implements MachNode { + final int _imm; + AndIARM(Node and, int imm) { + super(and); + _inputs.pop(); + _imm = imm; + } + @Override public String op() { return "andi"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public void encoding( Encoding enc ) { + arm.imm_inst_n(enc,this, in(1), arm.OPI_AND,_imm); + } + // General form: "andi rd = rs1 & imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & #").p(arm.decodeImm12(_imm)); + } +}
\ No newline at end of file diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java new file mode 100644 index 00000000..b83fb3cb --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java @@ -0,0 +1,18 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Arithmetic Shift Right (register) +public class AsrARM extends MachConcreteNode implements MachNode { + AsrARM(Node asr) {super(asr);} + @Override public String op() { return "sar"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.DMASK; } + @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,arm.OP_ASR); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >> ").p(code.reg(in(2))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java new file mode 100644 index 00000000..38373e67 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java @@ -0,0 +1,31 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; + +public class AsrIARM extends MachConcreteNode implements MachNode { + final int _imm; + AsrIARM(Node asr, int imm) { + super(asr); + _inputs.pop(); + _imm = imm; + } + @Override public String op() { return "asri"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public void encoding( Encoding enc ) { + short rd = enc.reg(this); + short rn = enc.reg(in(1)); + assert _imm > 0; + enc.add4(arm.imm_shift(arm.OPI_ASR,_imm, 0b111111, rn, rd)); + } + // General form: "asri rd = rs1 >> imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >> #").p(_imm); + } +}
\ No newline at end of file diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java new file mode 100644 index 00000000..b9ede544 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java @@ -0,0 +1,77 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +// Jump on flags, uses flags +public class BranchARM extends IfNode implements MachNode, RIPRelSize { + String _bop; + BranchARM(IfNode iff, String bop ) { + super(iff); + _bop = bop; + } + @Override public String op() { return "j"+_bop; } + @Override public String label() { return op(); } + + @Override public void postSelect(CodeGen code) { + Node set = in(1); + if( set==null ) return; // Never-node cutout + Node cmp = set.in(1); + // Bypass an expected Set and just reference the cmp directly + if( set instanceof SetARM) + _inputs.set(1,cmp); + else + throw Utils.TODO(); + } + + @Override public RegMask regmap(int i) { assert i==1; return arm.FLAGS_MASK; } + @Override public RegMask outregmap() { return null; } + @Override public void negate() { _bop = negate(_bop); } + + @Override public void encoding( Encoding enc ) { + // Assuming that condition flags are already set. These flags are set + // by comparison (or sub). No need for regs because it uses flags + if( in(1)!=null ) { + // B.cond + enc.add4( arm.b_cond(arm.OP_BRANCH, 0, arm.make_condition(_bop)) ); + } else { + if( _bop=="!=" ) return; // Inverted, no code + enc.add4(arm.b(arm.OP_UJMP, 0)); + } + enc.jump(this,cproj(0)); + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { + if( in(1)==null && _bop=="!=" ) return 0; // Inverted never-node, no code + if( -(1<<19) <= delta && delta < (1<<19) ) return 4; + // 2 word encoding needs a tmp register, must teach RA + throw Utils.TODO(); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + assert !( in(1)==null && _bop=="!=" ); // Inverted never-node, no code no patch + if( opLen==4 ) { + enc.patch4(opStart,arm.b_cond(arm.OP_BRANCH, delta, arm.make_condition(_bop))); + } else { + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + if( in(1)!=null ) { // Never-node + String src = code.reg(in(1)); + if( src!="flags" ) sb.p(src).p(" "); + } else if( _bop=="!=" ) { + sb.p("never"); + return; + } + CFGNode prj = cproj(0).uctrlSkipEmpty(); + if( !prj.blockHead() ) prj = prj.cfg0(); + sb.p(label(prj)); + } + @Override public String comment() { return "L"+cproj(1)._nid; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java new file mode 100644 index 00000000..427cf2e2 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java @@ -0,0 +1,50 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; + +public class CallARM extends CallNode implements MachNode, RIPRelSize { + final TypeFunPtr _tfp; + final String _name; + CallARM(CallNode call, TypeFunPtr tfp) { + super(call); + _inputs.pop(); // Pop constant target + assert tfp.isConstant(); + _tfp = tfp; + FunNode fun = CodeGen.CODE.link(tfp); + _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls + } + + @Override public String op() { return "call"; } + @Override public String label() { return op(); } + @Override public String name() { return _name; } + @Override public TypeFunPtr tfp() { return _tfp; } + @Override public RegMask regmap(int i) { return arm.callInMask(_tfp,i,fun()._maxArgSlot); } + @Override public RegMask outregmap() { return null; } + @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr + + @Override public void encoding( Encoding enc ) { + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); + // BL + enc.add4(arm.b(arm.OP_CALL,0)); // Target patched at link time + } + + // Delta is from opcode start, but X86 measures from the end of the 5-byte encoding + @Override public byte encSize(int delta) { return 4; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + enc.patch4(opStart,arm.b(arm.OP_CALL,delta)); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(_name).p(" "); + for( int i=0; i<nargs(); i++ ) + sb.p(code.reg(arg(i+2))).p(", "); + sb.unchar(2); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java new file mode 100644 index 00000000..c84aa9e5 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java @@ -0,0 +1,32 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class CallRRARM extends CallNode implements MachNode { + CallRRARM(CallNode call) { super(call); } + @Override public String op() { return "callr"; } + @Override public String label() { return op(); } + @Override public RegMask regmap(int i) { + return i==_inputs._len + ? arm.RMASK // Function call target + : arm.callInMask(tfp(),i,fun()._maxArgSlot); // Normal argument + } + @Override public RegMask outregmap() { return null; } + + @Override public void encoding( Encoding enc ) { + // Needs a register, typically a jump-and-link-register opcode + // blr + short self = enc.reg(this); + enc.add4(arm.blr(arm.OP_CALLRARM, self)); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(fptr())).p(" "); + for( int i=0; i<nargs(); i++ ) + sb.p(code.reg(arg(i))).p(", "); + sb.unchar(2); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java new file mode 100644 index 00000000..794ff0c9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java @@ -0,0 +1,22 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class CmpARM extends MachConcreteNode implements MachNode { + CmpARM( Node cmp ) { super(cmp); } + @Override public String op() { return "cmp"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.FLAGS_MASK; } + + // SUBS (shifted register) + @Override public void encoding( Encoding enc ) { arm.r_reg_subs(enc,this,arm.OP_CMP); } + + // General form: "cmp rs1, rs2" + @Override public void asm(CodeGen code, SB sb) { + String dst = code.reg(this); + if( dst!="flags" ) sb.p(dst).p(" = "); + sb.p(code.reg(in(1))).p(", ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java new file mode 100644 index 00000000..67ffc27b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java @@ -0,0 +1,22 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// compare instruction on float regs input(D-registers) +public class CmpFARM extends MachConcreteNode implements MachNode{ + CmpFARM(Node cmp) {super(cmp);} + @Override public String op() { return "cmpf"; } + @Override public RegMask regmap(int i) { return arm.DMASK; } + @Override public RegMask outregmap() { return arm.FLAGS_MASK; } + + // FCMP + @Override public void encoding( Encoding enc ) { arm.f_cmp(enc,this); } + // General form: "cmp d0, d1" + @Override public void asm(CodeGen code, SB sb) { + String dst = code.reg(this); + if( dst!="flags" ) sb.p(dst).p(" = "); + sb.p(code.reg(in(1))).p(", ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java new file mode 100644 index 00000000..f84a1649 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java @@ -0,0 +1,40 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Compare with immediate. +// CMP (immediate) - SUBS +public class CmpIARM extends MachConcreteNode implements MachNode { + final int _imm; + final String _bop; + CmpIARM(BoolNode bool, int imm) { + super(bool); + _inputs.pop(); + _bop = bool.op(); + _imm = imm; + } + CmpIARM( CmpIARM cmp ) { + super((Node)null); + addDef(null); + addDef(cmp.in(1)); + _bop = cmp._bop; + _imm = cmp._imm; + } + @Override public String op() { return _imm==0 ? "test" : "cmp"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.FLAGS_MASK; } + @Override public boolean isClone() { return true; } + @Override public Node copy() { return new CmpIARM(this); } + + @Override public void encoding( Encoding enc ) { arm.imm_inst_subs(enc,in(1),in(1), arm.OPI_CMP,_imm); } + + // General form: "cmp rs1, 1" + @Override public void asm(CodeGen code, SB sb) { + String dst = code.reg(this); + if( dst!="flags" ) sb.p(dst).p(" = "); + sb.p(code.reg(in(1))); + if( _imm != 0 ) sb.p(", #").p(_imm); + } + } diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java new file mode 100644 index 00000000..de254eeb --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class DivARM extends MachConcreteNode implements MachNode { + DivARM( Node div ) { super(div); } + @Override public String op() { return "div"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + // SDIV + @Override public void encoding( Encoding enc ) { arm.madd(enc,this,arm.OP_DIV,3); } + // General form: "div dst /= src" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java new file mode 100644 index 00000000..813bebe4 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class DivFARM extends MachConcreteNode implements MachNode { + DivFARM( Node divf) { super(divf); } + @Override public String op() { return "divf"; } + @Override public RegMask regmap(int i) { return arm.DMASK; } + @Override public RegMask outregmap() { return arm.DMASK; } + + // FDIV (scalar) + @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,arm.OPF_DIV); } + // General form: "VDIF = dst /= src" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java new file mode 100644 index 00000000..b47b65ad --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java @@ -0,0 +1,43 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +//FMOV (scalar, immediate) +//Floating-point move immediate. +public class FloatARM extends ConstantNode implements MachNode, RIPRelSize { + FloatARM(ConstantNode con) { super(con); } + @Override public String op() { return "ld8"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return arm.DMASK; } + @Override public boolean isClone() { return true; } + @Override public FloatARM copy() { return new FloatARM(this); } + + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,_con,0,-1/*TODO: ARM-style ELF patching*/); + short dst = (short)(enc.reg(this) - arm.D_OFFSET); + enc.add4(arm.load_pc(arm.OPF_ARM, 0, dst)); + } + + // Delta is from opcode start. + @Override public byte encSize(int delta) { return 4; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = (short)(enc.reg(this) - arm.D_OFFSET); + enc.patch4(opStart, arm.load_pc(arm.OPF_ARM, delta, dst)); + } + + // Human-readable form appended to the SB. Things like the encoding, + // indentation, leading address or block labels not printed here. + // Just something like "ld4\tR17=[R18+12] // Load array base". + // General form: "op\tdst=src+src" + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" = #")); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java new file mode 100644 index 00000000..44a417f9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java @@ -0,0 +1,22 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.FunNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class FunARM extends FunNode implements MachNode { + FunARM(FunNode fun) { super(fun); } + @Override public void computeFrameAdjust(CodeGen code, int maxReg) { + super.computeFrameAdjust(code,maxReg); + if( _hasCalls ) // If non-leaf, pad to 16b + _frameAdjust = ((_frameAdjust+8) & -16); + } + @Override public void encoding( Encoding enc ) { + int sz = _frameAdjust; + if( sz == 0 ) return; // Skip if no frame adjust + if( sz >= 1L<<12 ) throw Utils.TODO(); + enc.add4(arm.imm_inst(arm.OPI_ADD, -sz&0xFFF, arm.RSP, arm.RSP)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java new file mode 100644 index 00000000..f1fa162f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java @@ -0,0 +1,25 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class I2F8ARM extends MachConcreteNode implements MachNode { + I2F8ARM(Node i2f8) { super(i2f8); } + @Override public String op() { return "cvt"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.DMASK; } + @Override public void encoding( Encoding enc ) { + // SCVTF + short self = (short)(enc.reg(this )-arm.D_OFFSET); + short reg1 = enc.reg(in(1)); + int body = arm.float_cast(arm.OP_FLOAT_C, 1, reg1, self); + enc.add4(body); + } + + // General form: "i2f8 (flt)int_value" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p("(flt)").p(code.reg(in(1))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java new file mode 100644 index 00000000..ee74b95e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java @@ -0,0 +1,67 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; + +// Integer constants +public class IntARM extends ConstantNode implements MachNode { + IntARM( ConstantNode con ) { super(con); } + + @Override public String op() { return "ldi"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return arm.WMASK; } + + @Override public boolean isClone() { return true; } + @Override public IntARM copy() { return new IntARM(this); } + + @Override public void encoding( Encoding enc ) { + short self = enc.reg(this); + long x = _con==Type.NIL ? 0 : ((TypeInteger)_con).value(); + int nb0 = 0; + int nb1 = 0; + // Count number of 0000 and FFFF blocks + for (int i=0; i<64; i+=16) { + int block = (int)(x >> i) & 0xFFFF; + if (block == 0) nb0++; + if (block == 0xFFFF) nb1++; + } + int pattern; + int op; + if(nb0 >= nb1) { + // More 0 blocks then F blocks, use movz + pattern = 0; + op = arm.OP_MOVZ; + } else { + // More F blocks then 0 blocks, use movn + pattern = 0xFFFF; + op = arm.OP_MOVN; + } + int invert = pattern; + for (int i=0; i<4; i++) { + int block = (int)x & 0xFFFF; + x >>= 16; + if (block != pattern) { + enc.add4(arm.mov(op, i, block ^ invert, self)); + op = arm.OP_MOVK; + invert = 0; + } + } + if (op != arm.OP_MOVK) { + // All blocks are the same, special case + enc.add4(arm.mov(op, 0, 0, self)); + } + } + + // Human-readable form appended to the SB. Things like the encoding, + // indentation, leading address or block labels not printed here. + // Just something like "ld4\tR17=[R18+12] // Load array base". + // General form: "op\tdst=src+src" + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + _con.print(sb.p(reg).p(" = #")); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java new file mode 100644 index 00000000..1e5d2094 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java @@ -0,0 +1,39 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.LoadNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; + +// Load memory addressing on ARM +// Support imm, reg(direct), or reg+off(indirect) addressing +// Base = base - base pointer, offset is added to base +// idx = null +// off = off - offset added to base + +public class LoadARM extends MemOpARM { + LoadARM(LoadNode ld, Node base, Node idx, int off) { + super(ld, base, idx, off, 0); + } + @Override public String op() { return "ld"+_sz; } + @Override public RegMask outregmap() { return arm.MEM_MASK; } + + private static final int[] OP_LOADS = new int[]{ arm.OP_LOAD_IMM_8, arm.OP_LOAD_IMM_16, arm.OP_LOAD_IMM_32, arm.OP_LOAD_IMM_64, }; + private int imm_op() { + return _declaredType == TypeFloat.F32 ? arm.OPF_LOAD_IMM_32 + : _declaredType == TypeFloat.F64 ? arm.OPF_LOAD_IMM_64 + : OP_LOADS[_declaredType.log_size()]; + } + + private static final int[] OP_LOAD_RS = new int[]{ arm.OP_LOAD_R_8 , arm.OP_LOAD_R_16 , arm.OP_LOAD_R_32 , arm.OP_LOAD_R_64, }; + + // ldr(immediate - unsigned offset) | ldr(register) + @Override public void encoding( Encoding enc ) { + ldst_encode(enc, imm_op(), OP_LOAD_RS[_declaredType.log_size()], this, size()); + } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(","); + asm_address(code,sb); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java new file mode 100644 index 00000000..80ce493f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Logical Shift Left (register) +public class LslARM extends MachConcreteNode implements MachNode { + LslARM(Node asr) {super(asr);} + @Override public String op() { return "shr"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + + @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,arm.OP_LSL); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" << ").p(code.reg(in(2))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java new file mode 100644 index 00000000..7fe16cbe --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java @@ -0,0 +1,33 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; + +public class LslIARM extends MachConcreteNode implements MachNode { + final int _imm; + LslIARM(Node lsl, int imm) { + super(lsl); + _inputs.pop(); + _imm = imm; + } + @Override public String op() { return "lsli"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public void encoding( Encoding enc ) { + short rd = enc.reg(this); + short rn = enc.reg(in(1)); + assert _imm > 0; + // UBFM <Xd>, <Xn>, #(-<shift> MOD 64), #(63-<shift>) + // immr must be (-<shift> MOD 64) = 64 - shift + enc.add4(arm.imm_shift(arm.OPI_LSL, 64 - _imm, (64 - _imm) - 1, rn, rd)); + } + // General form: "lsli rd = rs1 << imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" << #").p(_imm); + } +}
\ No newline at end of file diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java new file mode 100644 index 00000000..fc005e04 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Logical Shift Right (register) +public class LsrARM extends MachConcreteNode implements MachNode { + LsrARM(Node asr) {super(asr);} + @Override public String op() { return "shr"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + + @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,arm.OP_LSR); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >>> ").p(code.reg(in(2))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java new file mode 100644 index 00000000..78844b0a --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java @@ -0,0 +1,28 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// logical right shift immediate +public class LsrIARM extends MachConcreteNode implements MachNode { + final int _imm; + LsrIARM(Node lsr, int imm) { + super(lsr); + _inputs.pop(); + _imm = imm; + } + @Override public String op() { return "lsri"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public void encoding( Encoding enc ) { + short rd = enc.reg(this); + short rn = enc.reg(in(1)); + assert _imm > 0; + enc.add4(arm.imm_shift(arm.OPI_LSR,_imm, 0b111111, rn,rd)); + } + // General form: "lsri rd = rs1 >>> imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >>> #").p(_imm); + } +}
\ No newline at end of file diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java new file mode 100644 index 00000000..e877931d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java @@ -0,0 +1,68 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.lang.StringBuilder; +import java.util.BitSet; + +public abstract class MemOpARM extends MemOpNode implements MachNode { + final int _off; // Limit 9 bits sized, or (13 bits<<logsize) unsigned + final int _imm; // Limit ? bits + final char _sz = (char)('0'+(1<<_declaredType.log_size())); + MemOpARM(MemOpNode mop, Node ptr, Node idx, int off, int imm) { + super(mop,mop); + assert ptr._type instanceof TypeMemPtr && !(ptr instanceof AddNode); + assert ptr() == ptr; + _inputs.setX(2, ptr); + _inputs.setX(3, idx); + _off = off; + _imm = imm; + } + + // Store-based flavors have a value edge + MemOpARM( MemOpNode mop, Node ptr, Node idx, int off, int imm, Node val ) { + this(mop,ptr,idx,off,imm); + _inputs.setX(4,val); + } + + @Override public String label() { return op();} + Node val() { return in(4); } // Only for stores + + @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); } + + @Override public Type compute() { throw Utils.TODO(); } + @Override public Node idealize() { throw Utils.TODO(); } + + int size() { return 1<<_declaredType.log_size(); } + + // Wider mask to store both GPRs and FPRs + @Override public RegMask regmap(int i) { + // 0 - ctrl + if( i==1 ) return null; // memory + if( i==2 ) return arm.RMASK; // ptr/base + if( i==3 ) return arm.RMASK; // off/index + if( i==4 ) return arm.RMASK; // value + return null; // Anti-dependence + } + + // Shared encoding for loads and stores(int and float) + public void ldst_encode( Encoding enc, int opcode_imm, int opcode_reg, Node xval, int size) { + short ptr = enc.reg(ptr()); + short off = enc.reg(off()); + short val = enc.reg(xval); + int body = off() == null + ? arm.load_str_imm(opcode_imm, _off, ptr, val, size) + : arm.indr_adr(opcode_reg, off, arm.STORE_LOAD_OPTION.SXTX, 0, ptr, val); + enc.add4(body); + } + + SB asm_address(CodeGen code, SB sb) { + sb.p("[").p(code.reg(ptr())).p("+"); + if( off() != null ) sb.p(code.reg(off())); + else sb.p(_off); + return sb.p("]"); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java new file mode 100644 index 00000000..a23ec75b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// mulh signed multiply instruction(no-imm form) +public class MulARM extends MachConcreteNode implements MachNode { + MulARM(Node mul) {super(mul);} + @Override public String op() { return "mul"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + + @Override public void encoding( Encoding enc ) { arm.madd(enc,this,arm.OP_MUL,31); } + // General form: "rd = rs1 * rs2" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java new file mode 100644 index 00000000..73ebbf00 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java @@ -0,0 +1,18 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class MulFARM extends MachConcreteNode implements MachNode{ + MulFARM(Node mulf) {super(mulf);} + @Override public String op() { return "mulf"; } + @Override public RegMask regmap(int i) { return arm.DMASK; } + @Override public RegMask outregmap() { return arm.DMASK; } + @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,arm.OPF_MUL); } + // Default on double precision for now(64 bits) + // General form: "VMUL.f32 rd = src1 * src2 + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java new file mode 100644 index 00000000..881b41f9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java @@ -0,0 +1,25 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; + +public class NegARM extends MachConcreteNode implements MachNode { + NegARM(Node sub) { + super(sub); + //_inputs.pop(); + } + @Override public String op() { return "neg"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public void encoding( Encoding enc ) { + // reverse subtract with immediate 0 + arm.imm_inst(enc,this, in(1), 0b00100110, 0); + } + // General form: "subi rd = rs1 - imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = -").p(code.reg(in(1))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java new file mode 100644 index 00000000..c1aad15f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java @@ -0,0 +1,37 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class NewARM extends NewNode implements MachNode, RIPRelSize { + // A pre-zeroed chunk of memory. + NewARM(NewNode nnn) { super(nnn); } + @Override public void encoding( Encoding enc ) { + // BL(branch with link) + enc.external(this,"calloc"). + add4(arm.mov(arm.OP_MOVZ, 0, 1, 0)). // movz x0,#1 + add4(arm.b(arm.OP_CALL, 0)); + } + + // Patch is for running "new" in a JIT. + // Delta is from opcode start + @Override public byte encSize(int delta) { return 4*2; } + + // Patch is for running "new" in a JIT. + // Delta is from opcode start + @Override public void patch(Encoding enc, int opStart, int opLen, int delta ) { + // Negative patches are JIT emulator targets. + if( opStart+delta < 0 ) { + enc.patch4(opStart+4, arm.b_calloc(arm.OP_CALL, delta-4)); + } else { + throw Utils.TODO(); + } + } + // General form: "alloc #bytes PC" + @Override public void asm(CodeGen code, SB sb) { + sb.p("ldi x0=#1\n"); + sb.p("call #calloc"); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java new file mode 100644 index 00000000..027a8128 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java @@ -0,0 +1,27 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.util.SB; + +public class NotARM extends MachConcreteNode implements MachNode{ + NotARM(NotNode not) {super(not);} + @Override public String op() { return "not"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public RegMask killmap() { return arm.FLAGS_MASK; } + @Override public void encoding( Encoding enc ) { + // subs xzr, rs, #0 + // cset rd, eq // Set rd to 1 if rs == 0 (equal), else 0 + // subtracting zero from rs will just yield rs, it sets the zero flag and then it's used in cset + short self = enc.reg(this ); + short reg1 = enc.reg(in(1)); + int subs = arm.imm_inst(arm.OP_SUBS, 0, reg1, self); + enc.add4(subs); + int cset = arm.cond_set(arm.OP_CSET, 31, arm.COND.EQ, 63, reg1); + enc.add4(cset); + } + + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java new file mode 100644 index 00000000..e8245749 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java @@ -0,0 +1,20 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Not using the ORRS variant. +public class OrARM extends MachConcreteNode implements MachNode { + OrARM(Node and) { super(and); } + @Override public String op() { return "or"; } + @Override public String glabel() { return "|"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_OR); } + // General form: #rd = rs1 & rs2 + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" | ").p(code.reg(in(2))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java new file mode 100644 index 00000000..a48caa51 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java @@ -0,0 +1,24 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class OrIARM extends MachConcreteNode implements MachNode { + final int _imm; + OrIARM(Node or, int imm) { + super(or); + _inputs.pop(); + _imm = imm; + } + @Override public String op() { return "ori"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public void encoding( Encoding enc ) { + arm.imm_inst_n(enc, this, in(1), arm.OPI_OR, _imm); + } + // General form: "ori rd = rs1 | imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" | #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java new file mode 100644 index 00000000..b419fe0a --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.ParmNode; + +public class ParmARM extends ParmNode implements MachNode { + final RegMask _rmask; + ParmARM(ParmNode parm) { + super(parm); + _rmask = arm.callInMask(fun().sig(),_idx,0); + } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return _rmask; } + @Override public void encoding( Encoding enc ) { } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/ProjARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/ProjARM.java new file mode 100644 index 00000000..4b7d6f13 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/ProjARM.java @@ -0,0 +1,15 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.ProjNode; + +public class ProjARM extends ProjNode implements MachNode { + ProjARM( ProjNode p ) { super(p); } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { + return ((MachNode)in(0)).outregmap(_idx); + } + @Override public void encoding( Encoding enc ) { } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/RetARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/RetARM.java new file mode 100644 index 00000000..2136ebf5 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/RetARM.java @@ -0,0 +1,15 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; + +public class RetARM extends ReturnNode implements MachNode { + RetARM(ReturnNode ret, FunNode fun) { super(ret, fun); fun.setRet(this); } + @Override public void encoding( Encoding enc ) { + int frameAdjust = ((FunARM)fun())._frameAdjust; + if( frameAdjust > 0 ) + enc.add4(arm.imm_inst(arm.OPI_ADD, (frameAdjust*-8)&0xFFF, arm.RSP, arm.RSP)); + enc.add4(arm.ret(arm.OP_RET)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java new file mode 100644 index 00000000..e1b3b3b6 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java @@ -0,0 +1,33 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// conditional set? +// e.g CSET, stores flag info into GPRS after compare +public class SetARM extends MachConcreteNode implements MachNode { + final String _bop; // One of <,<=,== + SetARM(Node cmp, String bop) { + super(cmp); + _inputs.setLen(1); // Pop the cmp inputs + // Replace with the matched cmp + _inputs.push(cmp); + _bop = bop; + } + @Override public String op() { return "set"+_bop; } + @Override public RegMask regmap(int i) { assert i==1; return arm.FLAGS_MASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + + @Override public void encoding( Encoding enc ) { + // Using RM==RN==31 implies a *zero* value, not R31. + int body = arm.cset(arm.OP_CSET,0b11111, arm.make_condition(_bop), 0b011111, enc.reg(this)); + enc.add4(body); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)); + String src = code.reg(in(1)); + if( src!="flags" ) sb.p(" = ").p(src); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java new file mode 100644 index 00000000..5af45892 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java @@ -0,0 +1,65 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.FunNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.SplitNode; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class SplitARM extends SplitNode { + SplitARM(String kind, byte round) { super(kind,round,new Node[2]);} + @Override public RegMask regmap(int i) { return arm.SPLIT_MASK; } + @Override public RegMask outregmap() { return arm.SPLIT_MASK; } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this ); + short src = enc.reg(in(1)); + + boolean dstX = dst >= arm.D_OFFSET; + boolean srcX = src >= arm.D_OFFSET; + + if (dst >= arm.MAX_REG) { + // store to sp + if(src >= arm.MAX_REG) { + throw Utils.TODO(); + } + int off = enc._fun.computeStackOffset(enc._code,dst); + if( srcX ) src -= arm.D_OFFSET; + enc.add4(arm.load_str_imm(arm.OP_STORE_IMM_64, off, arm.RSP, src, 8)); + return; + } + + if(src >= arm.MAX_REG) { + // Load from SP + int off = enc._fun.computeStackOffset(enc._code,src); + if( dstX ) dst -= arm.D_OFFSET; + enc.add4(arm.load_str_imm(arm.OP_LOAD_IMM_64, off, arm.RSP, dst, 8)); + return; + } + + // pick opcode based on regs + if(!dstX && !srcX) { + // GPR->GPR + enc.add4(arm.mov_reg(arm.OP_MOV, src, dst)); + } else if(dstX && srcX) { + // FPR->FPR + // fmov reg + enc.add4(arm.f_mov_reg(arm.OP_FMOV_REG, src - arm.D_OFFSET,dst - arm.D_OFFSET)); + } else if(!srcX && dstX) { + // GPR->FPR + // FMOV(general) 64 bits to DOUBLE-PRECISION + enc.add4(arm.f_mov_general(arm.OP_FMOV, 0b01, 0, 0b111, src, dst - arm.D_OFFSET)); + } else if( srcX && !dstX) { + //FPF->GPR + // FMOV(general) DOUBLE-PRECISION to 64 bits + enc.add4(arm.f_mov_general(arm.OP_FMOV, 0b01, 0, 0b110, src - arm.D_OFFSET, dst)); + } + } + + // General form: "mov dst = src" + @Override public void asm(CodeGen code, SB sb) { + FunNode fun = code._encoding==null ? null : code._encoding._fun; + sb.p(code.reg(this,fun)).p(" = ").p(code.reg(in(1),fun)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java new file mode 100644 index 00000000..91385ac9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java @@ -0,0 +1,43 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.StoreNode; +import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; + +// Store memory addressing on ARM +// Support imm, reg(direct), or reg+off(indirect) addressing +// base - base pointer, offset is added to base +// null - index never allowed (no [reg+reg] mode) +// off - offset added to base +// imm - immediate value to store, only if val is null +// val - value to store or null + +//e.g s.cs[0] = 67; // C +// base = s.cs, off = 4, imm = 67, val = null +public class StoreARM extends MemOpARM { + StoreARM(StoreNode st, Node base, Node idx, int off, Node val) { + super(st, base, idx, off, 0, val); + } + @Override public String op() { return "st"+_sz; } + @Override public RegMask outregmap() { return null; } + + private static final int[] OP_STORES = new int[]{ arm.OP_STORE_IMM_8, arm.OP_STORE_IMM_16, arm.OP_STORE_IMM_32, arm.OP_STORE_IMM_64, }; + private int imm_op() { + return _declaredType == TypeFloat.F32 ? arm.OPF_STORE_IMM_32 + : _declaredType == TypeFloat.F64 ? arm.OPF_STORE_IMM_64 + : OP_STORES[_declaredType.log_size()]; + } + + private static final int[] OP_STORE_RS = new int[]{ arm.OP_STORE_R_8, arm.OP_STORE_R_16, arm.OP_STORE_R_32, arm.OP_STORE_R_64, }; + + @Override public void encoding( Encoding enc ) { + ldst_encode(enc, imm_op(), OP_STORE_RS[_declaredType.log_size()], val(), size()); + } + @Override public void asm(CodeGen code, SB sb) { + asm_address(code,sb).p(","); + if( val()==null ) sb.p("#").p(_imm); + else sb.p(code.reg(val())); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java new file mode 100644 index 00000000..e3b95e50 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class SubARM extends MachConcreteNode implements MachNode { + SubARM(Node sub) { super(sub); } + @Override public String op() { return "sub"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_SUB); } + + // General form: "sub # rd = rs1 - rs2" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java new file mode 100644 index 00000000..a252e542 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java @@ -0,0 +1,18 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class SubFARM extends MachConcreteNode implements MachNode { + SubFARM(Node subf) {super(subf);} + @Override public String op() { return "subf"; } + @Override public RegMask regmap(int i) { return arm.DMASK; } + @Override public RegMask outregmap() { return arm.DMASK; } + @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,arm.OPF_SUB); } + // Default on double precision for now(64 bits) + // General form: "vsub.f32 rd = src1 + src2 + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java new file mode 100644 index 00000000..b50107c9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java @@ -0,0 +1,28 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; + +public class SubIARM extends MachConcreteNode implements MachNode { + final int _imm; + SubIARM(Node sub, int imm) { + super(sub); + _inputs.pop(); + _imm = imm; + } + @Override public String op() { return _imm == -1 ? "dec" : "subi"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + + @Override public void encoding( Encoding enc ) { + arm.imm_inst(enc,this, in(1), arm.OPI_SUB,_imm); + } + + // General form: "subi rd = rs1 - imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java new file mode 100644 index 00000000..29d490ef --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java @@ -0,0 +1,56 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { + TFPARM( ConstantNode con ) { super(con); } + @Override public String op() { return "ldx"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TFPARM copy() { return new TFPARM(this); } + @Override public void encoding( Encoding enc ) { + enc.relo(this); + short self = enc.reg(this); + // adrp x0, 0 + int adrp = arm.adrp(1,0, arm.OP_ADRP, 0,self); + // add x0, x0, 0 + enc.add4(adrp); + arm.imm_inst(enc,arm.OPI_ADD,0, 0); + } + + @Override public byte encSize(int delta) { + return 8; + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short rpc = enc.reg(this); + if(opLen == 8 ) { + // ARM encoding delta is from PC & 0xFFF + int target = opStart+delta; + int base = opStart & ~0xFFF; + delta = target-base; + int adrp_delta = delta >> 12; + // patch upper 20 bits via adrp + enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, rpc)); + // low 12 bits via add + enc.patch4(opStart+4, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, rpc)); + } else { + // should not happen as one instruction is 4 byte, and TFP arm encodes 2. + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + _con.print(sb.p(reg).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java new file mode 100644 index 00000000..cdcaa433 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java @@ -0,0 +1,54 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class TMPARM extends ConstantNode implements MachNode, RIPRelSize { + TMPARM( ConstantNode con ) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TMPARM copy() { return new TMPARM(this); } + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + short dst = enc.reg(this); + // adrp x0, 0 + enc.add4(arm.adrp(1,0, arm.OP_ADRP, 0,dst)); + // add x0, x0, 0 + arm.imm_inst(enc,arm.OPI_ADD,0, dst); + } + + @Override public byte encSize(int delta) { + return 8; + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + if(opLen == 8 ) { + // ARM encoding delta is from PC & 0xFFF + int target = opStart+delta; + int base = opStart & ~0xFFF; + delta = target-base; + int adrp_delta = delta >> 12; + // patch upper 20 bits via adrp + enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, dst)); + // low 12 bits via add + enc.patch4(opStart+4, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, dst)); + } else { + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + _con.print(sb.p(reg).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java new file mode 100644 index 00000000..2dd5fd6b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java @@ -0,0 +1,49 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +// unconditional jump +public class UJmpARM extends CFGNode implements MachNode, RIPRelSize { + UJmpARM() { } + @Override public String op() { return "jmp"; } + @Override public String label() { return op(); } + @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { + return sb.append("jmp "); + } + @Override public RegMask regmap(int i) {return null; } + @Override public RegMask outregmap() { return null; } + @Override public Type compute() { throw Utils.TODO(); } + @Override public Node idealize() { throw Utils.TODO(); } + @Override public void encoding( Encoding enc ) { + enc.jump(this,uctrl()); + int body = arm.b(arm.OP_UJMP, 0); + enc.add4(body); + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { + if( -(1<<26) <= delta && delta < (1<<26) ) return 4; + // 2 word encoding needs a tmp register, must teach RA + throw Utils.TODO(); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + if( opLen==4 ) { + enc.patch4(opStart,arm.b(arm.OP_UJMP, delta)); + } else { + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + CFGNode target = uctrl(); + //assert target.nOuts() > 1; // Should optimize jmp to empty targets + sb.p(label(target)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java new file mode 100644 index 00000000..52bda021 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class XorARM extends MachConcreteNode implements MachNode{ + XorARM(Node xor) {super(xor);} + @Override public String op() { return "xor"; } + @Override public String glabel() { return "^"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_XOR); } + // General form: "rd = x1 ^ x2" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ ").p(code.reg(in(2))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java new file mode 100644 index 00000000..23b29644 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java @@ -0,0 +1,26 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; + +public class XorIARM extends MachConcreteNode implements MachNode { + final int _imm; + XorIARM(Node xor, int imm) { + super(xor); + _inputs.pop(); + _imm = imm; + } + + @Override public String op() { return "xori"; } + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.WMASK; } + + // General form: "xori rd = rs1 ^ imm" + @Override public void encoding( Encoding enc ) { arm.imm_inst_n(enc,this, in(1), arm.OPI_XOR,_imm); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java new file mode 100644 index 00000000..1c61bb37 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java @@ -0,0 +1,816 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; + +public class arm extends Machine { + public arm( CodeGen code ) { + if( !"SystemV".equals(code._callingConv) ) + throw new IllegalArgumentException("Unknown calling convention "+code._callingConv); + } + + // ARM64 + @Override public String name() { return "arm"; } + + // GPR(S) + public static final int X0 = 0, X1 = 1, X2 = 2, X3 = 3, X4 = 4, X5 = 5, X6 = 6, X7 = 7; + public static final int X8 = 8, X9 = 9, X10 = 10, X11 = 11, X12 = 12, X13 = 13, X14 = 14, X15 = 15; + public static final int X16 = 16, X17 = 17, X18 = 18, X19 = 19, X20 = 20, X21 = 21, X22 = 22, X23 = 23; + public static final int X24 = 24, X25 = 25, X26 = 26, X27 = 27, X28 = 28, X29 = 29, X30 = 30, RSP = 31; + + // Floating point registers + public static final int D0 = 32, D1 = 33, D2 = 34, D3 = 35, D4 = 36, D5 = 37, D6 = 38, D7 = 39; + public static final int D8 = 40, D9 = 41, D10 = 42, D11 = 43, D12 = 44, D13 = 45, D14 = 46, D15 = 47; + public static final int D16 = 48, D17 = 49, D18 = 50, D19 = 51, D20 = 52, D21 = 53, D22 = 54, D23 = 55; + public static final int D24 = 56, D25 = 57, D26 = 58, D27 = 59, D28 = 60, D29 = 61, D30 = 62, D31 = 63; + + static final int FLAGS = 64; + static final int MAX_REG = 65; + public static final int D_OFFSET = 32; + + static final String[] REGS = new String[] { + "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", + "X8", "X9", "X10", "X11", "X12", "X13", "X14", "X15", + "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23", + "X24", "X25", "X26", "X27", "X28", "X29", "RPC", "RSP", + "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", + "D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15", + "D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23", + "D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31", + "flags" + }; + @Override public String[] regs() { return REGS; } + + // from (x0-x30) + // General purpose register mask: pointers and ints, not floats + static final long RD_BITS = 0xFFFFFFFFL; + static final RegMask RMASK = new RegMask(RD_BITS); + static final long WR_BITS = 0x7FFFFFFFL; // All the GPRs, not RSP + static final RegMask WMASK = new RegMask(WR_BITS); + + // Float mask from(d0–d31) + static final long FP_BITS = 0xFFFFFFFFL<<D0; + static final RegMask DMASK = new RegMask(FP_BITS); + + // Load/store mask; both GPR and FPR + static final RegMask MEM_MASK = new RegMask(WR_BITS | FP_BITS); + + static final RegMask SPLIT_MASK = new RegMask(WR_BITS | FP_BITS, -2L/*skip flags*/); + + static final RegMask FLAGS_MASK = new RegMask(FLAGS); + + // Arguments masks + static final RegMask X0_MASK = new RegMask(X0); + static final RegMask X1_MASK = new RegMask(X1); + static final RegMask X2_MASK = new RegMask(X2); + static final RegMask X3_MASK = new RegMask(X3); + static final RegMask X4_MASK = new RegMask(X4); + static final RegMask X5_MASK = new RegMask(X5); + static final RegMask X6_MASK = new RegMask(X6); + static final RegMask X7_MASK = new RegMask(X7); + + // Arguments(float) masks + static final RegMask D0_MASK = new RegMask(D0); + static final RegMask D1_MASK = new RegMask(D1); + static final RegMask D2_MASK = new RegMask(D2); + static final RegMask D3_MASK = new RegMask(D3); + static final RegMask D4_MASK = new RegMask(D4); + static final RegMask D5_MASK = new RegMask(D5); + static final RegMask D6_MASK = new RegMask(D6); + static final RegMask D7_MASK = new RegMask(D7); + + // major opcode: OP + public static int OP_ADD = 0b10_001_011; + public static int OPF_ADD = 0b00_011_110; + public static int OPF_OP_ADD = 0b00_101_0; + public static int OPI_ADD = 0b10_010_00100; + + public static int OPI_SUB = 0b11_010_00100; + public static int OP_UJMP = 0b000101; + + public static int OP_ADRP = 0b10000; + + public static int OP_ASR = 0b1010; + public static int OPI_ASR = 0b10_0100_1101; + + public static int OP_LSL = 0b1000; + public static int OPI_LSL =0b1101001101; + + public static int OP_LSR = 0b1001; + public static int OPI_LSR = 0b1101001101; + + public static int OP_BRANCH = 0b01_0101_00; + public static int OP_CALL = 0b10_010_1; + + public static int OP_CALLRARM = 0b1101011000111111000000; + + public static int OP_SUBS = 0b1111000100; + public static int OP_CSET = 0b10011010100; + public static int OP_CMP = 0b11101011; + public static int OPI_CMP = 0b1111000100; + + public static int OP_DIV = 0b10011010110; + public static int OPF_DIV = 0b000110; + + public static int OP_MUL = 0b10011011000; + public static int OPF_MUL = 0b10; + + public static int OPF_ARM = 0b01011100; + + public static int OP_FLOAT_C = 0b10011110; + + public static int OP_XOR = 0b11001010; + public static int OPI_XOR = 0b110100100; + + public static int OP_AND = 0b10_0010_10; + public static int OPI_AND = 0b10_0100_100; + + public static int OP_OR = 0b10101010; + public static int OPI_OR = 0b101100100; + + public static int OP_SUB = 0b11001011; + public static int OPF_SUB = 0b1110; + + public static int OP_MOVK = 0b111100101; + public static int OP_MOVN = 0b100100101; + public static int OP_MOVZ = 0b110100101; + + public static int OP_RET = 0b1101011001011111000000; + // Store/load opcodes + public static int OP_LOAD_R_64 = 0b11111000011; + public static int OP_LOAD_R_32 = 0b10111000011; + public static int OP_LOAD_R_16 = 0b01111000010; + public static int OP_LOAD_R_8 = 0b00111000011; + + public static int OP_LOAD_IMM_64 = 0b1111100101; + public static int OP_LOAD_IMM_32 = 0b1011100101; + public static int OP_LOAD_IMM_16 = 0b0111100101; + public static int OP_LOAD_IMM_8 = 0b0011100101; + + // load + public static int OPF_LOAD_R_64 = 0b11111100011; + public static int OPF_LOAD_R_32 = 0b10111100011; + + public static int OPF_LOAD_IMM_64 = 0b1111110101; + public static int OPF_LOAD_IMM_32 = 0b1011110101; + + public static int OP_STORE_R_64 = 0b11111000001; + public static int OP_STORE_R_32 = 0b10111000001; + public static int OP_STORE_R_16 = 0b01111000001; + public static int OP_STORE_R_8 = 0b00111000001; + + public static int OP_STORE_IMM_64 = 0b1111100100; + public static int OP_STORE_IMM_32 = 0b1011100100; + public static int OP_STORE_IMM_16 = 0b0111100100; + public static int OP_STORE_IMM_8 = 0b0011100100; + + public static int OPF_STORE_R_64 = 0b11111100001; + public static int OPF_STORE_R_32 = 0b10111100001; + + public static int OPF_STORE_IMM_32 = 0b1111110100; + public static int OPF_STORE_IMM_64 = 0b1111110100; + + + public static int OP_FMOV = 0b10011110; + public static int OP_FMOV_REG = 0b00011110; + // https://docsmirror.github.io/A64/2023-06/mov_orr_log_shift.html + public static int OP_MOV = 0b10101010000; + // Calling convention; returns a machine-specific register + // for incoming argument idx. + // index 0 for control, 1 for memory, real args start at index 2 + static final RegMask[] CALLINMASK = new RegMask[] { + X0_MASK, + X1_MASK, + X2_MASK, + X3_MASK, + X4_MASK, + X5_MASK, + X6_MASK, + X7_MASK, + }; + static final RegMask[] XMMS = new RegMask[] { + D0_MASK, + D1_MASK, + D2_MASK, + D3_MASK, + D4_MASK, + D5_MASK, + D6_MASK, + D7_MASK, + }; + + // ARM ENCODING + public enum OPTION { + UXTB, + UXTH, + UXTX, + SXTB, + SXTH, + SXTW, + SXTX, + } + + static public int cset(int opcode, int rm, COND cond, int rn, int rd) { + assert 0 <= rm && rm < 32; + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + return (opcode << 21) | (rm << 16) | (cond.ordinal() << 12) | (0b01 << 10) | (rn << 5) | rd; + } + + static public int cset(int opcode, COND cond, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + return (opcode << 16) | (cond.ordinal() << 12) | (rn << 5) | rd; + } + + public enum STORE_LOAD_OPTION { + UXTW, // base+ u32 index [<< logsize] + UXTX, // base+ u64 index [<< logsize] + SXTW, // base+ s32 index [<< logsize] + SXTX, // base+ s64 index [<< logsize] + } + + public enum COND { + EQ, + NE, + CS, + CC, + MI, + PL, + VS, + VC, + HI, + LS, + GE, + LT, + GT, + LE, + AL, + NV + } + + // True if signed 9-bit immediate + private static boolean imm9(TypeInteger ti) { + // 55 = 64-9 + return ti.isConstant() && ((ti.value()<<55)>>55) == ti.value(); + } + // True if signed 12-bit immediate + private static boolean imm12(TypeInteger ti) { + // 52 = 64-12 + return ti.isConstant() && ((ti.value()<<52)>>52) == ti.value(); + } + + + // Can we encode this in ARM's 12-bit LOGICAL immediate form? + // Some combination of shifted bit-masks. + private static int imm12Logical(TypeInteger ti) { + if( !ti.isConstant() ) return -1; + if( !ti.isConstant() ) return -1; + long val = ti.value(); + if (val == 0 || val == -1) return -1; // Special cases are not allowed + int immr = 0; + // Rotate until we have 0[...]1 + + // Rotate until: + // The number is negative (MSB is 1) + // Or the LSB is not 1 + while (val < 0 || (val & 1)==0) { + // circular rotation + val = (val >>> 63) | (val << 1); + immr++; + } + // Start by assuming that val might be made of two 32-bit chunks that repeat. + int size = 32; + long pattern = val; + // Is upper half of pattern the same as the lower? + while ((pattern & ((1L<<size)-1)) == (pattern >> size)) { + // Then only take one half + pattern >>= size; + size >>= 1; + } + size <<= 1; + int imms = Long.bitCount(pattern); + // Pattern should now be zeros followed by ones 0000011111 + if (pattern != (1L<<imms)-1) return -1; + imms--; + if (size == 64) return 0x1000 | immr << 6 | imms; + return (32-size)<<1 | immr << 6 | imms; + } + + // sh is encoded in opcode + public static int imm_inst(int opcode, int imm12, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + assert opcode >=0 && imm12 >= 0; // Caller zeros high order bits + return (opcode << 22) | (imm12 << 10) | (rn << 5) | rd; + } + + public static int imm_shift(int opcode, int imm, int imms, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + return (opcode << 22) | (1 << 22) | (imm << 16) | (imms << 10) | (rn << 5) | rd; + } + + public static void imm_inst(Encoding enc, Node n,Node n2, int opcode, int imm12) { + short self = enc.reg(n); + short reg1 = enc.reg(n2); + + int body = imm_inst(opcode, imm12&0xFFF, reg1, self); + enc.add4(body); + } + + public static void imm_inst_subs(Encoding enc, Node n,Node n2, int opcode, int imm12) { + short reg1 = enc.reg(n2); + // 31 = 11111 + int body = imm_inst(opcode, imm12&0xFFF, reg1, 31); + enc.add4(body); + } + + // for cases where rs1 and dst are the same, eg add x0, x0, 1 + public static void imm_inst(Encoding enc, int opcode, int imm12, int self) { + int body = imm_inst(opcode, imm12&0xFFF, self, self); + enc.add4(body); + } + + public static void imm_inst_n(Encoding enc, Node n, Node n2, int opcode, int imm13) { + short self = enc.reg(n); + short reg1 = enc.reg(n2); + int body = imm_inst_n(opcode, imm13, reg1, self); + enc.add4(body); + } + + // nth bit comes from immediate and not opcode + public static int imm_inst_n(int opcode, int imm13, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + assert 0 <= imm13 && imm13 <= 0x1FFF; + return (opcode << 23) | (imm13 << 10) | (rn << 5) | rd; + } + + public static int imm_inst_l(int opcode, int imm12, int self) { + int body = imm_inst(opcode, imm12&0xFFF, self, self); + return body; + } + + // for cases where rs1 and dst are the same, eg add x0, x0, 1 + public static int imm_inst_l(Encoding enc, Node n, int opcode, int imm12) { + short self = enc.reg(n); + short reg1 = enc.reg(n.in(1)); + int body = imm_inst(opcode, imm12&0xFFF, reg1, self); + return body; + } + + // for normal add, reg1, reg2 cases (reg-to-reg) + // using shifted-reg form + public static int r_reg(int opcode, int shift, int rm, int imm6, int rn, int rd) { + assert 0 <= rm && rm < 32; + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + return (opcode << 24) | (shift << 21) | (rm << 16) | (imm6 << 10) | (rn << 5) | rd; + } + public static void r_reg(Encoding enc, Node n, int opcode) { + short self = enc.reg(n); + short reg1 = enc.reg(n.in(1)); + short reg2 = enc.reg(n.in(2)); + int body = r_reg(opcode, 0, reg2, 0, reg1, self >= 32 ? reg1: self); + enc.add4(body); + } + + public static void r_reg_subs(Encoding enc, Node n, int opcode) { + short reg1 = enc.reg(n.in(1)); + short reg2 = enc.reg(n.in(2)); + // 31 = 11111 + int body = r_reg(opcode, 0, reg2, 0, reg1, 31); + enc.add4(body); + } + + public static int shift_reg(int opcode, int rm, int op2, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rm && rm < 32; + assert 0 <= rd && rd < 32; + return (opcode << 21) | (rm << 16) | (op2 << 10) | (rn << 5) | rd; + } + public static void shift_reg(Encoding enc, Node n, int op2) { + short self = enc.reg(n); + short reg1 = enc.reg(n.in(1)); + short reg2 = enc.reg(n.in(2)); + int body = shift_reg(0b10011010110, reg2, op2, reg1, self); + enc.add4(body); + } + + // MUL can be considered an alias for MADD with the third operand Ra being set to 0 + public static int madd(int opcode, int rm, int ra, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + assert 0 <= rm && rm < 32; + return (opcode << 21) | (rm << 16) | (ra << 10) | (rn << 5) | rd; + } + public static void madd(Encoding enc, Node n, int opcode, int ra) { + short self = enc.reg(n); + short reg1 = enc.reg(n.in(1)); + short reg2 = enc.reg(n.in(2)); + int body = madd(opcode, reg2, ra, reg1, self); + enc.add4(body); + } + + // encodes movk, movn, and movz + public static int mov(int opcode, int shift, int imm16, int rd) { + assert 0 <= rd && rd < 32; + return (opcode << 23) | (shift << 21) | (imm16 << 5) | rd; + } + + public static int mov_reg(int opcode, int src, int rd) { + assert 0 <= rd && rd < 32; + return (opcode << 21) | (src << 16) | 0b11111 << 5 | rd; + } + + public static int ret(int opcode) { + return (opcode << 10); + } + + // FMOV (scalar, immediate) + public static int f_scalar(int opcode, int ftype, int rm, int op, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + assert 0 <= rm && rm < 32; + return (opcode << 24) | (ftype << 22) | (1 << 21) | (rm << 16) | (op << 10) | (rn << 5) | rd; + } + + public static int f_mov_reg(int opcode, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + return (opcode << 24) | (0b01100000010000 << 10) | (rn << 5) | rd; + } + public static int f_mov_general(int opcode, int ftype, int rmode, int opcode1, int rn, int rd) { + assert 0 <= rn && rn < 32; + assert 0 <= rd && rd < 32; + return (opcode << 24) |(ftype << 22) | (1 << 21) | (rmode << 19) | (opcode1 << 16) | (rn << 5) | rd; + } + public static void f_scalar(Encoding enc, Node n, int op ) { + short self = (short)(enc.reg(n) -D_OFFSET); + short reg1 = (short)(enc.reg(n.in(1))-D_OFFSET); + short reg2 = (short)(enc.reg(n.in(2))-D_OFFSET); + int body = f_scalar(0b00011110, 1, reg2, op, reg1, self); + enc.add4(body); + } + + // share same encoding with LDR (literal, SIMD&FP) flavour + public static int load_pc(int opcode, int offset, int rt) { + offset>>=2; + return (opcode << 24) | (offset << 5) | rt; + } + // int l + public static int adrp(int op, int imlo,int opcode, int imhi, int rd) { + assert 0 <= rd && rd < 32; + return (op << 31) | (imlo << 29) |(opcode << 24) | (imhi << 5) | rd; + } + + // [Rptr+Roff] + public static int indr_adr(int opcode, int off, STORE_LOAD_OPTION option, int s, int ptr, int rt) { + assert 0 <= ptr && ptr < 32; + assert 0 <= rt && rt < 32; + return (opcode << 21) | (off << 16) | (option.ordinal() << 13) | (s << 12) | (2 << 10) | (ptr << 5) | rt; + } + // [Rptr+imm9] + public static int load_str_imm(int opcode, int imm12, int ptr, int rt, int size) { + assert 0 <= ptr && ptr < 32; + assert 0 <= rt && rt < 32; + + if(size == 8) imm12 = imm12 >> 3; + if(size == 4) imm12 = imm12 >> 2; + if(size == 2) imm12 = imm12 >> 1; + // size == 1 imm12 = imm12 + return (opcode << 22) | ((imm12) << 10) | (ptr << 5) | rt; + } + + // encoding for vcvt, size is encoded in operand + // <Qd>, <Qm> + // F32.S32 + //encoded as op = 0b00, size = 0b10. + // VCVT<c>.<Td>.<Tm> <Dd>, <Dm> + // opcode is broken down into 4 pieces + public static int f_convert(int opcode_1, int opcode_2, int opcode_3, int opcode_4, int vd, int vm) { + return (opcode_1 << 28) | (opcode_2 << 24) | (opcode_3 << 20) | (opcode_4 << 16) | + (vd << 12) | (0x01100010 << 4) | vm; + } + public static int float_cast(int opcode, int ftype, int rn, int rd) { + assert 0 <= rd && rd < 32; + assert 0 <= rn && rn < 32; + return (opcode << 24) | (ftype << 22) | (2176 << 10) | (rn << 5) | rd; + } + + + // ftype = 3 + public static int f_cmp(int opcode, int ftype, int rm, int rn) { + assert 0 <= rn && rn < 32; + assert 0 <= rm && rm < 32; + // Todo: |8 is not needed + return (opcode << 24) | (ftype << 21) | (rm << 16) | (8 << 10) | (rn << 5); + } + public static void f_cmp(Encoding enc, Node n) { + short reg1 = (short)(enc.reg(n.in(1))-D_OFFSET); + short reg2 = (short)(enc.reg(n.in(2))-D_OFFSET); + int body = f_cmp(0b00011110, 3, reg1, reg2); + enc.add4(body); + } + + public static COND make_condition(String bop) { + return switch (bop) { + case "==" -> COND.EQ; + case "!=" -> COND.NE; + case "<" -> COND.LT; + case "<=" -> COND.LE; + case ">=" -> COND.GE; + case ">" -> COND.GT; + default -> throw Utils.TODO(); + }; + } + + public static int b_cond(int opcode, int delta, COND cond) { + // 24-5 == 19bits offset range + assert -(1<<19) <= delta && delta < (1<<19); + assert (delta&3)==0; + delta>>=2; + delta &= (1L<<19)-1; // Zero extend + return (opcode << 24) | ((delta)<< 5) | cond.ordinal(); + } + + public static int cond_set(int opcode, int rm, COND cond, int rn, int rd) { + assert 0 <= rd && rd < 32; + assert 0 <= rn && rn < 32; + return (opcode << 21) | (rm << 16) | (cond.ordinal() << 12) | (rn << 5) | rd; + } + + // Branch with Link to Register calls a subroutine at an address in a register, setting register X30 to PC+4. + public static int blr(int opcode, int rd) { + assert 0 <= rd && rd < 32; + return opcode << 10 | rd << 5; + } + public static int b(int opcode, int delta) { + assert -(1<<26) <= delta && delta < (1<<26); + assert (delta&3)==0; + delta>>=2; + delta &= (1L<<26)-1; // Zero extend + return (opcode << 26) | delta; + } + // no aligned assert(assert (delta&3)==0;) + public static int b_calloc(int opcode, int delta) { + assert -(1<<26) <= delta && delta < (1<<26); + delta>>=2; + delta &= (1L<<26)-1; // Zero extend + return (opcode << 26) | delta; + } + + @Override public RegMask callArgMask(TypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); } + static RegMask callInMask(TypeFunPtr tfp, int idx, int maxArgSlot ) { + if( idx==0 ) return CodeGen.CODE._rpcMask; + if( idx==1 ) return null; + // Count floats in signature up to index + if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence + // Count floats in signature up to index + int fcnt=0; + for( int i=2; i<idx; i++ ) + if( tfp.arg(i-2) instanceof TypeFloat) + fcnt++; + // Floats up to XMMS in XMM registers + if( tfp.arg(idx-2) instanceof TypeFloat ) { + if( fcnt < XMMS.length ) + return XMMS[fcnt]; + } else { + RegMask[] cargs = CALLINMASK; + if( idx-2-fcnt < cargs.length ) + return cargs[idx-2-fcnt]; + } + throw Utils.TODO(); // Pass on stack slot + } + + public static long decodeImm12(int imm12) { + int immr = (imm12 >> 6) & 0x3F; + int imms = imm12 & 0x3F; + int size; + if ((imm12 & 0x1000) != 0) { + size = 64; + } else { + size = 31-(imms >> 1); + size |= size >> 1; + size |= size >> 2; + size |= size >> 4; + size++; + imms &= ~((32-size) << 1); + } + long val = (2L << imms)-1; + while (size < 64) { + val |= val << size; + size <<= 1; + } + val = (val >>> immr) | val << (64-immr); + return val; + } + + // Return the max stack slot used by this signature, or 0 + @Override public short maxArgSlot( TypeFunPtr tfp ) { + int icnt=0, fcnt=0; // Count of ints, floats + for( int i=0; i<tfp.nargs(); i++ ) { + if( tfp.arg(i) instanceof TypeFloat ) fcnt++; + else icnt++; + } + int nstk = Math.max(icnt-8,0)+Math.max(fcnt-8,0); + return (short)nstk; + } + + private static final long CALLEE_SAVE = + 1L<<X19 | + 1L<<X20 | 1L<<X21 | 1L<<X22 | 1L<<X23 | + 1L<<X24 | 1L<<X25 | 1L<<X26 | 1L<<X27 | + 1L<<X28 | + 1L<<D9 | 1L<<D10 | 1L<<D11 | + 1L<<D12 | 1L<<D13 | 1L<<D14 | 1L<<D15; + static final long CALLER_SAVE = ~CALLEE_SAVE & ~(1L<<RSP); + @Override public long callerSave() { return CALLER_SAVE; } + @Override public long neverSave() { return 1L<<RSP; } + @Override public RegMask retMask( TypeFunPtr tfp ) { + return tfp.ret() instanceof TypeFloat ? D0_MASK : X0_MASK; + } + @Override public int rpc() { return X30; } + + // Create a split op; any register to any register, including stack slots + @Override public SplitNode split(String kind, byte round, LRG lrg) { return new SplitARM(kind,round); } + + // Return a MachNode unconditional branch + @Override public CFGNode jump() { + return new UJmpARM(); + } + + // Instruction selection + @Override public Node instSelect(Node n ) { + return switch( n ) { + case AddFNode addf -> new AddFARM(addf); + case AddNode add -> add(add); + case AndNode and -> and(and); + case BoolNode bool -> cmp(bool); + case CallNode call -> call(call); + case CastNode cast -> new CastMach(cast); + case CallEndNode cend-> new CallEndMach(cend); + case CProjNode c -> new CProjNode(c); + case ConstantNode con-> con(con); + case DivFNode divf -> new DivFARM(divf); + case DivNode div -> new DivARM(div); + case FunNode fun -> new FunARM(fun); + case IfNode iff -> jmp(iff); + case LoadNode ld -> ld(ld); + case MemMergeNode mem-> new MemMergeNode(mem); + case MinusNode neg -> new NegARM(neg); + case MulFNode mulf -> new MulFARM(mulf); + case MulNode mul -> new MulARM(mul); + case NewNode nnn -> new NewARM(nnn); + case NotNode not -> new NotARM(not); + case OrNode or -> or(or); + case ParmNode parm -> new ParmARM(parm); + case PhiNode phi -> new PhiNode(phi); + case ProjNode prj -> new ProjARM(prj); + case ReadOnlyNode read -> new ReadOnlyMach(read); + case ReturnNode ret -> new RetARM(ret,ret.fun()); + case SarNode sar -> asr(sar); + case ShlNode shl -> lsl(shl); + case ShrNode shr -> lsr(shr); + case StartNode start -> new StartNode(start); + case StopNode stop -> new StopNode(stop); + case StoreNode st -> st(st); + case SubFNode subf -> new SubFARM(subf); + case SubNode sub -> sub(sub); + case ToFloatNode tfn -> new I2F8ARM(tfn); + case XorNode xor -> xor(xor); + + case LoopNode loop -> new LoopNode(loop); + case RegionNode region-> new RegionNode(region); + default -> throw Utils.TODO(); + }; + } + + private Node cmp(BoolNode bool){ + Node cmp = _cmp(bool); + return new SetARM(cmp, bool.op()); + } + private Node _cmp(BoolNode bool) { + if( bool.isFloat() ) + return new CmpFARM(bool); + return bool.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti + ? new CmpIARM(bool, (int)ti.value()) + : new CmpARM(bool); + } + + private Node ld(LoadNode ld) { + return new LoadARM(address(ld), ld.ptr(), idx, off); + } + + private Node jmp(IfNode iff) { + // If/Bool combos will match to a Cmp/Set which sets flags. + // Most general arith ops will also set flags, which the Jmp needs directly. + // Loads do not set the flags, and will need an explicit TEST + String op = "!="; + if( iff.in(1) instanceof BoolNode bool ) op = bool.op(); + else if( iff.in(1)==null ) op = "=="; // Never-node cutout + else iff.setDef(1, new BoolNode.NE(iff.in(1), new ConstantNode(TypeInteger.ZERO))); + return new BranchARM(iff, op); + } + + private Node add(AddNode add) { + return add.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && imm12(ti) + ? new AddIARM(add, (int)ti.value()) + : new AddARM(add); + } + + private Node sub(SubNode sub) { + return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) + ? new SubIARM(sub, (int)(ti.value())) + : new SubARM(sub); + } + + private Node con( ConstantNode con ) { + if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs + return switch( con._con ) { + case TypeInteger ti -> new IntARM(con); + case TypeFloat tf -> new FloatARM(con); + case TypeFunPtr tfp -> new TFPARM(con); + case TypeMemPtr tmp -> new TMPARM(con); + case TypeNil tn -> throw Utils.TODO(); + // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. + case Type t -> t==Type.NIL ? new IntARM(con) : new ConstantNode(con); + }; + } + + private Node call(CallNode call){ + return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp + ? new CallARM(call, tfp) + : new CallRRARM(call); + } + + private Node or(OrNode or) { + int imm12; + return or.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && (imm12 = imm12Logical(ti)) != -1 + ? new OrIARM(or, imm12) + : new OrARM(or); + } + + private Node xor(XorNode xor) { + int imm12; + return xor.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && (imm12 = imm12Logical(ti)) != -1 + ? new XorIARM(xor, imm12) + : new XorARM(xor); + } + + private Node and(AndNode and) { + int imm12; + return and.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && (imm12 = imm12Logical(ti)) != -1 + ? new AndIARM(and, imm12) + : new AndARM(and); + } + + private Node asr(SarNode asr) { + return asr.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && ti.value() >= 0 && ti.value() < 63 + ? new AsrIARM(asr, (int)ti.value()) + : new AsrARM(asr); + } + + private Node lsl(ShlNode lsl) { + return lsl.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && ti.value() >= 0 && ti.value() < 63 + ? new LslIARM(lsl, (int)ti.value()) + : new LslARM(lsl); + } + + private Node lsr(ShrNode lsr) { + return lsr.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && ti.value() >= 0 && ti.value() < 63 + ? new LsrIARM(lsr, (int)ti.value()) + : new LsrARM(lsr); + } + + + private static int off; + private static Node idx; + private Node st(StoreNode st) { + return new StoreARM(address(st),st.ptr(),idx,off,st.val()); + } + + // Gather addressing mode bits prior to constructing. This is a builder + // pattern, but saving the bits in a *local* *global* here to keep mess + // contained. + private <N extends MemOpNode> N address(N mop ) { + off = 0; // Reset + idx = null; + Node base = mop.ptr(); + // Skip/throw-away a ReadOnly, only used to typecheck + if( base instanceof ReadOnlyNode read ) base = read.in(1); + assert !(base instanceof AddNode) && base._type instanceof TypeMemPtr; // Base ptr always, not some derived + if( mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm9(ti) ) { + off = (int)ti.value(); + assert off == ti.value(); // In 32-bit range + } else { + idx = mop.off(); + } + return mop; + } + + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java new file mode 100644 index 00000000..2cd00845 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java @@ -0,0 +1,42 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +// Add upper 20bits to PC. Immediate comes from the relocation info. +public class AUIPC extends ConstantNode implements MachNode, RIPRelSize { + AUIPC( Type tfp ) { super(tfp); } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public AUIPC copy() { return new AUIPC(_con); } + @Override public String op() { return "auipc"; } + @Override public void encoding( Encoding enc ) { + enc.relo(this); + short dst = enc.reg(this); + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 0)); + } + + // Delta is from opcode start, but X86 measures from the end of the 5-byte encoding + @Override public byte encSize(int delta) { return 4; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + //short rpc = enc.reg(this); + //// High half is where the TFP constant used to be, the last input + //short auipc = enc.reg(in(_inputs._len-1)); + //enc.patch4(opStart,riscv.i_type(0x67, rpc, 0, auipc, delta)); + throw Utils.TODO(); + } + + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + sb.p(reg).p(" = PC+#"); + if( _con == null ) sb.p("---"); + else _con.print(sb); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java new file mode 100644 index 00000000..8636df9f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// fadd.d +public class AddFRISC extends MachConcreteNode implements MachNode { + AddFRISC(Node addf) {super(addf);} + @Override public String op() { return "addf"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.FMASK; } + @Override public RegMask outregmap() { return riscv.FMASK; } + @Override public void encoding( Encoding enc ) { riscv.rf_type(enc,this,riscv.RM.RNE,1); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java new file mode 100644 index 00000000..511b0583 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java @@ -0,0 +1,21 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class AddIRISC extends ImmRISC { + // Used to inst-selection as a direct match against an ideal Add/Sub + public AddIRISC( Node add, int imm12, boolean pop ) { super(add,imm12,pop); } + @Override public String op() { return "addi"; } + @Override public String glabel() { return "+"; } + @Override int opcode() { return riscv.OP_IMM; } + @Override int func3() {return 0;} + @Override public AddIRISC copy() { + // Clone the AddI, using the same inputs-only code used during inst select. + // Output edges are missing. + AddIRISC add = new AddIRISC(in(1),_imm12,false); + // Copys happen when output edges should be valid, so correct missing output edges. + in(1)._outputs.add(add); + return add; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java new file mode 100644 index 00000000..7010916f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java @@ -0,0 +1,21 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class AddRISC extends MachConcreteNode implements MachNode { + public AddRISC( Node add ) { super(add); } + AddRISC( Node base, Node off ) { + super(new Node[3]); + _inputs.set(1,base); + _inputs.set(2,off ); + } + @Override public String op() { return "add"; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0,0); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java new file mode 100644 index 00000000..842c8bdc --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java @@ -0,0 +1,12 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class AndIRISC extends ImmRISC { + public AndIRISC( Node and, int imm) { super(and,imm); } + @Override public String op() { return "andi"; } + @Override public String glabel() { return "&"; } + @Override int opcode() { return riscv.OP_IMM; } + @Override int func3() {return 7;} +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java new file mode 100644 index 00000000..1845985e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java @@ -0,0 +1,16 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class AndRISC extends MachConcreteNode implements MachNode { + public AndRISC(Node and) { super(and); } + @Override public String op() { return "and"; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0b111,0); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java new file mode 100644 index 00000000..b7284265 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java @@ -0,0 +1,93 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +// Conditional branch such as: BEQ +public class BranchRISC extends IfNode implements MachNode, RIPRelSize { + String _bop; + // label is obtained implicitly + public BranchRISC( IfNode iff, String bop, Node n1, Node n2 ) { + super(iff); + _bop = bop; + _inputs.setX(1,n1); + _inputs.setX(2,n2); + } + + @Override public String op() { return "b"+_bop; } + @Override public String label() { return op(); } + @Override public String comment() { return "L"+cproj(1)._nid; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return null; } + @Override public void negate() { + _bop = negate(_bop); + // Cannot encode ">" or "<=", so flip these + if( _bop.equals(">") || _bop.equals("<=") ) { + swap12(); // Cannot negate the test, so swap the operands + _bop = swap(_bop); // Swap test to match + } + } + + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { + sb.append("if( "); + if( in(1)==null ) sb.append("0"); + else in(1)._print0(sb,visited); + sb.append(_bop); + if( in(2)==null ) sb.append("0"); + else in(2)._print0(sb,visited); + return sb.append(" )"); + } + + @Override public void encoding( Encoding enc ) { + if( in(1)==null && _bop=="!=" ) return; // Inverted never-node, no code + enc.jump(this,cproj(0)); + if( in(1)==null ) // Never node + enc.add4(riscv.j_type(riscv.OP_JAL, 0, 0)); + else { + // Todo: relocs (for offset - immf) + short src1 = enc.reg(in(1)); + short src2 = in(2)==null ? (short)riscv.ZERO : enc.reg(in(2)); + enc.add4(riscv.b_type(riscv.OP_BRANCH, riscv.jumpop(_bop), src1, src2, 0)); + } + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { + if( in(1)==null && _bop=="!=" ) return 0; // Inverted never-node, no code + if( -4*1024 <= delta && delta < 4*1024 ) return 4; + // 2 word encoding needs a tmp register, must teach RA + throw Utils.TODO(); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + assert !( in(1)==null && _bop=="!=" ); // Inverted never-node, no code no patch + if( in(1)==null ) { // Never node + enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, 0, delta)); + } else { + short src1 = enc.reg(in(1)); + short src2 = in(2)==null ? (short)riscv.ZERO : enc.reg(in(2)); + if( opLen==4 ) { + enc.patch4(opStart,riscv.b_type(riscv.OP_BRANCH, riscv.jumpop(_bop), src1, src2, delta)); + } else { + throw Utils.TODO(); + } + } + } + + @Override public void asm(CodeGen code, SB sb) { + if( in(1)==null && _bop=="!=" ) { + sb.p("never"); + return; + } + String src1 = in(1)==null ? "#0" : code.reg(in(1)); + String src2 = in(2)==null ? "#0" : code.reg(in(2)); + sb.p(src1).p(" ").p(_bop).p(" ").p(src2).p(" "); + CFGNode prj = cproj(0).uctrlSkipEmpty(); + if( !prj.blockHead() ) prj = prj.cfg0(); + sb.p(label(prj)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java new file mode 100644 index 00000000..bd5dabe5 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java @@ -0,0 +1,62 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class CallRISC extends CallNode implements MachNode, RIPRelSize { + final TypeFunPtr _tfp; + final String _name; + CallRISC( CallNode call, TypeFunPtr tfp ) { + super(call); + assert tfp.isConstant(); + _inputs.pop(); // Pop constant target + _tfp = tfp; + FunNode fun = CodeGen.CODE.link(tfp); + _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls + } + + @Override public String op() { return "call"; } + @Override public String label() { return op(); } + @Override public String name() { return _name; } + @Override public TypeFunPtr tfp() { return _tfp; } + @Override public RegMask regmap(int i) { return riscv.callInMask(_tfp,i,fun()._maxArgSlot); } + @Override public RegMask outregmap() { return riscv.RPC_MASK; } + @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr + + @Override public void encoding( Encoding enc ) { + // Short form +/-4K: beq r0,r0,imm12 + // Long form: auipc rX,imm20/32; jal r0,[rX+imm12/32] + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); + short rpc = enc.reg(this); + enc.add4(riscv.j_type(riscv.OP_JAL, rpc, 0)); + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { + if( -(1L<<20) <= delta && delta < (1L<<20) ) return 4; + // 2 word encoding needs a tmp register, must teach RA + throw Utils.TODO(); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short rpc = enc.reg(this); + if( opLen==4 ) { + enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, rpc, delta)); + } else { + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(_name).p(" "); + for( int i=0; i<nargs(); i++ ) + sb.p(code.reg(arg(i+2))).p(", "); + sb.unchar(2); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java new file mode 100644 index 00000000..298789e8 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java @@ -0,0 +1,31 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class CallRRISC extends CallNode implements MachNode { + CallRRISC( CallNode call ) { super(call); } + @Override public String op() { return "callr"; } + @Override public String label() { return op(); } + @Override public RegMask regmap(int i) { + return i==_inputs._len-1 + ? riscv.RMASK // Function call target + : riscv.callInMask(tfp(),i,fun()._maxArgSlot); // Normal argument + } + @Override public RegMask outregmap() { return null; } + + @Override public void encoding( Encoding enc ) { + short rpc = enc.reg(this); + short src = enc.reg(in(_inputs._len-1)); + int body = riscv.i_type(riscv.OP_JALR, rpc, 0, src, 0); + enc.add4(body); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(fptr())).p(" "); + for( int i=0; i<nargs(); i++ ) + sb.p(code.reg(arg(i))).p(", "); + sb.unchar(2); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java new file mode 100644 index 00000000..68ed6f6c --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// fdiv.d +public class DivFRISC extends MachConcreteNode implements MachNode{ + DivFRISC(Node divf) {super(divf);} + @Override public String op() { return "divf"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.FMASK; } + @Override public RegMask outregmap() { return riscv.FMASK; } + @Override public void encoding( Encoding enc ) { riscv.rf_type(enc,this,riscv.RM.RUP,13); } + // Default on double precision for now(64 bits) + // General form: "fdiv.d rd = src1 / src2 + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java new file mode 100644 index 00000000..515ffa47 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; + +public class DivRISC extends MachConcreteNode implements MachNode{ + public DivRISC(Node div) {super(div);} + @Override public String op() { return "div"; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,4,1); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2))); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java new file mode 100644 index 00000000..81726200 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java @@ -0,0 +1,46 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class FltRISC extends ConstantNode implements MachNode, RIPRelSize { + FltRISC(ConstantNode con) { super(con); } + @Override public String op() { return "ld8"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.FMASK; } + @Override public boolean isClone() { return true; } + @Override public FltRISC copy() { return new FltRISC(this); } + + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,_con, 0, -1); + short dst = (short)(enc.reg(this) - riscv.F_OFFSET); + short tmp = (short)riscv.T6; + // AUIPC dst,#hi20_constant_pool + enc.add4(riscv.u_type(riscv.OP_AUIPC, tmp, 0)); + // Load dst,[dst+#low12_constant_pool] + enc.add4(riscv.i_type(riscv.OP_LOADFP, dst, 0b11, tmp, 0)); + } + @Override public RegMask killmap() { return new RegMask(riscv.T6); } + + // Delta is from opcode start. + @Override public byte encSize(int delta) { return 8; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = (short)(enc.reg(this) - riscv.F_OFFSET); + short tmp = (short)riscv.T6; + // AUIPC dst,#hi20_constant_pool + enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, tmp, delta>>12)); + // Load dst,[dst+#low12_constant_pool] + enc.patch4(opStart+4, riscv.i_type(riscv.OP_LOADFP, dst, 0b11, tmp, delta & 0xFFF)); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" = #")); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java new file mode 100644 index 00000000..6fce6244 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java @@ -0,0 +1,22 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.FunNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class FunRISC extends FunNode implements MachNode { + FunRISC(FunNode fun) {super(fun);} + @Override public void computeFrameAdjust(CodeGen code, int maxReg) { + super.computeFrameAdjust(code,maxReg); + if( _hasCalls ) // If non-leaf, pad to 16b + _frameAdjust = ((_frameAdjust+8) & -16); + } + @Override public void encoding( Encoding enc ) { + int sz = _frameAdjust; + if( sz == 0 ) return; // Skip if no frame adjust + if( sz >= 1L<<12 ) throw Utils.TODO(); + enc.add4(riscv.i_type(riscv.OP_IMM, riscv.RSP, 0, riscv.RSP, -sz & 0xFFF)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java new file mode 100644 index 00000000..db0547fe --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java @@ -0,0 +1,23 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// fcvt.d.w +// Converts a 32-bit signed integer, in integer register rs1 into a double-precision floating-point number in floating-point register rd. +public class I2F8RISC extends MachConcreteNode implements MachNode { + I2F8RISC(Node i2f8) {super(i2f8);} + @Override public String op() { return "cvtf"; } + @Override public RegMask regmap(int i) { assert i==1; return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.FMASK; } + @Override public void encoding( Encoding enc ) { + short dst = (short)(enc.reg(this )-riscv.F_OFFSET); + short src1 = enc.reg(in(1)); + int body = riscv.r_type(riscv.OP_FP,dst,riscv.RM.RNE.ordinal(),src1,0,0x69); + enc.add4(body); + } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p("(flt)").p(code.reg(in(1))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java new file mode 100644 index 00000000..f2beb25c --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java @@ -0,0 +1,53 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; +import java.util.BitSet; + +abstract public class ImmRISC extends MachConcreteNode implements MachNode { + public final int _imm12; + ImmRISC( Node add, int imm12, boolean pop ) { + super(add); + _imm12 = imm12; + // If pop, we are moving from an ideal Node to MachNode; the ideal Node + // inputs got copied here, but we are absorbing the immediate into the + // MachNode and so do not want the constant input. + if( pop ) _inputs.pop(); + // if NOT pop, we are the 2nd-half of a 2-part expansion, reset the + // input edges to no-control + else { _inputs.set(0,null); _inputs.setX(1,add); } + } + ImmRISC( Node add, int imm12 ) { this(add,imm12,true); } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { + // Allow cloning of the 2nd half of a 2-part constant; this might + // trigger cloning the first part also. + return in(1) instanceof LUI || in(1) instanceof AUIPC; + } + + @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { + int imm12 = (_imm12<<20)>>20; // Sign extend 12 bits + in(1)._print0(sb.append("( "), visited); + return sb.append(String.format(" %s #%d )",glabel(),imm12)); + } + + abstract int opcode(); + abstract int func3(); + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this ); + short src = enc.reg(in(1)); + enc.add4(riscv.i_type(opcode(), dst, func3(), src, _imm12 & 0xFFF)); + } + + // General form: "addi rd = rs1 + imm" + @Override public void asm(CodeGen code, SB sb) { + int imm12 = (_imm12<<20)>>20; // Sign extend 12 bits + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ").p(glabel()).p(" #").p(imm12); + if( in(1) instanceof LUI lui ) + sb.p(" // #").hex4((int)(((TypeInteger)lui._con).value()) + imm12); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java new file mode 100644 index 00000000..edd1850f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java @@ -0,0 +1,46 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; + +// Special instruction for loading 8 byte constants from the constant pool. + +public class Int8RISC extends ConstantNode implements MachNode, RIPRelSize { + public Int8RISC(ConstantNode con) { super(con); } + + @Override public String op() { return "ld8"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public Int8RISC copy() { return new Int8RISC(this); } + + @Override public byte encSize(int delta) { return 8; } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); + short tmp = (short)riscv.T6; + enc.largeConstant(this,_con, 0, -1); + // AUIPC dst,#hi20_constant_pool + enc.add4(riscv.u_type(riscv.OP_AUIPC, tmp, 0)); + // Load dst,[dst+#low12_constant_pool] + enc.add4(riscv.i_type(riscv.OP_LOAD, dst, 0b11, tmp, 0)); + } + @Override public RegMask killmap() { return new RegMask(riscv.T6); } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + short tmp = (short)riscv.T6; + // AUIPC dst,#hi20_constant_pool + enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, tmp, delta>>12)); + // Load dst,[dst+#low12_constant_pool] + enc.patch4(opStart+4, riscv.i_type(riscv.OP_LOAD, dst, 0b11, tmp, delta & 0xFFF)); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" = #")); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java new file mode 100644 index 00000000..f8af913a --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java @@ -0,0 +1,30 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; + +// 12-bit integer constant. Larger constants are made up in the instruction +// selection by adding with a LUI. +public class IntRISC extends ConstantNode implements MachNode { + public IntRISC(ConstantNode con) { super(con); } + @Override public String op() { return "ldi"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public IntRISC copy() { return new IntRISC(this); } + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); + int val = _con==Type.NIL ? 0 : (int)(((TypeInteger)_con).value() & 0xFFF); + // Explicit truncation of larger immediates; this will sign-extend on + // load and this is handled during instruction selection. + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, riscv.ZERO, val)); + } + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + _con.print(sb.p(reg).p(" = #")); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java new file mode 100644 index 00000000..7333f2b7 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java @@ -0,0 +1,32 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; + +// Load upper 20bits. +public class LUI extends ConstantNode implements MachNode { + public LUI( int imm20 ) { + super(TypeInteger.constant(imm20)); + assert (imm20 & 0xFFF)==0; + } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public LUI copy() { return new LUI((int)((TypeInteger)_con).value()); } + @Override public String op() { return "lui"; } + @Override public void encoding( Encoding enc ) { + long x = ((TypeInteger)_con).value(); + int imm20 = (int)(x>>12) & 0xFFFFF; + short dst = enc.reg(this); + int lui = riscv.u_type(riscv.OP_LUI, dst, imm20); + enc.add4(lui); + } + + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + sb.p(reg).p(" = #").hex4((int)(((TypeInteger)_con).value())); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java new file mode 100644 index 00000000..7e08a01d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java @@ -0,0 +1,29 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Load memory addressing on RISC +// Support imm, reg(direct), or reg+off(indirect) addressing +// Base = base - base pointer, offset is added to base +// idx = null +// off = off - imm12 added to base +public class LoadRISC extends MemOpRISC { + public LoadRISC(LoadNode ld, Node base, int off) { super(ld, base, off, null); } + @Override public String op() { return "ld" +_sz; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.MEM_MASK; } + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this ); + short ptr = enc.reg(ptr()); + int op = dst >= riscv.F_OFFSET ? riscv.OP_LOADFP : riscv.OP_LOAD; + if( dst >= riscv.F_OFFSET ) dst -= riscv.F_OFFSET; + enc.add4(riscv.i_type(op, dst, func3(), ptr, _off)); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(","); + asm_address(code,sb); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java new file mode 100644 index 00000000..93c90052 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java @@ -0,0 +1,76 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import java.util.BitSet; + +public abstract class MemOpRISC extends MemOpNode implements MachNode { + final int _off; // Limit 12 bits + final char _sz; + MemOpRISC(MemOpNode mop, Node base, int off, Node val) { + super(mop,mop); + assert base._type instanceof TypeMemPtr; + _inputs.setX(2, base ); // Base can be an Add, is no longer raw object base + _inputs.setX(3, null); // Never an index + _inputs.setX(4, val ); + _off = off; + _sz = (char)('0'+(1<<_declaredType.log_size())); + } + + @Override public String label() { return op(); } + Node val() { return in(4); } // Only for stores + + @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); } + + @Override public Type compute() { throw Utils.TODO(); } + @Override public Node idealize() { throw Utils.TODO(); } + + // func3 is based on load/store size and extend + int func3() { + int func3 = -1; + // no unsigned flavour for store, so both signed and unsigned trigger the same + if(this instanceof StoreRISC) { + if( _declaredType == TypeInteger. I8 || _declaredType == TypeInteger.U8 || _declaredType == TypeInteger.BOOL) func3=0; // SB + if( _declaredType == TypeInteger.I16 || _declaredType == TypeInteger.U16 ) func3=1; // SH + if( _declaredType == TypeInteger.I32 || _declaredType == TypeInteger.U32 ) func3=2; // SW + if( _declaredType instanceof TypeMemPtr) func3=3; // SD + if( _declaredType == TypeInteger.BOT ) func3=3; // SD + if( func3 == -1 ) throw Utils.TODO(); + return func3; + } + if( _declaredType == TypeInteger. I8 ) func3=0; // LB + if( _declaredType == TypeInteger.I16 ) func3=1; // LH + if( _declaredType == TypeInteger.I32 ) func3=2; // LW + if( _declaredType == TypeInteger.BOT ) func3=3; // LD + if( _declaredType == TypeInteger. U8 ) func3=4; // LBU + if( _declaredType == TypeInteger.BOOL) func3=4; // LBU + if( _declaredType == TypeInteger.U16 ) func3=5; // LHU + if( _declaredType == TypeInteger.U32 ) func3=6; // LWU + + // float + if( _declaredType == TypeFloat.F32) func3 = 2; // fLW fSW + if( _declaredType == TypeFloat.F64) func3 = 3; // fLD fSD + + if( _declaredType instanceof TypeMemPtr) func3 = 3; // 8 byte pointers (pick ld) + if( func3 == -1 ) throw Utils.TODO(); + return func3; + } + + // Register mask allowed on input i. + @Override public RegMask regmap(int i) { + // 0 - ctrl + // 1 - memory + if( i==2 ) return riscv.RMASK; // base + // 2 - index + if( i==4 ) return riscv.MEM_MASK; // value + throw Utils.TODO(); + } + + SB asm_address(CodeGen code, SB sb) { + sb.p("[").p(code.reg(ptr())).p("+"); + return sb.p(_off).p("]"); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java new file mode 100644 index 00000000..5cc40079 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// fmul.d +public class MulFRISC extends MachConcreteNode implements MachNode { + MulFRISC(Node mulf) {super(mulf);} + @Override public String op() { return "mulf"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.FMASK; } + @Override public RegMask outregmap() { return riscv.FMASK; } + @Override public void encoding( Encoding enc ) { riscv.rf_type(enc,this,riscv.RM.RNE,9); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java new file mode 100644 index 00000000..9cb9ace7 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// mulh signed multiply instruction(no-imm form) +public class MulRISC extends MachConcreteNode implements MachNode{ + public MulRISC(Node mul) {super(mul);} + @Override public String op() { return "mul"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0,1); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java new file mode 100644 index 00000000..d8183d09 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java @@ -0,0 +1,20 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class NegRISC extends MachConcreteNode implements MachNode { + public NegRISC( Node neg ) { super(neg); } + @Override public String op() { return "neg"; } + @Override public RegMask regmap(int i) { assert i==1; return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this ); + short src = enc.reg(in(1)); + riscv.r_type(riscv.OP,dst,0,0,src,0x20); + } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = -").p(code.reg(in(1))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java new file mode 100644 index 00000000..6c03bda6 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java @@ -0,0 +1,47 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.print.ASMPrinter; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class NewRISC extends NewNode implements MachNode, RIPRelSize { + // A pre-zeroed chunk of memory. + NewRISC( NewNode nnn ) { super(nnn); } + @Override public void encoding( Encoding enc ) { + // Generic external encoding; 2 ops. + enc.external(this,"calloc"); + // A1 is a caller-save, allowed to crush building external address + // auipc + enc.add4(riscv.i_type(riscv.OP_IMM , _arg2Reg , 0, riscv.ZERO, 1)); + enc.add4(riscv.u_type(riscv.OP_AUIPC, riscv.A2 , 0)); + enc.add4(riscv.i_type(riscv.OP_JALR , riscv.RPC, 0, riscv.A2, 0)); + } + + // Patch is for running "new" in a JIT. + // Delta is from opcode start + @Override public byte encSize(int delta) { return 4*3; } + + // Patch is for running "new" in a JIT. + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + // Negative patches are JIT emulator targets. + if( opStart+delta < 0 ) { + delta -= 4; // Offset from the AUIPC start + int imm20 = delta>>12; + if( ((delta>>11)&1)==1 ) imm20++; // Correct accidental sign extension + int imm12 = delta&0xFFF; + enc.patch4(opStart+4,riscv.u_type(riscv.OP_AUIPC, riscv.A2 , imm20)); + enc.patch4(opStart+8,riscv.i_type(riscv.OP_JALR , riscv.RPC, 0, riscv.A2, imm12)); + } else + throw Utils.TODO(); + } + + // General form: "alloc #bytes PC" + @Override public void asm(CodeGen code, SB sb) { + sb.p("ldi a1=#1\n"); + sb.p("auipc a2=#calloc\n"); + sb.p("call a2+#calloc, a0"); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java new file mode 100644 index 00000000..1369ee76 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java @@ -0,0 +1,20 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.NotNode; +import com.seaofnodes.simple.util.SB; + +public class NotRISC extends MachConcreteNode implements MachNode { + public NotRISC(NotNode not) { super(not); } + @Override public String op() { return "not"; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this ); + short src = enc.reg(in(1)); + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 2, src, 1)); + } + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java new file mode 100644 index 00000000..963b9d50 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java @@ -0,0 +1,12 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class OrIRISC extends ImmRISC { + public OrIRISC( Node and, int imm) { super(and,imm); } + @Override int opcode() { return riscv.OP_IMM; } + @Override int func3() { return 6; } + @Override public String glabel() { return "|"; } + @Override public String op() { return "ori"; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java new file mode 100644 index 00000000..a310a1f4 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java @@ -0,0 +1,16 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class OrRISC extends MachConcreteNode implements MachNode { + public OrRISC(Node or) { super(or); } + @Override public String op() { return "or"; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,6,0); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" | ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java new file mode 100644 index 00000000..0f8db4e5 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.ParmNode; + +public class ParmRISC extends ParmNode implements MachNode { + final RegMask _rmask; + ParmRISC(ParmNode parm) { + super(parm); + _rmask = riscv.callInMask(fun().sig(),_idx,0); + } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return _rmask; } + @Override public void encoding( Encoding enc ) { } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ProjRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ProjRISC.java new file mode 100644 index 00000000..2f9ac469 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ProjRISC.java @@ -0,0 +1,15 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.ProjNode; + +public class ProjRISC extends ProjNode implements MachNode { + ProjRISC(ProjNode p) { super(p); } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { + return ((MachNode)in(0)).outregmap(_idx); + } + @Override public void encoding( Encoding enc ) { } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java new file mode 100644 index 00000000..7e4631d3 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java @@ -0,0 +1,21 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.FunNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.ReturnNode; +import com.seaofnodes.simple.util.Utils; + +public class RetRISC extends ReturnNode implements MachNode { + public RetRISC(ReturnNode ret, FunNode fun) { super(ret, fun); fun.setRet(this); } + @Override public void encoding( Encoding enc ) { + int sz = fun()._frameAdjust; + if( sz >= 1L<<12 ) throw Utils.TODO(); + if( sz != 0 ) + enc.add4(riscv.i_type(riscv.OP_IMM, riscv.RSP, 0, riscv.RSP, sz & 0xFFF)); + short rpc = enc.reg(rpc()); + enc.add4(riscv.i_type(riscv.OP_JALR, riscv.ZERO, 0, rpc, 0)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java new file mode 100644 index 00000000..3424cd01 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java @@ -0,0 +1,33 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.BoolNode; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; + +// corresponds to feq.d = equal +// fle.d = less than or equal +// flt.d = less than +public class SetFRISC extends MachConcreteNode implements MachNode { + final String _bop; // One of <,<=,== + SetFRISC( BoolNode bool ) { + super(bool); + assert bool.isFloat(); + _bop = bool.op(); + } + @Override public String op() { return "set"+_bop; } + @Override public RegMask regmap(int i) { return riscv.FMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this ); + short src1 = (short)(enc.reg(in(1))-riscv.F_OFFSET); + short src2 = (short)(enc.reg(in(2))-riscv.F_OFFSET); + int body = riscv.r_type(riscv.OP_FP,dst,riscv.fsetop(_bop),src1,src2,0b1010001/*FCMP*/); + enc.add4(body); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ").p(_bop).p(" ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java new file mode 100644 index 00000000..690e2102 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.node.Node; + +// corresponds to slti,sltiu +public class SetIRISC extends ImmRISC { + final boolean _unsigned; // slti vs sltiu + public SetIRISC( Node src, int imm12, boolean unsigned ) { + super(src,imm12); + _unsigned = unsigned; + } + @Override public String op() { return "slt" + (_unsigned ? "u":"") + "i"; } + @Override public String glabel() { return "<"+ (_unsigned ? "u":""); } + @Override int opcode() { return 0b0010011; } + @Override int func3() { return _unsigned ? 0b011 : 0b010; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java new file mode 100644 index 00000000..848cc59f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java @@ -0,0 +1,20 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// corresponds to slt sltu +public class SetRISC extends MachConcreteNode implements MachNode { + final boolean _unsigned; + public SetRISC( Node cmp, boolean unsigned ) { super(cmp); _unsigned=unsigned; } + @Override public String op() { return "slt" + (_unsigned ? "u":""); } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { + riscv.r_type(enc,this,_unsigned ? 0b011 : 0b010,0); + } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" < ").p(code.reg(in(2))); + } +}
\ No newline at end of file diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java new file mode 100644 index 00000000..12c0ddec --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java @@ -0,0 +1,12 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class SllIRISC extends ImmRISC { + public SllIRISC( Node and, int imm) { super(and,imm); } + @Override int opcode() { return riscv.OP_IMM; } + @Override int func3() { return 1; } + @Override public String glabel() { return "<<"; } + @Override public String op() { return "slli"; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java new file mode 100644 index 00000000..5a4d4cc6 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Shift left logical +public class SllRISC extends MachConcreteNode implements MachNode { + public SllRISC(Node sll) { super(sll); } + @Override public String op() { return "shl"; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,1,0); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" << ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java new file mode 100644 index 00000000..6082cbbf --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java @@ -0,0 +1,66 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.FunNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.SplitNode; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class SplitRISC extends SplitNode { + SplitRISC( String kind, byte round ) { super(kind,round, new Node[2]); } + @Override public RegMask regmap(int i) { return riscv.SPLIT_MASK; } + @Override public RegMask outregmap() { return riscv.SPLIT_MASK; } + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this ); + short src = enc.reg(in(1)); + + // Flag for being either XMM or stack + boolean dstX = dst >= riscv.F_OFFSET; + boolean srcX = src >= riscv.F_OFFSET; + + if( dst >= riscv.MAX_REG ) { + // Store to SP + if( src >= riscv.MAX_REG ) { + throw Utils.TODO(); // Very rare stack-stack move + } + int off = enc._fun.computeStackOffset(enc._code,dst); + int op = srcX ? riscv.OP_STOREFP : riscv.OP_STORE; + if( srcX ) src -= riscv.F_OFFSET; + enc.add4(riscv.s_type(op, 0b011, riscv.RSP, src, off)); + return; + } + if( src >= riscv.MAX_REG ) { + // Load from SP + int off = enc._fun.computeStackOffset(enc._code,src); + int op = dstX ? riscv.OP_LOADFP : riscv.OP_LOAD; + if( dstX ) dst -= riscv.F_OFFSET; + enc.add4(riscv.i_type(op, dst, 0b011, riscv.RSP, off)); + return; + } + // pick opcode based on regs + if( !dstX && !srcX ) { + // GPR->GPR + enc.add4(riscv.r_type(riscv.OP,dst,0,src,riscv.ZERO,0)); + } else if( dstX && srcX ) { + // FPR->FPR + src -= riscv.F_OFFSET; + dst -= riscv.F_OFFSET; + enc.add4(riscv.r_type(riscv.OP_FP, dst, 0b000, src, src, 0b0010101)); // dst = FMIN(src,src) + } else if(!srcX && dstX) { + //GPR->FPR + // fmv.d.x + enc.add4(riscv.r_type(riscv.OP_FP, dst - riscv.F_OFFSET, 0, src, 0, 0b1111001)); + } else if(srcX && !dstX) { + //FPR->GPR + //fmv.x.d + enc.add4(riscv.r_type(riscv.OP_FP, dst, 0, src - riscv.F_OFFSET, 0, 0b1110001)); + } + } + + // General form: "mov dst = src" + @Override public void asm(CodeGen code, SB sb) { + FunNode fun = code._encoding==null ? null : code._encoding._fun; + sb.p(code.reg(this,fun)).p(" = ").p(code.reg(in(1),fun)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java new file mode 100644 index 00000000..fcfa0774 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java @@ -0,0 +1,14 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class SraIRISC extends ImmRISC { + public SraIRISC( Node and, int imm) { + super(and,imm | (0x20 << 5)); + } + @Override int opcode() { return riscv.OP_IMM; } + @Override int func3() { return 5;} + @Override public String glabel() { return ">>"; } + @Override public String op() { return "srai"; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java new file mode 100644 index 00000000..e2e34415 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Right Shift Arithmetic +public class SraRISC extends MachConcreteNode implements MachNode { + public SraRISC(Node sra) { super(sra); } + @Override public String op() { return "sar"; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0b101,0b00100000); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >> ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java new file mode 100644 index 00000000..2f73e139 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java @@ -0,0 +1,12 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class SrlIRISC extends ImmRISC { + public SrlIRISC( Node and, int imm, boolean pop) { super(and,imm,pop); } + @Override int opcode() { return riscv.OP_IMM; } + @Override int func3() { return 5; } + @Override public String glabel() { return ">>>"; } + @Override public String op() { return "srli"; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java new file mode 100644 index 00000000..1eccc1c8 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Right Shift Logical +public class SrlRISC extends MachConcreteNode implements MachNode { + public SrlRISC(Node srli) { super(srli); } + @Override public String op() { return "shr"; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,7,0); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >>> ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java new file mode 100644 index 00000000..d06c0c35 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java @@ -0,0 +1,47 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +// Store memory addressing on ARM +// Support imm, reg(direct), or reg+off(indirect) addressing +// Base = base - base pointer, offset is added to base +// idx = null +// off = off - offset added to base) +// imm = imm - immediate value to store +// val = Node of immediate value to store(null if its a constant immediate) + +//e.g s.cs[0] = 67; // C +// base = s.cs, off = 4, imm = 67, val = null + +// sw rs2,offset(rs1) +public class StoreRISC extends MemOpRISC { + StoreRISC( StoreNode st, Node base, int off, Node val ) { super(st, base, off, val); } + @Override public String op() { return "st"+_sz; } + @Override public RegMask regmap(int i) { + // 0 - ctrl + if( i==1 ) return null; // mem + if( i==2 ) return riscv.RMASK; // ptr + // 2 - index + if( i==4 ) return riscv.MEM_MASK; // Wide mask to store GPR and FPR + return null; // Anti-dependence + } + @Override public RegMask outregmap() { return null; } + + @Override public void encoding( Encoding enc ) { + short val = enc.reg(val()); + short ptr = enc.reg(ptr()); + int op = val >= riscv.F_OFFSET ? riscv.OP_STOREFP : riscv.OP_STORE; + if( val >= riscv.F_OFFSET ) val -= riscv.F_OFFSET; + enc.add4(riscv.s_type(op, func3()&7, ptr, val == -1 ? riscv.ZERO : val, _off)); + } + + @Override public void asm(CodeGen code, SB sb) { + asm_address(code,sb).p(","); + if( val()==null ) sb.p("#").p("0"); + else sb.p(code.reg(val())); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java new file mode 100644 index 00000000..da3e92f4 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// fsub.d +public class SubFRISC extends MachConcreteNode implements MachNode { + SubFRISC(Node subf) {super(subf);} + @Override public String op() { return "subf"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.FMASK; } + @Override public RegMask outregmap() { return riscv.FMASK; } + @Override public void encoding( Encoding enc ) { riscv.rf_type(enc,this,riscv.RM.RNE,5); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java new file mode 100644 index 00000000..2adfce23 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java @@ -0,0 +1,16 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class SubRISC extends MachConcreteNode implements MachNode { + public SubRISC( Node sub ) { super(sub); } + @Override public String op() { return "sub"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0,0x20); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java new file mode 100644 index 00000000..7e057507 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java @@ -0,0 +1,55 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { + TFPRISC(ConstantNode con) { super(con); } + @Override public String op() { return "ldx"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TFPRISC copy() { return new TFPRISC(this); } + @Override public void encoding( Encoding enc ) { + enc.relo(this); + // TODO: 1 op encoding, plus a TODO if it does not fit + short dst = enc.reg(this); + TypeFunPtr tfp = (TypeFunPtr)_con; + // auipc t0,0 + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 0)); + // addi t1,t0 + #0 + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0)); + } + + @Override public byte encSize(int delta) { + if( -(1L<<11) <= delta && delta < (1L<<11) ) return 4; + throw Utils.TODO(); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short rpc = enc.reg(this); + if( opLen==8 ) { + // AUIPC (upper 20 bits) + // opstart of add + int next = opStart + opLen; + enc.patch4(opStart,riscv.u_type(riscv.OP_AUIPC, rpc, delta>>12)); + // addi(low 12 bits) + enc.patch4(next,riscv.i_type(riscv.OP_IMM, rpc, 0, rpc, delta & 0xFFF)); + // addi + } else { + // should not happen as one instruction is 4 byte, and TFP arm encodes 2. + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java new file mode 100644 index 00000000..44e73d1d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java @@ -0,0 +1,41 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.util.SB; + +public class TMPRISC extends ConstantNode implements MachNode, RIPRelSize { + TMPRISC(ConstantNode con) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TMPRISC copy() { return new TMPRISC(this); } + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + short dst = enc.reg(this); + // AUIPC dst,#hi20_constant_pool + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 0)); + // addi dst,[dst+#low12_constant_pool] + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0)); + } + + @Override public byte encSize(int delta) { return 8; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + // AUIPC dst,#hi20_constant_pool + enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, dst, delta>>12)); + // Load dst,[dst+#low12_constant_pool] + enc.patch4(opStart+4, riscv.i_type(riscv.OP_IMM, dst, 0, dst, delta & 0xFFF)); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java new file mode 100644 index 00000000..c4d5d8af --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java @@ -0,0 +1,47 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +// unconditional jump +public class UJmpRISC extends CFGNode implements MachNode, RIPRelSize { + @Override public String op() { return "jmp"; } + @Override public String label() { return op(); } + @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return sb.append("jmp "); } + @Override public RegMask regmap(int i) {return null; } + @Override public RegMask outregmap() { return null; } + @Override public Type compute() { throw Utils.TODO(); } + @Override public Node idealize() { throw Utils.TODO(); } + @Override public void encoding( Encoding enc ) { + // Short form +/-4K: beq r0,r0,imm12 + // Long form: auipc rX,imm20/32; jal r0,[rX+imm12/32] + enc.jump(this,uctrl()); + enc.add4(riscv.j_type(riscv.OP_JAL, 0, 0)); + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { + if( -(1L<<20) <= delta && delta < (1L<<20) ) return 4; + // 2 word encoding needs a tmp register, must teach RA + throw Utils.TODO(); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + if( opLen==4 ) { + enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, 0, delta)); + } else { + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + CFGNode target = uctrl(); + //assert target.nOuts() > 1; // Should optimize jmp to empty targets + sb.p(label(target)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java new file mode 100644 index 00000000..19ea6bc7 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java @@ -0,0 +1,13 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class XorIRISC extends ImmRISC { + public XorIRISC( Node and, int imm) { super(and,imm); } + public XorIRISC( Node and, int imm, boolean pop) { super(and,imm,pop); } + @Override int opcode() { return riscv.OP_IMM; } + @Override int func3() { return 4; } + @Override public String glabel() { return "^"; } + @Override public String op() { return "xori"; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java new file mode 100644 index 00000000..413a7c3b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java @@ -0,0 +1,16 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class XorRISC extends MachConcreteNode implements MachNode { + public XorRISC(Node or) { super(or); } + @Override public String op() { return "xor"; } + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,4,0); } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java new file mode 100644 index 00000000..7a6361bc --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java @@ -0,0 +1,543 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; + +public class riscv extends Machine { + + public riscv(CodeGen code) { + if( !"SystemV".equals(code._callingConv) ) + throw new IllegalArgumentException("Unknown calling convention "+code._callingConv); + } + + @Override public String name() {return "riscv";} + //@Override public int maxReg() { return MAX_REG; } + + // Using ABI names instead of register names + public static int ZERO = 0, RPC= 1, RSP= 2, S12= 3, S13= 4, T0 = 5, T1 = 6, T2 = 7; + public static int S0 = 8, S1 = 9, A0 = 10, A1 = 11, A2 = 12, A3 = 13, A4 = 14, A5 = 15; + public static int A6 = 16, A7 = 17, S2 = 18, S3 = 19, S4 = 20, S5 = 21, S6 = 22, S7 = 23; + public static int S8 = 24, S9 = 25, S10= 26, S11= 27, T3 = 28, T4 = 29, T5 = 30, T6 = 31; + + // FP registers + public static int F0 = 32, F1 = 33, F2 = 34, F3 = 35, F4 = 36, F5 = 37, F6 = 38, F7 = 39; + public static int FS0 = 40, FS1 = 41, FA0 = 42, FA1 = 43, FA2 = 44, FA3 = 45, FA4 = 46, FA5 = 47; + public static int FA6 = 48, FA7 = 49, FS2 = 50, FS3 = 51, FS4 = 52, FS5 = 53, FS6 = 54, FS7 = 55; + public static int FS8 = 56, FS9 = 57, FS10 = 58, FS11 = 59, FT8 = 60, FT9 = 61, FT10 = 62, FT11 = 63; + + static final int MAX_REG = 64; + + public static final int F_OFFSET = 32; + + static final String[] REGS = new String[] { + "zero","rpc" , "rsp" , "s12" , "s13" , "t0" , "t1" , "t2" , + "s0" , "s1" , "a0" , "a1" , "a2" , "a3" , "a4" , "a5" , + "a6" , "a7" , "s2" , "s3" , "s4" , "s5" , "s6" , "s7" , + "s8" , "s9" , "s10" , "s11" , "t3" , "t4" , "t5" , "t6" , + "f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , + "fs0" , "fs1" , "fa0" , "fa1" , "fa2" , "fa3" , "fa4" , "fa5" , + "fa6" , "fa7" , "fs2" , "fs3" , "fs4" , "fs5" , "fs6" , "fs7" , + "fs8" , "fs9" , "fs10", "fs11", "ft8" , "ft9" , "ft10", "ft11" + // Register-based naming hella easier to debug than "official" register + // names when single-stepping in debugger. + //"zero", "r1" , "rsp" , "r3" , "r4" , "r5" , "r6" , "r7" , + //"r8" , "r9" , "r10" , "r11", "r12", "r13", "r14", "r15", + //"r16" , "r17" , "r18" , "r19", "r20", "r21", "r22", "r23", + //"r24" , "r25" , "r26" , "r27", "r28", "r29", "r30", "r31", + //"f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , + //"fs0" , "fs1" , "fa0" , "fa1" , "fa2" , "fa3" , "fa4" , "fa5" , + //"fa6" , "fa7" , "fs2" , "fs3" , "fs4" , "fs5" , "fs6" , "fs7" , + //"fs8" , "fs9" , "fs10", "fs11", "ft8" , "ft9" , "ft10", "ft11" + }; + @Override public String[] regs() { return REGS; } + + // General purpose register mask: pointers and ints, not floats + static final long RD_BITS = 0b11111111111111111111111111111111L; // All the GPRs + static final RegMask RMASK = new RegMask(RD_BITS); + + static final long WR_BITS = 0b11111111111111111111111111111010L; // All the GPRs, minus ZERO and RSP + static final RegMask WMASK = new RegMask(WR_BITS); + // Float mask from(f0-ft10). TODO: ft10,ft11 needs a larger RegMask + static final long FP_BITS = 0b11111111111111111111111111111111L<<F0; + static final RegMask FMASK = new RegMask(FP_BITS); + + // Load/store mask; both GPR and FPR + static final RegMask MEM_MASK = new RegMask(WR_BITS | FP_BITS); + + static final RegMask SPLIT_MASK = new RegMask( WR_BITS | FP_BITS, -1L ); + + + // Arguments masks + public static RegMask A0_MASK = new RegMask(A0); + public static RegMask A1_MASK = new RegMask(A1); + public static RegMask A2_MASK = new RegMask(A2); + public static RegMask A3_MASK = new RegMask(A3); + public static RegMask A4_MASK = new RegMask(A4); + public static RegMask A5_MASK = new RegMask(A5); + public static RegMask A6_MASK = new RegMask(A6); + public static RegMask A7_MASK = new RegMask(A7); + + public static final RegMask RPC_MASK = new RegMask(RPC); + + // Float arguments masks + public static RegMask FA0_MASK = new RegMask(FA0); + public static RegMask FA1_MASK = new RegMask(FA1); + public static RegMask FA2_MASK = new RegMask(FA2); + public static RegMask FA3_MASK = new RegMask(FA3); + public static RegMask FA4_MASK = new RegMask(FA4); + public static RegMask FA5_MASK = new RegMask(FA5); + public static RegMask FA6_MASK = new RegMask(FA6); + public static RegMask FA7_MASK = new RegMask(FA7); + + // Int arguments calling conv + static RegMask[] CALLINMASK = new RegMask[] { + A0_MASK, + A1_MASK, + A2_MASK, + A3_MASK, + A4_MASK, + A5_MASK, + A6_MASK, + A7_MASK + }; + + static RegMask[] XMMS = new RegMask[] { + FA0_MASK, + FA1_MASK, + FA2_MASK, + FA3_MASK, + FA4_MASK, + FA5_MASK, + FA6_MASK, + FA7_MASK + }; + + // major opcode: OP + public static int OP_LOAD = 0b00_000_11; + public static int OP_LOADFP = 0b00_001_11; + public static int OP_CUSTOM0 = 0b00_010_11; + public static int OP_IMM = 0b00_100_11; + public static int OP_AUIPC = 0b00_101_11; + + public static int OP_STORE = 0b01_000_11; + public static int OP_STOREFP = 0b01_001_11; + public static int OP_CUSTOM1 = 0b01_010_11; + public static int OP = 0b01_100_11; + public static int OP_LUI = 0b01_101_11; + + public static int OP_CUSTOM2 = 0b10_010_11; + public static int OP_FP = 0b10_100_11; + + public static int OP_BRANCH = 0b11_000_11; + public static int OP_JALR = 0b11_001_11; + public static int OP_RESERVED= 0b11_010_11; + public static int OP_JAL = 0b11_011_11; + + + // Since riscv instructions are fixed we can just or them together + public static int r_type(int opcode, int rd, int func3, int rs1, int rs2, int func7) { + assert 0 <= rs1 && rs1 < 32; + assert 0 <= rs2 && rs2 < 32; + assert 0 <= rd && rd < 32; + return (func7 << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode; + } + public static void r_type(Encoding enc, Node n, int func3, int func7) { + short dst = enc.reg(n); + short src1 = enc.reg(n.in(1)); + short src2 = enc.reg(n.in(2)); + int body = r_type(OP,dst,func3,src1,src2,func7); + enc.add4(body); + } + + public static void rf_type(Encoding enc, Node n, RM func3, int func7) { + short dst = (short)(enc.reg(n )-F_OFFSET); + short src1 = (short)(enc.reg(n.in(1))-F_OFFSET); + short src2 = (short)(enc.reg(n.in(2))-F_OFFSET); + int body = r_type(OP_FP,dst,func3.ordinal(),src1,src2,func7); + enc.add4(body); + } + + + public static int u_type(int opcode, int rd, int imm20) { + assert 0 <= rd && rd < 32; + return (imm20 << 12) | (rd << 7) | opcode; + } + + public static int j_type(int opcode, int rd, int delta) { + assert -(1L<<20) <= delta && delta < (1L<<20); + assert 0 <= rd && rd < 32; + // Messy branch offset encoding + // 31 30-21 20 19-12 11-7 6-0 + // 20 10- 1 11 19-12 rpc JAL + assert (delta&1)==0; // Low bit is always zero, not encoded + int imm10_01 = (delta>> 1) & 0x3FF; + int imm11 = (delta>>11) & 1; + int imm12_19 = (delta>>12) & 0xFF; + int imm20 = (delta>>19) & 1; + int bits = imm20<<19 | imm10_01 << 9 | imm11 << 8 | imm12_19; + return bits << 12 | rd << 7 | opcode; + } + + + public static int i_type(int opcode, int rd, int func3, int rs1, int imm12) { + assert 0 <= rd && rd < 32; + assert 0 <= rs1 && rs1 < 32; + assert opcode >= 0 && func3 >=0 && imm12 >= 0; // Zero-extend by caller + return (imm12 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode; + } + + // S-type instructions(store) + public static int s_type(int opcode, int func3, int rs1, int rs2, int imm12) { + assert 0 <= rs1 && rs1 < 32; + assert 0 <= rs2 && rs2 < 32; + assert 0 <= func3; + + assert imm12 >= 0; // Masked to high zero bits by caller + int imm_lo = imm12 & 0x1F; + int imm_hi = imm12 >> 5; + return (imm_hi << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (imm_lo << 7) | opcode; + } + + // BRANCH + public static int b_type(int opcode, int func3, short rs1, short rs2, int delta) { + assert 0 <= rs1 && rs1 < 32; + assert 0 <= rs2 && rs2 < 32; + assert -4*1024 <= delta && delta < 4*1024; + assert (delta&1)==0; // Low bit is always zero, not encoded + // Messy branch offset encoding + // 31 30 29 28 27 26 25 24-20 19-15 14-12 11 10 9 8 7 6-0 + // 12 10 9 8 7 6 5 SRC2 SRC1 FUNC3 4 3 2 1 11 OP + int imm4_1 = (delta>> 1) & 0xF; + int imm10_5= (delta>> 5) &0x3F; + int imm11 = (delta>>11) & 1; + int imm12 = (delta>>12) & 1; + int imm5 = imm4_1<<1 | imm11; + int imm7 = imm12<<6 | imm10_5; + return (imm7 << 25 ) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (imm5 << 7) | opcode; + } + + public enum RM { + RNE, // Round to Nearest, ties to Even + RTZ, // Round towards Zero + RDN, // Round Down + RUP, // Round Up + DIRECT, // Round to Nearest, ties to Max Magnitude + RESERVED1, // Reserved for futue use + RESERVED2, // Reserved for future use + DYN, // In instruction’s rm field, selects dynamic rounding mode; In Rounding Mode register, reserved + } + + // Since opcode is the same just return back func3 + static public int jumpop(String op) { + return switch(op) { + case "==" -> 0x0; + case "!=" -> 0x1; + case "<" -> 0x4; + case ">=" -> 0x5; + case "u<" -> 0x6; + case "u<=" -> 0x7; + default -> throw Utils.TODO(); + }; + } + + // Since opcode is the same just return back func3 + static public int fsetop(String op) { + return switch(op) { + case "<" -> 1; + case "<=" -> 0; + case "==" -> 2; + default -> throw Utils.TODO(); + }; + } + + @Override public RegMask callArgMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); } + static RegMask callInMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { + if( idx==0 ) return RPC_MASK; + if( idx==1 ) return null; + if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence + // Count floats in signature up to index + int fcnt=0; + for( int i=2; i<idx; i++ ) + if( tfp.arg(i-2) instanceof TypeFloat ) + fcnt++; + // Floats up to XMMS in XMM registers + if( tfp.arg(idx-2) instanceof TypeFloat ) { + if( fcnt < XMMS.length ) + return XMMS[fcnt]; + } else { + RegMask[] cargs = CALLINMASK; + if( idx-2-fcnt < cargs.length ) + return cargs[idx-2-fcnt]; + } + // Pass on stack slot(8 and higher) + if( maxArgSlot>0 ) throw Utils.TODO(); + return new RegMask(MAX_REG + 1 + (idx - 2)); + } + + @Override public short maxArgSlot( TypeFunPtr tfp ) { + int icnt=0, fcnt=0; // Count of ints, floats + for( int i=0; i<tfp.nargs(); i++ ) { + if( tfp.arg(i) instanceof TypeFloat ) fcnt++; + else icnt++; + } + int nstk = Math.max(icnt-8,0)+Math.max(fcnt-8,0); + return (short)nstk; + } + + static final long CALLER_SAVE = + (1L<<RPC) | + (1L<<A0 ) | (1L<<A1 ) | (1L<<A2 ) | (1L<<A3 ) | (1L<<A4 ) | (1L<<A5 ) | (1L<<A6 ) | (1L<<A7 ) | + (1L<<T0 ) | (1L<<T1 ) | (1L<<T2 ) | (1L<<T3 ) | (1L<<T4 ) | (1L<<T5 ) | (1L<<T6 ) | + (1L<<FA0) | (1L<<FA1) | (1L<<FA2) | (1L<<FA3) | (1L<<FA4) | (1L<<FA5) | (1L<<FA6) | (1L<<FA7) | + (1L<<F0 ) | (1L<<F1 ) | (1L<<F2 ) | (1L<<F3 ) | (1L<<F4 ) | (1L<<F5 ) | (1L<<F6 ) | (1L<<F7 ) | + (1L<<FT8) | (1L<<FT9) | (1L<<FT10)| (1L<<FT11); + + @Override public long callerSave() { return CALLER_SAVE; } + @Override public long neverSave() { return (1L<<RSP) | (1L<<ZERO); } + @Override public RegMask retMask( TypeFunPtr tfp ) { + return tfp.ret() instanceof TypeFloat ? FA0_MASK : A0_MASK; + } + @Override public int rpc() { return RPC; } + + + // Return a MachNode unconditional branch + @Override public CFGNode jump() { return new UJmpRISC(); } + + // Create a split op; any register to any register, including stack slots + @Override public SplitNode split(String kind, byte round, LRG lrg) { return new SplitRISC(kind,round); } + + // True if signed 12-bit immediate + public static boolean imm12(TypeInteger ti) { + // 52 = 64-12 + return ti.isConstant() && ((ti.value()<<52)>>52) == ti.value(); + } + // True if HIGH 20-bit signed immediate, with all zeros low. + public static boolean imm20Exact(TypeInteger ti) { + // shift left 32 to clear out the upper 32 bits. + // shift right SIGNED to sign-extend upper 32 bits; then shift 12 more to clear out lower 12 bits. + // shift left 12 to re-center the bits. + return ti.isConstant() && (((ti.value()<<32)>>44)<<12) == ti.value(); + } + + @Override public Node instSelect( Node n ) { + return switch (n) { + case AddFNode addf -> addf(addf); + case AddNode add -> add(add); + case AndNode and -> and(and); + case BoolNode bool -> cmp(bool); + case CallNode call -> call(call); + case CastNode cast -> new CastMach(cast); + case CallEndNode cend -> new CallEndMach(cend); + case CProjNode c -> new CProjNode(c); + case ConstantNode con -> con(con); + case DivFNode divf -> new DivFRISC(divf); + case DivNode div -> new DivRISC(div); + case FunNode fun -> new FunRISC(fun); + case IfNode iff -> jmp(iff); + case LoadNode ld -> ld(ld); + case MemMergeNode mem -> new MemMergeNode(mem); + case MinusNode neg -> new NegRISC(neg); + case MulFNode mulf -> new MulFRISC(mulf); + case MulNode mul -> new MulRISC(mul); + case NewNode nnn -> nnn(nnn); + case NotNode not -> new NotRISC(not); + case OrNode or -> or(or); + case ParmNode parm -> new ParmRISC(parm); + case PhiNode phi -> new PhiNode(phi); + case ProjNode prj -> prj(prj); + case ReadOnlyNode read-> new ReadOnlyMach(read); + case ReturnNode ret -> new RetRISC(ret, ret.fun()); + case SarNode sar -> sra(sar); + case ShlNode shl -> sll(shl); + case ShrNode shr -> srl(shr); + case StartNode start -> new StartNode(start); + case StopNode stop -> new StopNode(stop); + case StoreNode st -> st(st); + case SubFNode subf -> new SubFRISC(subf); + case SubNode sub -> sub(sub); + case ToFloatNode tfn -> i2f8(tfn); + case XorNode xor -> xor(xor); + + case LoopNode loop -> new LoopNode(loop); + case RegionNode region -> new RegionNode(region); + default -> throw Utils.TODO(); + }; + } + + private Node addf(AddFNode addf) { + return new AddFRISC(addf); + } + + private Node add(AddNode add) { + if( add.in(2) instanceof ConstantNode off2 && off2._con instanceof TypeInteger ti && imm12(ti) ) + return new AddIRISC(add, (int)ti.value(),true); + return new AddRISC(add); + } + + private Node and(AndNode and) { + if( and.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti ) { + if( imm12(ti) ) + return new AndIRISC(and, (int)ti.value()); + // Could be any size low bit mask + if( ti.value() == 0xFFFFFFFFL ) + return new SrlIRISC(new SllIRISC(and,32),32,false); + } + return new AndRISC(and); + } + + private Node call(CallNode call) { + return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp + ? new CallRISC(call, tfp) + : new CallRRISC(call); + } + private Node nnn(NewNode nnn) { + // TODO: pass in the TFP for alloc + return new NewRISC(nnn); + } + + private Node cmp(BoolNode bool) { + // Float variant directly implemented in hardware + if( bool.isFloat() ) + return new SetFRISC(bool); + + // Only < and <u are implemented in hardware. + // x < y - as-is + // x <= y - flip and negate; !(y < x); `slt tmp=y,x; xori dst=tmp,#1` + // x == y - sub and vs0 == `sub tmp=x-y; sltu dst=tmp,#1` + + // x > y - swap; y < x + // x >= y - swap and negate; !(x < y); `slt tmp=y,x;` then NOT. + // x != y - sub and vs0 == `sub tmp=x-y; sltu dst=tmp,#1` then NOT. + + // The ">", ">=" and "!=" in Simple include a NotNode, which can be + // implemented with a XOR. If one of the above is followed by a NOT + // we can remove the double XOR in the encodings. + + return switch( bool.op() ) { + case "<" -> bool.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) + ? new SetIRISC(bool, (int)ti.value(),false) + : new SetRISC(bool, false); + // x <= y - flip and negate; !(y < x); `slt tmp=y,x; xori dst=tmp,#1` + case "<=" -> new XorIRISC(new SetRISC(bool.swap12(), false),1,false); + // x == y - sub and vs0 == `sub tmp=x-y; sltu dst=tmp,#1` + case "==" -> new SetIRISC(new SubRISC(bool),1,true); + default -> throw Utils.TODO(); + }; + } + + private Node con( ConstantNode con ) { + if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs + return switch( con._con ) { + case TypeInteger ti -> { + if( imm12(ti) ) yield new IntRISC(con); + long x = ti.value(); + if( imm20Exact(ti) ) yield new LUI((int)x); + if( (x<<32)>>32 == x ) { // Signed lower 32-bit immediate + // Here, the low 12 bits get sign-extended, which means if + // bit11 is set, the value is negative and lowers the LUI + // value. Add a bit 12 to compensate + if( ((x>>11)&1)==1 ) x += 0x1000; + yield new AddIRISC(new LUI((int)(x & ~0xFFF)), (int)(x & 0xFFF),false); + } + // Need more complex sequence for larger constants... or a load + // from a constant pool, which does not need an extra register + yield new Int8RISC(con); + } + // Load from constant pool + case TypeFloat tf -> new FltRISC(con); + case TypeFunPtr tfp -> new TFPRISC(con); + case TypeMemPtr tmp -> new TMPRISC(con); + case TypeNil tn -> throw Utils.TODO(); + // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. + case Type t -> t==Type.NIL ? new IntRISC(con) : new ConstantNode(con); + }; + } + + private Node jmp( IfNode iff ) { + if( iff.in(1) instanceof BoolNode bool && !bool.isFloat() ) { + // if less than or equal switch inputs + String bop = bool.op(); + if( bop.equals("<=") || bop.equals(">") ) + return new BranchRISC(iff, IfNode.swap(bop), bool.in(2), bool.in(1)); + return new BranchRISC(iff, bop, bool.in(1), bool.in(2)); + } + // Vs zero + return new BranchRISC(iff, iff.in(1)==null ? "==" : "!=", iff.in(1), null); + } + + private Node or(OrNode or) { + if( or.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) + return new OrIRISC(or, (int)ti.value()); + return new OrRISC(or); + } + + private Node xor(XorNode xor) { + if( xor.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) + return new XorIRISC(xor, (int)ti.value()); + return new XorRISC(xor); + } + + private Node sra(SarNode sar) { + if( sar.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) + return new SraIRISC(sar, (int)ti.value()); + return new SraRISC(sar); + } + + private Node srl(ShrNode shr) { + if( shr.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) + return new SrlIRISC(shr, (int)ti.value(),true); + return new SrlRISC(shr); + } + + private Node sll(ShlNode sll) { + if( sll.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)) + return new SllIRISC(sll, (int)ti.value()); + return new SllRISC(sll); + } + + private Node sub(SubNode sub) { + return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) + ? new AddIRISC(sub, (int)(-ti.value()),true) + : new SubRISC(sub); + } + + private Node i2f8(ToFloatNode tfn) { + assert tfn.in(1)._type instanceof TypeInteger ti; + return new I2F8RISC(tfn); + } + + private Node prj(ProjNode prj) { + return new ProjRISC(prj); + } + + private Node ld(LoadNode ld) { + return new LoadRISC(ld,address(ld),off); + } + + private Node st(StoreNode st) { + Node xval = st.val() instanceof ConstantNode con && con._con == TypeInteger.ZERO ? null : st.val(); + return new StoreRISC(st,address(st), off, xval); + } + + // Gather addressing mode bits prior to constructing. This is a builder + // pattern, but saving the bits in a *local* *global* here to keep mess + // contained. + private static int off; + private Node address( MemOpNode mop ) { + off = 0; // Reset + Node base = mop.ptr(); + // Skip/throw-away a ReadOnly, only used to typecheck + if( base instanceof ReadOnlyNode read ) base = read.in(1); + assert !(base instanceof AddNode) && base._type instanceof TypeMemPtr; // Base ptr always, not some derived + if( mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) ) { + off = (int)ti.value(); + } else { + base = new AddRISC(base,mop.off()); + base._type = mop.ptr()._type; + } + return base; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java new file mode 100644 index 00000000..2513de37 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java @@ -0,0 +1,44 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class AddFMemX86 extends MemOpX86 { + AddFMemX86( AddFNode add, LoadNode ld , Node base, Node idx, int off, int scale, Node val ) { + super(add,ld, base, idx, off, scale, 0, val ); + } + @Override public String op() { return "addf"+_sz; } + @Override public RegMask regmap(int i) { + if( i==1 ) return null; // Memory + if( i==2 ) return x86_64_v2.RMASK; // base + if( i==3 ) return x86_64_v2.RMASK; // index + if( i==4 ) return x86_64_v2.XMASK; // value + throw Utils.TODO(); + } + @Override public RegMask outregmap() { return x86_64_v2.XMASK; } + @Override public int twoAddress() { return 4; } + @Override public void encoding( Encoding enc ) { + // addsd xmm0, DWORD PTR [rdi+0xc] + short dst = enc.reg(this ); + short ptr = enc.reg(ptr()); + short idx = enc.reg(idx()); + // F opcode + enc.add1(0xF2); + // rex prefix must come next (REX.W is not set) + x86_64_v2.rexF(dst, ptr, idx, false, enc); + + // FP ADD + enc.add1(0x0F).add1(0x58); + + x86_64_v2.indirectAdr(_scale, idx, ptr, _off, dst, enc); + } + + // General form: "add dst = src + [base + idx<<2 + 12]" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = "); + sb.p(val()==null ? "#"+_imm : code.reg(val())).p(" + "); + asm_address(code,sb); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java new file mode 100644 index 00000000..02e0c7ea --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java @@ -0,0 +1,33 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class AddFX86 extends MachConcreteNode implements MachNode { + AddFX86( Node addf ) { super(addf); } + @Override public String op() { return "addf"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.XMASK; } + @Override public RegMask outregmap() { return x86_64_v2.XMASK; } + @Override public int twoAddress() { return 1; } + @Override public boolean commutes() { return true; } + + @Override public void encoding( Encoding enc ) { + // F2 0F 58 /r ADDSD xmm1, xmm2/m64 + short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET); + short src = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET); + // Fopcode + enc.add1(0xF2); + // rex prefix must come next (REX.W is not set) + x86_64_v2.rexF(dst, src, 0, false, enc); + + enc.add1(0x0F).add1(0x58); + + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } + + // General form: "addf dst += src" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" += ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java new file mode 100644 index 00000000..0ba390c6 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java @@ -0,0 +1,24 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class AddIX86 extends ImmX86 { + AddIX86( Node add, int imm ) { super(add,imm); } + @Override public String op() { + return _imm == 1 ? "inc" : (_imm == -1 ? "dec" : "addi"); + } + @Override public String glabel() { return "+"; } + @Override int opcode() { return 0x81; } + @Override int mod() { return 0; } + @Override public final void encoding( Encoding enc ) { + if( _imm== 1 || _imm== -1 ) { + short dst = enc.reg(this); // Also src1 + enc.add1( x86_64_v2.rex(0,dst,0)); + enc.add1(0xFF); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, _imm==1 ? 0 : 1, dst) ); + } else super.encoding(enc); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java new file mode 100644 index 00000000..3ee721e3 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java @@ -0,0 +1,34 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class AddMemX86 extends MemOpX86 { + AddMemX86( AddNode add, LoadNode ld , Node base, Node idx, int off, int scale, int imm, Node val ) { + super(add,ld, base, idx, off, scale, imm, val ); + } + @Override public String op() { return "add"+_sz; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public int twoAddress() { return 4; } + @Override public void encoding( Encoding enc ) { + // add something to register from memory + // add eax,DWORD PTR [rdi+0xc] + // REX.W + 03 /r ADD r64, r/m64 + short dst = enc.reg(this ); + short ptr = enc.reg(ptr()); + short idx = enc.reg(idx()); + + enc.add1(x86_64_v2.rex(dst, ptr, idx)); + // opcode + enc.add1(0x03); + + x86_64_v2.indirectAdr(_scale, idx, ptr, _off, dst, enc); + } + + // General form: "add dst += [base + idx<<2 + 12]" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" += "); + asm_address(code,sb); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddX86.java new file mode 100644 index 00000000..84543e8f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddX86.java @@ -0,0 +1,11 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.node.Node; + +public class AddX86 extends RegX86 { + AddX86( Node add ) { super(add); } + @Override public String op() { return "add"; } + @Override public String glabel() { return "+"; } + @Override int opcode() { return 0x03; } + @Override public boolean commutes() { return true; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndIX86.java new file mode 100644 index 00000000..3c1b567c --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndIX86.java @@ -0,0 +1,11 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.node.Node; + +public class AndIX86 extends ImmX86 { + AndIX86( Node add, int imm ) { super(add,imm); } + @Override public String op() { return "andi"; } + @Override public String glabel() { return "&"; } + @Override int opcode() { return 0x81; } + @Override int mod() { return 4; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndX86.java new file mode 100644 index 00000000..dedbce45 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndX86.java @@ -0,0 +1,11 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.node.Node; + +public class AndX86 extends RegX86 { + AndX86( Node add ) { super(add); } + @Override public String op() { return "and"; } + @Override public String glabel() { return "&"; } + @Override int opcode() { return 0x23; } + @Override public boolean commutes() { return true; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java new file mode 100644 index 00000000..460f568b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java @@ -0,0 +1,33 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.CallNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; + +public class CallRX86 extends CallNode implements MachNode { + CallRX86( CallNode call ) { super(call); } + @Override public String op() { return "callr"; } + @Override public String label() { return op(); } + @Override public RegMask regmap(int i) { + return i==_inputs._len + ? x86_64_v2.WMASK // Function call target + : x86_64_v2.callInMask(tfp(),i,fun()._maxArgSlot); // Normal argument + } + @Override public RegMask outregmap() { return null; } + @Override public void encoding( Encoding enc ) { + // FF /2 CALL r/m64 + // calls the function in the register + short src = enc.reg(fptr()); + enc.add1(0xFF); + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT,2,src)); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(fptr())).p(" "); + for( int i=0; i<nargs(); i++ ) + sb.p(code.reg(arg(i))).p(" "); + sb.unchar(2); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java new file mode 100644 index 00000000..d74e3833 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java @@ -0,0 +1,48 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; + +public class CallX86 extends CallNode implements MachNode, RIPRelSize { + final TypeFunPtr _tfp; + final String _name; + CallX86( CallNode call, TypeFunPtr tfp ) { + super(call); + _inputs.pop(); // Pop constant target + assert tfp.isConstant(); + _tfp = tfp; + FunNode fun = CodeGen.CODE.link(tfp); + _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls + } + @Override public String op() { return "call"; } + @Override public String label() { return op(); } + @Override public String name() { return _name; } + @Override public TypeFunPtr tfp() { return _tfp; } + @Override public RegMask regmap(int i) { return x86_64_v2.callInMask(_tfp,i,fun()._maxArgSlot); } + @Override public RegMask outregmap() { return null; } + @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr + + @Override public void encoding( Encoding enc ) { + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); + enc.add1(0xe8).add4(0); + } + + // Delta is from opcode start, but X86 measures from the end of the 5-byte encoding + @Override public byte encSize(int delta) { return 5; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + enc.patch4(opStart+1, delta-5); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(_name).p(" "); + for( int i=0; i<nargs(); i++ ) + sb.p(code.reg(in(i+2))).p(", "); + sb.unchar(2); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java new file mode 100644 index 00000000..5b97ef63 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java @@ -0,0 +1,32 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class CmpFX86 extends MachConcreteNode implements MachNode { + CmpFX86( Node cmp ) { super(cmp); } + @Override public String op() { return "cmpf"; } + @Override public RegMask regmap(int i) { return x86_64_v2.XMASK; } + @Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; } + + @Override public void encoding( Encoding enc ) { + // UCOMISD + short src1 = (short)(enc.reg(in(1)) - x86_64_v2.XMM_OFFSET); + short src2 = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET); + // float opcode + enc.add1(0x66); + // rex prefix must come next (REX.W is not set) + x86_64_v2.rexF(src1, src2, 0, false, enc); + + enc.add1(0x0F).add1(0x2E); + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, src1, src2)); + } + + // General form: "cmp src1,src2" + @Override public void asm(CodeGen code, SB sb) { + String dst = code.reg(this); + if( dst!="flags" ) sb.p(dst).p(" = "); + sb.p(code.reg(in(1))).p(", ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java new file mode 100644 index 00000000..8b8318eb --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java @@ -0,0 +1,44 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +// Compare immediate. Sets flags. +public class CmpIX86 extends MachConcreteNode implements MachNode { + final int _imm; + CmpIX86( Node cmp, int imm, boolean swap ) { + super(cmp); + _inputs.del(swap ? 1 : 2); + _imm = imm; + } + CmpIX86( CmpIX86 cmp ) { + super((Node)null); + addDef(null); + addDef(cmp.in(1)); + _imm = cmp._imm; + } + + @Override public String op() { return _imm==0 ? "test" : "cmp"; } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; } + @Override public boolean isClone() { return true; } + @Override public Node copy() { return new CmpIX86(this); } + + @Override public final void encoding( Encoding enc ) { + short dst = enc.reg(in(1)); // Also src1 + enc.add1(x86_64_v2.rex(0, dst, 0)); + // opcode; 0x81 or 0x83; 0x69 or 0x6B + enc.add1( 0x81 + (x86_64_v2.imm8(_imm) ? 2 : 0) ); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 7, dst) ); + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + @Override public void asm(CodeGen code, SB sb) { + String dst = code.reg(this); + if( dst!="flags" ) sb.p(dst).p(" = "); + sb.p(code.reg(in(1))); + if( _imm != 0 ) sb.p(", #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java new file mode 100644 index 00000000..11f900ed --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java @@ -0,0 +1,78 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; + +public class CmpMemX86 extends MemOpX86 { + final boolean _swap; // Op switched LHS, RHS + CmpMemX86( BoolNode bool, LoadNode ld, Node base, Node idx, int off, int scale, int imm, Node val, boolean swap ) { + super(bool,ld, base, idx, off, scale, imm, val ); + _swap = swap; + assert !_swap || val() != null || bool.op()=="==" || bool.op()=="!="; // Cannot swap with immediate + } + @Override public String op() { return ((val()==null && _imm==0) ? "test" : "cmp") + _sz; } + @Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; } + @Override public void encoding( Encoding enc ) { + // REX.W + 81 /7 id CMP r/m64, imm32 | REX.W + 39 /r CMP r/m64,r64 + // CMP [mem], imm32 + + short ptr = enc.reg(ptr()); + short idx = enc.reg(idx()); + short src = enc.reg(val()); + + if(src == -1) { + assert !_swap; + int log = _declaredType.log_size(); + x86_64_v2.rexF(-1, ptr, idx, log==3, enc); + switch(log) { + case 0: enc.add1(0x80); break; + case 1: enc.add1(0x66).add1(0x81); break; + case 2: enc.add1(0x81); break; + case 3: enc.add1(0x81); break; + } + x86_64_v2.indirectAdr(_scale, idx, ptr, _off, 7, enc); + switch(log) { + case 0: enc.add1(_imm); break; + case 1: enc.add2(_imm); break; + case 2: enc.add4(_imm); break; + case 3: enc.add8(_imm); break; + } + } else { + encVal(enc, _declaredType, ptr, idx, src, _off, _scale, _swap); + } + } + + static void encVal(Encoding enc, Type decl, short ptr, short idx, short src, int off, int scale, boolean _swap) { + if(decl instanceof TypeFloat) { + src -= (short)x86_64_v2.XMM_OFFSET; + enc.add1(decl==TypeFloat.F32 ? 0xF3 : 0xF2).add1(0x0F).add1(0xC2); + } else { + int log = decl.log_size(); + x86_64_v2.rexF(src, ptr, idx, log == 3, enc); + int swap = _swap ? 2 : 0; + switch(log) { + case 0: enc.add1(0x38+swap); break; + case 1: enc.add1(0x66).add1(0x39+swap); break; + case 2: enc.add1(0x39+swap); break; + case 3: enc.add1(0x39+swap); break; + } + } + x86_64_v2.indirectAdr(scale, idx, ptr, off, src, enc); + } + + // General form: "cmp dst = src, [base + idx<<2 + 12]" + @Override public void asm(CodeGen code, SB sb) { + String dst = code.reg(this); + if( dst!="flags" ) sb.p(dst).p(" = "); + if( _swap ) asm_address(code,sb).p(","); + if( val()==null ) { + if( _imm!=0 ) sb.p("#").p(_imm); + } else { + sb.p(code.reg(val())); + } + if( !_swap ) asm_address(code,sb.p(", ")); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java new file mode 100644 index 00000000..e7305cdf --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java @@ -0,0 +1,32 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class CmpX86 extends MachConcreteNode implements MachNode { + CmpX86( Node add ) { super(add); } + @Override public String op() { return "cmp"; } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; } + // This one is marginal: cloning a Cmp[reg,reg] means stretching the + // lifetimes of 2 normal registers in exchange for shortening a flags + // register lifetime. Spilling flags is (probably) relatively expensive + // compared to some normal registers - and those normal registers might not + // be spilling! + @Override public boolean isClone() { return true; } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(in(1)); + short src = enc.reg(in(2)); + + enc.add1(x86_64_v2.rex(dst, src, 0)); + enc.add1(0x3B); + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } + @Override public void asm(CodeGen code, SB sb) { + String dst = code.reg(this); + if( dst!="flags" ) sb.p(dst).p(" = "); + sb.p(code.reg(in(1))).p(", ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java new file mode 100644 index 00000000..3427aea5 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java @@ -0,0 +1,34 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class DivFX86 extends MachConcreteNode implements MachNode { + DivFX86( Node divf) { super(divf); } + @Override public String op() { return "divf"; } + @Override public RegMask regmap(int i) { return x86_64_v2.XMASK; } + @Override public RegMask outregmap() { return x86_64_v2.XMASK; } + @Override public int twoAddress() { return 1; } + + @Override public void encoding( Encoding enc ) { + // F2 0F 5E /r DIVSD xmm1, xmm2/m64 + short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET); + short src = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET); + + // Fopcode + enc.add1(0xF2); + // rex prefix must come next (REX.W is not set) + x86_64_v2.rexF(dst, src, 0, false, enc); + + enc.add1(0x0F).add1(0x5E); + + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } + + + // General form: "divf dst /= src" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" /= ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java new file mode 100644 index 00000000..b5904a7f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java @@ -0,0 +1,33 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class DivX86 extends MachConcreteNode implements MachNode { + DivX86( Node div ) { super(div); } + @Override public String op() { return "div"; } + @Override public RegMask regmap(int i) { + return (i==1) ? x86_64_v2.RAX_MASK : x86_64_v2.DIV_MASK; + } + @Override public RegMask outregmap() { return x86_64_v2.RAX_MASK; } + @Override public RegMask killmap() { return x86_64_v2.RDX_MASK; } + + @Override public void encoding( Encoding enc ) { + // REX.W + F7 /7 IDIV r/m64 + short src = enc.reg(in(2)); + // sign extend rax before 128/64 bits division + // sign extend rax to rdx:rax + enc.add1(x86_64_v2.REX_W); + enc.add1(0x99); + enc.add1(x86_64_v2.rex(0, src, 0)); + // divide + enc.add1(0xF7); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0x07, src)); + } + // General form: "div dst /= src" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2))); + } + @Override public String comment() { return "kill rdx"; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java new file mode 100644 index 00000000..9bcbac8f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java @@ -0,0 +1,47 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class FltX86 extends ConstantNode implements MachNode, RIPRelSize{ + private byte _encSize; + FltX86(ConstantNode con ) { super(con); } + @Override public String op() { return "ld8"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return x86_64_v2.XMASK; } + @Override public boolean isClone() { return true; } + @Override public Node copy() { return new FltX86(this); } + + @Override public void encoding( Encoding enc ) { + // Load the constant into a FPR + // movsd xmm, [rip + 0] + // F2 0F 10 /r MOVSD xmm1, m64 + _encSize = 1/*Fop*/+0/*REX*/+2/*op*/+1/*MODRM*/+4/*offset*/; + short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET); + // Fopcode + enc.add1(0xF2); + // rex prefix must come next (REX.W is not set) + _encSize += x86_64_v2.rexF(dst, 0, 0, false, enc); + enc.add1(0x0F).add1(0x10); + // hard-code rip here + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0x05)); + enc.add4(0); + enc.largeConstant(this,_con,_encSize-4,2/*ELF encoding PC32*/); + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { + // TODO: 1-byte RIP offset? + return (byte)_encSize; + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + enc.patch4(opStart+opLen-4,delta-opLen); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" = #")); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java new file mode 100644 index 00000000..cbd5fdbf --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java @@ -0,0 +1,34 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.node.FunNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; + +public class FunX86 extends FunNode implements MachNode { + FunX86( FunNode fun ) { super(fun); } + @Override public void postSelect(CodeGen code) { + super.postSelect(code); + // One more for RPC pre-pushed; X86 special + _maxArgSlot++; + } + + @Override public void computeFrameAdjust(CodeGen code, int maxReg) { + super.computeFrameAdjust(code,maxReg); + // Alignment, but off by RPC + if( _hasCalls ) // If non-leaf, pad to 16b + _frameAdjust = ((_frameAdjust+8+8) & -16)-8; + } + + @Override public void encoding( Encoding enc ) { + int sz = _frameAdjust; + if( sz == 0 ) return; // Skip if no frame adjust + // opcode: 0x83, addi rsp with immediate 8 + enc.add1( x86_64_v2.REX_W ).add1( x86_64_v2.imm8(sz) ? 0x83 : 0x81 ); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0b101, x86_64_v2.RSP) ); + if( x86_64_v2.imm8(sz) ) enc.add1(sz); + else enc.add4(sz); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java new file mode 100644 index 00000000..9f3d7905 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java @@ -0,0 +1,31 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class I2f8X86 extends MachConcreteNode implements MachNode { + I2f8X86(Node i2f8 ) { super(i2f8); } + @Override public String op() { return "cvtf"; } + @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.WMASK; } + @Override public RegMask outregmap() { return x86_64_v2.XMASK; } + + @Override public void encoding( Encoding enc ) { + // F2 0F 2A /r CVTSI2SD xmm1, r32/m32 + short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET); + short src = enc.reg(in(1)); + + // Fopcode + enc.add1(0xF2); + // rex prefix must come next (REX.W is not set) + x86_64_v2.rexF(dst, src, 0, true, enc); + + enc.add1(0x0F).add1(0x2A); + + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p("(flt)").p(code.reg(in(1))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java new file mode 100644 index 00000000..5e406911 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java @@ -0,0 +1,38 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; + +public abstract class ImmX86 extends MachConcreteNode implements MachNode { + final int _imm; + ImmX86( Node add, int imm ) { + super(add); + _inputs.pop(); // Pop constant input off + _imm = imm; + } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public int twoAddress() { return 1; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } + + abstract int opcode(); + abstract int mod(); + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); // Also src1 + enc.add1(x86_64_v2.rex(0, dst, 0)); + // opcode; 0x81 or 0x83; 0x69 or 0x6B + enc.add1( opcode() + (x86_64_v2.imm8(_imm) ? 2 : 0) ); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, mod(), dst) ); + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + + // General form: "addi dst += #imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" ").p(glabel()).p("= #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java new file mode 100644 index 00000000..3f2f696c --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java @@ -0,0 +1,76 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; + +// Integer constants +public class IntX86 extends ConstantNode implements MachNode { + IntX86( ConstantNode con ) { super(con); } + @Override public String op() { + return _con == Type.NIL || _con == TypeInteger.ZERO ? "xor" : "ldi"; + } + @Override public boolean isClone() { return true; } + @Override public Node copy() { return new IntX86(this); } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + // Zero-set uses XOR kills flags + @Override public RegMask killmap() { + return _con == Type.NIL || _con == TypeInteger.ZERO ? x86_64_v2.FLAGS_MASK : null; + } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); + // Short form for zero + if( _con==Type.NIL || _con==TypeInteger.ZERO ) { + // XOR dst,dst. Can skip REX is dst is low 8, makes this a 32b + // xor, which will also zero the high bits. + if( dst >= 8 ) enc.add1(x86_64_v2.rex(dst, dst, 0)); + enc.add1(0x33); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst)); + return; + } + + // Simply move the constant into a GPR + // Conditional encoding based on 64 or 32 bits + //REX.W + C7 /0 id MOV r/m64, imm32 + + long imm = ((TypeInteger)_con).value(); + if (Integer.MIN_VALUE <= imm && imm < 0) { + // We need sign extension, so use imm32 into 64 bit register + // REX.W + C7 /0 id MOV r/m64, imm32 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1(0xC7); // 32 bits encoding + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0x00, dst)); + enc.add4((int)imm); + } else if (0 <= imm && imm <= 0xFFFFFFFFL) { + // We want zero extension into 64 bit register + // so move 32 bit into 32 bit register which zeros + // the upper bits in the 64 bit register. + // B8+ rd id MOV r32, imm32 + if (dst >= 8) enc.add1(0x41); + enc.add1(0xB8 + (dst & 0x07)); + enc.add4((int)imm); + } else { + // Just write the full 64 bit constant + // REX.W + B8+ rd io MOV r64, imm64 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1(0xB8 + (dst & 0x07)); + enc.add8(imm); // 64 bits encoding + } + } + + // Human-readable form appended to the SB. Things like the encoding, + // indentation, leading address or block labels not printed here. + // Just something like "ld4\tR17=[R18+12] // Load array base". + // General form: "op\tdst=src+src" + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + if( _con == Type.NIL || _con == TypeInteger.ZERO ) + sb.p(reg).p(",").p(reg); + else + _con.print(sb.p(reg).p(" = #")); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java new file mode 100644 index 00000000..de27aa5c --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java @@ -0,0 +1,81 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +// Jump on flags, uses flags +public class JmpX86 extends IfNode implements MachNode, RIPRelSize { + String _bop; + JmpX86( IfNode iff, String bop ) { + super(iff); + _bop = bop; + } + @Override public String op() { return "j"+_bop; } + @Override public String label() { return op(); } + @Override public void postSelect(CodeGen code) { + Node set = in(1); + if( set==null ) return; // Never-node cutout + Node cmp = set.in(1); + // Bypass an expected Set and just reference the cmp directly + if( set instanceof SetX86 setx && (cmp instanceof CmpX86 || cmp instanceof CmpIX86 || cmp instanceof CmpMemX86 || cmp instanceof CmpFX86) ) { + _inputs.set( 1, cmp ); + _bop = setx._bop; + } else + throw Utils.TODO(); + } + @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.FLAGS_MASK; } + @Override public RegMask outregmap() { return null; } + @Override public void negate() { _bop = negate(_bop); } + + @Override public void encoding( Encoding enc ) { + if( in(1)!=null ) { + int op = x86_64_v2.jumpop(_bop); + enc.add1(op-16).add1(0); // Short form jump + } else { + if( _bop=="!=" ) return; // Inverted, no code + enc.add1(0xEB).add1(0); // Never-node + } + enc.jump(this,cproj(0)); + } + + // Delta is from opcode start, but X86 measures from the end of the 2-byte encoding + @Override public byte encSize(int delta) { + if( in(1)==null && _bop=="!=" ) return 0; // Inverted never-node, no code + return (byte)(x86_64_v2.imm8(delta-2) ? 2 : 6); + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + assert !( in(1)==null && _bop=="!=" ); // Inverted never-node, no code no patch + byte[] bits = enc.bits(); + if( opLen==2 ) { + assert in(1)==null || bits[opStart] == x86_64_v2.jumpop(_bop)-16; + delta -= 2; // Offset from opcode END + assert (byte)delta==delta; + bits[opStart+1] = (byte)delta; + } else { + assert in(1)==null || bits[opStart] == x86_64_v2.jumpop(_bop)-16; + delta -= 6; // Offset from opcode END + bits[opStart] = 0x0F; + bits[opStart+1] = (byte)(in(1)==null ? 0xE9 : x86_64_v2.jumpop(_bop)); + enc.patch4(opStart+2,delta); + } + } + + @Override public void asm(CodeGen code, SB sb) { + if( in(1)!=null ) { // Never-node + String src = code.reg(in(1)); + if( src!="flags" ) sb.p(src).p(" "); + } else if( _bop=="!=" ) { + sb.p("never"); + return; + } + CFGNode prj = cproj(0).uctrlSkipEmpty(); // 0 is True is jump target + if( !prj.blockHead() ) prj = prj.cfg0(); + sb.p(label(prj)); + } + + @Override public String comment() { return "L"+cproj(1)._nid; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java new file mode 100644 index 00000000..2cd6018f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java @@ -0,0 +1,55 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class LeaX86 extends MachConcreteNode implements MachNode { + final int _scale; + final int _offset; + LeaX86( Node add, Node base, Node idx, int scale, int offset ) { + super(add); + assert scale==0 || scale==1 || scale==2 || scale==3; + _inputs.pop(); + _inputs.pop(); + _inputs.push(base); + _inputs.push(idx); + _scale = scale; + _offset = offset; + } + + @Override public String op() { return "lea"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + + @Override public void encoding( Encoding enc ) { + // REX.W + 8D /r LEA r64,m + short dst = enc.reg(this); + short ptr = enc.reg(in(1)); + short idx = enc.reg(in(2)); + // ptr is null + // just do: [(index * s) + disp32] + if( ptr == -1 ) { + enc.add1(x86_64_v2.rex(dst, 0, idx)); + enc.add1(0x8D); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0x04)); + enc.add1(x86_64_v2.sib(_scale, idx, x86_64_v2.RBP)); + enc.add4(_offset); + return; + } + + enc.add1(x86_64_v2.rex(dst, ptr, idx)); + enc.add1(0x8D); // opcode + // rsp is hard-coded here(0x04) + x86_64_v2.indirectAdr(_scale, idx, ptr, _offset, dst, enc); + } + + // General form: "lea dst = base + 4*idx + 12" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = "); + if( in(1) != null ) + sb.p(code.reg(in(1))).p(" + "); + sb.p(code.reg(in(2))).p("<<").p(_scale); + if( _offset!=0 ) sb.p(" + #").p(_offset); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java new file mode 100644 index 00000000..441cf693 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java @@ -0,0 +1,57 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.LoadNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class LoadX86 extends MemOpX86 { + LoadX86( LoadNode ld, Node base, Node idx, int off, int scale ) { + super(ld,ld, base, idx, off, scale, 0); + } + @Override public String op() { return "ld"+_sz; } + @Override public RegMask outregmap() { return x86_64_v2.MEM_MASK; } + @Override public void encoding( Encoding enc ) { + // REX.W + 8B /r MOV r64, r/m64 + // Zero extension for u8, u16 and u32 but sign extension i8, i16, i32 + // Use movsx and movzx + short dst = enc.reg(this ); + short ptr = enc.reg(ptr()); + short idx = enc.reg(idx()); + enc(enc, _declaredType, dst, ptr, idx, _off, _scale); + } + + static void enc( Encoding enc, Type decl, short dst, short ptr, short idx, int off, int scale ) { + if( decl == TypeFloat.F32) enc.add1(0xF3); + if( decl == TypeFloat.F64) enc.add1(0xF2); + + if( decl.isa(TypeFloat.F64) ) + dst -= (short)x86_64_v2.XMM_OFFSET; + + x86_64_v2.rexF(dst, ptr, idx, decl != TypeInteger.U32 && decl != TypeFloat.F32 && decl != TypeFloat.F64, enc); + + if( false ) ; + else if( decl == TypeFloat.F32 ) enc.add1(0x0F).add1(0x10); // F3 0F 10 /r MOVSS xmm1, m32 + else if( decl == TypeFloat.F64 ) enc.add1(0x0F).add1(0x10); // F2 0F 10 /r MOVSD xmm1, m64 + else if( decl.isa(TypeInteger.I8)) enc.add1(0x0F).add1(0xBE); // sign extend: REX.W + 0F BE /r MOVSX r64, r/m8 + else if( decl == TypeInteger.I16 ) enc.add1(0x0F).add1(0xBF); // sign extend: REX.W + 0F BF /r MOVSX r64, r/m16 + else if( decl == TypeInteger.I32 ) enc.add1(0x63); // sign extend: REX.W + 63 /r MOVSXD r64, r/m32 + else if( decl == TypeInteger.U8 ) enc.add1(0x0F).add1(0xB6); // zero extend: REX.W + 0F B6 /r MOVZX r64, r/m8 + else if( decl == TypeInteger.U16 ) enc.add1(0x0F).add1(0xB7); // zero extend: REX.W + 0F B7 /r MOVZX r64, r/m16 + // Covers U32, I64/BOT, TMP + else if( decl.log_size()>=2 ) enc.add1(0x8B); // zero extend: 8B /r MOV r32, r/m32 + else throw Utils.TODO(); + + // includes modrm internally + x86_64_v2.indirectAdr(scale, idx, ptr, off, dst, enc); + } + + + // General form: "ldN dst,[base + idx<<2 + 12]" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(","); + asm_address(code,sb); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java new file mode 100644 index 00000000..bd56d022 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java @@ -0,0 +1,40 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class MemAddX86 extends MemOpX86 { + MemAddX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) { + super(st, st, base, idx, off, scale, imm, val ); + } + @Override public String op() { + return (_imm == 1 ? "inc" : (_imm == -1 ? "dec" : "add")) + _sz; + } + // Register mask allowed as a result. 0 for no register. + @Override public RegMask outregmap() { return null; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } + @Override public void encoding( Encoding enc ) { + // add something to memory + // REX.W + 01 /r | REX.W + 81 /0 id + // ADD [mem], imm32/reg + short ptr = enc.reg(ptr()); + short idx = enc.reg(idx()); + short src = enc.reg(val()); + + enc.add1(x86_64_v2.rex(src, ptr, idx)); + // opcode + enc.add1( src == -1 ? (_imm==1 ? 0xFF : 0x81): 0x01); + + // includes modrm + x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src == -1 ? 0 : src, enc); + if( src == -1 && _imm!=1 ) enc.add4(_imm); + } + // General form: "add [base + idx<<2 + 12] += src" + @Override public void asm(CodeGen code, SB sb) { + asm_address(code,sb); + if( val()==null ) { + if( _imm != 1 && _imm != -1 ) sb.p(" += #").p(_imm); + } else sb.p(" += ").p(code.reg(val())); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java new file mode 100644 index 00000000..5f090717 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java @@ -0,0 +1,88 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.lang.StringBuilder; +import java.util.BitSet; + +// Generic X86 memory operand base. +// inputs: +// ctrl - will appear for possibly RCE (i.e. array ops) +// mem - memory dependence edge +// base - Basic object pointer +// idx/null - Scaled index offset, or null if none +// val/null - Value to store, as part of an op-to-mem or op-from-mem. Null for loads, or if an immediate is being used +// Constants: +// offset - offset added to base. Can be zero. +// scale - scale on index; only 0,1,2,4,8 allowed, 0 is only when index is null +// imm - immediate value to store or op-to-mem, and only when val is null +public abstract class MemOpX86 extends MemOpNode implements MachNode { + final int _off; // Limit 32 bits + final int _scale; // Limit 0,1,2,3 + final int _imm; // Limit 32 bits + final char _sz; // Handy print name + MemOpX86( Node op, MemOpNode mop, Node base, Node idx, int off, int scale, int imm ) { + super(op,mop); + assert base._type instanceof TypeMemPtr && !(base instanceof AddNode); + assert (idx==null && scale==0) || (idx!=null && 0<= scale && scale<=3); + + // Copy memory parts from e.g. the LoadNode over the opcode, e.g. an Add + if( op != mop ) { + _inputs.set(0,mop.in(0)); // Control from mem op + _inputs.set(1,mop.in(1)); // Memory from mem op + _inputs.set(2,base); // Base handed in + } + + assert ptr() == base; + _inputs.setX(3,idx); + _off = off; + _scale = scale; + _imm = imm; + _sz = (char)('0'+(1<<_declaredType.log_size())); + } + + // Store-based flavors have a value edge + MemOpX86( Node op, MemOpNode mop, Node base, Node idx, int off, int scale, int imm, Node val ) { + this(op,mop,base,idx,off,scale,imm); + _inputs.setX(4,val); + } + + Node idx() { return in(3); } + Node val() { return in(4); } // Only for stores, including op-to-memory + + @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { + return sb.append(".").append(_name); + } + + @Override public String label() { return op(); } + @Override public Type compute() { throw Utils.TODO(); } + @Override public Node idealize() { throw Utils.TODO(); } + + // Register mask allowed on input i. + @Override public RegMask regmap(int i) { + if( i==1 ) return null; // Memory + if( i==2 ) return x86_64_v2.RMASK; // base in GPR + if( i==3 ) return x86_64_v2.RMASK; // index in GPR + if( i==4 ) return _sz >= 2 + ? x86_64_v2.MEM_MASK // value in GPR or XMM + : x86_64_v2.RMASK; // Bytes and shorts in GPR only + return null; // Anti-dependence + } + + // "[base + idx<<2 + 12]" + SB asm_address(CodeGen code, SB sb) { + sb.p("[").p(code.reg(ptr())); + if( idx() != null ) { + sb.p("+").p(code.reg(idx())); + if( _scale != 0 ) + sb.p("*").p((1<<_scale)); + } + if( _off != 0 ) + sb.p("+").p(_off); + return sb.p("]"); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java new file mode 100644 index 00000000..7932c893 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java @@ -0,0 +1,32 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class MulFX86 extends MachConcreteNode implements MachNode { + MulFX86( Node mulf) { super(mulf); } + @Override public String op() { return "mulf"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.XMASK; } + @Override public RegMask outregmap() { return x86_64_v2.XMASK; } + @Override public int twoAddress() { return 1; } + @Override public boolean commutes() { return true; } + + @Override public void encoding( Encoding enc ) { + // F2 0F 59 /r MULSD xmm1,xmm2/m64 + short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET); + short src = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET); + + // Fopcode + enc.add1(0xF2); + // rex prefix must come next (REX.W is not set) + x86_64_v2.rexF(dst, src, 0, false, enc); + + enc.add1(0x0F).add1(0x59).add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } + + // General form: "mulf dst *= src" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" *= ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java new file mode 100644 index 00000000..280b8185 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java @@ -0,0 +1,34 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class MulIX86 extends MachConcreteNode implements MachNode { + final int _imm; + MulIX86( Node add, int imm ) { + super(add); + _inputs.pop(); // Pop the constant input + _imm = imm; // Record the constant + } + @Override public String op() { return "muli"; } + @Override public String glabel() { return "*"; } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + // Rare 3-address form + @Override public final void encoding( Encoding enc ) { + short dst = enc.reg(this ); // Also src1 + short src = enc.reg(in(1)); + enc.add1(x86_64_v2.rex(src, dst, 0)); + // opcode; 0x69 or 0x6B + enc.add1( 0x69 + (x86_64_v2.imm8(_imm) ? 2 : 0) ); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src) ); + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + // General form: "addi dst += #imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java new file mode 100644 index 00000000..4d2a11ed --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java @@ -0,0 +1,29 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class MulX86 extends MachConcreteNode implements MachNode { + MulX86( Node mul ) { super(mul); } + @Override public String op() { return "mul"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public int twoAddress() { return 1; } + @Override public boolean commutes() { return true; } + + @Override public void encoding( Encoding enc ) { + // REX.W + 0F AF /r IMUL r64, r/m64 + short dst = enc.reg(this ); // src1 + short src = enc.reg(in(2)); // src2 + enc.add1(x86_64_v2.rex(dst, src, 0)); + enc.add1(0x0F); // opcode + enc.add1(0xAF); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } + + // General form: "mul dst *= src" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java new file mode 100644 index 00000000..0c2baced --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java @@ -0,0 +1,22 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class NegX86 extends MachConcreteNode implements MachNode { + NegX86(MinusNode not) { super(not); } + @Override public String op() { return "neg"; } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.RMASK; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } + @Override public int twoAddress() { return 1; } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this ); + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1(0xF7); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 3, dst)); + } + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java new file mode 100644 index 00000000..fc896dce --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java @@ -0,0 +1,25 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; + +public class NewX86 extends NewNode implements MachNode { + // A pre-zeroed chunk of memory. + NewX86( NewNode nnn ) { super(nnn); } + @Override public void encoding( Encoding enc ) { + enc.external(this,"calloc"); + // ldi rcx,#1 // number of elements to calloc + enc.add1(0xB8 + _arg2Reg).add4(1); + // E8 cd CALL rel32; + enc.add1(0xE8); + enc.add4(0); // offset + } + // General form: "alloc #bytes PC" + @Override public void asm(CodeGen code, SB sb) { + sb.p("ldi rcx = #1\n"); + sb.p("call #calloc"); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java new file mode 100644 index 00000000..d9056be9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java @@ -0,0 +1,39 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class NotX86 extends MachConcreteNode implements MachNode { + NotX86(NotNode not) { super(not); } + @Override public String op() { return "not"; } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.RMASK; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } + + @Override public void encoding( Encoding enc ) { + assert !(in(1) instanceof NotNode); // Cleared out by peeps + assert !(in(1) instanceof BoolNode); // Cleared out by peeps + short dst = enc.reg(this ); + short src = enc.reg(in(1)); + + // Pre-zero using XOR dst,dst; since zero'd will not have a + // byte-dependency from the setz. Can skip REX is dst is low 8, makes + // this a 32b xor, which will also zero the high bits. + if( dst >= 8 ) enc.add1(x86_64_v2.rex(dst, dst, 0)); + enc.add1(0x33); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst)); + + // test rdi,rdi + enc.add1(x86_64_v2.rex(src, src, 0)); + enc.add1(0x85); + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, src, src)); + + // setz (sete dil) + enc.add1(x86_64_v2.rex(dst, 0, 0)); + enc.add1(0x0F); + enc.add1(0x94); + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, 0)); + } + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrIX86.java new file mode 100644 index 00000000..15f4824d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrIX86.java @@ -0,0 +1,11 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.node.Node; + +public class OrIX86 extends ImmX86 { + OrIX86( Node add, int imm ) { super(add,imm); } + @Override public String op() { return "ori"; } + @Override public String glabel() { return "|"; } + @Override int opcode() { return 0x81; } + @Override int mod() { return 1; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrX86.java new file mode 100644 index 00000000..bc8f0ea8 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrX86.java @@ -0,0 +1,11 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.node.Node; + +public class OrX86 extends RegX86 { + OrX86( Node add ) { super(add); } + @Override public String op() { return "or"; } + @Override public String glabel() { return "|"; } + @Override int opcode() { return 0x0B; } + @Override public boolean commutes() { return true; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java new file mode 100644 index 00000000..5cfdd804 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.ParmNode; + +public class ParmX86 extends ParmNode implements MachNode { + final RegMask _rmask; + ParmX86( ParmNode parm ) { + super(parm); + _rmask = x86_64_v2.callInMask(fun().sig(),_idx,1/*RPC*/); + } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return _rmask; } + @Override public void encoding( Encoding enc ) { } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java new file mode 100644 index 00000000..046c7b4c --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java @@ -0,0 +1,15 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.ProjNode; + +public class ProjX86 extends ProjNode implements MachNode { + ProjX86( ProjNode p ) { super(p); } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { + return ((MachNode)in(0)).outregmap(_idx); + } + @Override public void encoding( Encoding enc ) {} +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java new file mode 100644 index 00000000..5a475efe --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java @@ -0,0 +1,27 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public abstract class RegX86 extends MachConcreteNode { + RegX86( Node add ) { super(add); } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } + @Override public int twoAddress() { return 1; } + abstract int opcode(); + @Override public void encoding( Encoding enc ) { + // REX.W + 01 /r + short dst = enc.reg(in(1)); // src1 + short src = enc.reg(in(2)); // src2 + + enc.add1(x86_64_v2.rex(dst, src, 0)); + enc.add1(opcode()); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } + // General form: "add dst += src" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" ").p(glabel()).p("= ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java new file mode 100644 index 00000000..a35d43a2 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java @@ -0,0 +1,19 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; + +public class RetX86 extends ReturnNode implements MachNode { + RetX86( ReturnNode ret, FunNode fun ) { super(ret, fun); fun.setRet(this); } + @Override public void encoding( Encoding enc ) { + int sz = fun()._frameAdjust; + if( sz != 0 ) { + enc.add1( x86_64_v2.REX_W ).add1( x86_64_v2.imm8(sz) ? 0x83 : 0x81 ); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0b000, x86_64_v2.RSP) ); + if( x86_64_v2.imm8(sz) ) enc.add1(sz); + else enc.add4(sz); + } + enc.add1(0xC3); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java new file mode 100644 index 00000000..95e0c336 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java @@ -0,0 +1,39 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; + +// Arithmetic Right Shift +public class SarIX86 extends MachConcreteNode implements MachNode { + final int _imm; + SarIX86( Node sari, int imm ) { super(sari); assert x86_64_v2.imm8(imm); _inputs.pop(); _imm = imm; } + @Override public String op() { return "sari"; } + @Override public String glabel() { return ">>"; } + int opcode() { return 0xC1; } + int mod() { return 7; } + + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public int twoAddress() { return 1; } + + @Override public void encoding(Encoding enc) { + short dst = enc.reg(this); // Also src1 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1( opcode()); + + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, mod(), dst) ); + + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" ").p(glabel()).p("= #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java new file mode 100644 index 00000000..4cc8b558 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java @@ -0,0 +1,24 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class SarX86 extends RegX86 { + SarX86( Node add ) { super(add); } + @Override public String op() { return "sar"; } + @Override public String glabel() { return ">>"; } + @Override public RegMask regmap(int i) { + if (i == 1) return x86_64_v2.WMASK; + if (i == 2) return x86_64_v2.RCX_MASK; + throw Utils.TODO(); + } + @Override int opcode() { return 0xD3; } + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this ); // src1 + short src = enc.reg(in(2)); // src2 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1(opcode()); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 7, dst)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java new file mode 100644 index 00000000..177e35ab --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java @@ -0,0 +1,55 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +// Corresponds to the x86 instruction "sete && setne". +// Use result of comparison without jump. +public class SetX86 extends MachConcreteNode implements MachNode { + final String _bop; // One of <,<=,== + final boolean _unsigned; + // Constructor expects input is an X86 and not an Ideal node. + SetX86( Node cmp, String bop, boolean unsigned ) { + super(cmp); + _inputs.setLen(1); // Pop the cmp inputs + // Replace with the matched cmp + _inputs.push(cmp); + _bop = bop; + _unsigned = unsigned; + } + @Override public String op() { return "set"+_bop; } + @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.FLAGS_MASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + + @Override public void encoding( Encoding enc ) { + // REX + 0F 94 + short dst = enc.reg(this ); + + // Optional rex, for dst + if( dst >= 4 ) enc.add1(x86_64_v2.rex(0, dst, 0, false)); + enc.add1(0x0F); // opcode + enc.add1(switch (_bop) { + case "==" -> 0x94; // SETE + case "<" -> _unsigned ? 0x92 : 0x9C; // SETB /SETL + case "<=" -> _unsigned ? 0x96 : 0x9E; // SETBE/SETLE + case ">=" -> _unsigned ? 0x93 : 0x9D; // SETAE/SETGE + case ">" -> _unsigned ? 0x97 : 0x9F; // SETA /SETG + default -> throw Utils.TODO(); + }); + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0, dst)); + + // low 8 bites are set, now zero extend for next instruction + if( dst >= 4 ) enc.add1(x86_64_v2.rex(dst, dst, 0, false)); + enc.add1(0x0F); // opcode + enc.add1(0xB6); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst)); + } + + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)); + String src = code.reg(in(1)); + if( src!="flags" ) sb.p(" = ").p(src); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java new file mode 100644 index 00000000..f7b2f28a --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java @@ -0,0 +1,39 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; + +public class ShlIX86 extends MachConcreteNode implements MachNode { + final int _imm; + ShlIX86( Node shli, int imm ) { + super(shli); + assert x86_64_v2.imm8(imm); + _inputs.pop(); // Pop constant input off + _imm = imm; + } + public int opcode() { return 0xC1; } + public int mod() { return 4; } + + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public int twoAddress() { return 1; } + + @Override public String op() { return "shli"; } + @Override public String glabel() { return "<<"; } + @Override public void encoding(Encoding enc) { + short dst = enc.reg(this); // Also src1 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1( opcode()); + + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, mod(), dst) ); + + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" ").p(glabel()).p("= #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java new file mode 100644 index 00000000..5fee72d9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java @@ -0,0 +1,24 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class ShlX86 extends RegX86 { + ShlX86( Node add ) { super(add); } + @Override public String op() { return "shl"; } + @Override public String glabel() { return "<<"; } + @Override public RegMask regmap(int i) { + if (i == 1) return x86_64_v2.WMASK; + if (i == 2) return x86_64_v2.RCX_MASK; + throw Utils.TODO(); + } + @Override int opcode() { return 0xD3; } + @Override public final void encoding( Encoding enc ) { + short dst = enc.reg(this ); // src1 + short src = enc.reg(in(2)); // src2 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1(opcode()); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 4, dst)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java new file mode 100644 index 00000000..7e0378b1 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java @@ -0,0 +1,34 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; + +public class ShrIX86 extends MachConcreteNode implements MachNode { + final int _imm; + ShrIX86( Node shri, int imm ) { super(shri); assert x86_64_v2.imm8(imm); _inputs.pop(); _imm = imm; } + @Override public String op() { return "shri"; } + @Override public String glabel() { return ">>>"; } + int opcode() { return 0xC1; } + int mod() { return 5; } + + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public int twoAddress() { return 1; } + + @Override public void encoding(Encoding enc) { + short dst = enc.reg(this); // Also src1 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1( opcode()); + + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, mod(), dst) ); + + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" ").p(glabel()).p("= #").p(_imm); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java new file mode 100644 index 00000000..67dcf055 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java @@ -0,0 +1,24 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; + +public class ShrX86 extends RegX86 { + ShrX86( Node add ) { super(add); } + @Override public String op() { return "shr"; } + @Override public String glabel() { return ">>>"; } + @Override public RegMask regmap(int i) { + if (i == 1) return x86_64_v2.WMASK; + if (i == 2) return x86_64_v2.RCX_MASK; + throw Utils.TODO(); + } + @Override int opcode() { return 0xD3; } + @Override public final void encoding( Encoding enc ) { + short dst = enc.reg(this ); // src1 + short src = enc.reg(in(2)); // src2 + enc.add1(x86_64_v2.rex(0, dst, 0)); + enc.add1(opcode()); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 5, dst)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java new file mode 100644 index 00000000..4a14240a --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java @@ -0,0 +1,107 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.FunNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.SplitNode; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; + +public class SplitX86 extends SplitNode { + SplitX86( String kind, byte round ) { super(kind,round, new Node[2]); } + @Override public String op() { return "mov"; } + @Override public RegMask regmap(int i) { return x86_64_v2.SPLIT_MASK; } + @Override public RegMask outregmap() { return x86_64_v2.SPLIT_MASK; } + + // Need to handle 8 cases: . reg->reg, reg->xmm, reg->flags, xmm->reg, xmm->xmm, xmm->flags, flags->reg, flags->xmm, + // flags->flags. + @Override public void encoding( Encoding enc ) { + // REX.W + 8B /r MOV r64, r/m64 + short dst = enc.reg(this ); + short src = enc.reg(in(1)); + if( dst == x86_64_v2.FLAGS ) { + // mov reg, flags + // push rcx + // popf (Pop the top of the stack into the FLAGS register) + // 50+rd PUSH r64 + x86_64_v2.rexF(0,src,0,false,enc); + enc.add1(0x50 + src); + // popf + enc.add1(0x9D); + return; + } + if( src == x86_64_v2.FLAGS ) { + // mov flags, reg + // pushf; pop reg + enc.add1(0x9C); + // 58+ rd POP r64 + x86_64_v2.rexF(0,dst,0,false, enc); + enc.add1(0x58 + dst); + return; + } + + // Flag for being either XMM or stack + boolean dstX = dst >= x86_64_v2.XMM_OFFSET; + boolean srcX = src >= x86_64_v2.XMM_OFFSET; + + // Stack spills + if( dst >= x86_64_v2.MAX_REG ) { + int off = enc._fun.computeStackOffset(enc._code,dst); + if( src >= x86_64_v2.MAX_REG ) { + // Rare stack-stack move. push [RSP+soff]; pop [RSP+doff] + int soff = enc._fun.computeStackOffset(enc._code,src); + enc.add1(0xFF); + x86_64_v2.indirectAdr(0, (short)-1/*index*/, (short)x86_64_v2.RSP, soff, 6, enc); + enc.add1(0x8F); + x86_64_v2.indirectAdr(0, (short)-1/*index*/, (short)x86_64_v2.RSP, off, 0, enc); + return; + } + StoreX86.encVal(enc, srcX ? TypeFloat.F64 : TypeInteger.BOT, (short)x86_64_v2.RSP, (short)-1/*index*/, src, off, 0); + return; + } + if( src >= x86_64_v2.MAX_REG ) { + int off = enc._fun.computeStackOffset(enc._code,src); + LoadX86.enc(enc, dstX ? TypeFloat.F64 : TypeInteger.BOT, dst, (short)x86_64_v2.RSP, (short)-1, off, 0); + return; + } + + // reg-reg move. Adjust numbering for GPR vs FPR reg set + if( dstX ) dst -= (short) x86_64_v2.XMM_OFFSET; + if( srcX ) src -= (short) x86_64_v2.XMM_OFFSET; + + // 0x66 if moving between register classes + if( dstX ^ srcX ) enc.add1(0x66); + if( !dstX && srcX ) + { short tmp=src; src=dst; dst=tmp; } + enc.add1(x86_64_v2.rex(dst, src, 0)); + + // pick opcode based on regs + if( !dstX && !srcX ) { + // reg->reg (MOV r64, r/m64) + enc.add1(0x8B); + } else if( dstX && srcX ) { + // xmm->xmm (NP 0F 28 /r MOVAPS xmm1, xmm2/m128) + enc.add1(0x0F); + enc.add1(0x28); + } else if( dstX && !srcX ) { + // reg->xmm (66 REX.W 0F 6E /r MOVQ xmm, r/m64) + enc.add1(0x0F); + enc.add1(0x6E); + } else if( !dstX && srcX ) { + // xmm->reg(66 0F 7E /r MOVQ r/m64, xmm) + enc.add1(0x0F); + enc.add1(0x7E); + } + + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } + + // General form: "mov dst = src" + @Override public void asm(CodeGen code, SB sb) { + FunNode fun = code._encoding==null ? null : code._encoding._fun; + sb.p(code.reg(this,fun)).p(" = ").p(code.reg(in(1),fun)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java new file mode 100644 index 00000000..4403b02b --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java @@ -0,0 +1,85 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.StoreNode; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; +import java.util.BitSet; + +public class StoreX86 extends MemOpX86 { + StoreX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) { + super(st,st, base, idx, off, scale, imm, val); + } + @Override public String op() { return "st"+_sz; } + @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { + Node val = val(); + sb.append(".").append(_name).append("="); + if( val==null ) sb.append(_imm); + else val._print0(sb,visited); + return sb.append(";"); + } + // Register mask allowed as a result. 0 for no register. + @Override public RegMask outregmap() { return null; } + @Override public void encoding( Encoding enc ) { + // REX.W + C7 /0 id MOV r/m64, imm32 | + // REX.W + 89 /r MOV r/m64, r64 + short ptr = enc.reg(ptr()); + short idx = enc.reg(idx()); + short src = enc.reg(val()); + + if( src == -1 ) { + int log = _declaredType.log_size(); + x86_64_v2.rexF(-1, ptr, idx, log==3, enc); + switch( log ) { + case 0: enc .add1(0xC6); break; + case 1: enc.add1(0x66).add1(0xC7); break; + case 2: enc .add1(0xC7); break; + case 3: enc .add1(0xC7); break; + } + x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src, enc); + switch( log ) { + case 0: enc.add1(_imm); break; + case 1: enc.add2(_imm); break; + case 2: enc.add4(_imm); break; + case 3: enc.add4(_imm); break; // Limit of a 4 byte immediate + } + } else { + encVal(enc,_declaredType,ptr,idx,src,_off,_scale); + } + } + + // Non-immediate encoding + static void encVal( Encoding enc, Type decl, short ptr, short idx, short src, int off, int scale ) { + int log = decl.log_size(); + // Float reg being stored + if( src >= x86_64_v2.XMM_OFFSET ) { + src -= (short)x86_64_v2.XMM_OFFSET; + assert log == 2 || log == 3; + enc.add1( log==2 ? 0xF3 : 0xF2 ); + x86_64_v2.rexF(src,ptr,idx,false,enc); + enc.add1(0x0F).add1(0x11); + } else { + // byte stores from sil, dil, bpl, spl need a rex + if( log == 0 && src >= x86_64_v2.RSP ) enc.add1(x86_64_v2.rex(src,ptr,idx,false)); + else x86_64_v2.rexF(src,ptr,idx,log==3,enc); + switch( log ) { + case 0: enc .add1(0x88); break; + case 1: enc.add1(0x66).add1(0x89); break; + case 2: enc .add1(0x89); break; + case 3: enc .add1(0x89); break; + } + } + x86_64_v2.indirectAdr(scale, idx, ptr, off, src, enc); + } + + + // General form: "stN [base + idx<<2 + 12],val" + @Override public void asm(CodeGen code, SB sb) { + asm_address(code,sb).p(","); + if( val()==null ) sb.p("#").p(_imm); + else sb.p(code.reg(val())); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java new file mode 100644 index 00000000..b6530a87 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java @@ -0,0 +1,31 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; + +public class SubFX86 extends MachConcreteNode implements MachNode { + SubFX86( Node subf) { super(subf); } + @Override public String op() { return "subf"; } + @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.XMASK; } + @Override public RegMask outregmap() { return x86_64_v2.XMASK; } + @Override public int twoAddress() { return 1; } + + @Override public void encoding( Encoding enc ) { + // F2 0F 5C /r SUBSD xmm1, xmm2/m64 + short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET); + short src = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET); + // Fopcode + enc.add1(0xF2); + // rex prefix must come next (REX.W is not set) + x86_64_v2.rexF(dst, src, 0, false, enc); + + enc.add1(0x0F).add1(0x5C); + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); + } + + // General form: "subf dst -= src" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" -= ").p(code.reg(in(2))); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubX86.java new file mode 100644 index 00000000..8da34bf5 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubX86.java @@ -0,0 +1,10 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.node.Node; + +public class SubX86 extends RegX86 { + SubX86( Node add ) { super(add); } + @Override public String op() { return "sub"; } + @Override public String glabel() { return "-"; } + @Override int opcode() { return 0x2B; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java new file mode 100644 index 00000000..359b6d83 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java @@ -0,0 +1,67 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.cpus.riscv.riscv; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; + +// Function constants +public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize { + TFPX86( ConstantNode con ) { super(con); } + @Override public String op() { + return _con == Type.NIL ? "xor" : "ldx"; + } + @Override public boolean isClone() { return true; } + @Override public Node copy() { return new TFPX86(this); } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + // Zero-set uses XOR kills flags + @Override public RegMask killmap() { + return _con == Type.NIL ? x86_64_v2.FLAGS_MASK : null; + } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); + // Short form for zero + if( _con==Type.NIL ) { + // XOR dst,dst. Can skip REX is dst is low 8, makes this a 32b + // xor, which will also zero the high bits. + if( dst >= 8 ) enc.add1(x86_64_v2.rex(dst, dst, 0)); + enc.add1(0x33); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst)); + return; + } + + // lea to load function pointer address + // lea rax, [rip+disp32] + enc.relo(this); + enc.add1(x86_64_v2.rex(dst, 0, 0)); + enc.add1(0x8D); // opcode + enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0b101)); + enc.add4(0); + } + + @Override public byte encSize(int delta) { + return 7; + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + enc.patch4(opStart + 3, delta - 7); + } + + // Human-readable form appended to the SB. Things like the encoding, + // indentation, leading address or block labels not printed here. + // Just something like "ld4\tR17=[R18+12] // Load array base". + // General form: "op\tdst=src+src" + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + if( _con == Type.NIL ) + sb.p(reg).p(",").p(reg); + else + _con.print(sb.p(reg).p(" = #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java new file mode 100644 index 00000000..c23f6c5f --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java @@ -0,0 +1,39 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.util.SB; + +public class TMPX86 extends ConstantNode implements MachNode, RIPRelSize{ + TMPX86(ConstantNode con ) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public boolean isClone() { return true; } + @Override public Node copy() { return new TMPX86(this); } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); + x86_64_v2.rexF(dst, 0, 0, true, enc); + enc.add1(0x8D).add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0b101)).add4(0); + int opLen = 1/*rexF*/+1/*opcode 0x8D*/+1/*modrm*/+4/*pc rel offset*/; + // Base of constant array + TypeMemPtr tmp = (TypeMemPtr)_con; + int baseOff = tmp._obj.aryBase(); + enc.largeConstant(this,tmp._obj,opLen-baseOff,2/*ELF encoding PC32*/); + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { return (byte)7; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + enc.patch4(opStart+opLen-4,delta-opLen); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" = #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java new file mode 100644 index 00000000..92d2a87d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java @@ -0,0 +1,54 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.BitSet; + +// unconditional jump +public class UJmpX86 extends CFGNode implements MachNode, RIPRelSize { + UJmpX86() { } + @Override public String op() { return "jmp"; } + @Override public String label() { return op(); } + @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { + return sb.append("jmp "); + } + @Override public RegMask regmap(int i) {return null; } + @Override public RegMask outregmap() { return null; } + @Override public Type compute() { throw Utils.TODO(); } + @Override public Node idealize() { throw Utils.TODO(); } + @Override public void encoding( Encoding enc ) { + enc.jump(this,uctrl()); + // Short-form jump + enc.add1(0xEB).add1(0); + //// E9 cd JMP rel32 + //enc.add1(0xE9).add4(0); + } + + // Delta is from opcode start, but X86 measures from the end of the 2-byte encoding + @Override public byte encSize(int delta) { return (byte)(x86_64_v2.imm8(delta-2) ? 2 : 5); } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + byte[] bits = enc.bits(); + if( opLen==2 ) { + assert bits[opStart] == (byte)0xEB; + delta -= 2; // Offset from opcode END + assert (byte)delta==delta; + bits[opStart+1] = (byte)delta; + } else { + assert bits[opStart] == (byte)0xEB; + bits[opStart] = (byte)0xE9; // Long form + delta -= 5; // Offset from opcode END + enc.patch4(opStart+1,delta); + } + } + + @Override public void asm(CodeGen code, SB sb) { + CFGNode target = uctrl(); + //assert target.nOuts() > 1; // Should optimize jmp to empty targets + sb.p(label(target)); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorIX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorIX86.java new file mode 100644 index 00000000..2d989a50 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorIX86.java @@ -0,0 +1,11 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.node.Node; + +public class XorIX86 extends ImmX86 { + XorIX86( Node add, int imm ) { super(add,imm); } + @Override public String op() { return "xori"; } + @Override public String glabel() { return "^"; } + @Override int opcode() { return 0x81; } + @Override int mod() { return 6; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java new file mode 100644 index 00000000..86703903 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java @@ -0,0 +1,11 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.node.Node; + +public class XorX86 extends RegX86 { + XorX86( Node add ) { super(add); } + @Override public String op() { return "xor"; } + @Override public String glabel() { return "^"; } + @Override int opcode() { return 0x33; } + @Override public boolean commutes() { return true; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java new file mode 100644 index 00000000..026e12aa --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java @@ -0,0 +1,649 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; + +public class x86_64_v2 extends Machine { + public x86_64_v2( CodeGen code ) {} + // X86-64 V2. Includes e.g. SSE4.2 and POPCNT. + @Override public String name() { return "x86_64_v2"; } + @Override public int defaultOpSize() { return 5; } + + public static final int RAX = 0, RCX = 1, RDX = 2, RBX = 3, RSP = 4, RBP = 5, RSI = 6, RDI = 7; + public static final int R08 = 8, R09 = 9, R10 = 10, R11 = 11, R12 = 12, R13 = 13, R14 = 14, R15 = 15; + + public static final int XMM0 = 16, XMM1 = 17, XMM2 = 18, XMM3 = 19, XMM4 = 20, XMM5 = 21, XMM6 = 22, XMM7 = 23; + public static final int XMM8 = 24, XMM9 = 25, XMM10 = 26, XMM11 = 27, XMM12 = 28, XMM13 = 29, XMM14 = 30, XMM15 = 31; + public static final int FLAGS = 32; + public static final int MAX_REG = 33; + public static final int RPC = 33; + + // Human-readable name for a register number, e.g. "RAX". + public static final String[] REGS = new String[]{ + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8" , "r9" , "r10", "r11", "r12", "r13", "r14", "r15", + "xmm0", "xmm1", "xmm2" , "xmm3" , "xmm4" , "xmm5" , "xmm6" , "xmm7" , + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", + "flags", + }; + // Hard crash for bad register number, fix yer bugs! + @Override public String[] regs() { return REGS; } + + public static int XMM_OFFSET = 16; + // General purpose register mask: pointers and ints, not floats + static final long RD_BITS = 0b1111111111111111L; // All the GPRs + static RegMask RMASK = new RegMask(RD_BITS); + // No RSP in the *write* general set. + static final long WR_BITS = 0b1111111111101111L; // All the GPRs minus RSP + static RegMask WMASK = new RegMask(WR_BITS); + // Xmm register mask + static final long FP_BITS = 0b1111111111111111L << XMM0; // All the XMMs + static RegMask XMASK = new RegMask(FP_BITS); + static RegMask FLAGS_MASK = new RegMask(FLAGS); + static RegMask RPC_MASK = new RegMask(RPC); + // Divide mask: exclude RDX:RAX + static RegMask DIV_MASK = new RegMask(RD_BITS & ~(1L<<RAX) & ~(1L<<RDX)); + + static final long SPILLS = -(1L << MAX_REG); + static final RegMask SPLIT_MASK = new RegMask(WR_BITS | FP_BITS /* | (1L<<FLAGS)*/ | SPILLS, -1L ); + + // Load/store mask; both GPR and FPR + static RegMask MEM_MASK = new RegMask(WR_BITS | FP_BITS); + + public static RegMask RAX_MASK = new RegMask(RAX); + public static RegMask RCX_MASK = new RegMask(RCX); + public static RegMask RDX_MASK = new RegMask(RDX); + public static RegMask RDI_MASK = new RegMask(RDI); + public static RegMask R08_MASK = new RegMask(R08); + public static RegMask R09_MASK = new RegMask(R09); + public static RegMask RSI_MASK = new RegMask(RSI); + + public static RegMask XMM0_MASK = new RegMask(XMM0); + + // Encoding + public static int REX = 0x40; + public static int REX_W = 0x48; + public static int REX_WR = 0x4C; + public static int REX_WRB= 0x4D; + public static int REX_WB = 0x49; + + public enum MOD { + INDIRECT, // [mem] + INDIRECT_disp8, // [mem + 0x12] + INDIRECT_disp32, // [mem + 0x12345678] + DIRECT, // mem + }; + + // opcode included here + // 0F 84 cd JE rel32 + // 0F 85 cd JNE rel32 + // 0F 8F cd JG rel32 + // 0F 8C cd JL rel32 + // 0F 8E cd JLE rel32 + // 0F 8D cd JGE rel32 + static public int jumpop(String op) { + return switch (op) { + case "==" -> 0x84; + case "!=" -> 0x85; + case ">" -> 0x8F; + case "<" -> 0x8C; + case "<=" -> 0x8E; + case ">=" -> 0x8D; + default -> throw new IllegalArgumentException("Too many arguments"); + }; + } + + public static int modrm(MOD mod, int reg, int m_r) { + if( reg == -1 ) reg=0; // Missing reg in this flavor + // combine all the bits + assert 0 <= reg && reg < 16; + assert 0 <= m_r && m_r < 16; + return (mod.ordinal() << 6) | ((reg & 0x07) << 3) | m_r & 0x07; + } + + // 00 000 000 + // same bit-layout as modrm + public static int sib(int scale, int index, int base) { + assert 0 <= base && base < 16; + assert 0 <= index && index < 16; + return (scale << 6) | ((index & 0x07) << 3) | base & 0x07; + } + + // reg1 is reg(R) + // reg2 is r/mem(B) + // reg3 is X(index) + // reg4 is X(base) + + // 0 denotes no direct register + public static int rex(int reg, int ptr, int idx, boolean wide) { + // assuming 64 bit by default so: 0100 1000 + assert -1 <= reg && reg < 16; + assert -1 <= ptr && ptr < 16; + assert -1 <= idx && idx < 16; + + int rex = wide ? REX_W : REX; + if( 8 <= reg ) rex |= 0b00000100; // REX.R + if( 8 <= ptr ) rex |= 0b00000001; // REX.B + if( 8 <= idx ) rex |= 0b00000010; // REX.X + return rex; + } + + public static int rex(int reg, int ptr, int idx) { + return rex(reg, ptr, idx, true); + } + + // rex for floats. Return size (0 or 1) + // don't need to use REX if 0x40. + public static byte rexF(int reg, int ptr, int idx, boolean wide, Encoding enc) { + int rex = rex(reg, ptr, idx, wide); + if (rex == REX) return 0; + enc.add1(rex); + return 1; + } + // Function used for encoding indirect memory addresses + // Does not always generate SIB byte e.g index == -1. + // -1 denotes empty value, not set - note 0 is different from -1 as it can represent rax. + // Looks for best mod locally + public static void indirectAdr( int scale, short index, short base, int offset, int reg, Encoding enc ) { + // Assume indirect + assert 0 <= base && base < 16; + assert -1 <= index && index < 16 && index != RSP; + + MOD mod = MOD.INDIRECT; + // is 1 byte enough or need more? + if( offset != 0 ) + mod = imm8(offset) + ? MOD.INDIRECT_disp8 + : MOD.INDIRECT_disp32; + + if( mod == MOD.INDIRECT && (base == RBP || base == R13) ) { + mod = MOD.INDIRECT_disp8; + } else if( index == -1 && (base == RSP || base == R12) ) { + index = RSP; + } + + if( index == -1 ) { + enc.add1(modrm(mod, reg, base)); + } else { + enc.add1(modrm(mod, reg, x86_64_v2.RSP)); + enc.add1(sib(scale, index, base)); + } + + if( mod == MOD.INDIRECT_disp8 ) { + enc.add1(offset); + } else if( mod == MOD.INDIRECT_disp32 ) { + enc.add4(offset); + } + } + + + // Limit of float args passed in registers + static RegMask[] XMMS8 = new RegMask[]{ + new RegMask(XMM0), new RegMask(XMM1), new RegMask(XMM2), new RegMask(XMM3), + new RegMask(XMM4), new RegMask(XMM5), new RegMask(XMM6), new RegMask(XMM7), + }; + + // Map from function signature and argument index to register. + // Used to set input registers to CallNodes, and ParmNode outputs. + @Override public RegMask callArgMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); } + static RegMask callInMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { + if( idx==0 ) return RPC_MASK; + if( idx==1 ) return null; + if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence + return switch( CodeGen.CODE._callingConv ) { + case "SystemV" -> callSys5 (tfp,idx,maxArgSlot); + case "Win64" -> callWin64(tfp,idx,maxArgSlot); + default -> throw Utils.TODO(); + }; + } + + // Maximum stack args used by this signature + @Override public short maxArgSlot( TypeFunPtr tfp ) { + return switch( CodeGen.CODE._callingConv ) { + case "SystemV" -> maxArgSlotSys5 (tfp); + case "Win64" -> maxArgSlotWin64(tfp); + default -> throw Utils.TODO(); + }; + } + + // Win64 - max *4* args in registers of all kinds; after that on stack. + // Stack args land in increasing memory order with empty/mirror slots for + // every register. + // + // foo( int i0, flt f1, int i2, flt f3, int i4, flt f5, int i6, ... ) + // + // -- Prior Frame -- + // i6 + // f5 + // i4 + // empty mirror, XMM3= f3 + // empty mirror, R08 = i2 + // empty mirror, XMM1= f1 + // empty mirror, RCX = i0 + // -- Caller Frame; 16b align -- + // RPC + // PAD/ALIGN + // -- Callee Frame; 16b align -- + static RegMask[] WIN64_CALL = new RegMask[] { + RCX_MASK, + RDX_MASK, + R08_MASK, + R09_MASK, + }; + + static RegMask callWin64(TypeFunPtr tfp, int idx, int maxArgSlot ) { + // idx 2,3,4,5 passed in registers, with stack slot mirrors. + // idx >= 6 passed on stack, starting at slot#1 (#0 reserved for RPC). + if( idx >= 6 ) + return new RegMask(MAX_REG+maxArgSlot+(idx-2)); + return tfp.arg(idx-2) instanceof TypeFloat + ? XMMS8 [idx-2] + : WIN64_CALL[idx-2]; + } + static short maxArgSlotWin64(TypeFunPtr tfp) { + return (short)tfp.nargs(); + } + + // Sys5: max 6 GPRs and 8 FPRS filled first. Extra args land in increasing + // memory order as needed - no mirror space. + // + // foo( int i0, flt f1, int i2, flt f3, int i4, flt f5, int i6, ... ) + // RDI =i0, RSI =i2, RDX =i4, RCX =i6, R08 =i8, R09 =i10 + // XMM0=f1, XMM1=f3, XMM2=f5, XMM3=f7, XMM4=f9, XMM5=f11, XMM6=f13, XMM7=f15 + // + // -- Prior Frame -- + // f18 + // i18 + // f17 + // i16 + // i14 + // i12 + // -- Caller Frame; 16b align -- + // RPC + // PAD/ALIGN + // -- Callee Frame; 16b align -- + // SystemV(param passing) + static RegMask[] SYS5_CALL = new RegMask[] { + RDI_MASK, + RSI_MASK, + RDX_MASK, + RCX_MASK, + R08_MASK, + R09_MASK, + }; + + static RegMask callSys5(TypeFunPtr tfp, int idx, int maxArgSlot ) { + // First 6 integers passed in registers: rdi,rsi,rdx,rcx,r08,r09 + // First 8 floats passed in registers: xmm0-xmm7 + int icnt=0, fcnt=0; // Count of ints, floats + for( int i=2; i<idx; i++ ) { + if( tfp.arg(i-2) instanceof TypeFloat ) fcnt++; + else icnt++; + } + int nstk = Math.max(icnt-6,0)+Math.max(fcnt-8,0); + return tfp.arg(idx-2) instanceof TypeFloat + ? fcnt<8 ? XMMS8 [fcnt] : new RegMask(MAX_REG+maxArgSlot+nstk) + : icnt<6 ? SYS5_CALL[icnt] : new RegMask(MAX_REG+maxArgSlot+nstk); + } + static short maxArgSlotSys5(TypeFunPtr tfp) { + int icnt=0, fcnt=0; // Count of ints, floats + for( int i=0; i<tfp.nargs(); i++ ) { + if( tfp.arg(i) instanceof TypeFloat ) fcnt++; + else icnt++; + } + int nstk = Math.max(icnt-6,0)+Math.max(fcnt-8,0); + return (short)nstk; + } + + static final long SYSTEM5_CALLER_SAVE = + (1L << RAX) | (1L << RCX) | (1L << RDX) | + (1L << RDI) | (1L << RSI) | + (1L << R08) | (1L << R09) | (1L << R10) | (1L << R11) | + (1L << FLAGS) | // Flags are killed + // All FP regs are killed + FP_BITS; + + static final long WIN64_CALLER_SAVE = + (1L<< RAX) | (1L<< RCX) | (1L<< RDX) | + (1L<< R08) | (1L<< R09) | (1L<< R10) | (1L<< R11) | + (1L<<FLAGS)| // Flags are killed + // Only XMM0-XMM5 are killed; XMM6-XMM15 are preserved + (1L<<XMM0) | (1L<<XMM1) | (1L<<XMM2) | (1L<<XMM3) | + (1L<<XMM4) | (1L<<XMM5) ; + + @Override public long callerSave() { + return switch (CodeGen.CODE._callingConv) { + case "SystemV" -> SYSTEM5_CALLER_SAVE; + case "Win64" -> WIN64_CALLER_SAVE; + default -> throw new IllegalArgumentException("Unknown calling convention: " + CodeGen.CODE._callingConv); + }; + } + @Override public long neverSave() { return 1L<<RSP; } + @Override public RegMask retMask( TypeFunPtr tfp ) { + return tfp.ret() instanceof TypeFloat ? XMM0_MASK : RAX_MASK; + } + @Override public int rpc() { return RPC; } + + + // Create a split op; any register to any register, including stack slots + @Override public SplitNode split(String kind, byte round, LRG lrg) { + return new SplitX86(kind, round); + } + + // Return a MachNode unconditional branch + @Override public CFGNode jump() { + return new UJmpX86(); + } + + // Instruction selection + @Override + public Node instSelect(Node n) { + return switch (n) { + case AddFNode addf -> addf(addf); + case AddNode add -> add(add); + case AndNode and -> and(and); + case BoolNode bool -> cmp(bool); + case CProjNode c -> new CProjNode(c); + case CallEndNode cend -> new CallEndMach(cend); + case CallNode call -> call(call); + case CastNode cast -> new CastMach(cast); + case ConstantNode con -> con(con); + case DivFNode divf -> new DivFX86(divf); + case DivNode div -> new DivX86(div); + case FunNode fun -> new FunX86(fun); + case IfNode iff -> jmp(iff); + case LoadNode ld -> ld(ld); + case MemMergeNode mem -> new MemMergeNode(mem); + case MinusNode neg -> new NegX86(neg); + case MulFNode mulf -> new MulFX86(mulf); + case MulNode mul -> mul(mul); + case NewNode nnn -> new NewX86(nnn); + case NotNode not -> new NotX86(not); + case OrNode or -> or(or); + case ParmNode parm -> new ParmX86(parm); + case PhiNode phi -> new PhiNode(phi); + case ProjNode prj -> prj(prj); + case ReadOnlyNode read-> new ReadOnlyMach(read); + case ReturnNode ret -> new RetX86(ret, ret.fun()); + case SarNode sar -> sar(sar); + case ShlNode shl -> shl(shl); + case ShrNode shr -> shr(shr); + case StartNode start -> new StartNode(start); + case StopNode stop -> new StopNode(stop); + case StoreNode st -> st(st); + case SubFNode subf -> new SubFX86(subf); + case SubNode sub -> sub(sub); + case ToFloatNode tfn -> i2f8(tfn); + case XCtrlNode x -> new ConstantNode(Type.XCONTROL); + case XorNode xor -> xor(xor); + + case LoopNode loop -> new LoopNode(loop); + case RegionNode region -> new RegionNode(region); + default -> throw Utils.TODO(); + }; + } + + public static boolean imm8( long imm ) { return -128 <= imm && imm <= 127; } + + public static boolean imm32( long imm ) { return (int)imm==imm; } + + // Attempt a full LEA-style break down. + private Node add(AddNode add) { + Node lhs = add.in(1); + Node rhs = add.in(2); + if( lhs instanceof LoadNode ld && ld.nOuts() == 1 && ld._declaredType.log_size() >= 3) + return new AddMemX86(add, address(ld), ld.ptr(), idx, off, scale, 0, rhs); + +// if(rhs instanceof LoadNode ld && ld.nOuts() == 1 && ld._declaredType.log_size() >= 3) { +// throw Utils.TODO(); // Swap load sides +// } + + // Attempt a full LEA-style break down. + // Returns one of AddX86, AddIX86, LeaX86, or LHS + if( rhs instanceof ConstantNode off2 && off2._con instanceof TypeInteger toff ) { + long imm = toff.value(); + assert imm!=0; // Folded in peeps + if( (int)imm != imm ) // Full 64bit immediate + return new AddX86(add); + // Now imm <= 32bits + if( lhs instanceof AddNode ladd ) + // ((base + (idx << scale)) + off) + return _lea(add, ladd.in(1), ladd.in(2), (int)imm); + if( lhs instanceof ShlNode shift ) + // (idx << scale) + off; no base + return _lea(add, null, shift, (int)imm); + + // lhs + rhs1 + return new AddIX86(add, (int)imm); + } + return _lea(add, lhs, rhs, 0); + } + + + private Node addf(AddFNode addf) { + if(addf.in(1) instanceof LoadNode ld && ld.nOuts() == 1) + return new AddFMemX86(addf, address(ld), ld.ptr(), idx, off, scale, addf.in(2)); + +// if(addf.in(2) instanceof LoadNode ld && ld.nOuts() == 1) +// throw Utils.TODO(); // Swap load sides + + return new AddFX86(addf); + } + + + private Node _lea(Node add, Node base, Node idx, int off) { + int scale = 0; + if( base instanceof ShlNode && !(idx instanceof ShlNode) ) + throw Utils.TODO(); // Bug in canonicalization, should on RHS + if( idx instanceof ShlNode shift && shift.in(2) instanceof ConstantNode shfcon && + shfcon._con instanceof TypeInteger tscale && 0 <= tscale.value() && tscale.value() <= 3 ) { + idx = shift.in(1); + scale = ((int) tscale.value()); + } + // (base + idx) + off + return off == 0 && scale == 0 + ? new AddX86(add) + : new LeaX86(add, base, idx, scale, off); + } + + + private Node and(AndNode and) { + if( and.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) + return new AndIX86(and, (int)ti.value()); + return new AndX86(and); + } + + private Node call(CallNode call) { + return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp + ? new CallX86(call, tfp) + : new CallRX86(call); + } + + // Because X86 flags, a normal ideal Bool is 2 X86 ops: a "cmp" and at "setz". + // Ideal If reading from a setz will skip it and use the "cmp" instead. + private static boolean swap, unsigned; + private Node cmp( BoolNode bool ) { + swap = unsigned = false; + Node cmp = _cmp(bool); + return new SetX86(cmp, swap ? IfNode.swap(bool.op()) : bool.op(), unsigned); + } + + private Node _cmp(BoolNode bool) { + // Float variant + if( bool.isFloat() ) { + unsigned = true; + return new CmpFX86(bool); + } + Node lhs = bool.in(1); + Node rhs = bool.in(2); + + // Since cmp does not record a BOP, SetX/Jmp need to know if the CMP is swapped. + + // Vs memory + if( lhs instanceof LoadNode ld && ld.nOuts() == 1 && rhs._type.isa(ld._declaredType) ) + return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(rhs), val, false); + + // Operands swap in the encoding directly, no need for Set/Jmp to swap `bop` + if( rhs instanceof LoadNode ld && ld.nOuts() == 1 && lhs._type.isa(ld._declaredType) && + (val!=null || bool.op()=="==" || bool.op()=="!=") ) + return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(lhs), val, true ); + + // Vs immediate + if( rhs instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) + return new CmpIX86(bool, (int)ti.value(), false); + + // Operand swap compare; Set and Jmp need to swap `bop` + if( lhs instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) + return new CmpIX86(bool, (int)ti.value(), swap=true); + + // x vs y + return new CmpX86(bool); + } + + private Node con( ConstantNode con ) { + if( !con._con.isConstant() ) + return new ConstantNode(con); // Default unknown caller inputs + return switch (con._con) { + case TypeInteger ti -> new IntX86(con); + case TypeFloat tf -> new FltX86(con); + case TypeFunPtr tfp -> new TFPX86(con); + case TypeMemPtr tmp -> new TMPX86(con); + case TypeNil tn -> throw Utils.TODO(); + // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. + case Type t -> t == Type.NIL ? new IntX86(con) : new ConstantNode(con); + }; + } + + private Node i2f8(ToFloatNode tfn) { + assert tfn.in(1)._type instanceof TypeInteger ti; + return new I2f8X86(tfn); + } + + private Node jmp(IfNode iff) { + // If/Bool combos will match to a Cmp/Set which sets flags. + // Most general arith ops will also set flags, which the Jmp needs directly. + // Loads do not set the flags, and will need an explicit TEST + String op = "!="; + if( iff.in(1) instanceof BoolNode bool ) op = swap ? IfNode.swap(bool.op()) : bool.op(); + else if( iff.in(1)==null ) op = "=="; // Never-node cutout + else iff.setDef(1, new BoolNode.NE(iff.in(1), new ConstantNode(TypeInteger.ZERO))); + return new JmpX86(iff, op); + } + + private Node ld(LoadNode ld) { + return new LoadX86(address(ld), ld.ptr(), idx, off, scale); + } + + private Node mul(MulNode mul) { + if( mul.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) + return new MulIX86(mul, (int)ti.value()); + return new MulX86(mul); + } + + private Node or(OrNode or) { + if( or.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) + return new OrIX86(or, (int)ti.value()); + return new OrX86(or); + } + + private Node prj( ProjNode prj ) { + return new ProjX86(prj); + } + + private Node sar(SarNode sar) { + if( sar.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm8(ti.value())) + return new SarIX86(sar, (int)(ti.value() & 0xff) ); + return new SarX86(sar); + } + + private Node shl(ShlNode shl) { + if( shl.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm8(ti.value())) + return new ShlIX86(shl, (int)(ti.value() & 0xff) ); + return new ShlX86(shl); + } + + private Node shr( ShrNode shr ) { + if( shr.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm8(ti.value()) ) + return new ShrIX86(shr, (int)(ti.value() & 0xff) ); + return new ShrX86(shr); + } + + private Node st( StoreNode st ) { + // Look for "*ptr op= val" + Node op = st.val(); + if( op instanceof AddNode ) { + if( op.in(1) instanceof LoadNode ld && stld_match(st,ld) ) + return new MemAddX86(address(st), st.ptr(), idx, off, scale, imm(op.in(2)), val); + if( op.in(2) instanceof LoadNode ld && stld_match(st,ld) ) + return new MemAddX86(address(st), st.ptr(), idx, off, scale, imm(op.in(1)), val); + } + return new StoreX86(address(st), st.ptr(), idx, off, scale, imm(st.val()), val); + } + private static boolean stld_match(StoreNode st, LoadNode ld ) { + return + ld.in(0) == st.in(0) && + ld.mem() == st.mem() && + ld.ptr() == st.ptr() && + ld.off() == st.off(); + } + + + private Node sub (SubNode sub ){ + return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti + ? new AddIX86(sub, (int)-ti.value()) + : new SubX86(sub); + } + + private Node xor (XorNode xor){ + if( xor.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) ) + return new XorIX86(xor, (int)ti.value()); + return new XorX86(xor); + } + + // Gather X86 addressing mode bits prior to constructing. This is a + // builder pattern, but saving the bits in a *local* *global* here to keep + // mess contained. + private static int off, scale, imm; + private static Node idx, val; + private <N extends MemOpNode > N address(N mop) { + off = scale = imm = 0; // Reset + idx = val = null; + Node base = mop.ptr(); + // Skip/throw-away a ReadOnly, only used to typecheck + if(base instanceof ReadOnlyNode read) base = read.in(1); + assert !(base instanceof AddNode) && base._type instanceof TypeMemPtr; // Base ptr always, not some derived + if(mop.off() instanceof AddNode add && add.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti) { + off = (int) ti.value(); + assert off == ti.value(); // In 32-bit range + idx = add.in(1); + if(idx instanceof ShlNode shift && shift.in(2) instanceof ConstantNode shfcon && + shfcon._con instanceof TypeInteger tscale && 0 <= tscale.value() && tscale.value() <= 3) { + idx = shift.in(1); + scale = (int) tscale.value(); + } + } else { + if(mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti) { + off = (int) ti.value(); + assert off == ti.value(); // In 32-bit range + } else { + idx = mop.off(); + } + } + return mop; + } + + private int imm( Node xval ) { + assert val == null && imm == 0; + if( xval instanceof ConstantNode con && con._con instanceof TypeInteger ti) { + val = null; + imm = (int) ti.value(); + assert imm == ti.value(); // In 32-bit range + } else { + val = xval; + } + return imm; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter24/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java new file mode 100644 index 00000000..a9f86ce8 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java @@ -0,0 +1,306 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.Encoding.Relo; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.HashSet; + +public abstract class ASMPrinter { + + public static SB print(SB sb, CodeGen code) { + if( code._cfg==null ) + return sb.p("Need _cfg set, run after GCM"); + + // instruction address + int iadr = 0; + for( int i=0; i<code._cfg._len; i++ ) + if( code._cfg.at(i) instanceof FunNode fun ) + iadr = print(iadr,sb,code,fun,i); + + // constant pool + iadr = (iadr+15)&-16; // pad to 16 + Encoding enc = code._encoding; + if( enc!=null && !enc._bigCons.isEmpty() && iadr < enc._bits.size() ) { + // radix sort the big constants by alignment + Ary<Relo>[] raligns = new Ary[5]; + for( Node op : enc._bigCons.keySet() ) { + Relo relo = enc._bigCons.get(op); + int align = relo._t.alignment(); + Ary<Relo> relos = raligns[align]==null ? (raligns[align]=new Ary<>( Relo.class)) : raligns[align]; + relos.add(relo); + } + + HashSet<Type> targets = new HashSet<>(); + sb.p("--- Constant Pool ------").nl(); + + // By alignment + for( int align = 4; align >= 0; align-- ) { + Ary<Relo> relos = raligns[align]; + if( relos == null ) continue; + for( Relo relo : relos ) { + if( targets.contains(relo._t) ) continue; + targets.add(relo._t); + sb.hex2(iadr).p(" "); + switch( relo._t ) { + case TypeTuple tt -> { + for( Type tx : tt._types ) { + pN(enc,sb,iadr,align).p(" "); + iadr += (1<<align); + } + } + + case TypeStruct ts -> { + int sz = ts.size(); + int log = 1<<align; + sz = (sz + (log -1)) & -log; // Round up final padding + for( int i=0; i<sz; i++ ) + sb.hex1(enc.read1(iadr++)); + } + + // Simple primitive (e.g. larger int, float) + default -> { + pN(enc,sb,iadr,align).fix(9-(1<<align),""); + iadr += (1<<align); + } + } + relo._t.print(sb).nl(); + } + } + } + + return sb; + } + + private static SB pN( Encoding enc, SB sb, int iadr, int log ) { + switch( log ) { + case 0: sb.hex1(enc.read1(iadr)); break; + case 1: sb.hex2(enc.read2(iadr)); break; + case 2: sb.hex4(enc.read4(iadr)); break; + case 3: sb.hex8(enc.read8(iadr)); break; + } + return sb; + } + + + private static int print(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) { + FunNode old=null; + if( code._encoding!=null ) { + old = code._encoding._fun; + code._encoding._fun = fun; // Useful printing after RA + } + // Function header + sb.nl().p("---"); + if( fun._name != null ) sb.p(fun._name).p(" "); + fun.sig().print(sb); + sb.p("---------------------------").nl(); + if( code._encoding!=null && code._encoding._padFunHeads ) + iadr = (iadr + 15)&-16; // All function entries padded to 16 align + + if( fun._frameAdjust != 0 ) + iadr = doInst(iadr,sb,code,fun,cfgidx,fun,true,true); + while( !(code._cfg.at(cfgidx) instanceof ReturnNode) ) + iadr = doBlock(iadr,sb,code,fun,cfgidx++); + + // Function separator + sb.p("---"); + fun.sig().print(sb); + sb.p("---------------------------").nl(); + if( code._encoding != null ) + code._encoding._fun = old; + return iadr; + } + + static private final int opWidth = 5; + static private final int argWidth = 30; + static int doBlock(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) { + final int encWidth = code._mach==null ? 2 : code._mach.defaultOpSize()*2; + CFGNode bb = code._cfg.at(cfgidx); + if( bb != fun && !(bb instanceof IfNode) && !(bb instanceof CallEndNode) && !(bb instanceof CallNode) && !(bb instanceof CProjNode && bb.in(0) instanceof CallEndNode )) + sb.p(label(bb)).p(":").nl(); + if( bb instanceof CallNode ) return iadr; + final boolean postAlloc = code._phase.ordinal() > CodeGen.Phase.RegAlloc.ordinal(); + final boolean postEncode= code._phase.ordinal() >=CodeGen.Phase.Encoding.ordinal(); + + boolean once=false; + for( Node n : bb.outs() ) { + if( !(n instanceof PhiNode phi) ) continue; + if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) continue; // Nothing for the hidden ones + // Post-RegAlloc phi prints all on one line + if( postAlloc ) { + if( !once ) { once=true; sb.fix(4," ").p(" ").fix(encWidth,"").p(" "); } + sb.p(phi._label).p(':').p(code.reg(phi,fun)).p(','); + } else { + // Pre-RegAlloc phi prints one line per + sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ").p(code.reg(phi,fun)); + if( phi.getClass() == PhiNode.class ) { + sb.p(" = phi( "); + for( int i=1; i<phi.nIns(); i++ ) + sb.p("N").p(phi.in(i)._nid).p(","); + sb.unchar().p(" )"); + } + sb.nl(); + } + } + if( once ) sb.unchar().nl(); + + // All the non-phis + for( int i=0; i<bb.nOuts(); i++ ) + if( !(bb.out(i) instanceof PhiNode) ) + iadr = doInst(iadr, sb,code, fun, cfgidx, bb.out(i),postAlloc, postEncode ); + + return iadr; + } + + static int doInst( int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx, Node n, boolean postAlloc, boolean postEncode ) { + if( n==null || n instanceof CProjNode ) return iadr; + if( postAlloc && n instanceof CalleeSaveNode ) return iadr; + if( postEncode && n instanceof ProjNode ) return iadr; + if( n instanceof MemMergeNode ) return iadr; + if( n.getClass() == ConstantNode.class ) return iadr; // Default placeholders + final int dopz = code._mach==null ? 2 : code._mach.defaultOpSize(); + final int encWidth = dopz*2; + + // All blocks ending in a Region will need to either fall into or jump + // to this block. Until the post-reg-alloc block layout cleanup, we + // need to assume a jump. There's no real hardware op here, yet. + if( n instanceof RegionNode cfg && !(n instanceof FunNode) ) { + if( postEncode ) return iadr; // All jumps inserted already + while( cfgidx < code._cfg._len-1 ) { + CFGNode next = code._cfg.at(++cfgidx); + if( next == n ) return iadr; // Fall-through, no branch + if( next.nOuts()>1 ) + break; // Has code in the block, need to jump around + // No code in the block, can fall through it + } + sb.hex2(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,label(cfg)).nl(); + return iadr; + } + + // ProjNodes following a multi (e.g. Call or New results), + // get indent slightly and just print their index & node# + if( n instanceof ProjNode proj ) { + if( proj._type instanceof TypeMem ) return iadr; // Nothing for the hidden ones + sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,proj._label==null ? "---" : proj._label).p(" ").p(code.reg(n,fun)).nl(); + return iadr; + } + + // ADDR ENCODING Op--- dst = src op src // Comment + // 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment + sb.hex2(iadr).p(" "); + + // Encoding + int fatEncoding = 0; + if( code._encoding != null && code._encoding._opLen!=null ) { + int size = code._encoding._opLen[n._nid]; + if( code._asmLittle ) + for( int i=0; i<Math.min(size,dopz); i++ ) + sb.hex1(code._encoding._bits.buf()[iadr++]); + else { + iadr += Math.min(size,dopz); + for( int i=0; i<Math.min(size,dopz); i++ ) + sb.hex1(code._encoding._bits.buf()[iadr-i-1]); + } + for( int i=size*2; i<encWidth; i++ ) + sb.p(" "); + fatEncoding = size - (encWidth>>1); // Not-printed parts of encoding + } else + sb.fix(encWidth,""); + sb.p(" "); + + // Op; generally "ld4" or "call" + sb.fix(opWidth, n instanceof MachNode mach ? mach.op() : n.label()).p(" "); + + // General asm args + String isMultiOp = null; + if( n instanceof MachNode mach ) { + int old = sb.len(); + mach.asm(code,sb); + int len = sb.len(); + isMultiOp = isMultiOp(sb,old,len); + sb.fix(argWidth-(len-old),""); // Pad out + + } else if( !(n._type instanceof TypeMem) ) { + // Room for some inputs + sb.fix(5, n._nid+":" ); + int off = 0; + for( int i=0; i<n.nIns(); i++ ) { + sb.fix(5, n.in(i) == null ? "___" : String.valueOf(n.in(i)._nid)); + off += 5; + if( off >= argWidth ) break; + } + if( off < argWidth ) sb.fix(argWidth-off,""); + } + sb.p(" "); + + // Comment + String comment = n.comment(); + if( comment!=null ) sb.p("// ").p(comment); + + sb.nl(); + + // Printing more op bits than fit + if( isMultiOp != null && code._encoding != null && code._encoding._opLen!=null ) { + // Multiple ops, template style, no RA, no scheduling. Print out + // one-line-per-newline, with encoding bits up front. + int size = code._encoding._opLen[n._nid]; + int off = Math.min(size,dopz); + while( isMultiOp!=null ) { + sb.hex2(iadr).p(" "); + int len = Math.min(size-off,dopz); + for( int i=0; i<len; i++ ) + sb.hex1(code._encoding._bits.buf()[iadr++]); + off += len; + for( int i=len; i<dopz; i++ ) sb.p(" "); + sb.p(" "); + int x = isMultiOp.indexOf('\n'); + if( x== -1 ) { // Last line + sb.p(isMultiOp).nl(); + isMultiOp = null; + } else { + sb.p(isMultiOp.substring(0,x+1)); // Includes the newline + isMultiOp = isMultiOp.substring(x+1); + } + + } + + } else if( fatEncoding > 0 ) { + // Extra bytes past the default encoding width, all put on a line by + // themselves. X86 special for super long encodings + sb.hex2(iadr).p(" "); + for( int i=0; i<fatEncoding; i++ ) + sb.hex1(code._encoding._bits.buf()[iadr++]); + sb.nl(); + } + + + // MultiNodes are immediately followed by projection(s) + if( !(n instanceof CFGNode) && n instanceof MultiNode ) { + for( Node proj : n._outputs ) { + if( proj instanceof ProjNode ) // it could also be an ante-dep + doInst(iadr,sb,code,fun, cfgidx, proj,postAlloc,postEncode); + } + } + + return iadr; + } + + private static String label( CFGNode bb ) { + return (bb instanceof LoopNode ? "LOOP" : "L")+bb._nid; + } + + private static String isMultiOp(SB sb, int old, int len) { + for( int i=old; i<len; i++ ) + if( sb.at(i)=='\n' ) { + String s = sb.subString(i+1,len); + sb.setLen(i); + return s; + } + return null; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java b/chapter24/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java new file mode 100644 index 00000000..20c8439a --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java @@ -0,0 +1,287 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.node.*; +import java.util.*; +import static com.seaofnodes.simple.util.Utils.TODO; + +/** + * Simple visualizer that outputs GraphViz dot format. + * The dot output must be saved to a file and run manually via dot to generate the SVG output. + * Currently, this is done manually. + */ +public class GraphVisualizer { + + /** + * If set to true we put the control nodes in a separate cluster from + * data nodes. + */ + boolean _separateControlCluster = false; + + public GraphVisualizer(boolean separateControlCluster) { this._separateControlCluster = separateControlCluster; } + public GraphVisualizer() { this(false); } + + public String generateDotOutput(Parser parse) { return generateDotOutput(parse._code._stop,parse._scope,parse._xScopes); } + public String generateDotOutput(StopNode stop, Node scope, Stack<ScopeNode> xScopes) { + + // Since the graph has cycles, we need to create a flat list of all the + // nodes in the graph. + Collection<Node> all = findAll(xScopes, stop, scope); + StringBuilder sb = new StringBuilder(); + sb.append("digraph chapter18 {\n"); + sb.append("/*\n"); + sb.append(stop._src); + sb.append("\n*/\n"); + + // To keep the Scopes below the graph and pointing up into the graph we + // need to group the Nodes in a subgraph cluster, and the scopes into a + // different subgraph cluster. THEN we can draw edges between the + // scopes and nodes. If we try to cross subgraph cluster borders while + // still making the subgraphs DOT gets confused. + sb.append("\trankdir=BT;\n"); // Force Nodes before Scopes + + // CNC - turned off Apr/8/2024, gives more flex in the layout and + // removes some of the more ludicrous layout choices. + // Preserve node input order + //sb.append("\tordering=\"in\";\n"); + + // Merge multiple edges hitting the same node. Makes common shared + // nodes much prettier to look at. + sb.append("\tconcentrate=\"true\";\n"); + + // Force nested scopes to order + sb.append("\tcompound=\"true\";\n"); + + // Just the Nodes first, in a cluster no edges + nodes(sb, all); + + // Now the scopes, in a cluster no edges + if( xScopes != null ) + for( ScopeNode xscope : xScopes ) + if( !xscope.isDead() ) + scope( sb, xscope ); + + // Walk the Node edges + nodeEdges(sb, all); + + // Walk the active Scope edges + if( xScopes != null ) + for( ScopeNode xscope : xScopes ) + if( !xscope.isDead() ) + scopeEdges( sb, xscope ); + + sb.append("}\n"); + return sb.toString(); + } + + private void nodesByCluster(StringBuilder sb, boolean doCtrl, Collection<Node> all) { + if (!_separateControlCluster && doCtrl) // all nodes in 1 cluster + return; + // Just the Nodes first, in a cluster no edges + sb.append(doCtrl ? "\tsubgraph cluster_Controls {\n" : "\tsubgraph cluster_Nodes {\n"); // Magic "cluster_" in the subgraph name + for (Node n : all) { + if (n instanceof ProjNode || n instanceof CProjNode || n instanceof MemMergeNode || n==Parser.XCTRL) + continue; // Do not emit, rolled into MultiNode or Scope cluster already + if( _separateControlCluster && doCtrl && !(n instanceof CFGNode) ) continue; + if( _separateControlCluster && !doCtrl && (n instanceof CFGNode) ) continue; + sb.append("\t\t").append(n.uniqueName()).append(" [ "); + String lab = n.glabel(); + if (n instanceof MultiNode) { + // Make a box with the MultiNode on top, and all the projections on the bottom + sb.append("shape=plaintext label=<\n"); + sb.append("\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">\n"); + sb.append("\t\t\t<TR><TD BGCOLOR=\"yellow\">").append(lab).append("</TD></TR>\n"); + sb.append("\t\t\t<TR>"); + boolean doProjTable = false; + n._outputs.sort((x,y) -> x instanceof ProjNode xp && y instanceof ProjNode yp ? (xp._idx - yp._idx) : (x._nid - y._nid)); + for (Node use : n._outputs) { + if (use instanceof ProjNode proj) { + if (!doProjTable) { + doProjTable = true; + sb.append("<TD>").append("\n"); + sb.append("\t\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">").append("\n"); + sb.append("\t\t\t\t<TR>"); + } + sb.append("<TD PORT=\"p").append(proj._idx).append("\">").append(proj.glabel()).append("</TD>"); + } + if (use instanceof CProjNode proj) { + if (!doProjTable) { + doProjTable = true; + sb.append("<TD>").append("\n"); + sb.append("\t\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">").append("\n"); + sb.append("\t\t\t\t<TR>"); + } + sb.append("<TD PORT=\"p").append(proj._idx).append("\" BGCOLOR=\"yellow\">").append(proj.glabel()).append("</TD>"); + } + } + if (doProjTable) { + sb.append("</TR>").append("\n"); + sb.append("\t\t\t\t</TABLE>").append("\n"); + sb.append("\t\t\t</TD>"); + } + sb.append("</TR>\n"); + sb.append("\t\t\t</TABLE>>\n\t\t"); + + } else { + // control nodes have box shape + // other nodes are ellipses, i.e. default shape + if( n instanceof CFGNode ) sb.append("shape=box style=filled fillcolor=yellow "); + else if (n instanceof PhiNode) sb.append("style=filled fillcolor=lightyellow "); + sb.append("label=\"").append(lab).append("\" "); + } + sb.append("];\n"); + } + if (!_separateControlCluster) { + // Force Region & Phis to line up + for (Node n : all) { + if (n instanceof RegionNode region) { + sb.append("\t\t{ rank=same; "); + sb.append(region.uniqueName()).append(";"); + for (Node phi : region._outputs) + if (phi instanceof PhiNode) sb.append(phi.uniqueName()).append(";"); + sb.append("}\n"); + } + } + } + sb.append("\t}\n"); // End Node cluster + } + + private void nodes(StringBuilder sb, Collection<Node> all) { + nodesByCluster(sb, true, all); + nodesByCluster(sb, false, all); + } + + // Build a nested scope display, walking the _prev edge + private void scope( StringBuilder sb, ScopeNode scope ) { + sb.append("\tnode [shape=plaintext];\n"); + int last = scope.nIns(); + int max = scope.depth(); + for( int i = 0; i < max; i++ ) { + int level = max-i-1; + String scopeName = makeScopeName(scope, level); + sb.append("\tsubgraph cluster_").append(scopeName).append(" {\n"); // Magic "cluster_" in the subgraph name + // Special for memory ScopeMinNode + if( level==0 ) { + MemMergeNode n = scope.mem(); + sb.append("\t\t").append(n.uniqueName()).append(" [label=\"").append(n.glabel()).append("\"];\n"); + } + sb.append("\t\t").append(scopeName).append(" [label=<\n"); + sb.append("\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n"); + // Add the scope level + sb.append("\t\t\t<TR><TD BGCOLOR=\"cyan\">").append(level).append("</TD>"); + int lexStart = scope._kinds.at(level)._lexSize; + for( int j=lexStart; j<last; j++ ) { + var v = scope._vars.at(j); + sb.append("<TD PORT=\"").append(makePortName(scopeName, v._name)).append("\">").append(v._name).append("</TD>"); + } + last = lexStart; + sb.append("</TR>\n"); + sb.append("\t\t\t</TABLE>>];\n"); + } + // Scope clusters nest, so the graphics shows the nested scopes, so + // they are not closed as they are printed; so they just keep nesting. + // We close them all at once here. + sb.append( "\t}\n".repeat( max ) ); // End all Scope clusters + } + + private String makeScopeName(ScopeNode sn, int level) { return sn.uniqueName() + "_" + level; } + private String makePortName(String scopeName, String varName) { return scopeName + "_" + varName; } + + // Walk the node edges + private void nodeEdges(StringBuilder sb, Collection<Node> all) { + // All them edge labels + sb.append("\tedge [ fontname=Helvetica, fontsize=8 ];\n"); + for( Node n : all ) { + // Do not display the Constant->Start edge; + // ProjNodes handled by Multi; + // ScopeNodes are done separately + if( n instanceof ConstantNode || n instanceof ProjNode || n instanceof CProjNode || n instanceof ScopeNode || n==Parser.XCTRL ) + continue; + for( int i=0; i<n.nIns(); i++ ) { + Node def = n.in(i); + if( n instanceof PhiNode && def instanceof RegionNode ) { + // Draw a dotted use->def edge from Phi to Region. + sb.append('\t').append(n.uniqueName()); + sb.append(" -> "); + sb.append(def.uniqueName()); + sb.append(" [style=dotted taillabel=").append(i).append("];\n"); + } else if( def != null ) { + // Most edges land here use->def + sb.append('\t').append(n.uniqueName()).append(" -> "); + if( def instanceof CProjNode proj ) { + String mname = proj.ctrl().uniqueName(); + sb.append(mname).append(":p").append(proj._idx); + } else if( def instanceof ProjNode proj ) { + String mname = proj.in(0).uniqueName(); + sb.append(mname).append(":p").append(proj._idx); + } else sb.append(def.uniqueName()); + // Number edges, so we can see how they track + sb.append("[taillabel=").append(i); + // The edge from New to ctrl is just for anchoring the New + if ( n instanceof NewNode ) + sb.append(" color=green"); + // control edges are colored red + else if( def instanceof CFGNode ) + sb.append(" color=red"); + else if( def.isMem() ) + sb.append(" color=blue"); + // Backedges do not add a ranking constraint + if( i==2 && (n instanceof PhiNode || n instanceof LoopNode) ) + sb.append(" constraint=false"); + sb.append("];\n"); + } + } + } + } + + // Walk the scope edges + private void scopeEdges( StringBuilder sb, ScopeNode scope ) { + sb.append("\tedge [style=dashed color=cornflowerblue];\n"); + int level=0; + for( var v : scope._vars ) { + Node def = scope.in(v._idx); + while( def instanceof ScopeNode lazy ) + def = lazy.in(v._idx); + if( def==null ) continue; + while( level < scope.depth() && v._idx >= scope._kinds.at(level)._lexSize ) + level++; + String scopeName = makeScopeName(scope, level-1); + sb.append("\t") + .append(scopeName).append(":") + .append('"').append(makePortName(scopeName, v._name)).append('"') // wrap port name with quotes because $ctrl is not valid unquoted + .append(" -> "); + if( def instanceof CProjNode proj ) { + sb.append(def.in(0).uniqueName()).append(":p").append(proj._idx); + } else if( def instanceof ProjNode proj ) { + sb.append(def.in(0).uniqueName()).append(":p").append(proj._idx); + } else sb.append(def.uniqueName()); + sb.append(";\n"); + } + } + + /** + * Finds all nodes in the graph. + */ + public static Collection<Node> findAll(Stack<ScopeNode> ss, Node... ns) { + final HashMap<Integer, Node> all = new HashMap<>(); + for( Node n : ns ) + walk(all, n); + if( ss != null ) + for( Node n : ss ) + walk(all, n); + return all.values(); + } + + /** + * Walk a subgraph and populate distinct nodes in the all list. + */ + private static void walk(HashMap<Integer,Node> all, Node n) { + if(n == null ) return; + if (all.get(n._nid) != null) return; // Been there, done that + all.put(n._nid, n); + for (Node c : n._inputs) + walk(all, c); + for( Node c : n._outputs ) + walk(all, c); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java new file mode 100644 index 00000000..d1265bef --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -0,0 +1,331 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.HashMap; + +public abstract class IRPrinter { + + // Print a node on 1 line, columnar aligned, as: + // NNID NNAME DDEF DDEF [[ UUSE UUSE ]] TYPE + // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt + public static SB printLine( Node n, SB sb ) { + if( n==null ) return sb; + sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); + if( n._inputs==null ) + return sb.p("DEAD\n"); + for( Node def : n._inputs ) + sb.p(def==null ? "____" : "%4d".formatted(def._nid)) + // Lazy Phi indicator + .p(n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "); + for( int i = n._inputs.size(); i<4; i++ ) + sb.p(" "); + sb.p(" [[ "); + for( Node use : n._outputs ) + sb.p(use==null ? "____ " : "%4d ".formatted(use._nid)); + int lim = 6 - Math.max(n._inputs.size(),4); + for( int i = n._outputs.size(); i<lim; i++ ) + sb.p(" "); + sb.p(" ]] "); + if( n._type!= null ) sb.p(n._type.str()); + return sb.p("\n"); + } + + + public static String prettyPrint(Node node, int depth) { + return CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Schedule.ordinal() + ? _prettyPrintScheduled( node, depth ) + : _prettyPrint( node, depth ); + } + + // Another bulk pretty-printer. Makes more effort at basic-block grouping. + private static String _prettyPrint( Node node, int depth ) { + // First, a Breadth First Search at a fixed depth. + BFS bfs = new BFS(node,depth); + // Convert just that set to a post-order + ArrayList<Node> rpos = new ArrayList<>(); + BitSet visit = new BitSet(); + for( int i=bfs._lim; i< bfs._bfs.size(); i++ ) + postOrd( bfs._bfs.get(i), null, rpos, visit, bfs._bs); + // Reverse the post-order walk + SB sb = new SB(); + boolean gap=false; + for( int i=rpos.size()-1; i>=0; i-- ) { + Node n = rpos.get(i); + if( n instanceof CFGNode || n instanceof MultiNode ) { + if( !gap ) sb.p("\n"); // Blank before multihead + if( n instanceof FunNode fun ) + fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" ")).p("----------------------\n"); + printLine( n, sb ); // Print head + while( --i >= 0 ) { + Node t = rpos.get(i); + if( !(t.in(0) instanceof MultiNode) ) { i++; break; } + printLine( t, sb ); + } + if( n instanceof ReturnNode ret ) { + FunNode fun = ret.fun(); + sb.p("--- "); + if( fun != null ) + fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" ")); + sb.p("----------------------\n"); + } + if( !(n instanceof CallNode) ) { + sb.p("\n"); // Blank after multitail + gap = true; + } + } else { + printLine( n, sb ); + gap = false; + } + } + return sb.toString(); + } + + private static void postOrd(Node n, Node prior, ArrayList<Node> rpos, BitSet visit, BitSet bfs) { + if( !bfs.get(n._nid) ) + return; // Not in the BFS visit + if( n instanceof FunNode && !(prior instanceof StartNode) ) + return; // Only visit Fun from Start + if( visit.get(n._nid) ) return; // Already post-order walked + visit.set(n._nid); + // First walk the CFG, then everything + if( n instanceof CFGNode ) { + for( Node use : n._outputs ) + // Follow CFG, not across call/function borders, and not around backedges + if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) && + use.nOuts() >= 1 && !(use._outputs.get(0) instanceof LoopNode) ) + postOrd(use, n, rpos,visit,bfs); + for( Node use : n._outputs ) + // Follow CFG, not across call/function borders + if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) ) + postOrd(use,n,rpos,visit,bfs); + } + // Follow all outputs + for( Node use : n._outputs ) + if( use != null && + !(n instanceof CallNode && use instanceof FunNode) && + (n instanceof FunNode || !(use instanceof ParmNode)) ) + postOrd(use, n, rpos,visit,bfs); + // Post-order + rpos.add(n); + } + + // Breadth-first search, broken out in a class to keep in more independent. + // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead). + public static class BFS { + // A breadth first search, plus MultiHeads for any MultiTails + public final ArrayList<Node> _bfs; + public final BitSet _bs; // Visited members by node id + public final int _depth; // Depth limit + public final int _lim; // From here to _bfs._len can be roots for a reverse search + public BFS( Node base, int d ) { + _depth = d; + _bfs = new ArrayList<>(); + _bs = new BitSet(); + + add(base); // Prime the pump + int idx=0, lim=1; // Limit is where depth counter changes + while( idx < _bfs.size() ) { // Ran out of nodes below depth + Node n = _bfs.get(idx++); + for( Node def : n._inputs ) + if( def!=null && !_bs.get(def._nid) ) + add(def); + if( idx==lim ) { // Depth counter changes at limit + if( --d < 0 ) + break; // Ran out of depth + lim = _bfs.size(); // New depth limit + } + } + // Toss things past the limit except multi-heads + while( idx < _bfs.size() ) { + Node n = _bfs.get(idx); + if( n instanceof MultiNode ) idx++; + else del(idx); + } + // Root set is any node with no inputs in the visited set + lim = _bfs.size(); + for( int i=_bfs.size()-1; i>=0; i-- ) + if( !any_visited(_bfs.get(i)) ) + swap( i,--lim); + _lim = lim; + } + void swap( int x, int y ) { + if( x==y ) return; + Node tx = _bfs.get(x); + Node ty = _bfs.get(y); + _bfs.set(x,ty); + _bfs.set(y,tx); + } + void add(Node n) { + _bfs.add(n); + _bs.set(n._nid); + } + void del(int idx) { + _bs.clear(_bfs.get(idx)._nid); + Utils.del(_bfs, idx); + } + boolean any_visited( Node n ) { + for( Node def : n._inputs ) + if( def!=null && _bs.get(def._nid) ) + return true; + return false; + } + } + + public static String _prettyPrint( CodeGen code ) { + SB sb = new SB(); + // Print the Start "block" + printLine(code._start,sb); + for( Node n : code._start._outputs ) + printLine(n,sb); + sb.nl(); + + // Skip start, stop + for( int i=1; i<code._cfg._len-1; i++ ) { + CFGNode blk = code._cfg.at(i); + if( blk.blockHead() && (!(blk instanceof CProjNode) || (blk.cfg0() instanceof IfNode )) ) { + if( blk instanceof FunNode fun ) + sb.p("--- ").p(fun.label()).p(" ---------------------------").nl(); + // Print block header + sb.p("%-13.13s".formatted(label(blk)+":")); + sb.p( " ".repeat(4) ).p(" [[ "); + if( blk instanceof RegionNode ) + for( int j=1; j<blk.nIns(); j++ ) + label(sb,blk.cfg(j)); + else + label(sb,blk.cfg(0)); + sb.p(" ]] \n"); + } + printLine(blk,sb); + if( blk instanceof ReturnNode ret ) + sb.p("--- ").p(ret.fun().label()).p(" ---------------------------").nl(); + + // Block contents + for( Node n : blk._outputs ) { + if( n instanceof CFGNode cfg ) continue; + printLine(n,sb); + if( !(n instanceof CFGNode) && n instanceof MultiNode ) + for( Node use : n._outputs ) + if( use instanceof ProjNode ) + printLine(use,sb); + } + } + + printLine(code._stop,sb); + return sb.toString(); + } + + // Bulk pretty printer, knowing scheduling information is available + private static String _prettyPrintScheduled( Node node, int depth ) { + // Backwards DFS walk to depth. + HashMap<Integer,Integer> ds = new HashMap<>(); + Ary<Node> ns = new Ary<>(Node.class); + _walk(ds,ns,node,depth); + // Remove data projections, these are force-printed behind their multinode head + for( int i=0; i<ns.size(); i++ ) { + if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) { + ns.del(i--); + ds.remove(proj._nid); + } + } + // Print by block with least idepth + SB sb = new SB(); + Ary<Node> bns = new Ary<>(Node.class); + while( !ds.isEmpty() ) { + CFGNode blk = null; + for( Node n : ns ) { + CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0(); + if( blk==null || cfg.idepth() < blk.idepth() ) + blk = cfg; + } + Integer d = ds.remove(blk._nid); + ns.del(ns.find(blk)); + + // Print block header + sb.p("%-13.13s".formatted(label(blk)+":")); + sb.p( " ".repeat(4) ).p(" [[ "); + if( blk instanceof StartNode ) ; + else if( blk instanceof RegionNode || blk instanceof StopNode ) + for( int i=(blk instanceof StopNode ? 3 : 1); i<blk.nIns(); i++ ) + label(sb,blk.cfg(i)); + else + label(sb,blk.cfg(0)); + sb.p(" ]] \n"); + printLine(blk,sb); + + // Collect block contents that are in the depth limit + bns.clear(); + int xd = Integer.MAX_VALUE; + for( Node use : blk._outputs ) { + Integer i = ds.get(use._nid); + if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) { + if( bns.find(use)==-1 ) + bns.add(use); + xd = Math.min(xd,i); + } + } + // Print Phis up front, if any + for( int i=0; i<bns.size(); i++ ) + if( bns.get(i) instanceof PhiNode phi ) + printLine( phi, sb,bns,i--,ds,ns); + + // Print block contents in depth order, bumping depth until whole block printed + for( ; !bns.isEmpty(); xd++ ) + for( int i=0; i<bns.size(); i++ ) { + Node n = bns.get(i); + if( ds.get(n._nid)==xd ) { + printLine( n, sb, bns, i--, ds,ns ); + if( n instanceof MultiNode && !(n instanceof CFGNode) ) { + for( Node use : n._outputs ) { + if( use instanceof ProjNode ) + printLine(use,sb,bns,bns.indexOf(use),ds,ns); + } + } + } + } + sb.p("\n"); + } + return sb.toString(); + } + + private static void _walk( HashMap<Integer,Integer> ds, Ary<Node> ns, Node node, int d ) { + Integer nd = ds.get(node._nid); + if( nd!=null && d <= nd ) return; // Been there, done that + Integer old = ds.put(node._nid,d) ; + if( old == null ) + ns.add(node); + if( d == 0 ) return; // Depth cutoff + for( Node def : node._inputs ) + if( def != null && + !(node instanceof LoopNode loop && loop.back()==def) && + // Don't walk into or out of functions + !(node instanceof CallEndNode && def instanceof ReturnNode) && + !(node instanceof FunNode && def instanceof CallNode) && + !(node instanceof ParmNode && !(def instanceof FunNode)) + ) + _walk(ds,ns,def,d-1); + } + + static String label( CFGNode blk ) { + if( blk instanceof StartNode ) return "START"; + return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid; + } + static void label( SB sb, CFGNode blk ) { + if( !blk.blockHead() ) blk = blk.cfg(0); + sb.p( "%-9.9s ".formatted( label( blk ) ) ); + } + static void printLine( Node n, SB sb, Ary<Node> bns, int i, HashMap<Integer,Integer> ds, Ary<Node> ns ) { + printLine( n, sb ); + if( i != -1 ) bns.del(i); + ds.remove(n._nid); + int idx = ns.find(n); + if( idx!=-1 ) ns.del(idx); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/print/JSViewer.java b/chapter24/src/main/java/com/seaofnodes/simple/print/JSViewer.java new file mode 100644 index 00000000..62ff0001 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/print/JSViewer.java @@ -0,0 +1,405 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.Stack; +import static com.seaofnodes.simple.codegen.CodeGen.CODE; + +public class JSViewer implements AutoCloseable { + // Display programs in an endless loop + public static void main( String[] args ) throws Exception { + try(var js = new JSViewer()) { + js.run(); + } + } + + static boolean SHOW; + + // WebSocket to the browser for display + static SimpleWebSocket SERVER; + + static int N; // Dot frames + + JSViewer() throws Exception { + // Launch server; handshake + SERVER = new SimpleWebSocket(Paths.get("docs/index.html").toUri(),12345) ; + } + + void run( ) throws Exception { + SERVER.put("!"); + while( true ) { + String src = SERVER.get(); + switch( src ) { + case null: return; + case "null": return; + case "+": break; // Client requests more frames, but we send them all anyway + default: + System.out.println(src); + try { + N=0; + // Use parser scope, xscope when building views + CodeGen code = new CodeGen(src); + SHOW = true; + show(); + // Parse program, generating views at every parse point + code.parse(); + // No longer user parse internal state when building views + code.opto(); + + // Catch and ignore Parser errors + } catch(RuntimeException re) { + System.err.println(re); + } finally { + SHOW = false; + SERVER.put("#"); // Final frame + } + break; + } + } + } + + @Override public void close() throws IOException { + SERVER.close(); + SERVER=null; + } + + public static void show() { if( SERVER!=null && SHOW ) _show(); } + private static void _show() { + // Skip util we at least get the Parse object made + if( CODE._phase==null || CODE._phase.ordinal() < CodeGen.Phase.Parse.ordinal() ) + return; + boolean midParse = CODE._phase == CodeGen.Phase.Parse; + Stack<ScopeNode> xScopes = midParse ? CODE.P._xScopes : null; + + Collection<Node> all = GraphVisualizer.findAll(xScopes, CODE._stop, midParse ? CODE.P._scope: null); + SB sb = new SB(); + sb.p("digraph view_").p(N++).p(" {\n").ii(); + if( midParse ) + sb.i().p("// POS: ").p(CODE.P.pos()).nl(); + + // To keep the Scopes below the graph and pointing up into the graph we + // need to group the Nodes in a subgraph cluster, and the scopes into a + // different subgraph cluster. THEN we can draw edges between the + // scopes and nodes. If we try to cross subgraph cluster borders while + // still making the subgraphs DOT gets confused. + sb.i().p("rankdir=BT;\n"); // Force Nodes before Scopes + + // CNC - turned off Apr/8/2024, gives more flex in the layout and + // removes some of the more ludicrous layout choices. + // Preserve node input order + //sb.append("ordering=\"in\";\n"); + + // Merge multiple edges hitting the same node. Makes common shared + // nodes much prettier to look at. + sb.i().p("concentrate=\"true\";\n"); + + // Force nested scopes to order + sb.i().p("compound=\"true\";\n"); + + // Just the Nodes first, in a cluster no edges + nodes(sb, all); + + // Now the scopes, in a cluster no edges + if( midParse ) + for( ScopeNode xscope : xScopes ) + if( !xscope.isDead() ) + scope( sb, xscope ); + + // Walk the Node edges + nodeEdges(sb, midParse && !xScopes.empty() ? xScopes.peek() : null, all); + + // Walk the active Scope edges + if( midParse ) + for( ScopeNode xscope : xScopes ) + if( !xscope.isDead() ) + scopeEdges( sb, xscope ); + + + sb.p("}\n").di(); + // Tell client another DOT frame + String dot = sb.toString(); + System.out.println(dot); + try { + SERVER.put(dot); + } catch( IOException ioe ) { + try { SERVER.close();} catch( IOException ignored ){} + } + } + + + private static void nodes(SB sb, Collection<Node> all) { + // Just the Nodes first, in a cluster no edges + sb.i().p("subgraph cluster_Nodes {\n").ii(); // Magic "cluster_" in the subgraph name + for( Node n : all ) { + if( n instanceof ProjNode || n instanceof CProjNode || n instanceof MemMergeNode ) + continue; // Do not emit, rolled into MultiNode or Scope cluster already + sb.i().p(n.uniqueName()).p(" [ "); + if( n instanceof MultiNode && !(n instanceof StartNode) ) { + // Make a box with the MultiNode on top, and all the projections on the bottom + sb. p("shape=plaintext label=<\n").ii(); + sb.i().p("<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">\n"); + // Row over single cell for node label + cell(sb.i().p("<TR>"), n.glabel(), n, null).p("</TR>\n"); + // Row over single cell, for nested table + sb.i().p("<TR><TD>\n").ii(); + sb.i().p("<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">").p("\n"); + sb.i().p("<TR>"); + n._outputs.sort((x,y) -> x instanceof ProjNode xp && y instanceof ProjNode yp ? (xp._idx - yp._idx) : ((x==null ? 99999 : x._nid) - (y==null ? 99999 : y._nid))); + boolean empty_row=true; + for( Node use : n._outputs ) { + int idx = idx(n); + if( idx != -1 ) { + cell(sb,use.glabel(),use,"p"+idx); + empty_row=false; + } + } + // At least one cell on row + if( empty_row ) sb.p("<TD></TD>"); + sb. p("</TR>").p("\n"); + sb.i().p("</TABLE>").p("\n").di(); + sb.i().p("</TD></TR>\n"); + sb.i().p("</TABLE>>\n").di(); + sb.i().p("];\n"); + + } else { + // control nodes have box shape + // other nodes are ellipses, i.e. default shape + //else if (n instanceof PhiNode) sb.p("style=filled fillcolor=lightyellow "); + node(sb,n.glabel(),n); + sb.p("];\n"); + } + } + // Force Region & Phis to line up + for (Node n : all) { + if (n instanceof RegionNode region) { + sb.i().p("{ rank=same; "); + sb.p(region.uniqueName()).p(";"); + for (Node phi : region._outputs) + if (phi instanceof PhiNode) sb.p(phi.uniqueName()).p(";"); + sb.p("}\n"); + } + } + sb.di().i().p("}").nl(); // End Node cluster + } + + // Build a nested scope display, walking the _prev edge + private static void scope( SB sb, ScopeNode scope ) { + sb.i().p("node [shape=plaintext];\n"); + int last = scope.nIns(); + int max = scope.depth()+1; // One more than lexsize + for( int i = 0; i < max; i++ ) { + int level = max-i-1; + String scopeName = makeScopeName(scope, level); + sb.i().p("subgraph cluster_").p(scopeName).p(" {\n").ii(); // Magic "cluster_" in the subgraph name + sb.i().p(scopeName).p(" [label=<\n").ii(); + sb.i().p("<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n"); + int lexStart = level==0 ? 0 : scope._kinds.at(level-1)._lexSize; + + // Special for memory ScopeMinNode + MemMergeNode n = scope.nIns()>1 ? scope.mem() : null; + if( level==0 && n!=null && n.nIns()>2 ) { + sb.i().p("<TR>"); + for( int m=2; m<n.nIns(); m++ ) + cell(sb,"#"+m,n.alias(m),"m"+m); + sb.p("</TR>\n"); // End scope level + } + + // Scope variables, empty if none + if( lexStart<last ) { + sb.i().p("<TR>\n"); + for( int j=lexStart; j<last; j++ ) { + if( scope.in(j)==null ) continue; + var v = scope._vars.at(j); + cell(sb.i(),v._name,scope.in(j),makePortName(scopeName, v._name)).nl(); + } + last = lexStart; + sb.i().p("</TR>\n"); + } + sb.i().p("</TABLE>>];\n").di(); + // Scope label + sb.i().p(scopeName).p("A [label=\"").p(level).p("\" shape=doublecircle style=filled fillcolor=aqua fontsize=10 margin=0 width=0.2 ];\n"); + } + // Scope clusters nest, so the graphics shows the nested scopes, so + // they are not closed as they are printed; so they just keep nesting. + // We close them all at once here. + for( int i=0; i<max; i++ ) + sb.di().i().p("}\n"); + } + + // Append a cell, with color + private static SB cell(SB sb, String text, Node n, String port) { + sb.p("<TD"); + String color = color(n); + sb.p(" BGCOLOR=\"").p(color).p("\""); + if( port!=null ) sb.p(" PORT=\"").p(port).p("\""); + return colorcell(sb.p(">"),text,n,dark(color)).p("</TD>"); + } + private static SB node(SB sb, String text, Node n) { + String color = color(n); + sb.p("style=filled fillcolor=").p(color).p(" "); + String shape = switch( n ) { + case FunNode fun -> "shape=box peripheries=2"; + case CFGNode cfg -> "shape=box"; + default -> ""; + }; + sb.p(shape).p(" "); + return colorcell(sb.p("label=<"),text,n,dark(color)).p(">"); + } + + private static String color(Node n) { + return switch( n ) { + case CFGNode cfg -> "yellow"; + case NewNode nnn -> "lightgreen"; + case StructNode s -> "lightgreen"; + default -> typeColor(n._type); + }; + } + private static String typeColor(Type t) { + return t==null ? "white" : switch( t ) { + case TypeMem mem -> "blue"; + case TypeMemPtr tmp -> "green"; + case TypeFunPtr tfp -> "orange"; + case TypeRPC rpc -> "antiquewhite"; + case TypeInteger ti -> "lightblue"; + case TypeFloat tf -> "aqua"; + case Type tn -> tn==Type.NIL ? "lightgray" : "red"; + }; + } + private static final String[] DARKS = new String[]{"blue","green","black"}; + private static boolean dark(String color) { return Utils.find(DARKS,color) != -1; } + + + + // Called with an open div + private static SB colorcell(SB sb, String text, Node n, boolean dark) { + if( dark ) sb.p("<font color=\"white\">"); + sb.p(text); + if( n._type!=null ) { + sb.p("<br /><font point-size=\"10\">"); + n._type.gprint(sb); + sb.p("</font>"); + } + if( dark ) sb.p("</font>"); + return sb; + } + + + private static String makeScopeName(ScopeNode sn, int level) { return sn.uniqueName() + "_" + level; } + private static String makePortName(String scopeName, String varName) { return scopeName + "_" + varName; } + + // Walk the node edges + private static void nodeEdges(SB sb, ScopeNode scope, Collection<Node> all) { + // All them edge labels + String scopeName = scope!=null ? makeScopeName(scope, 0) : null; + sb.i().p("edge [ fontname=Helvetica, fontsize=8 ];\n"); + for( Node n : all ) { + // Do not display the Constant->Start edge; + if( n instanceof ConstantNode || + n instanceof XCtrlNode || + // ProjNodes handled by Multi; + n instanceof ProjNode || + n instanceof CProjNode || + // ScopeNodes are done separately + n instanceof ScopeNode || + n instanceof MemMergeNode + ) + continue; + if( n.isDead() ) + throw Utils.TODO(); + // Normal edges + for( int i=0; i<n.nIns(); i++ ) { + Node def = n.in(i); + if( def==null ) continue; + sb.i().p(n.uniqueName()).p(" -> "); + if( n instanceof PhiNode && def instanceof RegionNode ) { + // Draw a dotted use->def edge from Phi to Region. + sb.p(def.uniqueName()); + sb.p(" [style=dotted taillabel=").p(i).p("];\n"); + } else { + // Most edges land here use->def + if( def instanceof CProjNode proj ) { + String mname = proj.ctrl().uniqueName(); + sb.p(mname).p(":p").p(proj._idx); + } else if( def instanceof ProjNode proj ) { + String mname = proj.in(0).uniqueName(); + sb.p(mname).p(":p").p(proj._idx); + } else sb.p(def.uniqueName()); + // Number edges, so we can see how they track + sb.p("[taillabel=").p(i); + // Color the edge + nodeEdgeColor(sb,def._type); + // Backedges do not add a ranking constraint + if( i==2 && (n instanceof PhiNode || n instanceof LoopNode) ) + sb.p(" constraint=false"); + sb.p("];\n"); + } + } + + // Bonus edge if hooked by parser + if( (n.iskeep() || n.isUnused()) && scopeName != null ) { + sb.i().p(scopeName).p(" -> ").p(n.uniqueName()).p(" [ style=dashed color=grey];\n"); + } + // Force functions above return + if( n instanceof ReturnNode ret && ret.inProgress() && !ret.fun().isDead() ) + sb.i().p(ret.ctrl().uniqueName()).p(" -> ").p(ret.fun().uniqueName()).p("[style=invis]\n"); + } + } + + private static void nodeEdgeColor(SB sb, Type t) { + sb.p(" color=").p(typeColor(t)); + } + + // Walk the scope edges + private static void scopeEdges( SB sb, ScopeNode scope ) { + sb.i().p("edge [style=dashed color=cornflowerblue];\n"); + int level=0; + for( var v : scope._vars ) { + if( v._idx==1 ) continue; // Memory done separately + Node def = scope.in(v._idx); + while( def instanceof ScopeNode lazy ) + def = lazy.in(v._idx); + if( def==null ) continue; + while( level < scope.depth() && v._idx >= scope._kinds.at(level)._lexSize ) + level++; + String scopeName = makeScopeName(scope, level); + sb.i() + .p(scopeName).p(":") + .p('"').p(makePortName(scopeName, v._name)).p('"') // wrap port name with quotes because $ctrl is not valid unquoted + .p(" -> "); + defPort(sb,def).p(";\n"); + } + + // Memory + if( scope.nIns()>1 ) { + MemMergeNode n = scope.mem(); + for( int i=2; i<n.nIns(); i++ ) { + Node def = n.in(i); + while( def instanceof ScopeNode lazy ) + def = lazy.in(i); + if( def==null ) continue; + String scopeName = makeScopeName(scope, 0); + sb.i().p(scopeName).p(":m").p(i).p(" -> "); + defPort(sb,def).p(";\n"); + } + } + + } + + // (C)Projection index or -1 + private static int idx(Node n) { + return n instanceof ProjNode p ? p._idx : (n instanceof CProjNode cp ? cp._idx : -1); + } + + private static SB defPort(SB sb, Node def) { + int idx = idx(def); + return idx != -1 + ? sb.p(def.in(0).uniqueName()).p(":p").p(idx) + : sb.p(def.uniqueName()); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java b/chapter24/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java new file mode 100644 index 00000000..4077533d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java @@ -0,0 +1,149 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.simple.util.Utils; +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +// Why-Oh-Why is this needed? + +// Pass in a URI and a port. +// Opens the client; client has to open a websocket at the given port. +// Connects, handshakes. +// Thereafter you can call get/put to swap frames with client. + +class SimpleWebSocket extends ServerSocket { + final InputStream _in; + final OutputStream _out; + + SimpleWebSocket(URI uri, int port) throws IOException, NoSuchAlgorithmException { + super(port); + // Launch client + java.awt.Desktop.getDesktop().browse(uri); + // Look for client; get in/out streams + Socket sock = accept(); + _in = sock. getInputStream(); + _out = sock.getOutputStream(); + + + // Establish web socket with handshake; easier with a buffered reader + BufferedReader br = new BufferedReader(new InputStreamReader(_in)); + String key = null; + while( br.ready() ) { + String line = br.readLine(); + if( line.startsWith("Sec-WebSocket-Key: ") ) + key = line.substring(19); + } + assert key!=null; + // Magic handshake + byte[] response = ("HTTP/1.1 101 Switching Protocols\r\n" + + "Connection: Upgrade\r\n" + + "Upgrade: websocket\r\n" + + "Sec-WebSocket-Accept: " + + Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-1").digest((key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes( StandardCharsets.UTF_8 ))) + + "\r\n\r\n").getBytes( StandardCharsets.UTF_8 ); + _out.write(response,0,response.length); + } + + final byte[] _ins = new byte[1024]; + final byte[] _str = new byte[1024]; + final byte[] _key = new byte[4]; + int _x, _len; + private int rawget() { assert _x<_len; return _ins[_x++]&0xFF; } + + // TODO: Flip to Direct Byte Buffer, this is just a poor-mans version + private void flipRead() throws IOException { + // Move _x to _len to offset 0 + System.arraycopy(_ins,_x,_ins,0,(_len-_x)); + _len = _len-_x; + _x=0; + // Read more + int len = _in.read(_ins,_len,_ins.length-_len); + if( len == -1 ) + throw Utils.TODO(); // EOF + _len += len; + } + // Block until you read at least len + private void atLeast(int len) throws IOException { + if( _x+len <= _len ) return; + flipRead(); + } + + + // Classic read from browser client. Encoded, so decoded here + public String get() throws IOException { + atLeast(1); // Need 1 byte for opcode + int op = rawget(); + if( (op&0x80)!=0x80 ) // FIN bit not set? + throw Utils.TODO( "Multi-part from client: " + op ); // Multipart message + op &= 0x7F; // Strip FIN bit + switch( op&15) { + case 1: { + atLeast(5); // Min message length + // Message length + int len = rawget()-128; + if( len > 125 ) { + if( len > 126 ) + throw Utils.TODO(); // Multi-byte length + len = (rawget()<<8) | rawget(); + } + atLeast(len+4); // Rest of message + // Encoding key + _key[0] = (byte)rawget(); + _key[1] = (byte)rawget(); + _key[2] = (byte)rawget(); + _key[3] = (byte)rawget(); + + // Decode bytes + for( int i=0; i<len; i++ ) + _str[i] = (byte)(rawget() ^ _key[i & 3]); + + return new String(_str,0,len); + } + // Client closes + case 8: return null; + // Ping + case 9: + // Send a PONG back. TODO: echo PING data in the PONG + _out.write(0x8A); // FIN + PONG + _out.write(0x00); // LENGTH==0 + return get(); + // Not (yet) implemented: continuation frames, ping/pong + default: + throw Utils.TODO("Unexpected op from client: "+op); // Multi-part message + } + } + + // Classic put to browser client. No encoding. + public void put(String msg) throws IOException { + int len = msg.length(); + if( len <= 125 ) { + _out.write(129); // FIN, opcode 1 - whole text message + _out.write(len); + for( int i=0; i<msg.length(); i++ ) + _out.write(msg.charAt(i)); + return; + } + if( len > 65535 ) + throw Utils.TODO("MOAR LENGTH"); + _out.write(129); // FIN, opcode 1 - whole text message + _out.write(126); // Length is 16b + _out.write(len>>>8); + _out.write(len&255); + for( int i=0; i<msg.length(); i++ ) + _out.write(msg.charAt(i)); + } + + @Override public void close() throws IOException { + if( _out != null ) { + _out.write(0b10001000); + _out.flush(); + } + super.close(); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/sys.java b/chapter24/src/main/java/com/seaofnodes/simple/sys.java new file mode 100644 index 00000000..45106770 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/sys.java @@ -0,0 +1,25 @@ +package com.seaofnodes.simple; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + + +/** Default included namespaces for Simple. + + You can think of this as {@code #include <stdio.h>} for C or {@code import java.lang.*} for Java. + */ +public abstract class sys { + + public static final String SYS; + + static { + try { + SYS = Files.readString(Path.of("src/main/smp/sys.smp")); + } + catch( Exception e ) { + throw new RuntimeException(e); + } + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/Field.java b/chapter24/src/main/java/com/seaofnodes/simple/type/Field.java new file mode 100644 index 00000000..b2b2deca --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/Field.java @@ -0,0 +1,136 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import java.util.*; + +/** + * Represents a field in a struct. This is not a Type in the type system. + */ +public class Field extends Type { + + // The pair {fieldName,type} uniquely identifies a field. + + // Field name + public String _fname; + // Type of the field + public Type _t; + // Unique memory alias, not sensibly part of a "type" but very convenient here. + public int _alias; + // Field must be written to exactly once, no more, no less + public boolean _final; + // Field is final in the declaration; value is the same for all instances + // and will be moved to the class object + public boolean _one; + + private static final Ary<Field> FREE = new Ary<>(Field.class); + private Field(String fname, Type type, int alias, boolean xfinal, boolean one ) { super(TFLD); init(fname,type,alias,xfinal,one); } + private Field init(String fname, Type type, int alias, boolean xfinal, boolean one ) { + _fname = fname; + _t = type; + _alias = alias; + _final = xfinal; + _one = one; + return this; + } + + // Return a filled-in Field; either from free list or alloc new. + private static Field malloc(String fname, Type type, int alias, boolean xfinal, boolean one ) { + return FREE.isEmpty() ? new Field(fname,type,alias,xfinal,one) : FREE.pop().init(fname,type,alias,xfinal,one); + } + // Malloc-from + public Field malloc( ) { return malloc(_fname,null,_alias,_final,_one); } + @Override Field free(Type t) { + Field f = (Field)t; + assert !f.isFree() && !f._terned; + f._t = null; + f._dual = null; + f._hash = 0; + FREE.push(f); + return this; + } + @Override boolean isFree() { return _t ==null; } + + // Make and intern with listed fields + public static Field make( String fname, Type type, int alias, boolean xfinal, boolean one ) { + Field f = malloc(fname,type,alias,xfinal,one); + Field f2 = f.intern(); + if( f2==f ) return f; + return VISIT.isEmpty() ? f2.free(f) : f2.delayFree(f); + } + public Field makeFrom( Type type ) { + return type == _t ? this : make(_fname,type,_alias,_final,_one); + } + public Field makeFrom( boolean xfinal ) { + return xfinal == _final ? this : make(_fname,_t,_alias,xfinal,_one); + } + + // Cycle-making-breaking + void setType(Type t) { assert _t ==null; _t = t; } + + public static final Field BOT = make(" ",Type.BOTTOM,-999,true,false); + public static final Field TEST = make("test",Type.NIL,-2,false,false); + public static final Field TEST2 = make("test",Type.NIL,-2,true, false); + public static final Field FLT = make("flt ",TypeFloat.F32,-2,false,false); + public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST2); ts.add(FLT); } + + @Override Field xmeet( Type that ) { + Field fld = (Field)that; // Invariant + if( this==BOT || fld==BOT ) return BOT; + if( this==BOT.dual() ) return fld ; + if( fld ==BOT.dual() ) return this; + if( _fname!=fld._fname ) { assert !_fname.equals(fld._fname); return BOT; } + assert _alias==fld._alias; + assert _one ==fld._one ; + return make(_fname, _t.meet(fld._t ),_alias,_final | fld._final, _one); + } + + @Override + Field xdual() { return malloc(_fname, _t.dual(),_alias,!_final,_one); } + + @Override Field rdual() { + if( _dual!=null ) return dual(); + assert !_terned; + Field d = malloc(_fname,null,_alias,!_final,_one); + (_dual = d)._dual = this; // Cross link duals + d._t = _t._terned ? _t.dual() : _t.rdual(); + return d; + } + + @Override boolean _isConstant() { return _t._isConstant(); } + @Override boolean _isFinal() { return _final && _t._isFinal(); } + @Override Field _makeRO() { return _final ? this : make(_fname, _t._makeRO(),_alias,true,_one); } + boolean isGLB2() { return _final && _t._isGLB(true); } + Field glb2() { + Type glb = _t._glb(true); + return (glb== _t && _final ) ? this : make(_fname,glb,_alias,true,_one); + } + @Override Field _close() { return makeFrom( _t._close()); } + + // Override in subclasses + int hash() { return _fname.hashCode() ^ _t.hashCode() ^ _alias ^ (_final ? 1024 : 0) ^ (_one ? 2048 : 0); } + + private boolean static_eq( Field f ) { + return _fname.equals(f._fname) && _alias==f._alias && _final==f._final && _one==f._one && _t !=null && f._t !=null; + } + @Override boolean eq( Type t ) { + Field f = (Field)t; + return static_eq(f) && _t ==f._t; + } + @Override boolean cycle_eq(Type t) { + Field f = (Field)t; + return static_eq(f) && _t.cycle_eq(f._t ); + } + + @Override int nkids() { return 1; } + @Override Type at( int idx ) { return _t; } + @Override void set( int idx, Type t ) { _t = t; } + + @Override + public SB _print( SB sb, BitSet visit, boolean html ) { + sb.p(_final?"":"!").p(_one?"$":"").p(_fname).p(":").p(_alias).p(" : "); + return _t ==null ? sb.p("---") : _t.print(sb,visit,html); + } + + @Override public String str() { return (_final?"":"!")+(_one?"$":"")+_fname; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/Type.java b/chapter24/src/main/java/com/seaofnodes/simple/type/Type.java new file mode 100644 index 00000000..b7a8408e --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/Type.java @@ -0,0 +1,514 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.*; +import java.util.*; + +/** + * These types are part of a Monotone Analysis Framework, + * @see <a href="https://www.cse.psu.edu/~gxt29/teaching/cse597s21/slides/08monotoneFramework.pdf">see for example this set of slides</a>. + * <p> + * The types form a lattice; @see <a href="https://en.wikipedia.org/wiki/Lattice_(order)">a symmetric complete bounded (ranked) lattice.</a> + * <p> + * This wild lattice theory will be needed later to allow us to easily beef up + * the analysis and optimization of the Simple compiler... but we don't need it + * now, just know that it is coming along in a later Chapter. + * <p>g + * One of the fun things here is that while the theory is deep and subtle, the + * actual implementation is darn near trivial and is generally really obvious + * what we're doing with it. Right now, it's just simple integer math to do + * simple constant folding e.g. 1+2 == 3 stuff. + */ + +public class Type /*implements Cloneable*/ { + // Interning tables + + // Main intern table; a collection of all unique types. + static final HashMap<Type,Type> INTERN = new HashMap<>(); + // Starting intern table; used to rapidly reset the main table between tests + private static final HashMap<Type,Type> INTERN0= new HashMap<>(); + // Lifetime management during cyclic installs is complex; this is used to + // track created-but-already-interned objects + private static final Ary<Type> FREES = new Ary<>(Type.class); + // "visit" bit management, based solely on _uid + static final BitSet BITS = new BitSet(); + + // "visit" bit management. Key varies by kind of visit: + + // - "close" an open cyclic type. Used by the Parser, it will hit on + // same-named structs, even if the structs have different states of + // completion/fields. + // - "uid/name" - Either the UID or name works (unlike "close" which must + // use the name). Used to make cyclic copies with changes, like make + // read-only where there should be only 1 copy of a name in a cycle. + // - "pair of uids" - For recursive MEET, where we need to key off two types + static final HashMap<Object,Type> VISIT = new HashMap<>(); + + // Every Type has a UID to allow visit bits on cyclic visits + private static int UID=1; + public char _uid; // Unique ID for every type + + // ---------------------------------------------------------- + // Simple types are implemented fully here. "Simple" means: the code and + // type hierarchy are simple, not that the Type is conceptually simple. + static final byte TBOT = 0; // Bottom (ALL) + static final byte TTOP = 1; // Top (ANY) + static final byte TCTRL = 2; // Ctrl flow bottom + static final byte TXCTRL = 3; // Ctrl flow top (mini-lattice: any-xctrl-ctrl-all) + static final byte TNIL = 4; // low null of all flavors + static final byte TXNIL = 5; // high or choice null + static final byte TSIMPLE = 6; // End of the Simple Types + + static final byte TPTR = 7; // All nil-able scalar values + static final byte TINT = 8; // All Integers; see TypeInteger + static final byte TFLT = 9; // All Floats ; see TypeFloat + static final byte TCONARY =10; // Constant array + static final byte TRPC =11; // Return Program Control (Return PC or RPC) + static final byte TTUPLE =12; // Tuples; finite collections of unrelated Types, kept in parallel + + static final byte TCYCLIC =13; // Has internal pointers, needs recursive treatment + static final byte TMEMPTR =13; // Memory pointer to a struct type + static final byte TFUNPTR =14; // Function pointer; unique signature and code address (just a bit) + static final byte TMEM =15; // All memory (alias 0) or A slice of memory - with specific alias + static final byte TSTRUCT =16; // Structs; tuples with named fields + static final byte TFLD =17; // Named fields in structs + + // Basic RTTI, useful for a lot of fast tests. + public final byte _type; + public boolean _terned; + + public boolean is_simple() { return _type < TSIMPLE; } + private static final String[] STRS = new String[]{"Bot","Top","Ctrl","~Ctrl","null","~nil"}; + static final int[] CNTS = new int[TFLD+1]; + protected Type(byte type) { + _type = type; // RTTI + _uid = (char)UID++; // A unique ID for every type + assert _uid!=0; // Overflow + CNTS[type]++; + } + + public static final Type BOTTOM = new Type( TBOT ).intern(); // ALL + public static final Type TOP = BOTTOM.dual(); + public static final Type CONTROL = new Type( TCTRL ).intern(); // Ctrl + public static final Type XCONTROL = CONTROL.dual(); + public static final Type NIL = new Type( TNIL ).intern(); // low null of all flavors + public static final Type XNIL = NIL.dual(); + public static Type[] gather() { + ArrayList<Type> ts = new ArrayList<>(); + ts.add(BOTTOM); + ts.add(CONTROL); + ts.add(NIL); + TypeNil.gather(ts); + TypePtr.gather(ts); + TypeInteger.gather(ts); + TypeFloat.gather(ts); + TypeMemPtr.gather(ts); + TypeFunPtr.gather(ts); + TypeMem.gather(ts); + Field.gather(ts); + TypeStruct.gather(ts); + TypeTuple.gather(ts); + TypeRPC.gather(ts); + TypeConAry.gather(ts); + + int sz = ts.size(); + for( int i = 0; i < sz; i++ ) + ts.add(ts.get(i).dual()); + return ts.toArray(new Type[ts.size()]); + } + + // Is high or on the lattice centerline. + public boolean isHigh () { return _type==TTOP || _type==TXCTRL || _type==TXNIL; } + public boolean isHighOrConst() { return isHigh() || isConstant(); } + + // ---------------------------------------------------------- + + // Notes on Type interning: At the moment it is not easy to reset the + // interned types because we hold static references to several types and + // these are scattered around. This means the INTERN cache will retain all + // types from every run of the Parser. For this to work correctly types + // must be rigorous about defining when they are the same. Also types need + // to be immutable once defined. The rationale for interning is + // *correctness* with cyclic type definitions. Simple structural recursive + // checks go exponential with merely sharing, but with cycles they will + // stack overflow and crash. Interning means we do not need to have sharing + // checks with every type compare, only during interning. + + // Factory method which interns "this" + @SuppressWarnings("unchecked") + <T extends Type> T intern() { + //assert check(); + assert !_terned; // Do not ask for already-interned + T t2 = (T)INTERN.get(this); + if( t2!=null ) { + assert t2._dual != null; // Prior is complete with dual + assert this != t2; // Do not hashcons twice, should not get self back + return t2; // Return prior + } + // Mid recursive type construction + if( !VISIT.isEmpty() && _type >= TCYCLIC ) { + // No intern attempt at all + return (T)this; + } + // Not in type table + _dual = null; // No dual yet + INTERN.put(this,this); // Put in table without dual + _terned = true; + //Util.hash_quality_check_per(INTERN,"INTERN"); + T d = xdual(); // Compute dual without requiring table lookup, and not setting name + _dual = d; + if( this==d ) return d; // Self-symmetric? Dual is self + assert !equals(d); // Self-symmetric is handled by caller + assert d._dual==null; // Else dual-dual not computed yet + assert INTERN.get(d)==null; + d._dual = (T)this; + INTERN.put(d,d); // Install dual also + d._terned = true; + //assert check(); + return (T)this; + } + + // Recursive visit elsewhere, interns with dual already + <T extends Type> T _intern() { + //assert check(); + assert !_terned; + Type t = INTERN.get(this); + if( t!=null ) return (T)t.delayFree(this).delayFree(_dual); + assert !INTERN.containsKey( _dual ); + INTERN.put(this,this); + INTERN.put(_dual,_dual); + _terned = _dual._terned = true; + //assert check(); + return (T)this; + } + + private static boolean check() { + for( Type t : INTERN.keySet() ) { + Type t2 = INTERN.get(t); + assert t==t2; + } + return true; + } + + public static Type find(int uid) { + for( Type t : INTERN.keySet() ) + if( t._uid==uid ) return t; + return null; + } + + + int _hash; // Hash cache; not-zero when set. + @Override + public final int hashCode() { + if( _hash!=0 ) return _hash; + _hash = hash(); + if( _hash==0 ) _hash = 0xDEADBEEF; // Bad hash from subclass; use some junk thing + return _hash; + } + // Override in subclasses + int hash() { return _type; } + + @Override + public final boolean equals( Object o ) { + if( o==this ) return true; + if( !(o instanceof Type t)) return false; + if( _type != t._type ) return false; + return eq(t); + } + // Overridden in subclasses; subclass can assume "this!=t" and java classes are same + boolean eq(Type t) { return this==t; } + boolean cycle_eq(Type t) { assert _type < TCYCLIC; return eq(t); } + // A pair of uids + int pid( Type that ) { + return _uid < that._uid ? (_uid<<16 | that._uid) : (that._uid<<16 | _uid); + } + + // At/Set child at 'idx' to t + Type at ( int idx ) { throw Utils.TODO(); } + void set( int idx, Type t ) { throw Utils.TODO(); } + int nkids() { assert _type < TTUPLE; return 0; } // Number of kids + + + // Clear and re-insert the basic Type INTERN table + public static void reset() { + VISIT.clear(); + FREES.clear(); + if( INTERN0.isEmpty() ) { + // First time run all <clinit> and collect basic types + Type t = TypeRPC .BOT; // Force class load, intern + Type u = TypeTuple.BOT; // Force class load, intern + Type w = TypePtr .PTR; // Force class load, intern + INTERN0.putAll(INTERN); + } else { + // Later times, reset back to first time + VISIT.put(0,CONTROL); // Defeat assert + for( Iterator<Type> it = INTERN.keySet().iterator(); it.hasNext(); ) { + Type t = it.next(); + if( !INTERN0.containsKey(t) ) + { t._terned=false; t.free(t); } + it.remove(); + } + VISIT.clear(); + INTERN.putAll(INTERN0); + } + } + + // ---------------------------------------------------------- + public final Type meet(Type t) { + // Shortcut for the self case + if( t == this ) return this; + // Same-type is always safe in the subclasses + if( _type==t._type ) return xmeet(t); + // TypeNil vs TypeNil meet + if( this instanceof TypeNil ptr0 && t instanceof TypeNil ptr1 ) + return ptr0.nmeet(ptr1); + // Reverse; xmeet 2nd arg is never "is_simple" and never equal to "this". + if( is_simple() ) return this.xmeet(t ); + if( t.is_simple() ) return t .xmeet(this); + return Type.BOTTOM; // Mixing 2 unrelated types + } + + // Compute meet right now. Overridden in subclasses. + // Handle cases where 'this.is_simple()' and unequal to 't'. + // Subclassed xmeet calls can assert that '!t.is_simple()'. + Type xmeet(Type t) { + assert is_simple(); // Should be overridden in subclass + // ANY meet anything is thing; thing meet ALL is ALL + if( _type==TBOT || t._type==TTOP ) return this; + if( _type==TTOP || t._type==TBOT ) return t; + + // RHS TypeNil vs NIL/XNIL + if( _type== TNIL ) return t instanceof TypeNil ptr ? ptr.meet0() : (t._type==TXNIL ? TypePtr.PTR : BOTTOM); + if( _type== TXNIL ) return t instanceof TypeNil ptr ? ptr.meetX() : (t._type== TNIL ? TypePtr.PTR : BOTTOM); + + // 'this' is only {TCTRL,TXCTRL} + // Other non-simple RHS things bottom out + if( !t.is_simple() ) return BOTTOM; + // If RHS is NIL/XNIL + if( t._type==TNIL || t._type==TXNIL ) return BOTTOM; + // Both are {TCTRL,TXCTRL} and unequal to each other + return _type==TCTRL || t._type==TCTRL ? CONTROL : XCONTROL; + } + + + // The dual is pre-computed on creation and available "for free" thereafter + Type _dual; + public final <T extends Type> T dual() { return (T)_dual; } + + <T extends Type> T xdual() { + return (T)new Type(switch( _type ) { + case TBOT -> TTOP; + case TTOP -> TBOT; + case TCTRL -> TXCTRL; + case TXCTRL-> TCTRL; + case TNIL -> TXNIL; + case TXNIL -> TNIL; + default -> throw Utils.TODO(); // Should not reach here + }); + } + + + // ---------------------------------------------------------- + // Our lattice is defined with a MEET and a DUAL. + // JOIN is dual of meet of both duals. + public final Type join(Type t) { + if( this==t ) return this; + return dual().meet(t.dual()).dual(); + } + + // True if this "isa" t; e.g. 17 isa TypeInteger.BOT + public boolean isa( Type t ) { return meet(t)==t; } + + // True if this "isa" t up to named structures + public boolean shallowISA( Type t ) { return isa(t); } + + public Type nonZero() { return TypePtr.NPTR; } + + // Make a zero version of this type, 0 for integers and null for pointers. + public Type makeZero() { return Type.NIL; } + + // Is forward-reference + public boolean isFRef() { return false; } + + // ---------------------------------------------------------- + + // Cyclic types! Flag the start of a cyclic type by putting a sentinel in + // VISIT (and eventually clearing VISIT when done). Then do a normal + // recursive descent visit of all types; this will accumilate types without + // interning them. When done we have to visit the possibly cyclic type and + // intern the whole cycle, possibly hitting the entire cycle on a prior + // interned cycle. Any sub-part might also be interned, including whole + // disjoint cycles. + + // E.g. a new type: "A<->B -> C1<->D1" gets created; the "C1<->D1" cycle + // already exists as "C0<->D0", but the "A<->B" cycle is new. The "A<->B" + // cycle will get interned - except the pointer to C1 needs to get replaced + // with C0. The "C1<->D1" cycle gets freed and "B" will point to the + // "C0<->D0" cycle. + + Type recurOpen() { assert VISIT.isEmpty(); VISIT.put(0L,BOTTOM); return this; } + Type recurClose() { + VISIT.remove(0L); // Just ignore the sentinel + Ary<Type> ts = new Ary<>(Type.class); + ts.addAll(VISIT.values()); + if( ts.find(this)== -1 ) ts.add(this); + + // Pass #1: replace already interned fields + assert BITS.isEmpty(); + for( int i=0; i<ts._len; i++ ) + if( ts.at(i).tern()._terned ) + ts.del(i--); + BITS.clear(); + + // Pass#2: compute recursive duals + for( Type t : ts ) + t.rdual(); + + // Pass#3: Recursive install + for( Type t : ts ) + if( !t._terned && INTERN.get(t)==null ) + t.install(); + // Upgrade the result + Type rez = INTERN.get(this); + assert rez!=null; + + // Pass#4?: Free up any created-but-already interned + for( Type t : FREES ) + t.rfree(); + FREES.clear(); + VISIT.clear(); + return rez; + } + + // Read-only recursive visits do not *make* cyclic types and so the cleanup + // is much easier. + static boolean recurClose(boolean rez) { VISIT.clear(); return rez; } + + final Type tern() { + if( _terned ) return this; + if( !BITS.get(_uid) ) { + BITS.set(_uid); + int nkids = nkids(); + for( int i=0; i<nkids; i++ ) + set(i,at(i).tern()); + } + Type told = INTERN.get(this); + return told==null ? this : told.delayFree(this); + } + + // Recursive dual. Visit all types recursively. Each visited type is + // *new*, and hits in the intern table, or not. If not, we recursively + // call rdual to get its dual, and cross-link the duals. If hitting, we + // use the intern type and mark the prior type for freeing. + Type rdual() { assert !_terned; return xdual(); } + + // Recursively free type and children + final void rfree() { + if( isFree() ) return; + int nkids = nkids(); + for( int i=0; i<nkids; i++ ) + if( !at(i)._terned ) + at(i).rfree(); + free(this); + } + + Type free(Type free) { return this; } + boolean isFree() { return false; } + + <T extends Type> T delayFree(Type free) { + assert !free._terned; + FREES.push(free); + return (T)this; + } + + final Type install() { + if( this instanceof TypeStruct ) { + Type x = _intern(); // Stop the recursion + assert x==this; + } + int nkids = nkids(); + for( int i=0; i<nkids; i++ ) { + Type kid = at(i); + if( !kid._terned ) { + Type ikid = kid.install(); + if( ikid != kid ) { + set(i,ikid); + _dual.set(i,ikid.dual()); + } + } + } + return this instanceof TypeStruct ? this : _intern(); + } + + // Strict constant values, things on the lattice centerline. + // Excludes both high and low values + public final boolean isConstant() { return recurClose(recurOpen()._isConstant()); } + boolean _isConstant() { return _type==TNIL; } + + // Are all reachable struct Fields are final? + public final boolean isFinal() { return recurClose(recurOpen()._isFinal()); } + boolean _isFinal() { assert _type < TCYCLIC; return true; } + + public final Type makeRO() { + if( isFinal() ) return this; + return recurOpen()._makeRO().recurClose(); + } + Type _makeRO() { return this; } + + // Compute greatest lower bound in the lattice. If values are in memory, + // ints and floats cannot widen. + public final boolean isGLB(boolean mem) { return recurClose(recurOpen()._isGLB(mem)); }; + boolean _isGLB(boolean mem) { + return switch(_type) { + case TBOT -> false; + case TNIL -> false; + case TCTRL -> true; + case TXCTRL -> false; + case TXNIL -> false; + case TTOP -> false; + default -> throw Utils.TODO(); + }; + } + public final Type glb(boolean mem) { + if( isGLB(mem) ) return this; + Type glb = recurOpen()._glb(mem).recurClose(); + assert this.isa(glb); + return glb; + } + Type _glb(boolean mem) { assert is_simple(); return Type.BOTTOM; } + + Type _close() { return this; } + + // ---------------------------------------------------------- + + // Size in bits to hold an instance of this type. + // Sizes are expected to be between 1 and 64 bits. + // Size 0 means this either takes no space (such as a known-zero field) + // or isn't a scalar to be stored in memory. + public int log_size () { return 3; } // log-size of a type; log_size for a struct is usually undefined + public int size() { return 1<<log_size(); } + public int alignment() { return log_size(); } // alignment; for structs, max align of Fields + + // ---------------------------------------------------------- + // Useful in the debugger, which calls toString everywhere. + // This is a more verbose dev-friendly print. + @Override + public final String toString() { + return print(new SB(), new BitSet(), false).toString(); + } + public final String gprint() { + return print(new SB(), new BitSet(), true).toString(); + } + public final SB print(SB sb) { return print(sb, new BitSet(), false); } + public final SB gprint(SB sb) { return print(sb, new BitSet(), true ); } + + // Used during recursive printing, or combined with SB Node printing + public final SB print(SB sb, BitSet visit, boolean html ) { + if( visit.get(_uid) ) return sb.p(str()); + visit.set(_uid); + return _print(sb,visit,html); + } + SB _print(SB sb, BitSet visit, boolean html ) { return sb.p(str()); } + + // This is used by error messages, and is a shorted print. + public String str() { return STRS[_type]; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeConAry.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeConAry.java new file mode 100644 index 00000000..d4003f87 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeConAry.java @@ -0,0 +1,82 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; + +/** + * Represents a constant array of primitives + */ +public class TypeConAry<A> extends Type { + boolean _any; + // One of byte,short,int,long,float,double array + public final A _ary; + + TypeConAry( boolean any, byte type, A ary ) { super(type); _any = any; _ary = ary; } + public static final TypeConAry BOT = new TypeConAry(false, TINT, null).intern(); + public static void gather(ArrayList<Type> ts) { + ts.add(BOT); + TypeConAryB.gather(ts); + TypeConAryI.gather(ts); + } + + @Override public String str() { return (_any?"~":"") + "[]"; } + @Override TypeConAry xdual() { + if( _ary==null ) + return new TypeConAry(!_any,_type,null); + return this; + } + + @Override Type xmeet(Type t) { + if( t instanceof TypeInteger ti ) return imeet(ti); + TypeConAry ary = (TypeConAry)t; // Invariant + if( this==BOT ) return BOT; + if( ary ==BOT ) return BOT; + if( this==BOT.dual() ) return ary ; + if( ary ==BOT.dual() ) return this; + assert _ary!=ary._ary; // Already interned and this!=t + return elem().meet(ary.elem()); + } + Type imeet( TypeInteger ti ) { + if( this==BOT.dual() ) return ti; + if( this==BOT ) return BOT; + Type elem = elem(); + if( !(elem instanceof TypeInteger) ) return BOTTOM; + if( ti.isHigh() && elem.isa(ti.dual()) ) + return this; + return elem.meet(ti); + } + + + @Override public boolean isHigh() { return this==TOP; } + @Override boolean _isConstant() { return true; } + + // Meet-over-elements type + public Type elem() { + if( _ary==null ) + return _any ? Type.TOP : BOTTOM; + int len = len(); + long min = Long.MAX_VALUE; + long max = Long.MIN_VALUE; + for( int i=0; i<len; i++ ) { + min = Math.min(min,at8(i)); + max = Math.max(max,at8(i)); + } + return TypeInteger.make(min,max); + } + public long at8(int idx) { throw Utils.TODO(); } + public int len() { throw Utils.TODO(); } + @Override public int log_size() { throw Utils.TODO(); } + public void write( ByteArrayOutputStream baos ) { throw Utils.TODO(); } + + @Override boolean eq(Type t) { + return t instanceof TypeConAry ary && _any==ary._any && ary._ary==null; + } + + @Override int hash() { + assert _ary==null; + return _any ? 1024 : 0; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java new file mode 100644 index 00000000..fd2b2635 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java @@ -0,0 +1,21 @@ +package com.seaofnodes.simple.type; + +import java.util.ArrayList; +import java.util.Arrays; +import java.io.ByteArrayOutputStream; + +public class TypeConAryB extends TypeConAry<byte[]> { + private TypeConAryB(byte[] bs) { super(false,TINT,bs); } + public static TypeConAryB make( byte[] bs ) { return new TypeConAryB(bs).intern(); } + public static TypeConAryB make( String s ) { return make(s.getBytes()); } + static final TypeConAryB ABC = make("abc"); + static final TypeConAryB ABCD = make("abcd"); + public static void gather(ArrayList<Type> ts) { ts.add(ABC); ts.add(ABCD); } + @Override public long at8(int idx) { return _ary[idx]; } + @Override public int len() { return _ary.length; } + @Override public int log_size() { return 0; } + @Override public String str() { return "[\""+new String(_ary)+"\"]"; } + @Override boolean eq(Type t) { return Arrays.equals(_ary,((TypeConAryB)t)._ary); } + @Override int hash() { return Arrays.hashCode(_ary); } + @Override public void write( ByteArrayOutputStream baos ) { baos.write(_ary,0,_ary.length); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java new file mode 100644 index 00000000..924e3d73 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java @@ -0,0 +1,17 @@ +package com.seaofnodes.simple.type; + +import java.util.ArrayList; +import java.util.Arrays; + +public class TypeConAryI extends TypeConAry<int[]> { + private TypeConAryI(int[] bs) { super(false,TINT,bs); } + public static TypeConAryI make( int[] bs ) { return new TypeConAryI(bs).intern(); } + private static final TypeConAryI I123 = make(new int[]{1,2,3}); + public static void gather(ArrayList<Type> ts) { ts.add(I123); } + @Override public long at8(int idx) { return _ary[idx]; } + @Override public int len() { return _ary.length; } + @Override public int log_size() { return 2; } + @Override public String str() { return "[i32]"; } + @Override boolean eq(Type t) { return Arrays.equals(_ary,((TypeConAryI)t)._ary); } + @Override int hash() { return Arrays.hashCode(_ary); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeFloat.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeFloat.java new file mode 100644 index 00000000..f3de581c --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeFloat.java @@ -0,0 +1,110 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.util.Ary; +import java.util.ArrayList; + +/** + * Float Type + */ +public class TypeFloat extends Type { + + // - high -64, high -32, con 0, low +32, low +64 + public byte _sz; + + /** + * The constant value or 0 + */ + public double _con; + + private static final Ary<TypeFloat> FREE = new Ary<>(TypeFloat.class); + private TypeFloat(byte sz, double con) { super(TFLT); init(sz,con); } + private TypeFloat init( byte sz, double con ) { _sz = sz; _con = con; return this; } + public static TypeFloat malloc(byte sz, double con) { return FREE.isEmpty() ? new TypeFloat(sz,con) : FREE.pop().init(sz,con); } + private static TypeFloat make(int sz, double con) { + TypeFloat f = malloc((byte)sz,con); + TypeFloat t2 = f.intern(); + return t2==f ? f : t2.free(f); + } + @Override TypeFloat free(Type t) { + TypeFloat f = (TypeFloat)t; + f._hash = 0; + f._dual=null; + FREE.push(f); + return this; + } + + public static TypeFloat constant(double con) { return make(0, con); } + + public final static TypeFloat ONE = constant(1.0); + public final static TypeFloat FZERO = constant(0.0); + public final static TypeFloat F32 = make(32, 0); + public final static TypeFloat F64 = make(64, 0); + + public static void gather(ArrayList<Type> ts) { ts.add(F64); ts.add(F32); ts.add(constant(3.141592653589793)); } + + @Override public String str() { + return switch( _sz ) { + case -64 -> "~flt"; + case -32 -> "~f32"; + case 0 -> ""+_con+((float)_con==_con ? "f" : ""); + case 32 -> "f32"; + case 64 -> "flt"; + default -> throw Utils.TODO(); + }; + } + private boolean isF32() { return ((float)_con)==_con; } + + @Override public boolean isHigh () { return _sz< 0; } + @Override public int log_size() { return _sz==32 || _sz==-32 ? 2 : 3; } + + public double value() { return _con; } + + @Override + public TypeFloat xmeet(Type other) { + TypeFloat f = (TypeFloat)other; + // Invariant from caller: 'this' != 'other' and same class (TypeFloat). + TypeFloat i = (TypeFloat)other; // Contract + // Larger size in i1, smaller in i0 + TypeFloat i0 = _sz < i._sz ? this : i; + TypeFloat i1 = _sz < i._sz ? i : this; + + if( i1._sz== 64 ) return F64; + if( i0._sz==-64 ) return i1; + if( i1._sz== 32 ) + return i0._sz==0 && !i0.isF32() ? F64 : F32; + if( i1._sz!= 0 ) return i1; + // i1 is a constant + if( i0._sz==-32 ) + return i1.isF32() ? i1 : F64; + // Since both are constants, and are never equals (contract) unequals + // constants fall to bottom + return i0.isF32() && i1.isF32() ? F32 : F64; + } + + @Override + TypeFloat xdual() { + return _isConstant() ? this : new TypeFloat((byte)-_sz,0); // Constants are a self-dual + } + + @Override boolean _isGLB(boolean mem) { return _glb(mem)==this; } + @Override Type _glb(boolean mem) { + if( !mem ) return F64; + if( _isConstant() ) return isF32() ? F32 : F64; + return isHigh() ? dual() : this; + } + + @Override boolean _isConstant() { return _sz==0; } + + @Override public Type makeZero() { return FZERO; } + @Override + int hash() { return (int)(Double.hashCode(_con) ^ _sz ^ (1<<17)); } + @Override + public boolean eq( Type t ) { + TypeFloat i = (TypeFloat)t; // Contract + // Allow NaN to check for equality + return _sz==i._sz && Double.doubleToLongBits(_con)==Double.doubleToLongBits(i._con); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java new file mode 100644 index 00000000..b21dd451 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java @@ -0,0 +1,241 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.util.Ary; +import java.util.*; + +/** + * Represents a Pointer to a function. + * <p></p> + * Functions have argument types and a return type, making a function + * signature. Within a signature there can be many instances of functions, and + * each function is labeled with a small integer constant. A TFP can represent + * a single signature and a set of functions; the set might contain only 1 + * function or the zeroth function (the null ptr). + * <p></p> + * Functions with different signatures cannot be mixed, and will result in a + * bottom function type, which can only be null-checked. + */ +public class TypeFunPtr extends TypeNil { + // A TypeFunPtr is Signature and a set of functions. + public Type[] _sig; + public Type _ret; + // TODO: + boolean _open; // Extra args are true:BOTTOM, false:TOP + // Cheesy easy implementation for a small set; 1 bit per unique function + // within the same Type[]. Can be upgraded to a BitSet for larger classes + // of functions. Negative means "these 63 concrete bits plus infinite + // unknown more" + public long _fidxs; // 63 unique functions per signature + + private static final Ary<TypeFunPtr> FREE = new Ary<>(TypeFunPtr.class); + private TypeFunPtr(byte nil, boolean open, Type[] sig, Type ret, long fidxs) { super(TFUNPTR,nil); init(nil,open,sig,ret,fidxs); } + private TypeFunPtr init(byte nil, boolean open, Type[] sig, Type ret, long fidxs ) { + assert sig != null; + _nil = nil; + _open = open; + _sig = sig; + _ret = ret; + _fidxs= fidxs; + return this; + } + static TypeFunPtr malloc( byte nil, boolean open, Type[] sig, Type ret, long fidxs ) { + return FREE.isEmpty() ? new TypeFunPtr(nil,open,sig,ret,fidxs) : FREE.pop().init(nil,open,sig,ret,fidxs); + } + @Override TypeFunPtr free(Type t) { + TypeFunPtr fun = (TypeFunPtr)t; + assert !fun.isFree() && !fun._terned; + fun._sig = null; + fun._ret = null; + fun._dual = null; + fun._hash = 0; + FREE.push(fun); + return this; + } + @Override boolean isFree() { return _sig==null; } + + // All fields directly listed + public static TypeFunPtr make( byte nil, boolean open, Type[] sig, Type ret, long fidxs ) { + TypeFunPtr fun = malloc(nil,open,sig,ret,fidxs); + TypeFunPtr f2 = fun.intern(); + if( f2==fun ) return fun; + return VISIT.isEmpty() ? f2.free(fun) : f2.delayFree(fun); + } + public static TypeFunPtr make( boolean nil, boolean open, Type[] sig, Type ret ) { return make((byte)(nil ? 3 : 2),open,sig,ret,-1); } + + + @Override TypeFunPtr makeFrom( byte nil ) { return nil ==_nil ? this : make( nil,_open,_sig,_ret, _fidxs); } + public TypeFunPtr makeFrom( Type ret ) { return ret ==_ret ? this : make( _nil,_open,_sig, ret, _fidxs); } + public TypeFunPtr makeFrom( int fidx ) { return make((byte)2, _open, _sig,_ret,1L<<fidx ); } + + + public static final Type[] TEMPTY = new Type[0]; + static final Type[] TINT = new Type[]{TypeInteger.BOT}; + static final Type[] TINTMEM = new Type[]{TypeInteger.BOT,TypeFloat.F32}; + static final Type[] TINTINT = new Type[]{TypeInteger.BOT,TypeInteger.BOT}; + public static TypeFunPtr BOT = make((byte)3,true ,TEMPTY,Type.BOTTOM,-1); + public static TypeFunPtr TEST = make((byte)2,false,TINTMEM,TypeInteger.BOT, 1); + public static TypeFunPtr TEST0 = make((byte)3,false,TINTMEM,TypeInteger.BOT, 3); + public static TypeFunPtr MAIN = make((byte)3,false,TINT ,Type.BOTTOM,-1); // Main can return anything + public static TypeFunPtr CALLOC= make((byte)3,false,TINTINT,TypeMemPtr .BOT,-1); + public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST0); ts.add(BOT); ts.add(MAIN);ts.add(CALLOC); } + + @Override + Type xmeet(Type t) { + TypeFunPtr that = (TypeFunPtr) t; + // if equal, no matters. + // if short is BOT, chop ; recurPre on short. + // if short is TOP, copy long; recurPre on long. + TypeFunPtr min = _sig.length < that._sig.length ? this : that; + if( _sig.length != that._sig.length && (min._open ^ min==this) ) + return that.xmeet(this); + // Recurse all common fields + Type[] args = new Type[_sig.length]; + for( int i=0; i<min._sig.length; i++ ) + args[i] = _sig[i].meet(that._sig[i]); + // Handle extra args + for( int i=min._sig.length; i<_sig.length; i++ ) + args[i] = _sig[i]; + return make(xmeet0(that),_open | that._open, args, _ret.meet(that._ret), _fidxs | that._fidxs); + } + static Type[] xmeet( Type[] ts0, Type[] ts1) { + if( ts0==ts1 ) return ts0; + assert ts0.length==ts1.length; + Type[] ts = new Type[ts0.length]; + for( int i=0; i<ts0.length; i++ ) + ts[i] = ts0[i].meet(ts1[i]); + return ts; + } + + @Override TypeFunPtr xdual() { return malloc(dual0(), !_open, xdual(_sig), _ret.dual(), ~_fidxs); } + static Type[] xdual(Type[] ts) { + Type[] dual = new Type[ts.length]; + for( int i=0; i<ts.length; i++ ) + dual[i] = ts[i].dual(); + return dual; + } + + @Override TypeFunPtr rdual() { + if( _dual!=null ) return dual(); + assert !_terned; + Type[] sigs = new Type[_sig.length]; + TypeFunPtr d = malloc(dual0(),!_open,sigs,null,~_fidxs); + (_dual = d)._dual = this; // Cross link duals + // Return rdual + d._ret = _ret._terned ? _ret.dual() : _ret.rdual(); + // Signature rdual + for( int i=0; i<_sig.length; i++ ) + sigs[i] = _sig[i]._terned ? _sig[i].dual() : _sig[i].rdual(); + return d; + } + + // RHS is NIL; do not deep-dual when crossing the centerline + @Override public Type meet0() { return _nil==3 ? this : make((byte)3,_open,_sig,_ret,_fidxs); } + + @Override public boolean isHigh() { return _nil <= 1 || (_nil==2 && _fidxs==0); } + + @Override boolean _isConstant() { return (_nil==2 && Long.bitCount(_fidxs)==1) || (_nil==3 && _fidxs==0); } + + @Override boolean _isFinal() { return true; } + @Override boolean _isGLB(boolean mem) { return true; } + @Override TypeFunPtr _glb(boolean mem) { return this; } + @Override TypeFunPtr _close() { + Type[] sig = new Type[_sig.length]; + TypeFunPtr fun = malloc(_nil,false,sig,null,_fidxs); + // Now start the recursion + fun._ret = _ret._close(); + for( int i=0; i<sig.length; i++ ) + sig[i] = _sig[i]._close(); + + return fun; + } + + @Override public int log_size() { return 2; } // (1<<2)==4-byte pointers + + public Type arg(int i) { return _sig[i]; } + public long fidxs() { return _fidxs; } + public Type ret() { return _ret; } + public int nargs() { return _sig.length; } + public int fidx() { assert Long.bitCount(_fidxs)==1; return Long.numberOfTrailingZeros(_fidxs); } + + + @Override int nkids() { return _sig.length+1; } + @Override Type at( int idx ) { + return idx == _sig.length ? _ret : _sig[idx]; + } + @Override void set( int idx, Type t ) { + if( idx == _sig.length ) _ret = t; + else _sig[idx] = t; + } + + @Override + int hash() { + long hash = _ret.hashCode() ^ _fidxs ^ super.hash(); + for( Type arg : _sig ) + hash = hash*19 ^ arg.hashCode(); + return Utils.fold(hash); + } + + @Override + boolean eq(Type t) { + // Recursive; so use cyclic equals + if( !VISIT.isEmpty() ) { + assert TypeStruct.CEQUALS.isEmpty(); + boolean rez = cycle_eq(t); + TypeStruct.CEQUALS.clear(); + return rez; + } + TypeFunPtr fun = (TypeFunPtr)t; // Invariant + if( !super.eq(fun) || _open != fun._open || _fidxs != fun._fidxs || _sig.length != fun._sig.length ) return false; + if( _sig == fun._sig && _ret == fun._ret ) return true; + + if( !_ret.eq(fun._ret) ) return false; + for( int i = 0; i < _sig.length; i++ ) + if( !_sig[i].eq(fun._sig[i]) ) + return false; + return true; + } + @Override boolean cycle_eq(Type t) { + if( t._type != TFUNPTR ) return false; + TypeFunPtr fun = (TypeFunPtr)t; // Invariant + if( !super.eq(fun) || _open != fun._open || _fidxs != fun._fidxs || _sig.length != fun._sig.length ) return false; + if( _sig == fun._sig && _ret == fun._ret ) return true; + + // Check to see if we've ever compared this pair of types before; + // if so, then assume the cycle is equal here. + int pid = pid(fun); + if( TypeStruct.CEQUALS.find(pid)!= -1 ) return true; + TypeStruct.CEQUALS.push(pid); + if( !_ret.cycle_eq(fun._ret) ) return false; + for( int i = 0; i < _sig.length; i++ ) + if( !_sig[i].cycle_eq(fun._sig[i]) ) + return false; + return true; + } + + @Override public String str() { return "{"+printFIDX()+"}"; } + + SB _print(SB sb, BitSet visit, boolean html ) { + sb.p(x()).p("{ "); + if( _sig!=null ) + for( Type t : _sig ) + sb.p(t.str()).p(" "); // Short form in signature + _ret.print(sb.p(html ? "→ " : "-> "),visit,html).p(" #"); + // Print fidxs + return sb.p(printFIDX()).p("}").p(q()); + } + String printFIDX() { + String tilde = isHigh() ? "~" : ""; + long fidxs = isHigh() ? ~_fidxs : _fidxs; + String fidx = fidxs==0 ? "" + : Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs) + : fidxs == -1 ? "ALL" + : "b"+Long.toBinaryString(fidxs); // Just some function bits + return tilde+fidx; + } + + // Usage: for( long fidxs=fidxs(); fidxs!=0; fidxs=nextFIDX(fidxs) { int fidxs = Long.numberOfTrailingZeros(fidxs); ... } + public static long nextFIDX(long fidxs) { return fidxs & (fidxs-1); } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeInteger.java new file mode 100644 index 00000000..99f237a9 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeInteger.java @@ -0,0 +1,153 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.ArrayList; + +/** + * Integer Type + */ +public class TypeInteger extends Type { + /** + * Describes an integer *range* - everything from min to max; both min and + * max are inclusive. If min==max, this is a constant. + * <br> + * If min <= max, this is a below center (towards bottom). + * If min > max, this is an above center (towards top). + */ + public long _min, _max; + + private static final Ary<TypeInteger> FREE = new Ary<>(TypeInteger.class); + private TypeInteger(long min, long max) { super(TINT); init(min,max); } + private TypeInteger init(long min, long max) { _min = min; _max = max; return this; } + public static TypeInteger malloc(long lo, long hi) { return FREE.isEmpty() ? new TypeInteger(lo,hi) : FREE.pop().init(lo,hi); } + public static TypeInteger make(long lo, long hi) { + TypeInteger i = malloc(lo,hi); + TypeInteger t2 = i.intern(); + return t2==i ? i : t2.free(i); + } + @Override TypeInteger free(Type t) { + TypeInteger i = (TypeInteger)t; + i._min = i._max = 0; + i._hash = 0; + i._dual = null; + FREE.push(i); + return this; + } + + public static TypeInteger constant(long con) { return make(con, con); } + + public final static TypeInteger ZERO= make(0,0); + public final static TypeInteger FALSE=ZERO; + public final static TypeInteger TRUE= make(1,1); + public final static TypeInteger TWO = make(2,2); // Shows up in some Simple tests as the starting argument + + public final static TypeInteger I1 = make(-1,0); + public final static TypeInteger I8 = make(-128,127); + public final static TypeInteger I16 = make(-32768,32767); + public final static TypeInteger I32 = make(-1L<<31,(1L<<31)-1); + public final static TypeInteger BOT = make(Long.MIN_VALUE,Long.MAX_VALUE); + public final static TypeInteger TOP = (TypeInteger)BOT.dual(); + + public final static TypeInteger U1 = make(0,1); + public final static TypeInteger BOOL= U1; + public final static TypeInteger U8 = make(0,255); + public final static TypeInteger U16 = make(0,65535); + public final static TypeInteger U32 = make(0,(1L<<32)-1); + + public static void gather(ArrayList<Type> ts) { ts.add(I32); ts.add(BOT); ts.add(U1); ts.add(I1); ts.add(U8); } + + @Override public String str() { + if( _isConstant() ) return ""+_min; + long lo = _min, hi = _max; + String x = ""; + if( hi < lo ) { + lo = _max; hi = _min; + x = "~"; + } + return x+_str(lo,hi); + } + private static String _str(long lo, long hi) { + if( lo==Long.MIN_VALUE && hi==Long.MAX_VALUE ) return "i64"; + if( lo== 0 && hi== 1 ) return "bool"; + if( lo== -1 && hi== 0 ) return "i1"; + if( lo== -128 && hi== 127 ) return "i8"; + if( lo== -32768 && hi== 32767 ) return "i16"; + if( lo== -1L<<31 && hi==(1L<<31)-1 ) return "i32"; + if( lo== 0 && hi== 255 ) return "u8"; + if( lo== 0 && hi== 65535 ) return "u16"; + if( lo== 0 && hi==(1L<<32)-1 ) return "u32"; + return "["+lo+"-"+hi+"]"; + } + + @Override public boolean isHigh () { return _min > _max; } + + @Override public int log_size() { + if( isHigh() ) return 0; // High types are dead, and should never hit code emission. + if( this==I8 || this==U8 || this==BOOL ) return 0; // 1<<0 == 1 bytes + if( this==I16 || this==U16 ) return 1; // 1<<1 == 2 bytes + if( this==I32 || this==U32 ) return 2; // 1<<2 == 4 bytes + if( this==BOT ) return 3; // 1<<3 == 8 bytes + if( isConstant() ) { // just const here + if (-0xFF <= _min && _min <= 0xFF) return 0; + else if (-0xFFFF <= _min && _min <= 0xFFFF) return 1; + else if (-0xFFFFFFFFL <= _min && _min <= 0xFFFFFFFFL) return 2; + else return 3; + } + throw Utils.TODO(); + } + + public long value() { assert isConstant(); return _min; } + + // AND-mask of forced zeros. e.g. unsigned types will return their mask; + // u8 will return 0xFF. But also a range of 16-18 (0x10-0x12) will return + // 0x13 - no value in the range {16,17,18} will allow bit 0x04 to be set. + public long mask() { + if( isHigh() ) return 0; + if( isConstant() ) return _min; + // Those bit positions which differ min to max + long x = _min ^ _max; + // Highest '1' bit in the differ set. Since the range is from min to + // max, all values below here are possible. + long ff1 = Long.highestOneBit(x); + // Make a all-1's mask from ff1, and set over the same bits (either min + // or max is ok). + long mask = _min | (ff1-1) | ff1; + return mask; + } + + @Override + public Type xmeet(Type other) { + if( other instanceof TypeConAry ary ) return ary.imeet(this); + // Invariant from caller: 'this' != 'other' and same class (TypeInteger) + TypeInteger i = (TypeInteger)other; // Contract + return make(Math.min(_min,i._min), Math.max(_max,i._max)); + } + + @Override TypeInteger xdual() { + return _min==_max ? this : malloc(_max,_min); + } + + @Override public TypeInteger nonZero() { + if( isHigh() ) return this; + if( this==ZERO ) return null; // No sane answer + if( _min==0 ) return make(1,Math.max(_max,1)); // specifically good on BOOL + if( _max==0 ) return make(_min,-1); + return this; + } + @Override public Type makeZero() { return ZERO; } + @Override boolean _isConstant() { return _min == _max; } + @Override boolean _isGLB(boolean mem) { return _glb(mem)==this; } + @Override Type _glb(boolean mem) { + if( !mem ) return BOT; + // GLB is not well-defined in memory; depends on the size of the memory field + if( _isConstant() ) return BOT; + return isHigh() ? dual() : this; + } + + @Override int hash() { return Utils.fold(_min) * Utils.fold(_max); } + @Override public boolean eq( Type t ) { + return t instanceof TypeInteger i && _min==i._min && _max==i._max; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeMem.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeMem.java new file mode 100644 index 00000000..99b19c75 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeMem.java @@ -0,0 +1,108 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.ArrayList; +import java.util.BitSet; + + +/** + * Represents a slice of memory corresponding to a set of aliases + */ +public class TypeMem extends Type { + + // Which slice of memory? + // 1 and TOP means no slice. + // 1 and BOT means all memory. + // N means alias slice#N. + public int _alias; + public Type _t; // Memory contents, some scalar type + + private static final Ary<TypeMem> FREE = new Ary<>(TypeMem.class); + private TypeMem(int alias, Type t) { super(TMEM); init(alias,t); } + private TypeMem init(int alias, Type t) { + assert alias>1 || (t==Type.TOP || t==Type.BOTTOM); + _alias = alias; + _t = t; + return this; + } + @Override TypeMem free(Type t) { + TypeMem mem = (TypeMem)t; + mem._alias= -99; + mem._dual = null; + mem._hash = 0; + FREE.push(mem); + return this; + } + @Override boolean isFree() { return _alias == -99; } + + public static TypeMem malloc(int alias, Type t) { + return FREE.isEmpty() ? new TypeMem(alias,t) : FREE.pop().init(alias,t); + } + public static TypeMem make(int alias, Type t) { + TypeMem f = malloc(alias,t); + TypeMem f2 = f.intern(); + if( f2==f ) return f; + return VISIT.isEmpty() ? f2.free(f) : f2.delayFree(f); + } + + public static final TypeMem TOP = make(1, Type.TOP ); + public static final TypeMem BOT = make(1, Type.BOTTOM); + + public static void gather(ArrayList<Type> ts) { ts.add(make(2,Type.NIL)); ts.add(make(2,TypeInteger.ZERO)); ts.add(BOT); } + + @Override + TypeMem xmeet(Type t) { + TypeMem that = (TypeMem) t; // Invariant: TypeMem and unequal + if( this==TOP ) return that; + if( that==TOP ) return this; + if( this==BOT ) return BOT; + if( that==BOT ) return BOT; + int alias = _alias==that._alias ? _alias : 1; + Type mt = _t.meet(that._t); + return make(alias,mt); + } + + @Override + Type xdual() { return _t._dual==_t ? this : malloc(_alias,_t.dual()); } + + @Override TypeMem rdual() { + if( _dual!=null ) return dual(); + assert !_terned; + TypeMem d = malloc(_alias,null); + (_dual = d)._dual = this; // Cross link duals + d._t = _t._terned ? _t.dual() : _t.rdual(); + return d; + } + + @Override public boolean isHigh() { return _t.isHigh(); } + @Override public int log_size() { throw Utils.TODO(); } + @Override boolean _isFinal() { return _t._isFinal(); } + @Override boolean _isGLB(boolean mem) { return _t._isGLB(true); } + @Override public Type _glb(boolean mem) { return make(_alias,_t._glb(true)); } + + @Override int hash() { return 9876543 + _alias + _t.hashCode(); } + + @Override boolean eq(Type t) { + TypeMem that = (TypeMem) t; // Invariant + return _alias == that._alias && _t == that._t; + } + + @Override boolean cycle_eq(Type t) { + TypeMem that = (TypeMem) t; // Invariant + return _alias == that._alias && _t.cycle_eq(that._t); + } + + @Override int nkids() { return 1; } + @Override Type at( int idx ) { return _t; } + @Override void set( int idx, Type t ) { _t = t; } + + @Override public SB _print(SB sb, BitSet visit, boolean html) { + sb.p("#"); + if( _alias==0 ) return sb.p(_t._type==TTOP ? "TOP" : "BOT"); + return _t.print(sb.p(_alias).p(":"),visit,html); + } + + @Override public String str() { return toString(); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java new file mode 100644 index 00000000..6041155d --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java @@ -0,0 +1,147 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.*; + +/** + * Represents a Pointer to memory. + * + * Null is generic pointer to non-existent memory. + * *void is a non-Null pointer to all possible refs, both structs and arrays. + * Pointers can be to specific struct and array types, or a union with Null. + * The distinguished *$BOT ptr represents union of *void and Null. + * The distinguished *$TOP ptr represents the dual of *$BOT. + */ +public class TypeMemPtr extends TypeNil { + // A TypeMemPtr is pair (obj,nil) + // where obj is a TypeStruct, possibly TypeStruct.BOT/TOP + // where nil is an explicit null is allowed or not + + // Examples: + // (Person,false) - a not-nil Person + // (Person,true ) - a Person or a nil + // (BOT ,false) - a not-nil void* (unspecified struct) + // (TOP ,true ) - a nil + + public TypeStruct _obj; + public boolean _one; // Singleton instance + + private static final Ary<TypeMemPtr> FREE = new Ary<>(TypeMemPtr.class); + private TypeMemPtr(byte nil, TypeStruct obj, boolean one) { super(TMEMPTR,nil); init(nil,obj,one); } + private TypeMemPtr init(byte nil, TypeStruct obj, boolean one) { _nil=nil; _obj=obj; _one=one; return this; } + // Return a filled-in TypeMemPtr; either from free list or alloc new. + private static TypeMemPtr malloc(byte nil, TypeStruct obj, boolean one) { + return FREE.isEmpty() ? new TypeMemPtr(nil,obj,one) : FREE.pop().init(nil,obj,one); + } + + // All fields directly listed + public static TypeMemPtr make(byte nil, TypeStruct obj, boolean one) { + TypeMemPtr tmp = malloc(nil, obj, one); + TypeMemPtr t2 = tmp.intern(); + if( t2==tmp ) return tmp; + return VISIT.isEmpty() ? t2.free(tmp) : t2.delayFree(tmp); + } + @Override TypeMemPtr free(Type t) { + TypeMemPtr tmp = (TypeMemPtr)t; + tmp._nil = -99; + tmp._obj = null; + tmp._dual = null; + tmp._hash = 0; + FREE.push(tmp); + return this; + } + @Override boolean isFree() { return _obj==null; } + + static TypeMemPtr make(byte nil, TypeStruct obj) { return make(nil, obj, false); } + public static TypeMemPtr make (TypeStruct obj) { return make((byte)2, obj); } + public static TypeMemPtr makeNullable(TypeStruct obj) { return make((byte)3, obj); } + + public TypeMemPtr makeFrom(TypeStruct obj) { return obj==_obj ? this : make(_nil, obj, _one); } + public TypeMemPtr makeNullable() { return makeFrom((byte)3); } + @Override TypeMemPtr makeFrom(byte nil) { return nil==_nil ? this : make(nil, _obj, _one); } + + // An abstract pointer, pointing to either a Struct or an Array. + // Can also be null or not, so 4 choices {TOP,BOT} x {nil,not} + public static final TypeMemPtr BOT = make((byte)3, TypeStruct.BOT); + public static final TypeMemPtr TOP = BOT.dual(); + public static final TypeMemPtr NOTBOT = make((byte)2,TypeStruct.BOT); + + public static final TypeMemPtr TEST= make((byte)2, TypeStruct.TEST); + public static void gather(ArrayList<Type> ts) { ts.add(NOTBOT); ts.add(BOT); ts.add(TEST); } + + @Override + public TypeNil xmeet(Type t) { + TypeMemPtr that = (TypeMemPtr) t; + assert !isFree() && !that.isFree(); + return make(xmeet0(that), (TypeStruct)_obj.meet(that._obj), _one & that._one); + } + + @Override + TypeMemPtr xdual() { return malloc( dual0(), _obj.dual(), _one); } + + @Override TypeMemPtr rdual() { + if( _dual!=null ) return dual(); + assert !_terned; + TypeMemPtr d = malloc(dual0(), null, _one); + (_dual = d)._dual = this; // Cross link duals + d._obj = _obj._terned ? _obj.dual() : _obj.rdual(); + return d; + } + + // RHS is NIL; do not deep-dual when crossing the center line + @Override Type meet0() { return _nil==3 ? this : make((byte)3,_obj); } + + @Override boolean _isConstant() { return _one && _obj._isConstant(); } + @Override boolean _isFinal() { return _obj._isFinal(); } + @Override TypeMemPtr _makeRO() { return makeFrom(_obj._makeRO()); } + @Override boolean _isGLB(boolean mem) { return _obj.isGLB2(); } + @Override TypeMemPtr _glb(boolean mem) { return make((byte)3,_obj.glb2()); } + @Override TypeMemPtr _close() { return makeFrom(_obj._close()); } + + + // True if this "isa" t up to named structures + @Override public boolean shallowISA( Type t ) { + if( !(t instanceof TypeMemPtr that) ) return false; + if( this==that ) return true; + if( xmeet0(that)!=that._nil ) return false; + if( _obj==that._obj ) return true; + if( _obj._name.equals(that._obj._name) ) + return true; // Shallow, do not follow matching names, just assume ok + throw Utils.TODO(); // return _obj.shallowISA(that._obj); + } + + // Is forward-reference + @Override public boolean isFRef() { return _obj.isFRef(); } + + @Override public int log_size() { return 3; } // (1<<3)==8-byte pointers + + @Override int hash() { return _obj.hashCode() ^ super.hash() ^ (_one ? 2048 : 0); } + + @Override boolean eq(Type t) { + TypeMemPtr ptr = (TypeMemPtr)t; // Invariant + return super.eq(ptr) && _one == ptr._one && _obj == ptr._obj; + } + @Override boolean cycle_eq(Type t) { + if( t._type != TMEMPTR ) return false; + TypeMemPtr ptr = (TypeMemPtr)t; // Invariant + return super.eq(ptr) && _one == ptr._one && _obj.cycle_eq(ptr._obj); + } + + @Override int nkids() { return 1; } + @Override Type at( int idx ) { return _obj; } + @Override void set( int idx, Type t ) { _obj = (TypeStruct)t; } + + @Override public String str() { + if( this== NOTBOT) return "*void"; + if( this== BOT) return "*void?"; + return x()+"*"+_obj.str()+q(); + } + + @Override SB _print(SB sb, BitSet visit, boolean html ) { + if( this== NOTBOT) return sb.p("*void"); + if( this== BOT) return sb.p("*void?"); + return _obj.print(sb.p(x()).p("*"),visit,html).p(q()); + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeNil.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeNil.java new file mode 100644 index 00000000..56d73b00 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeNil.java @@ -0,0 +1,62 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.ArrayList; + +/** + * Nil-able Scalar types + */ +public abstract class TypeNil extends Type { + // 0 = high-subclass choice nil + // 1 = high-subclass no nil + // 2 = low -subclass no nil + // 3 = low -subclass also nil + byte _nil; + + TypeNil(byte t, byte nil ) { super(t); _nil = nil; } + + public static void gather(ArrayList<Type> ts) { } + + abstract TypeNil makeFrom(byte nil); + + byte xmeet0(TypeNil that) { return (byte)Math.max(_nil,that._nil); } + + byte dual0() { return (byte)(3-_nil); } + + // RHS is NIL + abstract Type meet0(); + + // RHS is XNIL + Type meetX() { + return _nil==0 ? XNIL : (_nil<=2 ? TypePtr.NPTR : TypePtr.PTR); + } + + Type nmeet(TypeNil tn) { + // Invariants: both are TypeNil subclasses and unequal classes. + // If this is TypePtr, we went to TypePtr.nmeet and not here. + // If that is TypePtr, this is not (invariant); reverse and go again. + if( tn instanceof TypePtr ts ) return ts.nmeet(this); + + // Two mismatched TypeNil, no Scalar. + if( _nil==0 && tn._nil==0 ) return XNIL; + if( _nil<=2 && tn._nil<=2 ) return TypePtr.NPTR; + return TypePtr.PTR; + } + + @Override public boolean isHigh () { return _nil <= 1; } + @Override public boolean isHighOrConst() { return isHigh() || isConstant(); } + + public boolean notNull() { return _nil==1 || _nil==2; } + public boolean nullable() { return _nil==3; } + + @Override boolean _isConstant() { return false; } + @Override Type _glb(boolean mem) { return Type.NIL; } + + final String q() { return _nil == 1 || _nil == 2 ? "" : "?"; } + final String x() { return isHigh() ? "~" : ""; } + + int hash() { return _nil<<17; } + + @Override boolean eq(Type ptr) { return ptr instanceof TypeNil nil && _nil ==nil._nil; } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypePtr.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypePtr.java new file mode 100644 index 00000000..75478119 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypePtr.java @@ -0,0 +1,55 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.ArrayList; +import java.util.BitSet; + +/** + * Represents a Scalar; a single register-sized value. + */ +public class TypePtr extends TypeNil { + private static final String[] STRS = new String[]{"~ptr","~nptr","nptr","ptr"}; + + private TypePtr(byte nil) { super(TPTR,nil); } + + // An abstract pointer, pointing to either a Struct or an Array. + // Can also be null or not, so 4 choices {TOP,BOT} x {nil,not} + public static TypePtr XPTR = new TypePtr((byte)0).intern(); + public static TypePtr XNPTR= new TypePtr((byte)1).intern(); + public static TypePtr NPTR = (TypePtr)XNPTR.dual(); + public static TypePtr PTR = (TypePtr)XPTR.dual(); + private static final TypePtr[] PTRS = new TypePtr[]{XPTR,XNPTR,NPTR,PTR}; + + public static void gather(ArrayList<Type> ts) { ts.add(PTR); ts.add(NPTR); } + + TypeNil makeFrom(byte nil) { throw Utils.TODO(); } + + @Override public TypeNil xmeet(Type t) { + TypePtr that = (TypePtr) t; + return PTRS[xmeet0(that)]; + } + + @Override TypePtr xdual() { return new TypePtr((byte)(3-_nil)); } + + // High scalar loses, low scalar wins + @Override TypeNil nmeet(TypeNil tn) { + if( _nil==0 ) return tn; // High scalar loses + if( _nil==1 ) return tn.makeFrom(xmeet0(tn)); // High scalar loses + if( _nil==2 ) return tn._nil==3 ? PTR : NPTR; // Low scalar wins + return PTR; // this + } + + + // RHS is NIL + @Override Type meet0() { return isHigh() ? NIL : PTR; } + // RHS is XNIL + // 0->xscalar, 1->nscalar, 2->nscalar, 3->scalar + @Override Type meetX() { return _nil==0 ? XNIL : (_nil==3 ? PTR : NPTR); } + + boolean _isGLB(boolean mem) { return this==PTR; } + @Override TypePtr _glb(boolean mem) { return PTR; } + + @Override public String str() { return STRS[_nil]; } + @Override public SB _print(SB sb, BitSet visit, boolean html) { return sb.p(str()); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeRPC.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeRPC.java new file mode 100644 index 00000000..bd5e2923 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeRPC.java @@ -0,0 +1,99 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.HashSet; + +/** + * Return Program Control or Return PC or RPC + */ +public class TypeRPC extends Type { + + // A set of CallEndNode IDs (or StopNode); commonly just one. + // Basically a sparse bit set + final HashSet<Integer> _rpcs; + + // If true, invert the meaning of the bits + final boolean _any; + + private TypeRPC(boolean any, HashSet<Integer> rpcs) { + super(TRPC); + _any = any; + _rpcs = rpcs; + } + private static TypeRPC make(boolean any, HashSet<Integer> rpcs) { + return new TypeRPC(any,rpcs).intern(); + } + + public static TypeRPC constant(int cend) { + HashSet<Integer> rpcs = new HashSet<>(); + rpcs.add(cend); + return make(false,rpcs); + } + + public static final TypeRPC BOT = make(true,new HashSet<>()); + private static final TypeRPC TEST2 = constant(2); + private static final TypeRPC TEST3 = constant(2); + + public static void gather(ArrayList<Type> ts) { ts.add(BOT); ts.add(TEST2); ts.add(TEST3); } + + @Override public String str() { + if( _rpcs.isEmpty() ) + return _any ? "$[ALL]" : "$[]"; + if( _rpcs.size()==1 ) + for( Integer rpc : _rpcs ) + return _any ? "$[-"+rpc+"]" : "$["+rpc+"]"; + return "$["+(_any ? "-" : "")+_rpcs+"]"; + } + + @Override + public TypeRPC xmeet(Type other) { + TypeRPC rpc = (TypeRPC)other; + // If the two sets are equal, the _any must be unequal (invariant), + // so they cancel and all bits are set. + if( _rpcs.equals(rpc._rpcs) ) + return BOT; + // Classic union of bit sets (which might be infinite). + HashSet<Integer> lhs = _rpcs, rhs = rpc._rpcs; + // Smaller on left + if( lhs.size() > rhs.size() ) { lhs = rpc._rpcs; rhs = _rpcs; } + + HashSet<Integer> rpcs = new HashSet<>(); + boolean any = true; + // If both sets are infinite, intersect. + if( _any && rpc._any ) { + for( Integer i : lhs ) if( rhs.contains(i) ) rpcs.add(i); + + } else if( !_any && !rpc._any ) { + // if neither set is infinite, union. + rpcs.addAll( lhs ); + rpcs.addAll( rhs ); + any = false; + } else { + // If one is infinite, subtract the other from it. + HashSet<Integer> sub = _any ? rpc._rpcs : _rpcs; + HashSet<Integer> inf = _any ? _rpcs : rpc._rpcs; + for( Integer i : inf ) + if( inf.contains(i) && !sub.contains(i) ) + rpcs.add(i); + } + return make(any,rpcs); + } + + @Override + Type xdual() { return new TypeRPC(!_any,_rpcs); } + + @Override boolean _isConstant() { return !_any && _rpcs.size()==1; } + @Override boolean _isGLB(boolean mem) { return true; } + + @Override + int hash() { return _rpcs.hashCode() ^ (_any ? -1 : 0) ; } + @Override + public boolean eq( Type t ) { + TypeRPC rpc = (TypeRPC)t; // Contract + return _any==rpc._any && _rpcs.equals(rpc._rpcs); + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeStruct.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeStruct.java new file mode 100644 index 00000000..73fecdab --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeStruct.java @@ -0,0 +1,480 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.util.*; +import java.util.*; + +/** + * Represents a struct type. + */ +public class TypeStruct extends Type { + + // A Struct has a name and a set of fields; the fields themselves have + // names, types and aliases. The name has no semantic meaning, but is + // useful for debugging. + + // During parsing a mid-declaration struct is flagged as a "open". It is + // treated as having infinite fields with correct name and type BOTTOM. + + public String _name; // Struct name + public boolean _open; // infinite fields are all true:BOTTOM, false:TOP + public Field[] _fields; + + private TypeStruct(String name, boolean open, Field[] fields) { + super(TSTRUCT); + _name = name; + _open = open; + _fields = fields; + } + + private static final Ary<TypeStruct> FREE = new Ary<>(TypeStruct.class); + // Return a filled-in TypeStruct; either from free list or alloc new. + private static TypeStruct malloc(String name, boolean open, Field[] fields) { + if( FREE.isEmpty() ) return new TypeStruct(name,open,fields); + TypeStruct ts = FREE.pop(); + assert ts.isFree(); + ts._name = name; + ts._open = open; + ts._fields = fields; + return ts; + } + // Free ts; return this. + @Override TypeStruct free(Type t) { + TypeStruct ts = (TypeStruct)t; + assert !ts.isFree() && !ts._terned; + ts._fields = null; + ts._offs = null; + ts._dual = null; + ts._hash = 0; + FREE.push(ts); + return this; + } + @Override boolean isFree() { return _fields==null; } + + + // All fields directly listed + public static TypeStruct make(String name, boolean open, Field... fields) { + TypeStruct ts = malloc(name, open, fields); + TypeStruct t2 = ts.intern(); + if( t2==ts ) return ts; + return VISIT.isEmpty() ? t2.free(ts) : ts.delayFree(ts); + } + // New open struct with no fields + public static TypeStruct open( String name ) { return make(name,true); } + + // Array + public static TypeStruct makeAry(String name, TypeInteger len, int lenAlias, Type body, int bodyAlias, boolean efinal) { + return make(name,false, + Field.make("#" ,len , lenAlias,true ,false), + Field.make("[]",body,bodyAlias,efinal,false)); + } + + public TypeStruct add( Field f ) { + assert _open && find(f._fname)==-1; // No double field names + Field[] flds = Arrays.copyOf(_fields,_fields.length+1); + flds[_fields.length] = f; + return make(_name,true,flds); + } + public TypeStruct replace( Field f ) { + assert !_open; + Field[] flds = Arrays.copyOf(_fields,_fields.length); + flds[find(f._fname)] = f; + return make(_name,false,flds); + } + + + public final TypeStruct close() { + return (TypeStruct)recurOpen()._close().recurClose(); + } + @Override TypeStruct _close() { + TypeStruct ts = (TypeStruct)VISIT.get(_name); + if( ts!=null ) return ts; + ts = recurPre(_name,false); + Field[] flds = ts._fields; + + // Now start the recursion + for( int i=0; i<flds.length; i++ ) + flds[i].setType(_fields[i]._t._close()); + + return ts; + } + + static final AryInt CEQUALS = new AryInt(); + + public static final TypeStruct BOT = open("$STRUCT"); + public static final TypeStruct TOP = BOT.dual(); + public static final TypeStruct TEST= make("test",false,Field.TEST); + private static final TypeStruct ARY = makeAry("[]i64",TypeInteger.U32,-1,TypeInteger.BOT,-2,false); + private static final TypeStruct STR = makeAry("[]u8" ,TypeInteger.U32,-1,TypeInteger.U8 ,-4,false); + private static final TypeStruct ABC = makeAry("[]u8",TypeInteger.constant(3),-1,TypeConAryB.ABC,-4,true); + + // A pair of self-cyclic types + private static final TypeStruct SINT0 = open("%SINT"); + private static final TypeStruct SFLT0 = open("%SFLT"); + private static final TypeStruct SINT1 = SINT0.add(Field.make("a", TypeInteger.U32, -1, false, false)).add(Field.make("s2",TypeMemPtr.make((byte)2,SFLT0),-2, false, false)); + private static final TypeStruct SFLT1 = SFLT0.add(Field.make("b", TypeFloat .F32, -3, false, false)).add(Field.make("s1",TypeMemPtr.make((byte)2,SINT1),-4, false, false)); + public static final TypeStruct SFLT2 = SFLT1.close(); + + + public static void gather(ArrayList<Type> ts) { + ts.add(BOT); + ts.add(TEST); + ts.add(ARY); + ts.add(STR); + ts.add(ABC); + ts.add(SINT0); + ts.add(SFLT0); + ts.add(SINT1); + ts.add(SFLT1); + ts.add(SFLT2); + ts.add(((TypeMemPtr)(SFLT2.field("s1")._t))._obj); + // Break cyclic init: built a struct + Field fcalloc = Field.make("calloc",TypeFunPtr.CALLOC,-2,true,true); + TypeStruct scalloc = make("calloc",false,fcalloc); + ts.add(scalloc); + + } + + // Find field index by name + public int find(String fname) { + for( int i=0; i<_fields.length; i++ ) + if( _fields[i]._fname.equals(fname) ) + return i; + return -1; + } + public Field field(String fname) { + int idx = find(fname); + return idx== -1 ? null : _fields[idx]; + } + + // Find field index by alias + public int findAlias( int alias ) { + for( int i=0; i<_fields.length; i++ ) + if( _fields[i]._alias==alias ) + return i; + return -1; + } + + @Override + TypeStruct xmeet(Type t) { + TypeStruct that = (TypeStruct) t; + assert !isFree() && !that.isFree(); + if( this==TOP ) return that; + if( that==TOP ) return this; + if( this==BOT ) return BOT; + if( that==BOT ) return BOT; + + // Within the same compilation unit, struct names are unique. If the + // names differ, its different structs. Across many compilation units, + // structs with the same name but different field layouts can be + // interned... which begs the question: + // "What is the meet of structs from two different compilation units?" + // And the answer is: "don't ask". + if( !_name.equals(that._name) ) + return BOT; // It's a struct; that's about all we know + + // if equal, no matters. + // if short is BOT, chop ; recurPre on short. + // if short is TOP, copy long; recurPre on long. + TypeStruct min = _fields.length < that._fields.length ? this : that; + if( _fields.length != that._fields.length && (min._open ^ min==this) ) + return that.xmeet(this); + + // Check all other fields are sanely similar; same struct type but + // different field contents (e.g. field "age" is either 'int' or '18'). + int len = Math.min(_fields.length,that._fields.length); + for( int i=0; i<len; i++ ) { + Field f0 = _fields[i], f1 = that._fields[i]; + if( !f0._fname.equals(f1._fname) || f0._alias != f1._alias || f0._one != f1._one ) + return BOT; + } + + // See if we get a mid-recursion hit; breaks cycles + Integer pid = pid(that); + TypeStruct ts = (TypeStruct)VISIT.get(pid); + if( ts!=null ) return ts; + // If not mid-recursion, we are now; flag recursion. + boolean notRecur = VISIT.isEmpty(); + if( notRecur ) recurOpen(); + + // Setup and install the type, prior to recursing, so we can find our + // recursive self again. + ts = recurPre(pid,_open | that._open); + + // Recurse all common fields + Field[] flds = ts._fields; + for( int i=0; i<len; i++ ) { + Field f0 = _fields[i], f1 = that._fields[i]; + flds[i].setType(f0._t.meet(f1._t )); + flds[i]._final = f0._final | f1._final; + } + + // Handle extra fields via `_open` + for( int i=len; i<_fields.length; i++ ) + flds[i].setType(_fields[i]._t ); + + // Cleanup post-recursion; intern/install at cycle end + if( notRecur ) ts = (TypeStruct)ts.recurClose(); + return ts; + } + + @Override + TypeStruct xdual() { + if( _name=="$STRUCT" ) + return malloc("$STRUCT",false,new Field[0]); + Field[] flds = new Field[_fields.length]; + for( int i=0; i<_fields.length; i++ ) + flds[i] = _fields[i].dual(); + return malloc(_name,!_open,flds); + } + + // Recursive dual + @Override TypeStruct rdual() { + if( _dual!=null ) return dual(); + assert !_terned; + Field[] flds = new Field[_fields.length]; + TypeStruct d = malloc(_name,!_open,flds); + (_dual = d)._dual = this; // Cross link duals + for( int i=0; i<_fields.length; i++ ) + flds[i] = _fields[i]._terned ? _fields[i].dual() : _fields[i].rdual(); + return d; + } + + // Is forward-reference + @Override public boolean isFRef() { return _open; } + + @Override boolean _isConstant() { + if( VISIT.containsKey(_uid) ) return true; // Cycles assume constant + VISIT.put(_uid,this); + // Check all fields for being constant + for( Field field : _fields ) + if( !field._isConstant() ) + return false; + return true; + } + + // All fields are final + @Override boolean _isFinal() { + if( _open ) return false; // May have more more non-final fields + if( VISIT.containsKey(_uid) ) // Test: been here before? + return true; // Cycles assume final + VISIT.put(_uid,this); // Set: dont do this again + for( Field fld : _fields ) + if( !fld._isFinal() ) + return false; + return true; + } + + private TypeStruct recurPre(Object key, boolean open) { + // Make a clone of original; suitable for hashing so can build + // e.g. TMPs to clone as part of cycles - but will fail the 'eq' check + // until the entire cycle is built. + Field[] flds = new Field[_fields.length]; + for( int i=0; i<flds.length; i++ ) + flds[i] = _fields[i].malloc(); // Blank copy, but can be hashed + TypeStruct ts = malloc(_name, open, flds ); + VISIT.put(key,ts); + return ts; + } + + // Make a read-only version + @Override TypeStruct _makeRO() { + // Check for already visited + TypeStruct ts = (TypeStruct)VISIT.get(_name); + if( ts!=null ) return ts; // Already visited + ts = recurPre(_name,_open); // Make a new type with blank fields + Field[] flds = ts._fields; + for( Field fld : flds ) fld._final = true; + + // Now start the recursion + for( int i=0; i<flds.length; i++ ) + flds[i].setType(_fields[i]._t._makeRO()); + + return ts; + } + + + // All fields are at GLB already + boolean isGLB2() { + if( VISIT.containsKey(_uid) ) return true; // Cycles assume GLB + VISIT.put(_uid,this); + for( Field fld : _fields ) + if( !fld.isGLB2() ) + return false; + return true; + } + + // Keeps the same struct, but lower-bounds all fields. + public TypeStruct glb2() { + TypeStruct ts = (TypeStruct)VISIT.get(_name); + if( ts!=null ) return ts; + ts = recurPre(_name,_open); + Field[] flds = ts._fields; + for( int i=0; i<flds.length; i++ ) + flds[i]._final = true ; + + // Now start the recursion + for( int i=0; i<flds.length; i++ ) + flds[i].setType(_fields[i]._t._glb(true)); + + return ts; + } + + // log_size for a struct is not defined, unless its exactly some power of + // 2. *Total size* is well-defined, and is available in the offsets. + @Override public int log_size() { throw Utils.TODO(); } + @Override public int size() { return offset(_fields.length); } + @Override public int alignment() { + int align = 0; + for( Field f : _fields ) + align = Math.max(align, f._t.alignment()); + return align; + } + + // If false, always false. + // If true , maybe true, need to check recursive fields. + private boolean static_eq( TypeStruct ts ) { + return _name.equals(ts._name) && _open==ts._open && _fields.length==ts._fields.length; + } + + @Override boolean eq(Type t) { + // Recursive; so use cyclic equals + if( !VISIT.isEmpty() ) { + assert CEQUALS.isEmpty(); + boolean rez = cycle_eq(t); + CEQUALS.clear(); + return rez; + } + // Normal equals + TypeStruct ts = (TypeStruct)t; // Invariant + if( !static_eq(ts) ) return false; + if( _fields==ts._fields ) return true; + for( int i = 0; i < _fields.length; i++ ) + if( !_fields[i].eq(ts._fields[i]) ) + return false; + return true; + } + + @Override boolean cycle_eq(Type t) { + if( this==t ) return true; + TypeStruct ts = (TypeStruct)t; // Invariant + if( !static_eq(ts) ) return false; + if( _fields==ts._fields ) return true; + // Check to see if we've ever compared this pair of types before; + // if so, then assume the cycle is equal here. + int pid = pid(ts); + if( CEQUALS.find(pid)!= -1 ) return true; + CEQUALS.push(pid); + // Recursively check fields + for( int i = 0; i < _fields.length; i++ ) + if( !_fields[i].cycle_eq(ts._fields[i]) ) + return false; + return true; + } + + @Override + int hash() { + long hash = _name.hashCode() ^ (_open ? 4 : 0); + for( Field f : _fields ) + hash = Utils.rot(hash,13) ^ ((long)f._fname.hashCode() * f._alias); + return Utils.fold(hash); + } + + @Override int nkids() { return _fields.length; } + @Override Type at( int idx ) { return _fields[idx]; } + @Override void set( int idx, Type t ) { _fields[idx] = (Field)t; } + + @Override + SB _print(SB sb, BitSet visit, boolean html ) { + if( isFree() ) return sb.p("FREE:").p(_name); + if( isAry() && field("[]")._t instanceof TypeConAry con ) + return sb.p(con.str()); + sb.p(_name); + if( html || isAry() ) + return sb; + sb.p(" {"); + for( Field f : _fields ) + (f._t ==null ? sb.p("---") : f._t.print(sb,visit,html)).p(f._final ? " " : " !").p(f._fname).p("; "); + if( _open ) sb.p("... "); + return sb.p("}"); + } + + @Override public String str() { return (isFree() ? "FREE:":"")+_name; } + + + public boolean isAry() { return _fields.length>=2 && _fields[_fields.length-1]._fname=="[]"; } + + public int aryBase() { + assert isAry(); + if( _offs==null ) _offs = offsets(); + return _offs[1]; + } + public int aryScale() { + assert isAry(); + return _fields[1]._t.log_size(); + } + + + // Field offsets as packed byte offsets + private int[] _offs; // Lazily computed and not part of the type semantics + public int offset(int idx) { + if( _offs==null ) _offs = offsets(); + return _offs[idx]; + } + private int[] offsets() { // Field byte offsets + assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.Opto.ordinal(); + // Compute a layout for a collection of fields + assert _fields != null; // No forward refs + + // Compute a layout + _offs = new int[_fields.length+1]; + if( isAry() ) { // Arrays used fixed u32 len, padding to elems, var length + assert _fields[1]._fname=="[]"; + // Pad out to the element alignment + int align = _fields[1]._t.alignment(); + _offs[1] = (4 + ((1<<align)-1)) & -(1<<align); + if( _fields[1]._t instanceof TypeConAry ary ) // Array length is well-defined for constants, not defined for runtime arrays + _offs[2] = _offs[1]+ary.len(); + + } else { + int[] cnts = new int[5]; // Count of fields at log field size + int flen = _fields.length; + for( int i=0; i<flen; i++ ) + if( !_fields[i]._one ) + cnts[_fields[i]._t.log_size()]++; // Log size is 0(byte), 1(i16/u16), 2(i32/f32), 3(i64/dbl) + int off = 0, idx = 0; // Base common struct fields go here, e.g. Mark/Klass + // Compute offsets to the start of each power-of-2 aligned fields. + int[] offs = new int[4]; + for( int i=3; i>=0; i-- ) { + offs[i] = off; + off += cnts[i]<<i; + } + // Assign offsets to all fields. + // Really a hidden radix sort. + for( int i=0; i<flen; i++ ) { + if( _fields[i]._one ) continue; + int log = _fields[i]._t.log_size(); + _offs[idx++] = offs[log]; // Field offset + offs[log] += 1<<log; // Next field offset at same alignment + cnts[log]--; // Count down, should be all zero at end + } + _offs[flen] = off; // Max struct size, no trailing padding + } + return _offs; + } + + // Field order with increasing offset + public int[] layout() { + offset(0); + int len = _offs.length; + int[] is = new int[len]; + for( int i=0; i<len; i++ ) is[i] = i; + // Stoopid hand rolled bubble sort + for( int i=0; i<len; i++ ) + for( int j=i+1; j<len; j++ ) + if( _offs[is[j]] < _offs[is[i]] ) + { int tmp = is[i]; is[i] = is[j]; is[j] = tmp; } + return is; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/type/TypeTuple.java b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeTuple.java new file mode 100644 index 00000000..df9aba31 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/type/TypeTuple.java @@ -0,0 +1,119 @@ +package com.seaofnodes.simple.type; + +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.*; + +public class TypeTuple extends Type { + + public Type[] _types; + + private static final Ary<TypeTuple> FREE = new Ary<>(TypeTuple.class); + private TypeTuple(Type[] types) { super(TTUPLE); _types = types; } + private TypeTuple init( Type[] types ) { _types = types; return this; } + private static TypeTuple malloc(Type[] types) { + return FREE.isEmpty() ? new TypeTuple(types) : FREE.pop().init(types); + } + // All fields directly listed + public static TypeTuple make(Type... types) { + TypeTuple tt = malloc(types); + TypeTuple t2 = tt.intern(); + return t2==tt ? tt : t2.free(tt); + } + @Override TypeTuple free(Type t) { + TypeTuple tt = (TypeTuple)t; + tt._types = null; + tt._dual = null; + tt._hash = 0; + FREE.push(tt); + return this; + } + @Override boolean isFree() { return _types==null; } + + + public static final TypeTuple BOT = malloc(new Type[0]).intern(); + public static final TypeTuple TOP = BOT.dual(); + + public static final TypeTuple TEST = make(TypeInteger.BOT,TypeMemPtr.TEST); + public static final TypeTuple START= make(Type.CONTROL,TypeMem.TOP,TypeInteger.BOT); + public static final TypeTuple RET = make(Type.CONTROL,TypeMem.BOT,Type.BOTTOM); + + public static final TypeTuple IF_BOTH = make(Type. CONTROL,Type. CONTROL); + public static final TypeTuple IF_NEITHER = make(Type.XCONTROL,Type.XCONTROL); + public static final TypeTuple IF_TRUE = make(Type. CONTROL,Type.XCONTROL); + public static final TypeTuple IF_FALSE = make(Type.XCONTROL,Type. CONTROL); + + public static void gather(ArrayList<Type> ts) { ts.add(BOT); ts.add(TEST); ts.add(START); ts.add(IF_TRUE); } + + @Override + Type xmeet(Type other) { + TypeTuple that = (TypeTuple)other; // contract from xmeet + if( this==TOP ) return that; + if( that==TOP ) return this; + if( _types.length != that._types.length ) + return BOT; + return make(TypeFunPtr.xmeet(_types,that._types)); + } + + @Override TypeTuple xdual() { + if( _types.length==0 ) return malloc(null); + return malloc(TypeFunPtr.xdual(_types)); + } + + @Override boolean _isConstant() { + for( Type t : _types ) + if( !t._isConstant() ) + return false; + return true; + } + @Override boolean _isFinal() { throw Utils.TODO(); } + + @Override TypeMemPtr _makeRO() { throw Utils.TODO(); } + + @Override public int log_size() { throw Utils.TODO(); } + @Override public int alignment() { + assert isConstant(); + int align = 0; + for( Type t : _types ) + align = Math.max(align,t.alignment()); + return align; + } + + public Type ret() { assert _types.length==3; return _types[2]; } + + @Override SB _print(SB sb, BitSet visit, boolean html ) { + if( this==TOP ) return sb.p("[TOP]"); + if( this==BOT ) return sb.p("[BOT]"); + sb.p("[ "); + for( Type t : _types ) + t.print(sb,visit,html).p(", "); + return sb.unchar(2).p("]"); + } + + @Override public String str() { return print(new SB(),new BitSet(),false).toString(); } + + @Override + int hash() { + int sum = 0; + if( _types!=null ) for( Type type : _types ) sum ^= type.hashCode(); + return sum; + } + + @Override + boolean eq( Type t ) { + TypeTuple that = (TypeTuple)t; // Contract + if( _types==null && that._types==null ) return true; + if( _types==null || that._types==null ) return false; + if( _types.length != that._types.length ) return false; + for( int i=0; i<_types.length; i++ ) + if( _types[i]!=that._types[i] ) + return false; + return true; + } + + @Override int nkids() { return _types.length; } + @Override Type at( int idx ) { return _types[idx]; } + @Override void set( int idx, Type t ) { _types[idx] = t; } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/util/Ary.java b/chapter24/src/main/java/com/seaofnodes/simple/util/Ary.java new file mode 100644 index 00000000..d67801c2 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/util/Ary.java @@ -0,0 +1,229 @@ +package com.seaofnodes.simple.util; + +import java.lang.StringBuilder; +import java.lang.reflect.Array; +import java.util.*; + +// ArrayList with saner syntax +public class Ary<E> extends AbstractList<E> implements List<E> { + public E[] _es; + public int _len; + + public Ary(E[] es) { this(es,es.length); } + public Ary(E[] es, int len) { if( es.length==0 ) es=Arrays.copyOf(es,1); _es=es; _len=len; } + @SuppressWarnings("unchecked") + public Ary(Class<E> clazz) { this((E[]) Array.newInstance(clazz, 1),0); } + + /** @return list is empty */ + public boolean isEmpty() { return _len==0; } + /** @return active list length */ + public int len() { return _len; } + public int size() { return len(); } + + /** @param i element index + * @return element being returned; throws if OOB + * @exception AIOOBE if !(0 <= i < _len) + */ + public E get( int i ) { return at(i); } + public E at( int i ) { + range_check(i); + return _es[i]; + } + public E atX( int i ) { + if( i >= _len ) return null; + return _es[i]; + } + + /** @return last element */ + public E last( ) { return at(_len-1); } + public E last(int x ) { return at(_len-1+x); } + + /** Add element in amortized constant time + * @param e Element to add at end of list + **/ + public E push( E e ) { + if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1)); + return (_es[_len++] = e); + } + /** @return remove and return last element */ + public E pop( ) { + return _len==0 ? null : _es[--_len]; + } + @Override public E removeLast() { return pop(); } + + + /** Add element in amortized constant time + * @param e Element to add at end of list + * @return true */ + public boolean add( E e ) { + if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1)); + _es[_len++] = e; + return true; + } + + /** Fast, constant-time, element removal. Does not preserve order + * @param i element to be removed + * @return element removed */ + public E del( int i ) { + range_check(i); + E tmp = _es[i]; + _es[i]=_es[--_len]; + return tmp; + } + + /** Slow, linear-time, element removal. Preserves order. + * @param i element to be removed + * @return element removed */ + @Override public E remove( int i ) { + range_check(i); + E e = _es[i]; + System.arraycopy(_es,i+1,_es,i,(--_len)-i); + return e; + } + + /** Slow, linear-time, element insertion. Preserves order. + * @param i where to insert + * @return element inserted */ + public E insert( E e, int i ) { + setLen(_len+1); + System.arraycopy(_es,i,_es,i+1,_len-i); + _es[i] = e; + return e; + } + + + /** Remove all elements */ + public void clear( ) { _len=0; } + + /** Set existing element + * @param i element to set + * @param e value to set + * @return old value + * @exception AIOOBE if !(0 <= i < _len) + */ + public E set( int i, E e ) { + range_check(i); + E old = _es[i]; + _es[i] = e; + return old; + } + + /** Set existing element + * @param i element to set + * @param e value to set + * @return old value + * @exception AIOOBE if !(0 <= i < _len) + */ + public E setX( int i, E e ) { + if( i >= _len ) { + while( i >= _es.length ) _es = Arrays.copyOf( _es, _es.length << 1 ); + _len = i+1; + } + E old = _es[i]; + _es[i] = e; + return old; + } + + public Ary<E> setLen( int len ) { + if( len > _len ) + while( len>= _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + _len = len; + while( _es.length > (len<<1) ) // Shrink if hugely too large + _es = Arrays.copyOf(_es,_es.length>>1); + Arrays.fill(_es,len,_es.length,null); + return this; + } + + public E swap( int i, int j ) { + range_check(i); + range_check(j); + E tmp = _es[i]; + if( i==j ) return tmp; + _es[i] = _es[j]; + _es[j] = tmp; + return tmp; + } + + + /** @param c Collection to be added */ + public boolean addAll( Collection<? extends E> c ) { + if( c==null ) return false; + for( E e : c ) add(e); + return true; + } + public Ary<E> addAll( Iterable<? extends E> it ) { for( E e : it ) add(e); return this; } + + /** @param es Array to be added */ + public <F extends E> Ary<E> addAll( F[] es ) { + if( es==null || es.length==0 ) return this; + while( _len+es.length > _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + System.arraycopy(es,0,_es,_len,es.length); + _len += es.length; + return this; + } + + /** @param c Collection to be added */ + public Ary<E> addAll( Ary<? extends E> c ) { + if( c==null || c._len==0 ) return this; + while( _len+c._len > _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + System.arraycopy(c._es,0,_es,_len,c._len); + _len += c._len; + return this; + } + + /** @return compact array version */ + public E[] asAry() { return Arrays.copyOf(_es,_len); } + + /** Find the first matching element using ==, or -1 if none. Note that + * most del calls shuffle the list, so the first element might be random. + * @param e Element to find + * @return index of first matching element, or -1 if none */ + public int find( E e ) { + for( int i=0; i<_len; i++ ) if( _es[i]==e ) return i; + return -1; + } + + + /** @return an iterator */ + @Override public Iterator<E> iterator() { return new Iter(); } + private class Iter implements Iterator<E> { + int _i=0; + @Override public boolean hasNext() { return _i<_len; } + @Override public E next() { return _es[_i++]; } + } + + @Override public String toString() { + StringBuilder sb = new StringBuilder().append('{'); + for( int i=0; i<_len; i++ ) { + if( i>0 ) sb.append(','); + if( _es[i] != null ) sb.append(_es[i].toString()); + } + return sb.append('}').toString(); + } + + private void range_check( int i ) { + if( i < 0 || i>=_len ) + throw new ArrayIndexOutOfBoundsException(""+i+" >= "+_len); + } + + // Note that the hashCode() and equals() are not invariant to changes in the + // underlying array. If the hashCode() is used (e.g., inserting into a + // HashMap) and the then the array changes, the hashCode() will change also. + @Override public boolean equals( Object o ) { + if( this==o ) return true; + if( !(o instanceof Ary ary) ) return false; + if( _len != ary._len ) return false; + if( _es == ary._es ) return true; + for( int i=0; i<_len; i++ ) + if( !(_es[i]==null ? (ary._es[i] == null) : _es[i].equals(ary._es[i])) ) + return false; + return true; + } + @Override public int hashCode( ) { + int sum=_len; + for( int i=0; i<_len; i++ ) + sum += _es[i]==null ? 0 : _es[i].hashCode(); + return sum; + } + +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/util/AryInt.java b/chapter24/src/main/java/com/seaofnodes/simple/util/AryInt.java new file mode 100644 index 00000000..b498fd78 --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/util/AryInt.java @@ -0,0 +1,192 @@ +package com.seaofnodes.simple.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.function.IntUnaryOperator; + +// ArrayList with saner syntax +public class AryInt { + public int[] _es; + public int _len; + public AryInt(int[] es) { this(es,es.length); } + public AryInt(int[] es, int len) { _es=es; _len=len; } + public AryInt() { this(new int[1],0); } + + /** @return list is empty */ + public boolean isEmpty() { return _len==0; } + /** @return active list length */ + public int len() { return _len; } + /** @param i element index + * @return element being returned; throws if OOB */ + public int at( int i ) { + range_check(i); + return _es[i]; + } + /** @param i element index + * @return element being returned, or 0 if OOB */ + public int atX( int i ) { + return i < _len ? _es[i] : 0; + } + /** @return last element */ + public int last( ) { return at(_len-1); } + public int last(int x ) { return at(_len-1+x); } + + /** @return remove and return last element */ + public int pop( ) { + range_check(0); + return _es[--_len]; + } + + /** Add element in amortized constant time + * @param e element to add at end of list + * @return 'this' for flow-coding */ + public AryInt push( int e ) { + if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1)); + _es[_len++] = e; + return this; + } + + /** Slow, linear-time, element insert. Preserves order. + * @param i index to insert at, between 0 and _len inclusive. + * @param e intlement to insert + */ + public void insert( int i, int e ) { + if( i < 0 || i>_len ) + throw new ArrayIndexOutOfBoundsException(""+i+" >= "+_len); + if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1)); + System.arraycopy(_es,i,_es,i+1,(_len++)-i); + _es[i] = e; + } + + /** Fast, constant-time, element removal. Does not preserve order + * @param i element to be removed + * @return element removed */ + public int del( int i ) { + range_check(i); + int tmp = _es[i]; + _es[i]=_es[--_len]; + return tmp; + } + + /** Slow, linear-time, element removal. Preserves order. + * @param i element to be removed + * @return element removed */ + public int remove( int i ) { + range_check(i); + int e = _es[i]; + System.arraycopy(_es,i+1,_es,i,(--_len)-i); + return e; + } + + /** Remove all elements */ + public void clear( ) { Arrays.fill(_es,0,_len,0); _len=0; } + + // Extend and set + public int setX( int i, int e ) { + while( i>= _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + if( i >= _len ) _len = i+1; + return (_es[i] = e); + } + + public int set( int i, int e ) { + range_check(i); + return (_es[i] = e); + } + + public AryInt set_as( int e ) { _es[0] = e; _len=1; return this; } + public AryInt set_len( int len ) { + if( len > _len ) + while( len>= _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + _len = len; + while( _es.length > (len<<1) ) // Shrink if hugely too large + _es = Arrays.copyOf(_es,_es.length>>1); + return this; + } + + /** @param c Collection to be added */ + public AryInt addAll( Collection<? extends Integer> c ) { for( int e : c ) push(e); return this; } + + /** @param es Array to be added */ + public AryInt addAll( int[] es ) { + if( es.length==0 ) return this; + while( _len+es.length > _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + System.arraycopy(es,0,_es,_len,es.length); + _len += es.length; + return this; + } + + /** @param es Array to be added */ + public AryInt addAll( AryInt ary ) { + if( ary._len==0 ) return this; + while( _len+ary._len > _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + System.arraycopy(ary._es,0,_es,_len,ary._len); + _len += ary._len; + return this; + } + + public AryInt map_update( IntUnaryOperator f ) { for( int i = 0; i<_len; i++ ) _es[i] = f.applyAsInt(_es[i]); return this; } + + /** @return compact array version, using the internal base array where possible. */ + public int[] asAry() { return _len==_es.length ? _es : Arrays.copyOf(_es,_len); } + + /** Sorts in-place */ + public void sort_update() { Arrays.sort(_es, 0, _len); } + /** Find the first matching element using ==, or -1 if none. Note that + * most del calls shuffle the list, so the first element might be random. + * @param e intlement to find + * @return index of first matching element, or -1 if none */ + public int find( int e ) { + for( int i=0; i<_len; i++ ) if( _es[i]==e ) return i; + return -1; + } + + @Override public String toString() { + SB sb = new SB().p('['); + for( int i=0; i<_len; i++ ) + sb.p(_es[i]).p(','); + return sb.unchar().p(']').toString(); + } + + private void range_check( int i ) { + if( i < 0 || i>=_len ) + throw new ArrayIndexOutOfBoundsException(""+i+" >= "+_len); + } + + // Binary search sorted _es. Returns insertion point. + // Undefined results if _es is not sorted. + public int binary_search( int e ) { + int lo=0, hi=_len-1; + while( lo <= hi ) { + int mid = (hi + lo) >>> 1; // midpoint, rounded down + int mval = _es[mid]; + if( e==mval ) { + // If dups, get to the first. + while( mid>0 && e==_es[mid-1] ) mid--; + return mid; + } + if( e >mval ) lo = mid+1; + else hi = mid-1; + } + return lo; + } + + // Note that the hashCode() and equals() are not invariant to changes in the + // underlying array. If the hashCode() is used (e.g., inserting into a + // HashMap) and the then the array changes, the hashCode() will change also. + @Override public boolean equals( Object o ) { + if( this==o ) return true; + if( !(o instanceof AryInt ary) ) return false; + if( _len != ary._len ) return false; + if( _es == ary._es ) return true; + for( int i=0; i<_len; i++ ) + if( _es[i] != ary._es[i] ) + return false; + return true; + } + @Override public int hashCode( ) { + int sum=_len; + for( int i=0; i<_len; i++ ) + sum += _es[i]; + return sum; + } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/util/SB.java b/chapter24/src/main/java/com/seaofnodes/simple/util/SB.java new file mode 100644 index 00000000..d7afd6eb --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/util/SB.java @@ -0,0 +1,99 @@ +package com.seaofnodes.simple.util; + +/** Tight/tiny StringBuilder wrapper. + * Short short names on purpose; so they don't obscure the printing. + * Can't believe this wasn't done long, long ago. */ +public final class SB { + private final StringBuilder _sb; + private int _indent = 0; + public SB( ) { _sb = new StringBuilder( ); } + public SB(String s) { _sb = new StringBuilder(s); } + public SB p( String s ) { _sb.append(s); return this; } + public SB p( float s ) { + if( Float.isNaN(s) ) + _sb.append( "Float.NaN"); + else if( Float.isInfinite(s) ) { + _sb.append(s > 0 ? "Float.POSITIVE_INFINITY" : "Float.NEGATIVE_INFINITY"); + } else _sb.append(s); + return this; + } + public SB p( double s ) { + if( Double.isNaN(s) ) + _sb.append("Double.NaN"); + else if( Double.isInfinite(s) ) { + _sb.append(s > 0 ? "Double.POSITIVE_INFINITY" : "Double.NEGATIVE_INFINITY"); + } else _sb.append(s); + return this; + } + public SB p( char s ) { _sb.append(s); return this; } + public SB p( int s ) { _sb.append(s); return this; } + public SB p( long s ) { _sb.append(s); return this; } + public SB p( boolean s) { _sb.append(s); return this; } + // 1 byte, 2 hex digits, 8 bits + public SB hex1(int s) { + int digit = (s>>4) & 0xf; + _sb.append((char)((digit <= 9 ? '0' : ('A'-10))+digit)); + digit = s & 0xf; + _sb.append((char)((digit <= 9 ? '0' : ('A'-10))+digit)); + return this; + } + // 2 bytes, 4 hex digits, 16 bits, Big Endian + public SB hex2(int s) { return hex1(s>> 8).hex1(s); } + // 4 bytes, 8 hex digits, 32 bits, Big Endian + public SB hex4(int s) { return hex2(s>>16).hex2(s); } + // 8 bytes, 16 hex digits, 64 bits, Big Endian + public SB hex8(long s) { return hex4((int)(s>>32)).hex4((int)s); } + + // Fixed width field + public SB fix( int sz, String s ) { + for( int i=0; i<sz; i++ ) + _sb.append( i < s.length() ? s.charAt(i) : ' '); + return this; + } + public char at(int idx ) { return _sb.charAt(idx); } + + // Not spelled "p" on purpose: too easy to accidentally say "p(1.0)" and + // suddenly call the autoboxed version. + public SB pobj( Object s ) { _sb.append(s.toString()); return this; } + public SB i( int d ) { for( int i=0; i<d+_indent; i++ ) p(" "); return this; } + public SB i( ) { return i(0); } + public SB ip(String s) { return i().p(s); } + public SB s() { _sb.append(' '); return this; } + + // Increase indentation + public SB ii( int i) { _indent += i; return this; } + public SB ii() { return ii(1); } + // Decrease indentation + public SB di( int i) { _indent -= i; return this; } + public SB di() { return di(1); } + + public SB nl( ) { return p(System.lineSeparator()); } + // Last printed a nl + public boolean was_nl() { + int len = _sb.length(); + String nl = System.lineSeparator(); + int nlen = nl.length(); + if( len < nlen ) return false; + for( int i=0; i<nlen; i++ ) + if( _sb.charAt(len-nlen+i)!=nl.charAt(i) ) + return false; + return true; + } + + // Delete last char. Useful when doing string-joins and JSON printing and an + // extra separater char needs to be removed: + // + // sb.p('['); + // for( Foo foo : foos ) + // sb.p(foo).p(','); + // sb.unchar().p(']'); // remove extra trailing comma + // + public SB unchar() { return unchar(1); } + public SB unchar(int x) { _sb.setLength(_sb.length()-x); return this; } + public SB setLen(int len) { _sb.setLength(len); return this; } + public String subString(int start, int end ) { return _sb.substring(start,end); } + + public SB clear() { _sb.setLength(0); return this; } + public int len() { return _sb.length(); } + @Override public String toString() { return _sb.toString(); } +} diff --git a/chapter24/src/main/java/com/seaofnodes/simple/util/Utils.java b/chapter24/src/main/java/com/seaofnodes/simple/util/Utils.java new file mode 100644 index 00000000..577a60af --- /dev/null +++ b/chapter24/src/main/java/com/seaofnodes/simple/util/Utils.java @@ -0,0 +1,53 @@ +package com.seaofnodes.simple.util; + +import java.util.ArrayList; + +public class Utils { + public static RuntimeException TODO() { return TODO("Not yet implemented"); } + public static RuntimeException TODO(String msg) { return new RuntimeException(msg); } + + /** + * Fast, constant-time, element removal. Does not preserve order + * + * @param array ArrayList to modify + * @param i element to be removed + * @return element removed + */ + public static <E> void del(ArrayList<E> array, int i) { + E last = array.removeLast(); + if (i < array.size()) array.set(i, last); + } + + /** + * Search a list for an element by reference + * + * @param ary List to search in + * @param x Object to be searched + * @return >= 0 on success, -1 on failure + */ + public static <E> int find( ArrayList<E> ary, E x ) { + for( int i=0; i<ary.size(); i++ ) + if( ary.get(i)==x ) + return i; + return -1; + } + /** + * Search a list for an element by reference + * + * @param ary List to search in + * @param x Object to be searched + * @return >= 0 on success, -1 on failure + */ + public static <E> int find( E[] ary, E x ) { + for( int i=0; i<ary.length; i++ ) + if( ary[i]==x ) + return i; + return -1; + } + + // Rotate a long, nice for hashes + public static long rot( long x, int n ) { return (x<<n) | (x>>>n); } + + // Fold a 64bit hash into 32 bits + public static int fold( long x ) { return (int)((x>>32) ^ x); } +} diff --git a/chapter24/src/main/smp/sys.smp b/chapter24/src/main/smp/sys.smp new file mode 100644 index 00000000..cda93abe --- /dev/null +++ b/chapter24/src/main/smp/sys.smp @@ -0,0 +1,199 @@ +// -*- mode: java; -*- + +// top-level default import +struct sys { + // libc bindings + /** https://www.man7.org/linux/man-pages/man2/<libc call>.2.html */ + struct libc { + i32 errno = "C"; + // fd buf len -> len + { i32 i64 u32 -> u32 } write = "C"; + // fd buf len -> len + { i32 i64 u32 -> u32 } read = "C"; + // status + { i32 -> i32 } _exit = "C"; + // addr len prot flags fd off -> void* + { i64 i64 i32 i32 i32 i32 -> i64 } mmap = "C"; + // mmap flags + i32 PROT_EXEC = 4; + i32 PROT_READ = 1; + i32 PROT_WRITE= 2; + i32 PROT_NONE = 0; + i32 MAP_PRIVATE = 2; + i32 MAP_ANON = 32; + }; + struct ary { + val copy = { u8[] dst, int doff, u8[~] src, int soff, int len -> + for( int i=0; i<len; i++ ) + dst[i+doff] = src[i+soff]; + return dst; + }; + }; + + // Ary/Vector of u8s - a resizable array of bytes. + struct aryu8 { + u32 !len = 0; + u8[] !buf; + // Grow as needed + val _grow = { int len2 -> + if( len+len2 < buf# ) return self; + int newlen = buf# * 2; + while( len+len2 >= newlen ) newlen *= 2; + u8[] buf2 = new u8[newlen]; + sys.ary.copy(buf2,0,buf,0,buf#); + buf = buf2; + self; + }; + + // Add a character to aryu8 + val add = { u8 c -> + _grow(1).buf[len++] = c; + self; + }; + + // Add a plain array to the aryu8 + val addAry = { u8[~] ary -> + _grow(ary#); + sys.ary.copy(buf,len,ary,0,ary#); + len += ary#; + self; + }; + + // Remove x chars from the tail. + val undo = { int x -> + len = len >= x ? len-x : 0; + self; + }; + + // Print ASCII number into aryu8 + val num = { i64 x -> + if( !x ) { add('0'); return self; } + if( x < 0 ) { add('-'); x = -x; } + i64 ten = 1, log = 0; + while( ten <= x ) { ten *= 10; log++; } + for( int i=0; i<log; i++ ) { + ten /= 10; + i64 q = x/ten; + u8 digit = q+'0'; + add(digit); + x -= q*ten; + } + self; + }; + + // Write to fd, returns the number of bytes written (len). + val write = { i32 fd -> i64 ptr = buf; sys.libc.write(fd,ptr,len); }; + }; + + + // Scanner; a simple string parser. + struct Scan { + int !x; + u8[~] buf; + + // Skip whitespace + val skip = { -> + while( buf[x] <= ' ' ) + x++; + return self; + }; + + // True if find required character, and skip it; else False. + val match = { u8 c -> + skip(); + if( buf[x] != c ) return false; + x++; + return true; + }; + + // Parse a simple number + val number = { -> + skip(); + bool neg = match('-'); + i64 n = 0; + while( '0' <= buf[x] & buf[x] <= '9' ) + n = n*10 + (buf[x++] - '0'); + return neg ? -n : n; + }; + }; + + // Ary/Vector of i64s + struct aryi64 { + u32 !len = 0; + i64[] !buf; + // Grow as needed + val _grow = { int len2 -> + if( len+len2 < buf# ) return self; + int newlen = buf# * 2; + while( len+len2 >= newlen ) newlen *= 2; + i64[] buf2 = new i64[newlen]; + for( int i=0; i<buf#; i++ ) + buf2[i] = buf[i]; + buf = buf2; + self; + }; + + // Add a i64 to aryu8 + val add = { i64 c -> + _grow(1).buf[len++] = c; + self; + }; + + // Write to aryu8 + val str = { -> + // TODO: clunky default constructor syntax + var str = new sys.aryu8 { buf = new u8[1]; }.add('['); + for( int i=0; i<len; i++ ) + str.num(buf[i]).add(',').add(' '); + str.undo(2).add(']'); + }; + }; + + // Parse a comma-separated list of numbers, wrapped with square brackets, + // with optional whitespace e.g. "[ -17, 0,99,12456789 ] ". + // parseAryI64 & aryi64.str are bijections modulo whitespace. + // Returns null if the parse failed. + val parseAryI64 = { u8[~] str -> + sys.Scan !s = new sys.Scan{ buf = str; }; + if( !s.match('[') ) return null; + // Array of parsed results + var nums = new sys.aryi64{ buf=new i64[1]; }; + // Parse a list of numbers + if( !s.match(']') ) { // Handle the empty list + // Parse "123, " until a something else + while( s.x < s.buf# ) { + nums.add(s.number()); + if( !s.match(',') ) + break; + }; + if( !s.match(']') ) return null; // Close the list + } + return nums; + }; + + struct io { + // Print string to stdout + val p = { u8[~] str -> + i64 ptr = str; // cast array base to i64 + return sys.libc.write(1,ptr,str#); + }; + + // Return stdin as a u8[] + val stdin = { -> + var buf = new u8[8*1024]; + i64 ptr = buf; + int len = 0; + while( true ) { + int rez = sys.libc.read(0,ptr,buf#); + if( rez < 0 ) sys.libc._exit(sys.libc.errno); + len += rez; + if( rez < buf# ) + break; + sys.libc._exit(-2); // Need to implement + } + // Compress + var dst = new u8[len]; + return sys.ary.copy(dst,0,buf,0,len); + }; + }; +}; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter24/src/test/java/com/seaofnodes/simple/BrainFuckTest.java new file mode 100644 index 00000000..1e1a1dc3 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/BrainFuckTest.java @@ -0,0 +1,38 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.cpus.arm.arm; +import com.seaofnodes.simple.node.cpus.riscv.riscv; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class BrainFuckTest { + + @Test public void testBrainFuck() throws IOException { + String brain_fuck = "Hello World!\n"; + TestC.run("brain_fuck", brain_fuck, 40); + + EvalRisc5 R5 = TestRisc5.build("brain_fuck", 0, 28, false); + int trap = R5.step(100000); + assertEquals(0,trap); + int ptr = (int)R5.regs[riscv.A0]; + assertEquals(brain_fuck.length(),R5.ld4s(ptr)); + for( int i=0; i<brain_fuck.length(); i++ ) + assertEquals(brain_fuck.charAt(i), R5.ld1z(ptr+4+i)); + + EvalArm64 A5 = TestArm64.build("brain_fuck", 0, 28, false); + int trap_arm = A5.step(100000); + assertEquals(0,trap_arm); + assertEquals(0,trap); + int ptr_arm = (int)A5.regs[arm.X0]; + assertEquals(brain_fuck.length(),A5.ld4s(ptr_arm)); + + for( int i=0; i<brain_fuck.length(); i++ ) + assertEquals(brain_fuck.charAt(i), A5.ld1z(ptr+4+i)); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter01Test.java new file mode 100644 index 00000000..ac9adacc --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter01Test.java @@ -0,0 +1,95 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeInteger; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class Chapter01Test { + + @Test + public void testSimpleProgram() { + CodeGen code = new CodeGen("return 1;").parse(); + Node expr = code.expr(); + if( expr instanceof ConstantNode con ) { + assertEquals(code._start,con.in(0)); + assertEquals(TypeInteger.constant(1), con._type); + } else { + fail(); + } + } + + @Test + public void testZero() { + CodeGen code = new CodeGen("return 0;"); + code.parse(); + Node use = code.expr(); + if( use instanceof ConstantNode con && con._type instanceof TypeInteger ) + assertEquals(TypeInteger.constant(0),con._type); + } + + @Test + public void testBad1() { + try { + new CodeGen("ret;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Undefined name 'ret'",e.getMessage()); + } + } + + @Test + public void testBad2() { + try { + new CodeGen("return 0123;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage()); + } + } + + @Test + public void testNotBad3() { + // this test used to fail in chapter 1 + assertEquals("return 12;", new CodeGen("return - -12;").parse()._stop.print()); + } + + @Test + public void testBad4() { + try { + new CodeGen("return 100").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected ;: ",e.getMessage()); + } + } + + @Test + public void testNotBad5() { + // this test used to fail in chapter 1 + assertEquals("return -100;", new CodeGen("return -100;").parse()._stop.print()); + } + + @Test + public void testBad6() { + try { + new CodeGen("return100;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Undefined name 'return100'",e.getMessage()); + } + } + + @Test + public void testBad7() { + try { + new CodeGen("return 1;}").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, unexpected: }",e.getMessage()); + } + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter02Test.java new file mode 100644 index 00000000..631e1487 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter02Test.java @@ -0,0 +1,61 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeInteger; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class Chapter02Test { + + @Test + public void testParseGrammar() { + CodeGen code = new CodeGen("return 1+2*3+-5;"); + code.parse(); // No more disable peepholes + assertEquals("return 2;", code.print()); + } + + @Test + public void testAddPeephole() { + CodeGen code = new CodeGen("return 1+2;"); + code.parse(); + assertEquals("return 3;", code.print()); + } + + @Test + public void testSubPeephole() { + CodeGen code = new CodeGen("return 1-2;"); + code.parse(); + assertEquals("return -1;", code.print()); + } + + @Test + public void testMulPeephole() { + CodeGen code = new CodeGen("return 2*3;"); + code.parse(); + assertEquals("return 6;", code.print()); + } + + @Test + public void testDivPeephole() { + CodeGen code = new CodeGen("return 6/3;"); + code.parse(); + assertEquals("return 2;", code.print()); + } + + @Test + public void testMinusPeephole() { + CodeGen code = new CodeGen("return 6/-3;"); + code.parse(); + assertEquals("return -2;", code.print()); + } + + @Test + public void testExample() { + CodeGen code = new CodeGen("return 1+2*3+-5;"); + code.parse(); + assertEquals("return 2;", code.print()); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter03Test.java new file mode 100644 index 00000000..c4e4c91e --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter03Test.java @@ -0,0 +1,73 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import org.junit.Test; +import static org.junit.Assert.*; + +public class Chapter03Test { + + @Test + public void testVarDecl() { + CodeGen code = new CodeGen("int a=1; return a;"); + code.parse(); assertEquals("return 1;", code.print()); + } + + @Test + public void testVarAdd() { + CodeGen code = new CodeGen("int a=1; int b=2; return a+b;"); + code.parse(); + assertEquals("return 3;", code.print()); + } + + @Test + public void testVarScope() { + CodeGen code = new CodeGen("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;"); + code.parse(); + assertEquals("return 4;", code.print()); + } + + @Test + public void testVarScopeNoPeephole() { + CodeGen code = new CodeGen("int a=1; int b=2; int !c=0; { int b=3; c=a+b; } return c; "); + code.parse(); // Peepholes always run now + assertEquals("return 4;", code.print()); + } + + @Test + public void testVarDist() { + CodeGen code = new CodeGen("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); "); + code.parse(); + assertEquals("return 8;", code.print()); + } + + @Test + public void testSelfAssign() { + try { + new CodeGen("int a=a; return a;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Undefined name 'a'",e.getMessage()); + } + } + + @Test + public void testRedeclareVar() { + try { + new CodeGen("int a=1; int b=2; int c=0; int b=3; c=a+b;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Redefining name 'b'",e.getMessage()); + } + } + + @Test + public void testBad1() { + try { + new CodeGen("int a=1; int b=2; int !c=0; { int b=3; c=a+b;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected }: ",e.getMessage()); + } + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter04Test.java new file mode 100644 index 00000000..1361d8b6 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -0,0 +1,131 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeInteger; +import org.junit.Test; +import org.junit.Ignore; + +import static org.junit.Assert.*; + +public class Chapter04Test { + + @Test + public void testPeephole() { + CodeGen code = new CodeGen("return 1+arg+2; "); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testPeephole2() { + CodeGen code = new CodeGen("return (1+arg)+2;"); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testAdd0() { + CodeGen code = new CodeGen("return 0+arg;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void testAddAddMul() { + CodeGen code = new CodeGen("return arg+0+arg;"); + code.parse(); + assertEquals("return (arg<<1);", code.print()); + } + + @Test + public void testPeephole3() { + CodeGen code = new CodeGen("return 1+arg+2+arg+3; "); + code.parse(); + assertEquals("return ((arg<<1)+6);", code.print()); + } + + @Test + public void testMul1() { + CodeGen code = new CodeGen("return 1*arg;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void testVarArg() { + CodeGen code = new CodeGen("return arg; "); + code.parse(); + assertTrue(code.ctrl() instanceof FunNode); + assertTrue(code.expr() instanceof ParmNode); + } + + // Adding functions means `main` does not constant fold the incoming arg value + @Ignore @Test + public void testConstantArg() { + CodeGen code = new CodeGen("return arg; ", TypeInteger.constant(2), 123L, true).parse(); + assertEquals("return 2;", code.expr().in(1).toString()); + } + + @Test + public void testCompEq() { + CodeGen code = new CodeGen("return 3==3; "); + code.parse(); + assertEquals("return 1;", code.print()); + } + + @Test + public void testCompEq2() { + CodeGen code = new CodeGen("return 3==4; "); + code.parse(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testCompNEq() { + CodeGen code = new CodeGen("return 3!=3; "); + code.parse(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testCompNEq2() { + CodeGen code = new CodeGen("return 3!=4; "); + code.parse(); + assertEquals("return 1;", code.print()); + } + + @Test + public void testBug1() { + CodeGen code = new CodeGen("int a=arg+1; int !b=a; b=1; return a+2; "); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testBug2() { + CodeGen code = new CodeGen("int !a=arg+1; a=a; return a; "); + code.parse(); + assertEquals("return (arg+1);", code.print()); + } + + @Test + public void testBug3() { + try { new CodeGen("inta=1; return a;").parse(); fail(); } + catch( RuntimeException e ) { assertEquals("Undefined name 'inta'",e.getMessage()); } + } + + @Test + public void testBug4() { + CodeGen code = new CodeGen("return -arg;"); + code.parse(); + assertEquals("return (-arg);", code.print()); + } + + @Test + public void testBug5() { + CodeGen code = new CodeGen("return arg--2;"); + code.parse(); + assertEquals("return (arg--2);", code.print()); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter05Test.java new file mode 100644 index 00000000..d1dfd216 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter05Test.java @@ -0,0 +1,186 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class Chapter05Test { + + @Test + public void testIfStmt() { + CodeGen code = new CodeGen( +""" +int a = 1; +if (arg == 1) + a = arg+2; +else { + a = arg-3; +} +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,(arg+2),(arg-3));", code.print()); + } + + @Test + public void testTest() { + CodeGen code = new CodeGen( +""" +int c = 3; +int b = 2; +if (arg == 1) { + b = 3; + c = 4; +} +return c; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,4,3);", code.print()); + } + + @Test + public void testReturn2() { + CodeGen code = new CodeGen( +""" +if( arg==1 ) + return 3; +else + return 4; +"""); + code.parse(); + assertEquals("return Phi(Region,3,4);", code.print()); + } + + @Test + public void testIfMergeB() { + CodeGen code = new CodeGen( +""" +int a=arg+1; +int b=0; +if( arg==1 ) + b=a; +else + b=a+1; +return a+b;"""); + code.parse().opto(); + assertEquals("return ((arg<<1)+Phi(Region,2,3));", code.print()); + } + + @Test + public void testIfMerge2() { + CodeGen code = new CodeGen( +""" +int a=arg+1; +int b=arg+2; +if( arg==1 ) + b=b+a; +else + a=b+1; +return a+b;"""); + code.parse().opto(); + assertEquals("return ((Phi(Region,(arg<<1),arg)+arg)+Phi(Region,4,5));", code.print()); + } + + @Test + public void testMerge3() { + CodeGen code = new CodeGen( +""" +int a=1; +if( arg==1 ) + if( arg==2 ) + a=2; + else + a=3; +else if( arg==3 ) + a=4; +else + a=5; +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,3,5,2,4);", code.print()); + } + + @Test + public void testMerge4() { + CodeGen code = new CodeGen( +""" +int a=0; +int b=0; +if( arg ) + a=1; +if( arg==0 ) + b=2; +return arg+a+b; +"""); + code.parse().opto(); + assertEquals("return ((arg+Phi(Region,1,0))+Phi(Region,2,0));", code.print()); + } + + @Test + public void testMerge5() { + CodeGen code = new CodeGen( +""" +int a=arg==2; +if( arg==1 ) +{ + a=arg==3; +} +return a; +"""); + code.parse().opto(); + assertEquals("return (arg==Phi(Region,3,2));", code.print()); + } + + @Test + public void testTrue() { + CodeGen code = new CodeGen("return true;").parse(); + assertEquals("return 1;",code.print()); + } + + @Test + public void testHalfDef() { + try { new CodeGen("if( arg==1 ) int b=2; return b;").parse(); fail(); } + catch( RuntimeException e ) { assertEquals("Cannot define a 'b' on one arm of an if",e.getMessage()); } + } + + @Test + public void testHalfDef2() { + try { new CodeGen("if( arg==1 ) { int b=2; } else { int b=3; } return b;").parse(); fail(); } + catch( RuntimeException e ) { assertEquals("Undefined name 'b'",e.getMessage()); } + } + + @Test + public void testRegress1() { + try { new CodeGen("if(arg==2) int a=1; else int b=2; return a;").parse(); fail(); } + catch( RuntimeException e ) { assertEquals("Cannot define a 'a' on one arm of an if",e.getMessage()); } + } + + + @Test + public void testBadNum() { + try { new CodeGen("return 1-;").parse(); fail(); } + catch( RuntimeException e ) { assertEquals("Syntax error, expected an identifier or expression: ;",e.getMessage()); } + } + + @Test + public void testKeyword1() { + try { new CodeGen("int true=0; return true;").parse(); fail(); } + catch( RuntimeException e ) { assertEquals("Expected an identifier, found 'true'",e.getMessage()); } + } + + @Test + public void testKeyword2() { + try { new CodeGen("int else=arg; if(else) else=2; else else=1; return else;").parse(); fail(); } + catch( RuntimeException e ) { assertEquals("Expected an identifier, found 'else'",e.getMessage()); } + } + + @Test + public void testKeyword3() { + try { new CodeGen("int a=1; ififif(arg);a=2;return a;").parse(); fail(); } + catch( RuntimeException e ) { assertEquals("Undefined name 'ififif'",e.getMessage()); } + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter06Test.java new file mode 100644 index 00000000..1ff875b4 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter06Test.java @@ -0,0 +1,305 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeInteger; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class Chapter06Test { + + @Test + public void testPeepholeReturn() { + CodeGen code = new CodeGen(""" +if( true ) return 2; +return 1; +"""); + code.parse().opto(); + assertEquals("return 2;", code.print()); + assertTrue(code.ctrl() instanceof FunNode); + } + + @Test + public void testPeepholeRotate() { + CodeGen code = new CodeGen( +""" +int a = 1; +if (arg) + a = 2; +return (arg < a) < 3; // Because (arg < a) is a bool/uint1/[0-1], its always less than 3 +"""); + code.parse().opto(); + assertEquals("return 1;", code.print()); + } + + @Test + public void testPeepholeCFG() { + CodeGen code = new CodeGen( +""" +int a=1; +if( true ) + a=2; +else + a=3; +return a; +"""); + code.parse().opto(); + assertEquals("return 2;", code.print()); + assertTrue(code.ctrl() instanceof FunNode); + } + + @Test + public void testIfIf() { + CodeGen code = new CodeGen( +""" +int a=1; +if( arg!=1 ) + a=2; +else + a=3; +int b=4; +if( a==2 ) + b=42; +else + b=5; +return b; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,42,5);", code.print()); + } + + @Test + public void testIfArgIf() { + CodeGen code = new CodeGen( +""" +int a=1; +if( 1==1 ) + a=2; +else + a=3; +int b=4; +if( arg==2 ) + b=a; +else + b=5; +return b;"""); + code.parse().opto(); + assertEquals("return Phi(Region,2,5);", code.print()); + } + + @Test + public void testMerge3With2() { + CodeGen code = new CodeGen( +""" +arg=2; +int a=1; +if( arg==1 ) + if( arg==2 ) + a=2; + else + a=3; +else if( arg==3 ) + a=4; +else + a=5; +return a; +""", TypeInteger.constant(2), 123L, true).parse().opto(); + assertEquals("return 5;", code.print()); + } + + @Test + public void testMerge3With1() { + CodeGen code = new CodeGen( +""" +arg=1; +int a=1; +if( arg==1 ) + if( arg==2 ) + a=2; + else + a=3; +else if( arg==3 ) + a=4; +else + a=5; +return a; +""", TypeInteger.constant(1), 123L, true).parse().opto(); + assertEquals("return 3;", code.print()); + } + + @Test + public void testMerge3Peephole() { + CodeGen code = new CodeGen( +""" +int a=1; +if( arg==1 ) + if( 1==2 ) + a=2; + else + a=3; +else if( arg==3 ) + a=4; +else + a=5; +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,3,5,4);", code.print()); + } + + @Test + public void testMerge3Peephole1() { + CodeGen code = new CodeGen( +""" +arg=1; +int a=1; +if( arg==1 ) + if( 1==2 ) + a=2; + else + a=3; +else if( arg==3 ) + a=4; +else + a=5; +return a; +""", TypeInteger.constant(1), 123L, true); + code.parse().opto(); + assertEquals("return 3;", code.print()); + } + + @Test + public void testMerge3Peephole3() { + CodeGen code = new CodeGen( +""" +arg=3; +int a=1; +if( arg==1 ) + if( 1==2 ) + a=2; + else + a=3; +else if( arg==3 ) + a=4; +else + a=5; +return a; +""", TypeInteger.constant(3), 123L, true); + code.parse().opto(); + assertEquals("return 4;", code.print()); + } + + @Test + public void testDemo1NonConst() { + CodeGen code = new CodeGen(""" +int a = 0; +int b = 1; +if( arg ) { + a = 2; + if( arg ) { b = 2; } + else b = 3; +} +return a+b; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,4,1);", code.print()); + } + + + @Test + public void testDemo1True() { + CodeGen code = new CodeGen( +""" +arg=1; +int a = 0; +int b = 1; +if( arg ) { + a = 2; + if( arg ) { b = 2; } + else b = 3; +} +return a+b; +""", TypeInteger.constant(1), 123L, true); + code.parse().opto(); + assertEquals("return 4;", code.print()); + } + + @Test + public void testDemo1False() { + CodeGen code = new CodeGen( +""" +arg=0; +int a = 0; +int b = 1; +if( arg ) { + a = 2; + if( arg ) { b = 2; } + else b = 3; +} +return a+b; +""", TypeInteger.constant(0), 123L, true); + code.parse().opto(); + assertEquals("return 1;", code.print()); + } + + @Test + public void testDemo2NonConst() { + CodeGen code = new CodeGen(""" +int a = 0; +int b = 1; +int c = 0; +if( arg ) { + a = 1; + if( arg==2 ) { c=2; } else { c=3; } + if( arg ) { b = 2; } + else b = 3; +} +return a+b+c; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,6,1,5);", code.print()); + } + + + @Test + public void testDemo2True() { + CodeGen code = new CodeGen( +""" +arg=1; +int a = 0; +int b = 1; +int c = 0; +if( arg ) { + a = 1; + if( arg==2 ) { c=2; } else { c=3; } + if( arg ) { b = 2; } + else b = 3; +} +return a+b+c; +""", TypeInteger.constant(1), 123L, true); + code.parse().opto(); + assertEquals("return 6;", code.print()); + } + + @Test + public void testDemo2arg2() { + CodeGen code = new CodeGen( +""" +arg=2; +int a = 0; +int b = 1; +int c = 0; +if( arg ) { + a = 1; + if( arg==2 ) { c=2; } else { c=3; } + if( arg ) { b = 2; } + else b = 3; +} +return a+b+c; +""", TypeInteger.constant(2), 123L, true); + code.parse().opto(); + assertEquals("return 5;", code.print()); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter07Test.java new file mode 100644 index 00000000..88554323 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter07Test.java @@ -0,0 +1,222 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class Chapter07Test { + + @Test + public void testExample() { + CodeGen code = new CodeGen( +""" +while(arg < 10) { + arg = arg + 1; +} +return arg; +"""); + code.parse(); + assertEquals("return Phi(Loop,arg,(Phi_arg+1));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testRegression() { + CodeGen code = new CodeGen( +""" +int a = 1; +if(arg){}else{ + while(a < 10) { + a = a + 1; + } +} +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,1,Phi(Loop,1,(Phi_a+1)));", code.print()); + } + + @Test + public void testWhileNested() { + CodeGen code = new CodeGen( +""" +int sum = 0; +int i = 0; +while(i < arg) { + i = i + 1; + int j = 0; + while( j < arg ) { + sum = sum + j; + j = j + 1; + } +} +return sum; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,0,Phi(Loop,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", code.print()); + } + + @Test + public void testWhileScope() { + CodeGen code = new CodeGen( +""" +int a = 1; +int b = 2; +while(a < 10) { + if (a == 2) a = 3; + else b = 4; +} +return b; +"""); + code.parse(); + assertEquals("return Phi(Loop,2,Phi(Region,Phi_b,4));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testWhileNestedIfAndInc() { + CodeGen code = new CodeGen( +""" +int a = 1; +int b = 2; +while(a < 10) { + if (a == 2) a = 3; + else b = 4; + b = b + 1; + a = a + 1; +} +return b; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,2,(Phi(Region,Phi_b,4)+1));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + + @Test + public void testWhile() { + CodeGen code = new CodeGen( +""" +int a = 1; +while(a < 10) { + a = a + 1; + a = a + 2; +} +return a; +"""); + code.parse(); + assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testWhilePeep() { + CodeGen code = new CodeGen( +""" +int a = 1; +while(a < 10) { + a = a + 1; + a = a + 2; +} +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testWhile2() { + CodeGen code = new CodeGen( +""" +int a = 1; +while(arg) a = 2; +return a; +"""); + code.parse(); + assertEquals("return Phi(Loop,1,2);", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testWhile2Peep() { + CodeGen code = new CodeGen( +""" +int a = 1; +while(arg) a = 2; +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,1,2);", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testWhile3() { + CodeGen code = new CodeGen( +""" +int a = 1; +while(a < 10) { + int b = a + 1; + a = b + 2; +} +return a; +"""); + code.parse(); + assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testWhile3Peep() { + CodeGen code = new CodeGen( +""" +int a = 1; +while(a < 10) { + int b = a + 1; + a = b + 2; +} +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testWhile4() { + CodeGen code = new CodeGen( +""" +int a = 1; +int b = 2; +while(a < 10) { + int b = a + 1; + a = b + 2; +} +return a; +"""); + code.parse(); + assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testWhile4Peep() { + CodeGen code = new CodeGen( +""" +int a = 1; +int b = 2; +while(a < 10) { + int b = a + 1; + a = b + 2; +} +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter08Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter08Test.java new file mode 100644 index 00000000..09669cc7 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter08Test.java @@ -0,0 +1,208 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class Chapter08Test { + + @Test + public void testEx6() { + CodeGen code = new CodeGen( + """ +while(arg < 10) { + arg = arg + 1; + if (arg == 5) + break; + if (arg == 6) + break; +} +return arg; + """); + code.parse().opto(); + assertEquals("return Phi(Region,(Phi(Loop,arg,Add)+1),Add,Phi_arg);", code.print()); + assertTrue(code.ctrl() instanceof RegionNode); + Assert.assertEquals( "5", Eval2.eval(code, 1)); + Assert.assertEquals("10", Eval2.eval(code, 6)); + } + + + @Test + public void testEx5() { + CodeGen code = new CodeGen( + """ +int a = 1; +while(arg < 10) { + arg = arg + 1; + if (arg == 5) + continue; + if (arg == 7) + continue; + a = a + 1; +} +return a; + """); + code.parse().opto(); + assertEquals("return Phi(Loop,1,Phi(Region,Phi_a,(Phi_a+1),Phi_a));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + + @Test + public void testEx4() { + CodeGen code = new CodeGen( + """ +while(arg < 10) { + arg = arg + 1; + if (arg == 5) + continue; + if (arg == 6) + break; +} +return arg; + """); + code.parse().opto(); + assertEquals("return Phi(Region,Phi(Loop,arg,(Phi_arg+1)),Add);", code.print()); + assertTrue(code.ctrl() instanceof RegionNode); + } + + @Test + public void testEx3() { + CodeGen code = new CodeGen( + """ +while(arg < 10) { + arg = arg + 1; + if (arg == 6) + break; +} +return arg; + """); + code.parse().opto(); + assertEquals("return Phi(Region,Phi(Loop,arg,(Phi_arg+1)),Add);", code.print()); + assertTrue(code.ctrl() instanceof RegionNode); + } + + + @Test + public void testEx2() { + CodeGen code = new CodeGen( + """ +while(arg < 10) { + arg = arg + 1; + if (arg == 5) + continue; + if (arg == 6) + continue; +} +return arg; + """); + code.parse().opto(); + assertEquals("return Phi(Loop,arg,(Phi_arg+1));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + + @Test + public void testEx1() { + CodeGen code = new CodeGen( + """ +while(arg < 10) { + arg = arg + 1; + if (arg == 5) + continue; +} +return arg; + """); + code.parse().opto(); + assertEquals("return Phi(Loop,arg,(Phi_arg+1));", code.print()); + assertTrue(code.ctrl() instanceof CProjNode); + } + + @Test + public void testRegress1() { + CodeGen code = new CodeGen( + """ +while( arg < 10 ) { + int a = arg+2; + if( a > 4 ) + break; +} +return arg; + """); + code.parse().opto(); + assertEquals("return arg;", code.print()); + } + + @Test + public void testRegress2() { + CodeGen code = new CodeGen("if(1) return 0; else while(arg>- -arg) arg=arg+1; return 0;"); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testBreakOutsideLoop() { + try { + new CodeGen(""" +if(arg <= 10) { + break; + arg = arg + 1; +} +return arg; +""").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("No active loop for a break or continue",e.getMessage()); + } + } + + @Test + public void testRegress3() { + CodeGen code = new CodeGen(""" +while(arg < 10) { + break; +} +return arg; +"""); + code.parse().opto(); + assertEquals("return arg;", code.print()); + } + + @Test + public void testRegress4() { + CodeGen code = new CodeGen(""" +int a = 1; +while(arg < 10) { + a = a + 1; + if (arg > 2) { + int a = 17; + break; + } +} +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,Phi(Loop,1,(Phi_a+1)),Add);", code.print()); + assertTrue(code.ctrl() instanceof RegionNode); + } + + @Test + public void testRegress5() { + CodeGen code = new CodeGen(""" +int a = 1; +while(1) { + a = a + 1; + if (a<10) continue; + break; +} +return a; +"""); + code.parse().opto(); + assertEquals("return (Phi(Loop,1,Add)+1);", code.print()); + assertTrue(code.ctrl() instanceof CProjNode prj && prj._idx==1 ); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter09Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter09Test.java new file mode 100644 index 00000000..54a14a25 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter09Test.java @@ -0,0 +1,299 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import org.junit.Assert; +import org.junit.Test; +import org.junit.Ignore; + +import static org.junit.Assert.*; + +public class Chapter09Test { + + @Test + @Ignore + public void testJig() { + CodeGen code = new CodeGen(""" +int v0=0; +arg=0; +while(v0) { + while(1) if(arg*arg*0==0) {} + while(0) {} + arg=1; +} +return 0; + """); + code.parse().opto(); + } + + @Test + public void testGVN1() { + CodeGen code = new CodeGen( + """ +int x = arg + arg; +if(arg < 10) { + return arg + arg; +} +else { + x = x + 1; +} +return x; + """); + code.parse().opto(); + assertEquals("return Phi(Region,(arg<<1),(Shl+1));", code.print()); + Assert.assertEquals( "2", Eval2.eval(code, 1)); + Assert.assertEquals("23", Eval2.eval(code, 11)); + } + + @Test + public void testGVN2() { + CodeGen code = new CodeGen("return arg*arg-arg*arg;"); + code.parse().opto(); + assertEquals("return 0;", code.print()); + Assert.assertEquals("0", Eval2.eval(code, 1, 1)); + } + + @Test + public void testWorklist1() { + CodeGen code = new CodeGen(""" +int step = 1; +while (arg < 10) { + arg = arg + step + 1; +} +return arg; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,arg,(Phi_arg+2));", code.print()); + Assert.assertEquals("11", Eval2.eval(code, 1)); + } + + @Test + public void testWorklist2() { + CodeGen code = new CodeGen( + """ +int cond = 0; +int one = 1; +while (arg < 10) { + if (cond) one = 2; + arg = arg + one*3 + 1; +} +return arg; + """); + code.parse().opto(); + assertEquals("return Phi(Loop,arg,(Phi_arg+4));", code.print()); + Assert.assertEquals("13", Eval2.eval(code, 1)); + } + + @Test + public void testWorklist3() { + CodeGen code = new CodeGen( + """ +int v1 = 0; +int v2 = 0; +int v3 = 0; +int v4 = 0; +int v5 = 0; +int v6 = 0; +int v7 = 0; +int v8 = 0; +while (arg) { + if (v1) v2 = 1; + if (v2) v3 = 1; + if (v3) v4 = 1; + if (v4) v5 = 1; + if (v5) v6 = 1; + if (v6) v7 = 1; + if (v7) v8 = 1; + arg = arg + v8 + 1; +} +return arg; + """); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testRegionPeepBug() { + CodeGen code = new CodeGen( + """ +int v0=0; +int v1=0; +while(v1+arg) { + arg=0; + int v2=v0; + while(arg+1) {} + v0=1; + v1=v2; +} +return 0; + """); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testWhile0() { + CodeGen code = new CodeGen("while(0) continue; if(0) arg=0; return arg;"); + code.parse().opto(); + assertEquals("return arg;", code.print()); + } + + @Test + public void testWhile1() { + CodeGen code = new CodeGen(""" +if(0) while(0) { + int arg=arg; + while(0) {} +} +return 0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + + @Test + public void testPrecedence() { + CodeGen code = new CodeGen("return 3-1+2;"); + code.parse().opto(); + assertEquals("return 4;", code.print()); + } + + @Test + public void testSwap2() { + CodeGen code = new CodeGen("return 1+(1+1);"); + code.parse().opto(); + assertEquals("return 3;", code.print()); + } + + + @Test + public void testFuzz0() { + CodeGen code = new CodeGen(""" +int one = 1; +int a = 0; +int zero = 0; +while(arg) { + a = -(one + a + 2); + arg = arg + 1; + one = one + zero; +} +return a; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,0,(-(Phi_a+3)));", code.print()); + } + + @Test + public void testFuzz1() { + CodeGen code = new CodeGen(""" +while(1) {} +while(arg) break; +while(arg) arg=0; +arg=0; +int v0=0!=0<-0; +return -0+0+0; +"""); + code.parse().opto(); + assertEquals("return Top;", code.print()); + } + + + @Test + public void testFuzz2() { + CodeGen code = new CodeGen("return 0+-0;"); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testFuzz3() { + CodeGen code = new CodeGen("int v0=0; while(0==69) while(v0) return 0; return 0;"); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testFuzz4() { + CodeGen code = new CodeGen(""" +while(1) { + arg=0<=0; + if(1<0) while(arg==-0) arg=arg-arg; +} +"""); + code.parse().opto(); + assertEquals("return Top;", code.print()); + } + + @Test + public void testFuzz5() { + CodeGen code = new CodeGen(""" +{ + int v0=0; + while(1) + int v1=0--0; + while(v0) + break; + while(-v0) { + while(0+0+v0) continue; + break; + } + if(-0!=-0+0+v0) while(0+0+0+0) + break; +} +return 0!=0; +"""); + code.parse().opto(); + assertEquals("return Top;", code.print()); + } + + @Test + public void testFuzz6() { + CodeGen code = new CodeGen( +""" +int v0=0; +while(0==1) while(v0) + v0=1+v0; +return 0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testFuzz7() { + CodeGen code = new CodeGen(""" +while(1) {} +int v0=0; +while(v0) + {} +int v1=0; +while(1) + v1=1; +return v1+v0; + """); + code.parse().opto(); + assertEquals("return Top;", code.print()); + } + + @Test + public void testFuzz8() { + CodeGen code = new CodeGen("while(arg) arg = arg - 1; return arg;"); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testMeet() { + Type t1 = Type.TOP; + Type t2 = TypeInteger.TOP; + Assert.assertEquals(TypeInteger.TOP, t1.meet(t2)); + Assert.assertEquals(TypeInteger.TOP, t2.meet(t1)); + t1 = Type.BOTTOM; + t2 = TypeInteger.BOT; + Assert.assertEquals(Type.BOTTOM, t1.meet(t2)); + Assert.assertEquals(Type.BOTTOM, t2.meet(t1)); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter10Test.java new file mode 100644 index 00000000..ec363239 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter10Test.java @@ -0,0 +1,399 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class Chapter10Test { + + @Test + public void testFuzzer() { + CodeGen code = new CodeGen( +""" +int a = arg/3; +int b = arg*5; +int x = arg*7; +int y = arg/11; +int p; int g; int h; +if( (arg/13)==0 ) { + p = x + y; + g = x; + h = y; +} else { + p = a + b; + g = a; + h = b; +} +int r = g+h; +return p-r; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testStruct() { + CodeGen code = new CodeGen(""" +struct Bar { + int a; + int b; +}; +struct Foo { + int x; +}; +Foo? foo = null; +Bar !bar = new Bar; +bar.a = 1; +bar.a = 2; +return bar.a; +"""); + code.parse().opto(); + assertEquals("return 2;", code.print()); + } + + @Test + public void testExample() { + CodeGen code = new CodeGen(""" +struct Vector2D { int x; int y; }; +Vector2D !v = new Vector2D; +v.x = 1; +if (arg) + v.y = 2; +else + v.y = 3; +return v; +"""); + code.parse().opto(); + assertEquals("return Vector2D;", code.print()); + } + + @Test + public void testBug() { + CodeGen code = new CodeGen(""" +struct s0 { + int v0; +}; +s0? v1=null; +int v3=v1.zAicm; +"""); + try { code.parse(); fail(); } + catch( Exception e ) { assertEquals("Accessing unknown field 'zAicm' from 'null'",e.getMessage()); } + } + + @Test + public void testBug2() { + CodeGen code = new CodeGen(""" +struct s0 { int v0; }; +arg=0+new s0.0; +"""); + try { code.parse(); fail(); } + catch( Exception e ) { assertEquals("Expected an identifier, found 'null'",e.getMessage()); } + } + + @Test + public void testLoop() { + CodeGen code = new CodeGen(""" +struct Bar { int a; }; +Bar !bar = new Bar; +while (arg) { + bar.a = bar.a + 2; + arg = arg + 1; +} +return bar.a; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,0,(Phi_a+2));", code.print()); + } + + @Test + public void testIf() { + CodeGen code = new CodeGen(""" +struct Bar { int a; }; +Bar !bar = new Bar; +if (arg) bar = null; +bar.a = 1; +return bar.a; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Type null is not of declared type *Bar",e.getMessage()); } + } + + @Test + public void testIf2() { + CodeGen code = new CodeGen(""" +struct Bar { int a; }; +Bar? !bar = null; +if (arg) bar = new Bar; +bar.a = 1; +return bar.a; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Might be null accessing 'a'",e.getMessage()); } + } + + @Test + public void testIf3() { + CodeGen code = new CodeGen(""" +struct Bar { int a; }; +Bar bar = null; +if (arg) bar = null; +bar.a = 1; +return bar.a; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Type null is not of declared type *Bar", e.getMessage()); } + } + + @Test + public void testIfOrNull() { + CodeGen code = new CodeGen(""" +struct Bar { int a; }; +Bar? !bar = new Bar; +if (arg) bar = null; +if( bar ) bar.a = 1; +return bar; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,null,Bar);", code.print()); + } + + @Test + public void testIfOrNull2() { + CodeGen code = new CodeGen( +""" +struct Bar { int a; }; +Bar? !bar = new Bar; +if (arg) bar = null; +int rez = 3; +if( !bar ) rez=4; +else bar.a = 1; +return rez; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,4,3);", code.print()); + } + + @Test + public void testWhileWithNullInside() { + CodeGen code = new CodeGen(""" +struct s0 {int v0;}; +s0? !v0 = new s0; +int ret = 0; +while(arg) { + ret = v0.v0; + v0 = null; + arg = arg - 1; +} +return ret; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { + assertEquals("Might be null accessing 'v0'", e.getMessage()); } + } + + @Test + public void testRedeclareStruct() { + CodeGen code = new CodeGen(""" +struct s0 { + int v0; +}; +s0? v1=new s0; +s0? v1; +v1=new s0; +"""); + try { code.parse(); fail(); } + catch( Exception e ) { assertEquals("Redefining name 'v1'", e.getMessage()); } + } + + @Test + public void testIter() { + // Build and use an iterator + CodeGen code = new CodeGen( +""" +struct Iter { + int x; + int len; +}; +Iter !i = new Iter; +i.len = arg; +int sum=0; +while( i.x < i.len ) { + sum = sum + i.x; + i.x = i.x + 1; +} +return sum; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum));", code.print()); + } + + + @Test + public void test1() { + CodeGen code = new CodeGen(""" +struct s0 {int v0;}; +s0 !ret = new s0; +while(arg) { + s0 !v0 = new s0; + v0.v0 = arg; + arg = arg-1; + if (arg==5) ret=v0; + +} +return ret; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", code.print()); + } + + @Test + public void test2() { + CodeGen code = new CodeGen(""" +struct s0 {int v0;}; +s0 !ret = new s0; +s0 !v0 = new s0; +while(arg) { + v0.v0 = arg; + arg = arg-1; + if (arg==5) ret=v0; + +} +return ret; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", code.print()); + } + + + @Test + public void test3() { + CodeGen code = new CodeGen(""" +struct s0 {int v0;}; +s0 !ret = new s0; +while(arg < 10) { + s0 !v0 = new s0; + if (arg == 5) ret=v0; + arg = arg + 1; +} +return ret; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", code.print()); + } + + @Test + public void testBug3() { + CodeGen code = new CodeGen(""" +struct s0 { int f0; }; +return new s0; +int v0=null.f0; +"""); + try { code.parse(); fail(); } + catch( Exception e ) { assertEquals("Syntax error, expected ;: .",e.getMessage()); } + } + + @Test + public void testBug4() { + CodeGen code = new CodeGen(""" +if(0) { + while(0) if(arg) continue; + int v0=0; + while(1) { + int v2=-arg; + v0=v2; + } +} +return 0; + """); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testBug5() { + CodeGen code = new CodeGen(""" +struct s0 { + int f0; +}; +if(0) return 0; +else return new s0; +if(new s0.f0) return 0; + """); + code.parse().opto(); + assertEquals("return s0;", code.print()); + } + + @Test + public void testBug6MissedWorklist() { + CodeGen code = new CodeGen(""" +while(0) {} +int v4=0; +while(0<arg) { + v4=v4+1; + while(1) v4=-v4; + while(0) arg=-1; +} +return 0; + """); + code.parse().opto(); + } + + @Test + public void testBug7() { + CodeGen code = new CodeGen(""" +struct s0 { int f0; }; +s0 v0 = new s0; +while(v0.f0) {} +s0 v1 = v0; +return v1; + """); + code.parse().opto(); + assertEquals("return s0;", code.print()); + } + + + @Test + public void testBug8() { + CodeGen code = new CodeGen(""" +int v2=0; +while(0) +while(0) {} +{ + { + { + int v36=0; + { + while(0) { + { + while(-v2) { + { + while(v36) { + while(v2) return 0; + break; + } } + if(-v2) break; + } + } + } + } + } } +} +return 0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testBug9() { + CodeGen code = new CodeGen(""" +int v0=arg==0; +while(v0) continue; +return 0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter11Test.java new file mode 100644 index 00000000..f6539ac4 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter11Test.java @@ -0,0 +1,551 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +public class Chapter11Test { + + // A placeholder test used to rapidly rotate through fuzzer produced issues + @Test + public void testFuzzer() { + CodeGen code = new CodeGen( +""" +while(---- -arg) { + while(-arg) { + while(-----arg*---0) { + int N=--false==false<--arg; + while(N<-4==N) { + N=N+N; + } + } + { + int kzEl_r7EYz=3*----0!=-arg<(37*--97!=0/arg==arg)<=-(--arg!=0); + while(kzEl_r7EYz<---1) { + kzEl_r7EYz=kzEl_r7EYz+kzEl_r7EYz*arg>=24; + if(7) continue; + kzEl_r7EYz=false; + if(-kzEl_r7EYz+arg<-3) continue; + else { + while(kzEl_r7EYz) continue; + arg=----3; + kzEl_r7EYz=-(-----arg*1>-kzEl_r7EYz); + int v2uF_4ba=9; + } + } + } + int pjcp7rv=arg; + { + int m2ya3=--arg-pjcp7rv; + while(m2ya3<-----pjcp7rv>=pjcp7rv+--pjcp7rv!=---pjcp7rv!=-arg<---(-m2ya3)>m2ya3<=-----true>14!=--m2ya3) { + m2ya3=m2ya3+-(--0<=false<pjcp7rv/arg<=-true); + while((--m2ya3)<--arg<-----arg*false!=arg<pjcp7rv*arg) { + pjcp7rv=-3+-arg; + break; + } + while(-3) { + while(67+0-61) m2ya3=m2ya3; + if(----pjcp7rv==---(---arg)) pjcp7rv=0!=-23; + else pjcp7rv=----89; + while(m2ya3!=m2ya3<pjcp7rv) m2ya3=1; + while(--arg<=pjcp7rv) pjcp7rv=-32<=-m2ya3+62; + } + break; + } + } + { + int arg=-1<-9!=(-arg>=-pjcp7rv>=arg<=arg); + while(arg<-arg) { + arg=arg+--arg; + { + while((--93)--pjcp7rv*-pjcp7rv+arg) arg=0-(6>=(--(---41/(0))!=--pjcp7rv)>=---2*33); + pjcp7rv=11; + int c=pjcp7rv; + if(--107) break; + else break; + } + } + } + pjcp7rv=pjcp7rv; + int aR0Wkua=-pjcp7rv==pjcp7rv; + { + if(-0!=-0) while(-true) break; + else { + while(aR0Wkua) pjcp7rv=-0/pjcp7rv; + pjcp7rv=pjcp7rv; + } + } + } + if(-arg) { + { + int Isdlt0fr91=0!=arg; + while(Isdlt0fr91<-Isdlt0fr91==-Isdlt0fr91+true) { + Isdlt0fr91=Isdlt0fr91+-1!=true; + if(-arg) if(--arg<=Isdlt0fr91) Isdlt0fr91=-Isdlt0fr91; + int i=---arg<---arg!=--40; + { + int jVX43Ln4Dm=-(6)==-Isdlt0fr91/----0; + while(jVX43Ln4Dm<--(3-3)) { + jVX43Ln4Dm=jVX43Ln4Dm+-0<25; + i=24<--(jVX43Ln4Dm); + } + } + i=(arg!=----false>=7); + int Te=5>-arg; + break; + } + } + arg=arg!=--true/arg; + { + int UX=arg; + while(UX<-3*arg) { + UX=UX+arg/-1; + arg=-3--(-UX- -47<arg==--arg==arg)/arg- -UX>=-arg; + if(---12) while(-UX) break; + break; + } + } + continue; + } + if(arg) arg=--0; + else if(1) continue; + int DtTlhjYq=19==arg; + { + arg=--DtTlhjYq<=(DtTlhjYq/---DtTlhjYq<=-DtTlhjYq); + if(---arg) continue; + else { + int Zsl=40; + while(Zsl<--Zsl--false>((Zsl))==Zsl!=--DtTlhjYq-DtTlhjYq-DtTlhjYq) { + Zsl=Zsl+arg; + } + } + if((arg)) if(-DtTlhjYq) { + } + else while(((2)==3*arg/DtTlhjYq)<=0==---arg) return false; + else { + int lwbF=arg>=0; + while(lwbF<57) { + lwbF=lwbF+--(-arg+lwbF)>=-2>=arg!=arg; + arg=----0+0; + while(49) break; + if(true) DtTlhjYq=-----arg; + DtTlhjYq=0!=-----(0); + } + } + arg=---arg!=DtTlhjYq/--0; + DtTlhjYq=-DtTlhjYq/(--arg<arg); + if(32) { + int q=-DtTlhjYq; + while(q<arg*(0*q)/0) { + q=q+DtTlhjYq; + DtTlhjYq=arg; + } + } + else if(--arg) if(15) break; + else arg=0==arg<=-55>DtTlhjYq; + else { + } + DtTlhjYq=-0; + { + while((0)<-arg) DtTlhjYq=-DtTlhjYq; + } + if(30/--(arg)>=0) DtTlhjYq=-0>=arg; + else { + int Y2wcIQJ=--DtTlhjYq*---11; + if(arg==arg) { + Y2wcIQJ=-----Y2wcIQJ; + Y2wcIQJ=Y2wcIQJ<7; + if(DtTlhjYq) arg=arg; + else break; + while(-arg!=-31==(false<=-15>=-DtTlhjYq+--6*-----Y2wcIQJ<=---arg!=-Y2wcIQJ<=---0<-arg*--Y2wcIQJ)) DtTlhjYq=arg!=3; + } + continue; + } + arg=DtTlhjYq; + arg=--3/(---arg)>=80>=-DtTlhjYq<=DtTlhjYq; + arg=51+---(-true)!=arg!=----1==-DtTlhjYq; + if(11<=arg) if((arg)+79<32+(-arg)) continue; + else if(true==DtTlhjYq) break; + break; + } +} +if(arg!=62==arg) { + while(---arg) { + { + int bhmDacPM=arg/arg; + while(bhmDacPM<arg) { + bhmDacPM=bhmDacPM+80*((-bhmDacPM)/---bhmDacPM>1)<bhmDacPM-2!=7; + arg=-0; + arg=bhmDacPM>=-arg+-arg; + break; + } + } + int arg=true; + arg=arg<=arg; + { + int KlC=30; + while(KlC<-2) { + KlC=KlC+-1!=25<=-KlC>KlC>----0; + int Ij=arg>=-arg<=---10; + { + int LAbgurVa2R=-arg!=Ij; + while(LAbgurVa2R<-true) { + LAbgurVa2R=LAbgurVa2R+Ij; + KlC=-LAbgurVa2R; + Ij=42*(-Ij>true); + while(Ij) arg=KlC; + KlC=-----7>-(--KlC<--7)==-LAbgurVa2R; + } + } + int a=Ij<=-KlC; + if(Ij) { + int r1W=a!=-false; + } + else { + arg=56>=Ij; + while(54) break; + arg=8>=-(a<--Ij)/a>=-a-KlC; + } + int Yt_T=KlC; + arg=KlC; + } + } + if(----false/--arg/12+-----0) if(-9+-arg) while(arg!=(arg)) arg=--1>=-71-arg!=---(--arg*11+102)/--arg; + else if(----arg) continue; + if(-arg-arg) { + arg=-(-arg)*--(-3)<(-7==-arg----arg); + { + int arg=arg; + while(arg<-0>arg==-arg-(-arg>1+11)) { + arg=arg+6-arg!=--0>---30>=---arg<=arg/(3)+---arg; + } + } + arg=-arg+arg; + arg=--47+-arg<1>arg*(-arg==-arg- -0>3); + arg=(----arg)!=arg+--59; + arg=- -4+arg==-(arg)-arg; + } + else { + while(--true-----true*-25+-18>arg>=-----(-arg)---13) { + arg=-0+--true<false; + continue; + } + arg=true<=arg; + break; + } + arg=arg*22<--(0+-arg); + { + continue; + } + } + arg=1*---((3<=true)==---2); + arg=7+-(-1); + return arg+--true; +} +else { + int o3ypEsewxM=-(---arg); + int vzXB=(-(---11<=--o3ypEsewxM>=--0))<=-0/-arg; + int L=-arg; + int B4mHcrf=---vzXB; + int oZWGdzZl=-o3ypEsewxM; + int K6tQqa1=11; + while(0!=--L) { + int sdZfTM=vzXB*true+K6tQqa1; + while(sdZfTM<false) { + sdZfTM=sdZfTM+arg; + sdZfTM=oZWGdzZl; + K6tQqa1=-K6tQqa1; + arg=---K6tQqa1; + while((3+-K6tQqa1)<oZWGdzZl) { + if(-----(-1)) sdZfTM=-false; + {} + } + K6tQqa1=vzXB!=-(B4mHcrf+-7>false); + sdZfTM=vzXB; + } + } + L=false; + while(31) B4mHcrf=arg; + oZWGdzZl=-0<--oZWGdzZl<=--2; + if(K6tQqa1>=20<=46) { + if(-1+-L) if(oZWGdzZl) { + int wmhv=-----0; + } + int arg=0; + o3ypEsewxM=---(oZWGdzZl); + return -oZWGdzZl/0; + } + else if(arg) { + int yKk5=B4mHcrf>=4>K6tQqa1<-B4mHcrf/o3ypEsewxM; + return -K6tQqa1; + } + else { + if(---0) { + {} + {} + } + return o3ypEsewxM; + } +} +"""); + code.parse().opto().typeCheck().GCM(); + assertEquals("return 9;", code.print()); + } + + + @Test + public void testPrimes() { + CodeGen code = new CodeGen( +""" +if( arg < 2 ) return 0; +int primeCount = 1; +int prime = 3; +while( prime <= arg ) { + int isPrime = 1; + // Check for even case, so the next loop need only check odds + if( (prime/2)*2 == prime ) + continue; + // Check odds up to sqrt of prime + int j = 3; + while( j*j <= prime ) { + if( (prime/j)*j == prime ) { + isPrime = 0; + break; + } + j = j + 2; + } + if( isPrime ) + primeCount = primeCount + 1; + prime = prime + 2; +} +return primeCount; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,0,Phi(Loop,1,Phi(Region,Phi_primeCount,Phi_primeCount,(Phi_primeCount+1))));", code.print()); + assertEquals("0", Eval2.eval(code, 1)); // No primes 1 or below + assertEquals("1", Eval2.eval(code, 2)); // 2 + assertEquals("2", Eval2.eval(code, 3)); // 2, 3 + assertEquals("2", Eval2.eval(code, 4)); // 2, 3 + assertEquals("3", Eval2.eval(code, 5)); // 2, 3, 5 + assertEquals("4", Eval2.eval(code, 10)); // 2, 3, 5, 7 + } + + @Test + public void testAntiDeps1() { + CodeGen code = new CodeGen( +""" +struct S { int f; }; +S !v=new S; +v.f = 2; +int i=new S.f; +i=v.f; +if (arg) v.f=1; +return i; +"""); + code.parse().opto(); + assertEquals("return 2;", code.print()); + assertEquals("2", Eval2.eval(code, 0)); + assertEquals("2", Eval2.eval(code, 1)); + } + + @Test + public void testAntiDeps2() { + CodeGen code = new CodeGen( +""" +struct S { int f; }; +S !v = new S; +v.f = arg; +S !t = new S; +int i = 0; +if (arg) { + if (arg+1) v = t; + i = v.f; +} else { + v.f = 2; +} +return i; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,.f,0);", code.print()); + } + + @Test + public void testAntiDeps3() { + CodeGen code = new CodeGen( +""" +struct S { int f; }; +S !v0 = new S; +S? v1; +if (arg) v1 = new S; +if (v1) { + v0.f = v1.f; +} else { + v0.f = 2; +} +return v0; +"""); + code.parse().opto(); + assertEquals("return S;", code.print()); + } + + + @Test + public void testAntiDeps4() { + CodeGen code = new CodeGen( +""" +struct S { int f; }; +S !v = new S; +v.f = arg; +S t = new S; +int i = v.f; +if (arg+1) arg= 0; +while (arg) v.f = 2; +return i; +"""); + code.parse().opto(); + assertEquals("return arg;", code.print()); + } + + @Test + public void testAntiDeps5() { + CodeGen code = new CodeGen( +""" +struct S { int f; }; +S !v = new S; +while(1) { + while(arg+1) { arg=arg-1; } + if (arg) break; + v.f = 2; +} +return v; +"""); + code.parse().opto(); + assertEquals("return S;", code.print()); + } + + @Test + public void testAntiDeps6() { + CodeGen code = new CodeGen( +""" +struct s { int v; }; +s !ptr=new s; +while( -arg ) + ptr = new s; +while(1) + arg = arg+ptr.v; +"""); + code.parse().opto(); + assertEquals("return Top;", code.print()); + } + + @Test + public void testAntiDeps7() { + CodeGen code = new CodeGen( +""" +struct S { int f; }; +S !v = new S; +S t = new S; +int i = v.f; +while (arg) { + v.f = arg; + arg = arg-1; +} +return i; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testAntiDeps8() { + CodeGen code = new CodeGen( +""" +struct S { int f; }; +S !v = new S; +S t = new S; +while(arg) { + arg=arg-1; + int f = v.f; + v.f = 2; + if (arg) arg = f; + else v.f = 3; +} +return arg; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testAntiDeps9() { + CodeGen code = new CodeGen( +""" +struct S { int f; }; +S !v = new S; +S t = new S; +if (arg) { + v.f=2; + int i=t.f; + v.f=i; +} +return v; +"""); + code.parse().opto(); + assertEquals("return S;", code.print()); + } + + @Test + public void testExample2() { + CodeGen code = new CodeGen( +""" +struct S { int f; }; +S !v = new S; +int i = arg; +while (arg > 0) { + int j = i/3; + if (arg == 5) + v.f = j; + arg = arg - 1; +} +return v; + """); + code.parse().opto(); + //assertEquals("return new S;", code.print()); + } + + @Test + public void testScheduleUse() { + CodeGen code = new CodeGen( +""" +int v0=0; +while(0>=0) { + u1 v1=0; + v1=v0; + if(v1*0) + v0=-v1; +} +return 0; +"""); + code.parse().opto(); + assertEquals("return Top;", code.print()); + } + + @Test + public void testLoopCarriedDep() { + CodeGen code = new CodeGen( +""" +u32 v0=0; +{ + int v1=0; + while(v1) { + v1=1>>>v0!=0; + v0=v1/0; + } + return v1; +} +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java new file mode 100644 index 00000000..8069ddaa --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -0,0 +1,61 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.StopNode; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class Chapter12Test { + @Test + public void testJig() { + CodeGen code = new CodeGen( +""" +return 3.14; +"""); + code.parse().opto(); + assertEquals("return 3.14;", code.print()); + assertEquals("3.14", Eval2.eval(code, 0)); + } + + @Test + public void testFloat() { + CodeGen code = new CodeGen( +""" +return 3.14; +"""); + code.parse().opto(); + assertEquals("return 3.14;", code.print()); + assertEquals("3.14", Eval2.eval(code, 0)); + } + + @Test + public void testSquareRoot() { + CodeGen code = new CodeGen( +""" +flt guess = arg; +while( 1 ) { + flt next = (arg/guess + guess)/2; + if( next == guess ) break; + guess = next; +} +return guess; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)*0.5f));", code.print()); + assertEquals("3.0", Eval2.eval(code, 9)); + assertEquals("1.414213562373095", Eval2.eval(code, 2)); + } + + @Test + public void testFPOps() { + CodeGen code = new CodeGen( +""" +flt x = arg; +return x+1==x; +"""); + code.parse().opto(); + assertEquals("return ((flt)arg==(ToFloat+1.0f));", code.print()); + assertEquals("0", Eval2.eval(code, 1)); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter13Test.java new file mode 100644 index 00000000..4e1db3b4 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter13Test.java @@ -0,0 +1,281 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class Chapter13Test { + @Test + public void testJig() { + CodeGen code = new CodeGen( +""" +return 3.14; +"""); + code.parse().opto(); + assertEquals("return 3.14;", code.print()); + assertEquals("3.14", Eval2.eval(code, 0)); + } + + @Test + public void testLinkedList0() { + CodeGen code = new CodeGen( +""" +struct LLI { LLI? next; int i; }; +LLI? !head = null; +while( arg ) { + LLI !x = new LLI; + x.next = head; + x.i = arg; + head = x; + arg = arg-1; +} +return head.next.i; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Might be null accessing 'next'",e.getMessage()); } + } + + @Test + public void testLinkedList1() { + CodeGen code = new CodeGen( +""" +struct LLI { LLI? next; int q; }; +LLI? !head = null; +while( arg ) { + LLI !x = new LLI; + x.next = head; + x.q = arg; + head = x; + arg = arg-1; +} +if( !head ) return 0; +LLI? next = head.next; +if( next==null ) return 1; +return next.q; +"""); + code.parse().opto().typeCheck(); + assertEquals("return Phi(Region,0,1,.q);", code.print()); + assertEquals("2", Eval2.eval(code, 3)); + } + + @Test + public void testCoRecur() { + CodeGen code = new CodeGen( +""" +struct int0 { int i; flt0? f; }; +struct flt0 { flt f; int0? i; }; +int0 !i0 = new int0; +i0.i = 17; +flt0 !f0 = new flt0; +f0.f = 3.14; +i0.f = f0; +f0.i = i0; +return f0.i.f.i.i; +"""); + code.parse().opto(); + assertEquals("return 17;", code.print()); + } + + @Test + public void testNullRef0() { + CodeGen code = new CodeGen( +""" +struct N { N? next; int i; }; +N n = new N; +return n.next; +"""); + code.parse().opto(); + assertEquals("return null;", code.print()); + } + + @Test + public void testNullRef1() { + CodeGen code = new CodeGen( +""" +struct M { int m; }; +struct N { M next; int i; }; +N n = new N { next = new M; }; +return n.next; +"""); + code.parse().opto(); + assertEquals("return (const)M;", code.print()); + } + + @Test + public void testNullRef2() { + CodeGen code = new CodeGen( +""" +struct M { int m; }; +struct N { M next; int i; }; +N n = new N { next = null; }; +return n.next; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Type null is not of declared type *M",e.getMessage()); } + } + + @Test + public void testNullRef3() { + CodeGen code = new CodeGen( +""" +struct N { N? next; int i; }; +N !n = new N; +n.i = 3.14; +return n.i; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Type 3.14 is not of declared type i64",e.getMessage()); } + } + + @Test + public void testNullRef4() { + CodeGen code = new CodeGen("return -null-5/null-5;"); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot '//' null",e.getMessage()); } + } + + @Test public void testNullRef5() { + CodeGen code = new CodeGen("return null+42;"); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot '+' null",e.getMessage()); } + } + + @Test + public void testEmpty() { + CodeGen code = new CodeGen( +""" +struct S{}; +return 0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + } + + @Test + public void testForwardRef0() { + CodeGen code = new CodeGen( +""" +struct S1 { S2? s; }; +return new S2; +"""); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("Unknown struct type 'S2'",e.getMessage()); } + } + + @Test + public void testForwardRef1() { + CodeGen code = new CodeGen( +""" +struct S1 { S2? s; }; +struct S2 { int x; }; +return new S1.s=new S2; +"""); + code.parse().opto(); + assertEquals("return S2;", code.print()); + } + + @Test + public void testcheckNull() { + CodeGen code = new CodeGen( +""" +struct I { int i; }; +struct P { I? pi; }; +P !p1 = new P; +P !p2 = new P; +p2.pi = new I; +p2.pi.i = 2; +if (arg) p1 = new P; +return p1.pi.i + 1; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Might be null accessing 'i'",e.getMessage()); } + } + + @Test + public void testCoRecur2() { + CodeGen code = new CodeGen( +""" +struct A { B? f0; C? f1; }; A !a = new A; +struct B { C? f0; A? f1; }; B !b = new B; +struct C { A? f0; B? f1; }; C !c = new C; + +a.f0=b; a.f1=c; +b.f0=c; b.f1=a; +c.f0=a; c.f1=b; + +return a.f0.f1.f0.f1.f0; + +"""); + code.parse().opto().typeCheck().GCM().localSched(); + assertEquals("return B;", code._stop.toString()); + assertEquals("B{f0=C},f1=A{f0=$cyclic,f1=$cyclic}}", Eval2.eval(code, 0)); + } + + @Test + public void testCoRecur3() { + CodeGen code = new CodeGen( +""" +struct A { L? a; T? b; F? c; }; A !a = new A; +struct B { M? a; U? b; G? c; }; B !b = new B; +struct C { N? a; V? b; H? c; }; C !c = new C; +struct D { O? a; W? b; I? c; }; D !d = new D; +struct E { P? a; X? b; J? c; }; E !e = new E; +struct F { Q? a; Y? b; K? c; }; F !f = new F; +struct G { R? a; Z? b; L? c; }; G !g = new G; +struct H { S? a; A? b; M? c; }; H !h = new H; +struct I { T? a; B? b; N? c; }; I !i = new I; +struct J { U? a; C? b; O? c; }; J !j = new J; +struct K { V? a; D? b; P? c; }; K !k = new K; +struct L { W? a; E? b; Q? c; }; L !l = new L; +struct M { X? a; F? b; R? c; }; M !m = new M; +struct N { Y? a; G? b; S? c; }; N !n = new N; +struct O { Z? a; H? b; T? c; }; O !o = new O; +struct P { A? a; I? b; U? c; }; P !p = new P; +struct Q { B? a; J? b; V? c; }; Q !q = new Q; +struct R { C? a; K? b; W? c; }; R !r = new R; +struct S { D? a; L? b; X? c; }; S !s = new S; +struct T { E? a; M? b; Y? c; }; T !t = new T; +struct U { F? a; N? b; Z? c; }; U !u = new U; +struct V { G? a; O? b; A? c; }; V !v = new V; +struct W { H? a; P? b; B? c; }; W !w = new W; +struct X { I? a; Q? b; C? c; }; X !x = new X; +struct Y { J? a; R? b; D? c; }; Y !y = new Y; +struct Z { K? a; S? b; E? c; }; Z !z = new Z; + +a.a=l; a.b=t; a.c=f; +b.a=m; b.b=u; b.c=g; +c.a=n; c.b=v; c.c=h; +d.a=o; d.b=w; d.c=i; +e.a=p; e.b=x; e.c=j; +f.a=q; f.b=y; f.c=k; +g.a=r; g.b=z; g.c=l; +h.a=s; h.b=a; h.c=m; +i.a=t; i.b=b; i.c=n; +j.a=u; j.b=c; j.c=o; +k.a=v; k.b=d; k.c=p; +l.a=w; l.b=e; l.c=q; +m.a=x; m.b=f; m.c=r; +n.a=y; n.b=g; n.c=s; +o.a=z; o.b=h; o.c=t; +p.a=a; p.b=i; p.c=u; +q.a=b; q.b=j; q.c=v; +r.a=c; r.b=k; r.c=w; +s.a=d; s.b=l; s.c=x; +t.a=e; t.b=m; t.c=y; +u.a=f; u.b=n; u.c=z; +v.a=g; v.b=o; v.c=a; +w.a=h; w.b=p; w.c=b; +x.a=i; x.b=q; x.c=c; +y.a=j; y.b=r; y.c=d; +z.a=k; z.b=s; z.c=e; + +return a.b.c.a.b.c.a.b.c.a.b.c.a.b.c.a.b.c; + +"""); + code.parse().opto().typeCheck().GCM().localSched(); + assertEquals("return R;", code._stop.toString()); + assertEquals("R{a=C{a=N},b=V},c=H}},b=K{a=$cyclic,b=D{a=O},b=W},c=I}},c=P}},c=$cyclic}", Eval2.eval(code, 0)); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter14Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter14Test.java new file mode 100644 index 00000000..7af35b56 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter14Test.java @@ -0,0 +1,226 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.StopNode; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class Chapter14Test { + + @Test + public void testJig() { + CodeGen code = new CodeGen( +""" +return 3.14; +"""); + code.parse().opto(); + assertEquals("return 3.14;", code.print()); + assertEquals("3.14", Eval2.eval(code, 0)); + } + + @Test + public void testRange() { + CodeGen code = new CodeGen( +""" +int b; +if( arg ) b=1; else b=0; +int c = 99; +if( b < 0 ) c = -1; +if( b > 2 ) c = 1; +return c; +"""); + code.parse().opto(); + assertEquals("return 99;", code.print()); + assertEquals("99", Eval2.eval(code, 0)); + } + + @Test + public void testU8() { + CodeGen code = new CodeGen( +""" +u8 b = 123; +b = b + 456;// Truncate +return b; +"""); + code.parse().opto(); + assertEquals("return 67;", code.print()); + assertEquals("67", Eval2.eval(code, 0)); + } + + + @Test + public void testU8While() { + CodeGen code = new CodeGen( +""" +u8 b = 123; +while( b ) b = b + 456;// Truncate +return b; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testU1() { + CodeGen code = new CodeGen( +""" +bool b = 123; +b = b + 456;// Truncate +u1 c = b; // No more truncate needed +return c; +"""); + code.parse().opto(); + assertEquals("return 1;", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test + public void testAnd() { + CodeGen code = new CodeGen( +""" +int b = 123; +b = b+456 & 31; // Precedence +return b; +"""); + code.parse().opto(); + assertEquals("return 3;", code.print()); + assertEquals("3", Eval2.eval(code, 0)); + } + + @Test + public void testRefLoad() { + CodeGen code = new CodeGen( +""" +struct Foo { u1 b; }; +Foo !f = new Foo; +f.b = 123; +return f.b; +"""); + code.parse().opto(); + assertEquals("return 1;", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test + public void testSigned() { + CodeGen code = new CodeGen( +""" +i8 b = 255; // Chopped +return b; // Sign extend +"""); + code.parse().opto(); + assertEquals("return -1;", code.print()); + assertEquals("-1", Eval2.eval(code, 0)); + } + + @Test + public void testI8() { + CodeGen code = new CodeGen( +""" +i8 b = arg; +b = b + 1;// Truncate +return b; +"""); + code.parse().opto(); + assertEquals("return (((((arg<<56)>>56)+1)<<56)>>56);", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + assertEquals("-128", Eval2.eval(code, 127)); + } + + @Test + public void testMask() { + CodeGen code = new CodeGen( +""" +u16 mask = (1<<16)-1; // AND mask +int c = 123456789 & mask; +return c; // +"""); + code.parse().opto(); + assertEquals("return 52501;", code.print()); + assertEquals("52501", Eval2.eval(code, 0)); + } + + @Test + public void testOr() { + CodeGen code = new CodeGen( +""" +return (arg | 123 ^ 456) >>> 1; +"""); + code.parse().opto(); + assertEquals("return (((arg|123)^456)>>>1);", code.print()); + assertEquals("217", Eval2.eval(code, 0)); + } + + @Test + public void testMaskFloat() { + CodeGen code = new CodeGen( +""" +flt f = arg; +arg = f & 1; +return arg; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot '&' flt",e.getMessage()); } + } + + @Test + public void testCloneAnd() { + CodeGen code = new CodeGen(""" +int v0=0; +u32 v1 = 1&(1<<arg)&(1<<arg); +while(arg) v1=-v0; +while(v1) break; +return v1; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,(((1<<arg)&1)&Shl),0);", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test + public void testAndHigh() { + CodeGen code = new CodeGen(""" +int v0=0; +if(0&0>>>0) { + while(0) { + u8 v1=0; + v0=0>>>0; + v1=arg; + while(v1+0) {} + } +} +return v0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + } + + @Test + public void testTypes() { + CodeGen code = new CodeGen( +""" +i8 xi8 = 123456789; if( xi8 != 21 ) return -8; +i16 xi16 = 123456789; if( xi16 != -13035 ) return -16; +i32 xi32 = 123456789; if( xi32 != 123456789 ) return -32; +i64 xi64 = 123456789; if( xi64 != 123456789 ) return -64; +int xint = 123456789; if( xint != 123456789 ) return -64; + +u1 ui1 = 123456789; if( ui1 != 1 ) return 1; +u8 ui8 = 123456789; if( ui8 != 21 ) return 8; +u16 ui16 = 123456789; if( ui16 != 52501 ) return 16; +u32 ui32 = 123456789; if( ui32 != 123456789 ) return 32; + +flt fflt = 3.141592653589793; if( fflt != 3.141592653589793 ) return 3; +f64 ff64 = 3.141592653589793; if( ff64 != 3.141592653589793 ) return 3; +f32 ff32 = 3.141592653589793; if( ff32 != 3.1415927410125732) return 5; + +return 0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter15Test.java new file mode 100644 index 00000000..6ba4e2b1 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter15Test.java @@ -0,0 +1,358 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.Test; +import org.junit.Ignore; +import static org.junit.Assert.*; + +public class Chapter15Test { + + @Test + public void testJig() { + CodeGen code = new CodeGen( +""" +return 3.14; +"""); + code.parse().opto(); + assertEquals("return 3.14;", code.print()); + assertEquals("3.14", Eval2.eval(code, 0)); + } + + @Test + public void testCyclic() { + CodeGen code = new CodeGen( +""" +struct C { C? l; }; +C !c = new C; +c.l = c; +return c; +"""); + code.parse().opto(); + assertEquals("return C;", code.print()); + assertEquals("C{l=$cyclic}", Eval2.eval(code, 0)); + } + + @Test + public void testSafetyCheck() { + CodeGen code = new CodeGen( +""" +u8[] old = new u8[0]; +u8[] !output = new u8[1]; +int i = 0; +while (i < old#) { + output[i] = old[i]; + i = i + 1; +} +output[i] = 1; +return output; +"""); + code.parse().opto(); + assertEquals("return []u8;", code.print()); + assertEquals("\u0001", Eval2.eval(code, 0)); + } + + @Test + public void testBasic1() { + CodeGen code = new CodeGen( +""" +int[] is = new int[2]; +return is[1]; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + } + + @Test + public void testBasic2() { + CodeGen code = new CodeGen( +""" +int[] is = new int[2]; +int[] is2 = new int[2]; +return is[1]; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + } + + @Test + public void testBasic3() { + CodeGen code = new CodeGen( +""" +int[] !a = new int[2]; +a[0] = 1; +a[1] = 2; +return a[0]; +"""); + code.parse().opto(); + assertEquals("return 1;", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test + public void testBasic4() { + CodeGen code = new CodeGen( +""" +struct A { int i; }; +A?[] !a = new A?[2]; +return a; +"""); + code.parse().opto(); + assertEquals("return []*A?;", code.print()); + assertEquals("*A {i64 !i; }?[ null,null]", Eval2.eval(code, 0)); + } + + @Test + public void testBasic5() { + CodeGen code = new CodeGen( +""" +struct S { int x; flt y; }; +// A new S +S !s = new S; s.x=99; s.y = 3.14; + +// Double-d array of Ss. Fill in one row. +S?[]?[] !iss = new S?[]?[2]; +iss[0] = new S?[7]; +iss[0][2] = s; + +// Now pull out the filled-in value, with null checks +flt rez; +S?[]? is = iss[arg]; +if( !is ) rez = 1.2; +else { + S? i = is[2]; + if( !i ) rez = 2.3; + else rez = i.y; +} +return rez; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,1.2,.y,2.3);", code.print()); + assertEquals("3.14", Eval2.eval(code, 0)); + assertEquals("1.2", Eval2.eval(code, 1)); + } + + @Test + public void testBasic6() { + CodeGen code = new CodeGen( +""" +struct S { int x; flt y; }; +// A new S +S !s = new S; s.x=99; s.y = 3.14; + +// Double-d array of Ss. Fill in one row. +S?[]?[] !iss = new S?[]?[2]; +iss[0] = new S?[7]; +iss[0][2] = s; + +// Now pull out the filled-in value, with null checks +flt rez = 1.2; +if( iss[arg] ) + if( iss[arg][2] ) + rez = iss[arg][2].y; +return rez;"""); + code.parse().opto().typeCheck(); + assertEquals("return Phi(Region,1.2,1.2,.y);", code.print()); + assertEquals("3.14", Eval2.eval(code, 0)); + try { Eval2.eval(code, 10); fail(); } // Fails AIOOBE in Eval2, no range checks + catch( Exception e ) { assertEquals("Index 10 out of bounds for length 2",e.getMessage()); } + } + + @Test + public void testTree() { + CodeGen code = new CodeGen( +""" +// Can we define a forward-reference array? +struct Tree { Tree?[]? _kids; }; +Tree !root = new Tree; +root._kids = new Tree?[2]; // NO BANG SO ARRAY IS OF IMMUTABLE TREES???? +root._kids[0] = new Tree; +return root; +"""); + code.parse().opto(); + assertEquals("return Tree;", code.print()); + assertEquals("Tree{_kids=*Tree {*[]*Tree?? !_kids; }?[ Tree{_kids=null},null]}", Eval2.eval(code, 0)); + } + + @Test + public void testNestedStructAddMemProj() { + CodeGen code = new CodeGen( +""" +struct S { int a; int[] b; }; +return 0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + @Test + public void testRollingSum() { + CodeGen code = new CodeGen( +""" +int[] !ary = new int[arg]; +// Fill [0,1,2,3,4,...] +int i=0; +while( i < ary# ) { + ary[i] = i; + i = i+1; +} +// Fill [0,1,3,6,10,...] +i=0; +while( i < ary# - 1 ) { + ary[i+1] = ary[i+1] + ary[i]; + i = i+1; +} +return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6 +"""); + code.parse().opto(); + assertEquals("return (.[]+(.[]*1000));", code.print()); + assertEquals("1006", Eval2.eval(code, 4)); + } + + @Test @Ignore + public void sieveOEratosthenes() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/sieve.smp")); + CodeGen code = new CodeGen(src+"return sieve(arg);"); + code.parse().opto(); + assertEquals("return []u32;", code.print()); + assertEquals("u32[ 2,3,5,7,11,13,17,19]",Eval2.eval(code, 20)); + } + + @Test + public void testNewNodeInit() { + CodeGen code = new CodeGen( +""" +struct S {int i; flt f;}; +S !s1 = new S; +S !s2 = new S; +s2.i = 3; +s2.f = 2.0; +if (arg) s1 = new S; +return s1.i + s1.f; +"""); + code.parse().opto(); + assertEquals("return ((flt).i+.f);", code.print()); + assertEquals("0.0", Eval2.eval(code, 0)); + } + + + @Test + public void testBad0() { + CodeGen code = new CodeGen( +""" +return new flt; +"""); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("Cannot allocate a flt",e.getMessage()); } + } + + @Test + public void testBad1() { + CodeGen code = new CodeGen( +""" +flt is = new int[2]; +return is; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Type *[]i64 is not of declared type flt",e.getMessage()); } + } + + @Test + public void testBad2() { + CodeGen code = new CodeGen( +""" +int[] is = new int[3.14]; +return is[1]; +"""); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("Cannot allocate an array with length 3.14",e.getMessage()); } + } + + @Test + public void testBad3() { + CodeGen code = new CodeGen(""" +int[] is = new int[arg]; +return is[1]; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + assertEquals("0", Eval2.eval(code, 4)); + try { Eval2.eval(code,-1); fail(); } + catch( NegativeArraySizeException e ) { assertEquals("-1",e.getMessage()); } + // This test will not pass (i.e., failed range-check) until we have range checks. + // Without the range check, the load `is[1]` optimizes against the `new int[]` + // and assumes it loads a zero then folds away, and the Eval2 never sees an OOB load. + //try { Eval2.eval(code,0); fail(); } + //catch( ArrayIndexOutOfBoundsException e ) { assertEquals("Array index 1 out of bounds for array length 0",e.getMessage()); } + } + + @Test + public void testProgress() { + CodeGen code = new CodeGen(""" +i8 v1=0&0; +u8 v2=0; +byte v4=0; +if(0) {} +while(v2<0) { + v4=0-v1; + break; +} +int v5=0&0; +while(v5+(0&0)) { + int v7=0&0; + while(v7) + v4=0>>>v5; + while(v1) + return 0; +} +return v1; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + } + + @Test + public void testSharpNot() { + CodeGen code = new CodeGen( +""" +if(0>>0) {} +while(0) {} +u32 v7=0; +int v8=0; +while(0<--1>>>---(v7*0==v8)) {} +return 0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } + + + @Test + public void testProgress2() { + CodeGen code = new CodeGen( +""" +if(1) {} +else { + while(arg>>>0&0>>>0) {} + byte v3=0>>>0; + while(0) {} + int v7=0>>>0; + while(v7<0>>>0) { + while(0+v7<=0) if(1) arg=-12; + if(arg) { + v3=arg+v3+0; + arg=0; + } + } +} +return 0; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter16Test.java new file mode 100644 index 00000000..2623fee5 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter16Test.java @@ -0,0 +1,259 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class Chapter16Test { + + @Test + public void testJig() { + CodeGen code = new CodeGen( +""" +return 3.14; +"""); + code.parse().opto(); + assertEquals("return 3.14;", code.print()); + assertEquals("3.14", Eval2.eval(code, 0)); + } + + + @Test + public void testMulti0() { + CodeGen code = new CodeGen( +""" +int x, y; +return x+y; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + } + @Test + public void testMulti1() { + CodeGen code = new CodeGen( +""" +int x=2, y=x+1; +return x+y; +"""); + code.parse().opto(); + assertEquals("return 5;", code.print()); + assertEquals("5", Eval2.eval(code, 0)); + } + +// @Test +// public void testFinal0() { +// CodeGen code = new CodeGen( +//""" +//int !x=2; +//x=3; +//return x; +//"""); +// try { code.parse().opto(); fail(); } +// catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); } +// } + + @Test + public void testFinal1() { + CodeGen code = new CodeGen( +""" +int x=2, y=3; +if( arg ) { int x = y; x = x*x; y=x; } // Shadow final x +return y; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,9,3);", code.print()); + assertEquals("3", Eval2.eval(code, 0)); + assertEquals("9", Eval2.eval(code, 1)); + } + + @Test + public void testConstruct0() { + CodeGen code = new CodeGen(""" +struct X { int x=3; }; +X z = new X; +return z.x; +"""); + code.parse().opto(); + assertEquals("return 3;", code.print()); + assertEquals("3", Eval2.eval(code, 0)); + } + + @Test + public void testConstruct1() { + CodeGen code = new CodeGen(""" +struct X { int !x; }; +X z = new X { x=3; }; +return z.x; +"""); + code.parse().opto(); + assertEquals("return 3;", code.print()); + assertEquals("3", Eval2.eval(code, 0)); + } + + @Test + public void testConstruct2() { + CodeGen code = new CodeGen(""" +struct X { int x=3; }; +X z = new X { x = 4; }; +return z.x; +"""); + code.parse().opto(); + assertEquals("return 4;", code.print()); + assertEquals("4", Eval2.eval(code, 0)); + } + + + @Test + public void testStructFinal0() { + CodeGen code = new CodeGen(""" +struct Point { int !x, !y; }; +Point p = new Point { x=3; y=4; }; +return p; +"""); + code.parse().opto(); + assertEquals("return Point;", code.print()); + assertEquals("Point{x=3,y=4}", Eval2.eval(code, 0)); + } + + @Test + public void testStructFinal1() { + CodeGen code = new CodeGen(""" +struct Point { int x=3, y=4; }; +val p = new Point { x=5; y=6; }; +p.x++; +return p; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test + public void testStructFinal2() { + CodeGen code = new CodeGen(""" +struct Point { int x=3, y=4; }; +val p = new Point; +p.x++; +return p; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test + public void testStructFinal3() { + CodeGen code = new CodeGen(""" +struct Point { var x; var y; }; +Point p = new Point; +p.x++; +return p; +"""); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("'Point' is not fully initialized, field 'x' needs to be set in a constructor",e.getMessage()); } + } + + @Test + public void testStructFinal4() { + CodeGen code = new CodeGen(""" +struct Point { val x=3; val y=4; }; +Point p = new Point; +p.x++; +return p; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test + public void testStructFinal5() { + CodeGen code = new CodeGen(""" +struct Point { var x=3; var y=4; }; +Point !p = new Point; +p.x++; +return p; +"""); + code.parse().opto(); + assertEquals("return Point;", code.print()); + assertEquals("Point{x=4,y=4}", Eval2.eval(code, 0)); + } + + // Same as the Chapter13 test with the same name, but using the new + // constructor syntax + @Test + public void testLinkedList1() { + CodeGen code = new CodeGen( +""" +struct LLI { LLI? next; int i; }; +LLI? !head = null; +while( arg ) { + head = new LLI { next=head; i=arg; }; + arg = arg-1; +} +if( !head ) return 0; +LLI? next = head.next; +if( !next ) return 1; +return next.i; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,0,1,.i);", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + assertEquals("1", Eval2.eval(code, 1)); + assertEquals("2", Eval2.eval(code, 3)); + } + + @Test + public void testLinkedList2() { + CodeGen code = new CodeGen( +""" +struct LLI { LLI? next; int i; }; +LLI? !head = null; +while( arg ) { + head = new LLI { + next=head; + // Any old code in the constructor + int !tmp=arg; + while( arg > 10 ) { + tmp = tmp + arg; + arg = arg - 1; + } + i=tmp; + }; + arg = arg-1; +} +if( !head ) return 0; +LLI? next = head.next; +if( !next ) return 1; +return next.i; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,0,1,.i);", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + assertEquals("1", Eval2.eval(code, 1)); + assertEquals("2", Eval2.eval(code, 11)); + } + + @Test + public void testSquare() { + CodeGen code = new CodeGen( +""" +struct Square { + flt !side = arg; + // Newtons approximation to the square root, computed in a constructor. + // The actual allocation will copy in this result as the initial + // value for 'diag'. + flt !diag = arg*arg/2; + while( 1 ) { + flt next = (side/diag + diag)/2; + if( next == diag ) break; + diag = next; + } +}; +return new Square; +"""); + code.parse().opto(); + assertEquals("return Square;", code.print()); + assertEquals("Square{side=3.0,diag=1.7320508075688772}", Eval2.eval(code, 3)); + assertEquals("Square{side=4.0,diag=2.0}", Eval2.eval(code, 4)); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter17Test.java new file mode 100644 index 00000000..53c23ecd --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter17Test.java @@ -0,0 +1,556 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class Chapter17Test { + + @Test + public void testJig() { + CodeGen code = new CodeGen( +""" +return 1; +"""); + code.parse().opto().typeCheck(); + assertEquals("return 1;", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + + // --------------------------------------------------------------- + @Test + public void testInc0() { + CodeGen code = new CodeGen(""" +return arg++; +"""); + code.parse().opto(); + assertEquals("return arg;", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + } + + @Test + public void testInc1() { + CodeGen code = new CodeGen(""" +return arg+++arg++; +"""); + code.parse().opto(); + assertEquals("return ((arg<<1)+1);", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test + public void testInc2() { + CodeGen code = new CodeGen(""" +// -(arg--)-(arg--) +return -arg---arg--; +"""); + code.parse().opto(); + assertEquals("return (-((arg<<1)+-1));", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test + public void testInc3() { + CodeGen code = new CodeGen(""" +int[] !xs = new int[arg]; +xs[0]++; +xs[1]++; +return xs[0]; +"""); + code.parse().opto(); + assertEquals("return 1;", code.print()); + assertEquals("1", Eval2.eval(code, 2)); + } + + @Test + public void testInc4() { + CodeGen code = new CodeGen(""" +u8[] !xs = new u8[1]; +xs[0]--; +return xs[0]; +"""); + code.parse().opto(); + assertEquals("return 255;", code.print()); + assertEquals("255", Eval2.eval(code, 2)); + } + + @Test + public void testInc5() { + CodeGen code = new CodeGen(""" +struct S { u16 x; }; +S !s = new S; +s.x--; +return s.x; +"""); + code.parse().opto(); + assertEquals("return 65535;", code.print()); + assertEquals("65535", Eval2.eval(code, 2)); + } + + @Test + public void testInc6() { + CodeGen code = new CodeGen("return --arg;"); + code.parse().opto(); + assertEquals("return (arg+-1);", code.print()); + assertEquals("-1", Eval2.eval(code, 0)); + } + + @Test + public void testInc7() { + CodeGen code = new CodeGen("u8 x=0; return --x;"); + code.parse().opto(); + assertEquals("return 255;", code.print()); + assertEquals("255", Eval2.eval(code, 0)); + } + + @Test + public void testInc8() { + CodeGen code = new CodeGen("int x; x+=2; return x+=3;"); + code.parse().opto(); + assertEquals("return 5;", code.print()); + assertEquals("5", Eval2.eval(code, 0)); + } + + @Test + public void testInc9() { + CodeGen code = new CodeGen("flt x = 1.5; x++; return x;"); + code.parse().opto(); + assertEquals("return 2.5f;", code.print()); + assertEquals("2.5", Eval2.eval(code, 0)); + } + + @Test public void testInt10() { + CodeGen code = new CodeGen("flt x = 1.5; x++; int i = x; return i;"); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Type 2.5f is not of declared type i64",e.getMessage()); } + } + + + // --------------------------------------------------------------- + @Test public void testVar0() { + CodeGen code = new CodeGen("var d; return d;"); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("Syntax error, expected =expression: ;",e.getMessage()); } + } + + @Test public void testVar1() { + CodeGen code = new CodeGen("val d; return d;"); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("Syntax error, expected =expression: ;",e.getMessage()); } + } + + @Test public void testVar2() { + CodeGen code = new CodeGen("int x; x=3; x++; return x; // Ok, no initializer so x is mutable "); + code.parse().opto(); + assertEquals("return 4;", code.print()); + assertEquals("4", Eval2.eval(code, 0)); + } + + @Test public void testVar3() { + CodeGen code = new CodeGen("int x=3; x++; return x; // Ok, primitive so x is mutable despite initializer "); + code.parse().opto(); + assertEquals("return 4;", code.print()); + assertEquals("4", Eval2.eval(code, 0)); + } + + @Test public void testVar4() { + CodeGen code = new CodeGen("struct S{int x;}; S? s; s=new S; s.x++; return s.x; // Ok, no initializer so x is mutable "); + code.parse().opto(); + assertEquals("return 1;", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test public void testVar5() { + CodeGen code = new CodeGen("struct S{int x;}; S? s; s=new S{x=3;}; s.x++; return s.x; // Ok, no initializer so x is mutable "); + code.parse().opto(); + assertEquals("return 4;", code.print()); + assertEquals("4", Eval2.eval(code, 0)); + } + + @Test public void testVar6() { + CodeGen code = new CodeGen("struct S{int x;}; val s = new S; s.x++; return s.x; // Error initializer so x is immutable "); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test public void testVar7() { + CodeGen code = new CodeGen("struct S{int x;}; val s = new S{x=3;}; s.x++; return s.x; // Error initializer so x is immutable "); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test public void testVar8() { + CodeGen code = new CodeGen("struct S{int x;}; S !s=new S; s.x++; return s.x; // Ok, has '!' so s.x is mutable "); + code.parse().opto(); + assertEquals("return 1;", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test public void testVar9() { + CodeGen code = new CodeGen("struct S{int x;}; var s=new S; s.x++; return s.x; // Ok, has var so s.x is mutable "); + code.parse().opto(); + assertEquals("return 1;", code.print()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test public void testVar10() { + CodeGen code = new CodeGen("struct S{int x;}; val s=new S; s.x++; return s.x; // Error, has val so x is immutable "); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test public void testVar11() { + CodeGen code = new CodeGen(""" +struct Bar { int x; }; +Bar !bar = new Bar; +bar.x = 3; // Ok, bar is mutable + +struct Foo { Bar? !bar; int y; }; +Foo !foo = new Foo { bar = bar; }; +foo.bar = bar; // Ok foo is mutable +foo.bar.x++; // Ok foo and foo.bar and foo.bar.x are all mutable + +val xfoo = foo; // Throw away mutability +xfoo.bar.x++; // Error, cannot mutate through xfoo +return xfoo.bar.x; + """); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } + } + + @Test public void testVar12() { + CodeGen code = new CodeGen(""" +struct Bar { int x; }; +Bar !bar = new Bar; +bar.x = 3; // Ok, bar is mutable + +struct Foo { Bar? !bar; int y; }; +Foo !foo = new Foo; +foo.bar = bar; // Ok bar is mutable +foo.bar.x++; // Ok foo and foo.bar and foo.bar.x are all mutable + +val xfoo = foo; // Throw away mutability +int x4 = xfoo.bar.x; // Ok to read through xfoo, gets 4 +foo.bar.x++; // Bumps to 5 +int x5 = xfoo.bar.x; // Ok to read through xfoo, gets 5 +return x4*10+x5; +"""); + code.parse().opto(); + assertEquals("return 45;", code.print()); + assertEquals("45", Eval2.eval(code, 0)); + } + + @Test + public void testVar13() { + CodeGen code = new CodeGen(""" +int i,i++; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Redefining name 'i'",e.getMessage()); } + } + + + @Test + public void testVar14() { + CodeGen code = new CodeGen(""" +struct B {}; +struct A { B b; }; +A x = new A { + return b; // read before init + b = new B; +}; +"""); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("Cannot read uninitialized field 'b'",e.getMessage()); } + } + + @Test + public void testVar15() { + CodeGen code = new CodeGen(""" +struct B {}; +struct A { B b; }; +return new A { + if (arg) b = new B; // Constructor ends with partial init of b +}.b; +"""); + try { code.parse(); fail(); } + catch( Exception e ) { assertEquals("'A' is not fully initialized, field 'b' needs to be set in a constructor",e.getMessage()); } + } + + @Test + public void testVar16() { + CodeGen code = new CodeGen( +""" +struct S{}; +val x = 1; +val s = new S{x = 2;}; +return x; +""" +); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); } + } + + @Test + public void testVar17() { + CodeGen code = new CodeGen( +""" +struct Person { + bool focused; +}; +val focus = { Person p -> + p.focused = true; +}; +Person me; // Person !me = new Person; +focus(me); +return me; +""" +); + try { code.parse(); fail(); } + catch( Exception e ) { assertEquals("Syntax error, expected =expression: ;",e.getMessage()); } + } + + // --------------------------------------------------------------- + @Test + public void testTrinary0() { + CodeGen code = new CodeGen(""" +return arg ? 1 : 2; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,1,2);", code.print()); + assertEquals("2", Eval2.eval(code, 0)); + assertEquals("1", Eval2.eval(code, 1)); + } + + @Test + public void testTrinary1() { + CodeGen code = new CodeGen(""" +return arg ? 0 : arg; +"""); + code.parse().opto(); + assertEquals("return 0;", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + } + + @Test + public void testTrinary2() { + CodeGen code = new CodeGen(""" +struct Bar { int x; }; +var b = arg ? new Bar : null; +return b ? b.x++ + b.x++ : -1; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,((.x<<1)+1),-1);", code.print()); + assertEquals("-1", Eval2.eval(code, 0)); + assertEquals("1", Eval2.eval(code, 1)); + } + + @Test + public void testTrinary3() { + CodeGen code = new CodeGen(""" +struct Bar { int x; }; +var b = arg ? new Bar; +return b ? b.x++ + b.x++ : -1; +"""); + code.parse().opto(); + assertEquals("return Phi(Region,((.x<<1)+1),-1);", code.print()); + assertEquals("-1", Eval2.eval(code, 0)); + assertEquals("1", Eval2.eval(code, 1)); + } + + @Test + public void testTrinary4() { + // This test case will benefit from an unzipping transformation + CodeGen code = new CodeGen(""" +struct Bar { Bar? next; int x; }; +var b = arg ? new Bar { next = (arg==2) ? new Bar{x=2;}; x=1; }; +return b ? b.next ? b.next.x : b.x; // parses "b ? (b.next ? b.next.x : b.x) : 0" +"""); + code.parse().opto(); + assertEquals("return Phi(Region,.x,0);", code.print()); + assertEquals("0", Eval2.eval(code, 0)); + assertEquals("1", Eval2.eval(code, 1)); + assertEquals("2", Eval2.eval(code, 2)); + } + + @Test + public void testTrinary5() { + CodeGen code = new CodeGen(""" +flt f=arg?1:1.2; +return f; // missing widening +"""); + code.parse().opto(); + assertEquals("return Phi(Region,1.0f,1.2);", code.print()); + assertEquals("1.2", Eval2.eval(code, 0)); + } + + + @Test + public void testTrinary6() { + CodeGen code = new CodeGen(""" +struct S{}; +return arg ? 7 : new S; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("No common type amongst int and reference",e.getMessage()); } + } + + // --------------------------------------------------------------- + @Test + public void testFor0() { + CodeGen code = new CodeGen(""" +int sum=0; +for( int i=0; i<arg; i++ ) + sum += i; +return sum; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,0,(Phi_sum+Phi(Loop,0,(Phi_i+1))));", code.print()); + assertEquals("3", Eval2.eval(code, 3)); + assertEquals("45", Eval2.eval(code, 10)); + } + @Test + public void testFor1() { + CodeGen code = new CodeGen(""" +int sum=0, i=0; +for( ; i<arg; i++ ) + sum += i; +return sum; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,0,(Phi_sum+Phi(Loop,0,(Phi_i+1))));", code.print()); + assertEquals("3", Eval2.eval(code, 3)); + assertEquals("45", Eval2.eval(code, 10)); + } + @Test + public void testFor2() { + CodeGen code = new CodeGen(""" +int sum=0; +for( int i=0; ; i++ ) { + if( i>=arg ) break; + sum += i; +} +return sum; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,0,(Phi_sum+Phi(Loop,0,(Phi_i+1))));", code.print()); + assertEquals("3", Eval2.eval(code, 3)); + assertEquals("45", Eval2.eval(code, 10)); + } + @Test + public void testFor3() { + CodeGen code = new CodeGen(""" +int sum=0; +for( int i=0; i<arg; ) + sum += i++; +return sum; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,0,(Phi_sum+Phi(Loop,0,(Phi_i+1))));", code.print()); + assertEquals("3", Eval2.eval(code, 3)); + assertEquals("45", Eval2.eval(code, 10)); + } + @Test + public void testFor4() { + CodeGen code = new CodeGen(""" +int sum=0; +for( int i=0; i<arg; i++ ) + sum += i; +return i; +"""); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("Undefined name 'i'",e.getMessage()); } + } + @Test + public void testFor5() { + CodeGen code = new CodeGen(""" +for(;;arg++;) {} +"""); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("Syntax error, expected Unexpected code after expression: ;",e.getMessage()); } + } + + + + // --------------------------------------------------------------- + @Test + public void testForward0() { + CodeGen code = new CodeGen(""" +struct A{ + B? f1; + B? f2; +}; +return new A; +"""); + code.parse().opto(); + assertEquals("return A;", code.print()); + assertEquals("A{f1=null,f2=null}", Eval2.eval(code,0)); + } + + @Test + public void testForward1() { + CodeGen code = new CodeGen(""" +struct A { + B?[]? nil_array_of_b; + B?[] array_of_b; +}; +return new A{array_of_b = new B?[0]; }.array_of_b; +"""); + code.parse().opto(); + assertEquals("return (const)[]*B?;", code.print()); + assertEquals("*B {... }?[]", Eval2.eval(code,0)); + } + + // --------------------------------------------------------------- + @Test + public void testLinkedList2() { + CodeGen code = new CodeGen(""" +struct LLI { LLI? next; int i; }; +LLI? !head = null; +while( arg-- ) + head = new LLI { next=head; i=arg; }; +int sum=0; +var ptr = head; // A read-only ptr, to be assigned from read-only next fields +for( ; ptr; ptr = ptr.next ) + sum += ptr.i; +return sum; +"""); + code.parse().opto(); + assertEquals("return Phi(Loop,0,(Phi_sum+.i));", code.print()); + assertEquals("45", Eval2.eval(code, 10)); + } + + @Test + public void sieveOfEratosthenes() { + CodeGen code = new CodeGen( +""" +var ary = new bool[arg], primes = new int[arg]; +var nprimes=0, p=0; +// Find primes while p^2 < arg +for( p=2; p*p < arg; p++ ) { + // skip marked non-primes + while( ary[p] ) p++; + // p is now a prime + primes[nprimes++] = p; + // Mark out the rest non-primes + for( int i = p + p; i < ary#; i += p ) + ary[i] = true; +} +// Now just collect the remaining primes, no more marking +for( ; p < arg; p++ ) + if( !ary[p] ) + primes[nprimes++] = p; +// Copy/shrink the result array +var !rez = new int[nprimes]; +for( int j=0; j<nprimes; j++ ) + rez[j] = primes[j]; +return rez; +"""); + code.parse().opto().typeCheck().GCM(); + assertEquals("return []i64;", code.print()); + assertEquals("i64[ 2,3,5,7,11,13,17,19]",Eval2.eval(code, 20)); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter18Test.java new file mode 100644 index 00000000..42f80d86 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter18Test.java @@ -0,0 +1,371 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen.Phase; +import com.seaofnodes.simple.codegen.CodeGen; +import org.junit.Ignore; +import org.junit.Test; +import static org.junit.Assert.*; +import static org.junit.Assert.fail; + +public class Chapter18Test { + + @Test + public void testJig() { + CodeGen code = new CodeGen( +""" +return 0; +"""); + code.driver(Phase.LocalSched); + assertEquals("return 0;", code._stop.toString()); + assertEquals("0", Eval2.eval(code, 2)); + } + + @Test + public void testPhiParalleAssign() { + CodeGen code = new CodeGen( +""" +int a = 1; +int b = 2; +while(arg--) { + int t = a; + a = b; + b = t; +} +return a; +"""); + code.parse().opto().typeCheck(); + assertEquals("return Phi(Loop,1,Phi(Loop,2,Phi_a));", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 0)); + assertEquals("2", Eval2.eval(code, 1)); + assertEquals("1", Eval2.eval(code, 2)); + assertEquals("2", Eval2.eval(code, 3)); + } + + + // --------------------------------------------------------------- + @Test + public void testType0() { + CodeGen code = new CodeGen( +""" +{int -> int}? x2 = null; // null function ptr +return x2; +"""); + code.parse().opto(); + assertEquals("return null;", code._stop.toString()); + assertEquals("null", Eval2.eval(code, 0 ) ); + } + + @Test + public void testFcn0() { + CodeGen code = new CodeGen( +""" +{int -> int}? sq = { int x -> + x*x; +}; +"""); + code.parse().opto(); + assertEquals("return (Parm_x(sq,i64)*x);", code._stop.toString()); + //assertEquals("{ int -> int #1}", Eval2.eval(code, 3)); + } + + @Test + public void testFcn1() { + CodeGen code = new CodeGen( +""" +var sq = { int x -> + x*x; +}; +return sq(arg)+sq(3); +"""); + code.driver(Phase.LocalSched); + assertEquals("Stop[ return (#2+#2); return (Parm_x(sq,i64)*x); ]", code._stop.toString()); + assertEquals("13", Eval2.eval(code, 2)); + } + + // Function scope test + @Test + public void testFcn2() { + CodeGen code = new CodeGen( +""" +int cnt=1; +return { -> cnt; }; +"""); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("Variable 'cnt' is out of function scope and must be a final constant",e.getMessage()); } + } + + // Function scope test + @Test + public void testFcn3() { + CodeGen code = new CodeGen( +""" +val cnt=2; +return { -> cnt; }(); +"""); + code.parse().opto(); + assertEquals("return 2;", code._stop.toString()); + assertEquals("2", Eval2.eval(code, 0)); + } + + // Function variables + @Test + public void testFcn4() { + CodeGen code = new CodeGen( +""" +var fcn = arg ? { int x -> x*x; } : { int x -> x+x; }; +return fcn(3); +"""); + code.parse().opto(); + assertEquals("Stop[ return #2; return (Parm_x($fun21,i64,3)*x); return (Parm_x($fun22,i64,3)<<1); ]", code._stop.toString()); + assertEquals("6", Eval2.eval(code, 0)); + assertEquals("9", Eval2.eval(code, 1)); + } + + // Recursive factorial test + @Test + public void testFcn5() { + CodeGen code = new CodeGen("val fact = { int x -> x <= 1 ? 1 : x*fact(x-1); }; return fact(arg);"); + code.parse().opto().typeCheck(); + assertEquals("Stop[ return #2; return Phi(Region,1,(Parm_x(fact,i64,arg,(x-1))*#2)); ]", code._stop.toString()); + assertEquals( "1", Eval2.eval(code, 0)); + assertEquals( "1", Eval2.eval(code, 1)); + assertEquals( "2", Eval2.eval(code, 2)); + assertEquals( "6", Eval2.eval(code, 3)); + assertEquals("24", Eval2.eval(code, 4)); + } + + @Test + public void testFcn6() { + CodeGen code = new CodeGen( +""" +struct S { int i; }; +val newS = { int x -> return new S { i=x; }; }; +return newS(1).i; +"""); + code.parse().opto().typeCheck().GCM(); + assertEquals("return 1;", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 0)); + } + + // Double forward reference + @Test + public void testFcn7() { + CodeGen code = new CodeGen( +""" +if( arg ? f : g ) return 1; +val f = {->1;}; +val g = {->2;}; +return 2; +"""); + code.parse().opto().typeCheck().GCM(); + assertEquals("Stop[ return 1; return 1; return 2; ]", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 0)); + } + + @Test + public void testFcn8() { + CodeGen code = new CodeGen( +""" +{int -> int}? i2i = null; +var id = {{int->int} f-> return f;}; +for(;;) { + if (i2i) return i2i(arg); + var x = {int i-> return i;}; + arg = x(3); + i2i = id(x); +} +"""); + code.driver(Phase.LocalSched); + assertEquals("Stop[ return #2; return Parm_i(x,i64); ]", code._stop.toString()); + assertEquals("3", Eval2.eval(code, 0)); + } + + @Test + public void testFcn9() { + CodeGen code = new CodeGen( +""" +{int -> int}? i2i = null; +for(;;) { + if (i2i) return i2i(arg); + var x = {int i-> return i;}; + arg = x(3); +} +"""); + code.driver(Phase.LocalSched); + assertEquals("return Top;", code._stop.toString()); + assertEquals("null", Eval2.eval(code, 0)); + } + + + @Test + public void testFcn10() { + CodeGen code = new CodeGen( +""" +struct Person { + int age; +}; + +val fcn = { Person?[] ps, int x -> + val tmp = ps[x]; + if( ps[x] ) + ps[x].age++; +}; + +var ps = new Person?[2]; +ps[0] = new Person; +ps[1] = new Person; +return fcn(ps,1); +"""); + code.driver(Phase.LocalSched); + assertEquals("return 0;", code._stop.toString()); + assertEquals("0", Eval2.eval(code, 0)); + } + + // Function break + @Test + public void testErr1() { + CodeGen code = new CodeGen( +""" +for(;;) { + val f = { -> + break; + }; + f(); + return 2; +} +return 1; +"""); + try { code.parse().opto(); fail(); } + catch( Exception e ) { assertEquals("No active loop for a break or continue",e.getMessage()); } + } + + // Calling and inlining a null function + @Test + public void testErr2() { + CodeGen code = new CodeGen( +""" +{int -> int}? !i2i = { int i -> return i; }; +for(;;) { + if (i2i(2) == arg) break; + i2i = null; +} +return 0; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Might be null calling { i64 -> i64 #21}?",e.getMessage()); } + } + + + @Test + public void testErr3() { + CodeGen code = new CodeGen( +""" +val f = { int i, int j -> return i+j; }; +return f(); +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Expecting 2 arguments, but found 0",e.getMessage()); } + } + + + @Test + public void testErr4() { + CodeGen code = new CodeGen( +""" +struct S { + {int} f = { -> x(); return 0; }; // Do not let fref x be a field +}; +val x = { -> return 1; }; +S? s = null; +for(;;) { + if (s) return s.x; +} +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Accessing unknown field 'x' from '*S'",e.getMessage()); } + } + + @Test + public void testErr5() { + CodeGen code = new CodeGen( +""" +val g = { -> + g(); +}; +return 0; +"""); + try { code.parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("No defined return type",e.getMessage()); } + } + + + // Mutual recursion. Fails without SCCP to lift the recursive return types. + @Ignore @Test + public void testFcnMutRec() { + CodeGen code = new CodeGen( +""" +val is_even = { int x -> x ? is_odd (x-1) : true ; }; +val is_odd = { int x -> x ? is_even(x-1) : false; }; +return is_even(arg); +"""); + code.parse().opto(); + assertEquals("Stop[ return is_even( arg); return Phi(Region,Phi(Region,is_even( ((Parm_x(is_even,int,arg,Sub)-1)-1)),0),1); ]", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 0)); + assertEquals("0", Eval2.eval(code, 1)); + assertEquals("1", Eval2.eval(code, 2)); + assertEquals("0", Eval2.eval(code, 3)); + } + + // Forward ref to 'x' means that + @Ignore @Test + public void testForwardRef1() { + CodeGen code = new CodeGen( +""" +struct S { + { int } f = { -> return x(); }; +}; +val x = { -> return 1; }; +S? s = null; +for(;;) { + if (s) return s.f; +} +"""); + code.parse().opto().typeCheck().GCM(); + assertEquals("return 0;", code._stop.toString()); + assertEquals("0", Eval2.eval(code, 0)); + } + + // Inline hidden called more than once + @Test + public void testInline() { + CodeGen code = new CodeGen( +""" +{int->int}?! i2i = {int i->return i;}; +{{int->int}->{int->int}}! f2f = {{int->int} f->return f;}; +val o = i2i; +if (arg) i2i = null; +if (i2i) return i2i(arg); +return f2f(o)(1); +"""); + code.driver(Phase.LocalSched); + assertEquals("Stop[ return Phi(Region,#2,#2); return Parm_i(i2i.o,i64); ]", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 2)); + } + + @Test + public void testOperField() { + CodeGen code = new CodeGen( +""" +struct Person { + int coffee_count; +}; +Person !p = new Person; +p.coffee_count += 1; +return p.coffee_count; +"""); + code.driver(Phase.LocalSched); + assertEquals("return 1;", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 2)); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter19Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter19Test.java new file mode 100644 index 00000000..e2a155ce --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter19Test.java @@ -0,0 +1,332 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen.Phase; +import com.seaofnodes.simple.codegen.CodeGen; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.Test; +import static org.junit.Assert.*; + +public class Chapter19Test { + + @Test + public void testJig() { + CodeGen code = new CodeGen(""" +return 0; +"""); + code.parse().opto().typeCheck(); + assertEquals("return 0;", code._stop.toString()); + assertEquals("0", Eval2.eval(code, 2)); + } + + + @Test + public void testString() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/stringHash.smp")); + CodeGen code = new CodeGen(src).parse().opto().typeCheck().GCM().localSched(); + assertEquals("Stop[ return Phi(Region,1,0,0,1); return Phi(Region,._hashCode,Phi(Region,123456789,Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash))))); ]", code._stop.toString()); + //assertEquals("-4898613127354160978", Eval2.eval(code, 2)); + } + + @Test + public void testBasic0() { + CodeGen code = new CodeGen("return 0;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return 0;", code._stop.toString()); + } + + @Test + public void testBasic1() { + CodeGen code = new CodeGen("return arg+1;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (inc,arg);", code._stop.toString()); + } + + @Test + public void testBasic2() { + CodeGen code = new CodeGen("return -17;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return -17;", code._stop.toString()); + } + + + @Test + public void testBasic3() { + CodeGen code = new CodeGen("return arg==1;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (set==,(cmp,arg));", code._stop.toString()); + } + + @Test + public void testBasic4() { + CodeGen code = new CodeGen("return arg<<1;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (shli,arg);", code._stop.toString()); + } + + @Test + public void testBasic5() { + CodeGen code = new CodeGen("return arg >> 1;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (sari,arg);", code._stop.toString()); + } + + @Test + public void testBasic6() { + CodeGen code = new CodeGen("return arg >>> 1;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (shri,arg);", code._stop.toString()); + } + + @Test + public void testBasic7() { + CodeGen code = new CodeGen("return arg / 2;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (div,arg,2);", code._stop.toString()); + } + + @Test + public void testBasic8() { + CodeGen code = new CodeGen("return arg * 6;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (muli,arg);", code._stop.toString()); + } + + @Test + public void testBasic9() { + CodeGen code = new CodeGen("return arg & 2;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (andi,arg);", code._stop.toString()); + } + + @Test + public void testBasic10() { + CodeGen code = new CodeGen("return arg | 2;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (ori,arg);", code._stop.toString()); + } + + @Test + public void testBasic11() { + CodeGen code = new CodeGen("return arg ^ 2;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (xori,arg);", code._stop.toString()); + } + + @Test + public void testBasic12() { + CodeGen code = new CodeGen("return arg + 2.0;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (addf,(cvtf,arg),2.0f);", code._stop.toString()); + } + + @Test + public void testBasic13() { + CodeGen code = new CodeGen("return arg - 2.0;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (subf,(cvtf,arg),2.0f);", code._stop.toString()); + } + + @Test + public void testBasic14() { + CodeGen code = new CodeGen("return arg * 2.0;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (mulf,(cvtf,arg),2.0f);", code._stop.toString()); + } + + @Test + public void testBasic15() { + CodeGen code = new CodeGen("return arg / 2.0;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (mulf,(cvtf,arg),0.5f);", code._stop.toString()); + } + + @Test + public void testBasic16() { + CodeGen code = new CodeGen( +""" +int arg1 = arg + 1; +return arg1 / arg;"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (div,(inc,arg),arg);", code._stop.toString()); + } + + @Test + public void testBasic17() { + CodeGen code = new CodeGen( +""" +int arg1 = arg + 1; +return arg1 * arg; +"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (mul,(inc,arg),arg);", code._stop.toString()); + } + + @Test + public void testToFloat() { + CodeGen code = new CodeGen(""" +int a = arg; +return a + 2.0; +""" + ).driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (addf,(cvtf,arg),2.0f);", code._stop.toString()); + } + + @Test + public void testIfStmt() { + CodeGen code = new CodeGen( +""" +int a = 1; +if (arg == 1) + a = arg+2; +else { + a = arg-3; +} +return a;"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return Phi(Region,(addi,arg),(addi,arg));", code.print()); + } + + @Test + public void testIfMerge2() { + CodeGen code = new CodeGen( +""" +int a=arg+1; +int b=arg+2; +if( arg==1 ) + b=b+a; +else + a=b+1; +return a+b;"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (add,(add,Phi(Region,(shli,arg),arg),arg),Phi(Region,4,5));", code.print()); + } + + @Test + public void testLoop() { + CodeGen code = new CodeGen( +""" +int sum=0; +for( int i=0; i<arg; i++ ) + sum += i; +return sum;"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return Phi(Loop,0,(add,Phi_sum,Phi(Loop,0,(inc,Phi_i))));", code.print()); + } + + @Test + public void testAlloc1() { + CodeGen code = new CodeGen( +""" +struct S { int a; S? c; }; +return new S;"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return S;", code.print()); + } + + @Test + public void testLea1() { + CodeGen code = new CodeGen("int x = arg/3; return arg+x+7;"); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (lea,arg,(div,arg,3));", code.print()); + } + + @Test + public void testLea2() { + CodeGen code = new CodeGen("int x = arg/3; return arg+x*4+7;"); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (lea,arg,(div,arg,3));", code.print()); + } + + @Test + public void testLea3() { + CodeGen code = new CodeGen("int x = arg/3; return x*4+arg;"); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return (lea,arg,(div,arg,3));", code.print()); + } + + @Test + public void testAlloc2() { + CodeGen code = new CodeGen("int[] !xs = new int[3]; xs[arg]=1; return xs[arg&1];"); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return .[];", code.print()); + } + + @Test + public void testAlloc3() { + CodeGen code = new CodeGen("int[] !xs = new int[3]; xs[arg]=1; return xs[arg&1]+3;"); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return .[];", code.print()); + } + + @Test + public void testArray1() { + CodeGen code = new CodeGen( +""" +int[] !ary = new int[arg]; +// Fill [0,1,2,3,4,...] +for( int i=0; i<ary#; i++ ) + ary[i] = i; +// Fill [0,1,3,6,10,...] +for( int i=0; i<ary#-1; i++ ) + ary[i+1] += ary[i]; +return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6 +"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return .[];", code.print()); + } + + @Test + public void testArray2() { + CodeGen code = new CodeGen( +""" +flt[] !A = new flt[arg], !B = new flt[arg]; +// Fill [0,1,2,3,4,...] +for( int i=0; i<A#; i++ ) + A[i] = i; +for( int i=0; i<A#; i++ ) + B[i] += A[i]; +return 0; +"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return 0;", code.print()); + } + + @Test + public void testArray3() { + CodeGen code = new CodeGen( +""" +byte[] !A = new byte[arg]; +for( int i=0; i<A#; i++ ) + A[i]++; +return A[1]; +"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return .[];", code.print()); + } + + @Test + public void testNewton() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/newtonFloat.smp")) + + "flt farg = arg; return test_sqrt(farg);"; + CodeGen code = new CodeGen(src).driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return Phi(Loop,(cvtf,arg),(mulf,(addf,(divf,cvtf,Phi_guess),Phi_guess),0.5f));", code.print()); + }; + + + @Test + public void sieveOfEratosthenes() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/sieve.smp")); + CodeGen code = new CodeGen(src).driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("return []u32;", code.print()); + //assertEquals("u32[ 2,3,5,7,11,13,17,19]",Eval2.eval(code, 20)); + } + + + @Test + public void testFcn1() { + CodeGen code = new CodeGen( +""" +val fcn = arg ? { int x -> x*x; } : { int x -> x+x; }; +return fcn(2)*10 + fcn(3); +"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("Stop[ return (add,#2,(muli,#2)); return (mul,Parm_x($fun21,i64),x); return (shli,Parm_x($fun22,i64)); ]", code.print()); + } + + @Test + public void testFcn2() { + CodeGen code = new CodeGen( +""" +val sq = { int x -> x*x; }; +return sq(arg) + sq(3); +"""); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); + assertEquals("Stop[ return (add,#2,#2); return (mul,Parm_x(sq,i64),x); ]", code.print()); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter20Test.java new file mode 100644 index 00000000..dcea5c87 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter20Test.java @@ -0,0 +1,152 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.print.ASMPrinter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import static org.junit.Assert.*; + +public class Chapter20Test { + + @Test + public void testJig() { + CodeGen code = new CodeGen("return 0;"); + code.parse().opto().typeCheck(); + assertEquals("return 0;", code._stop.toString()); + assertEquals("0", Eval2.eval(code, 2)); + } + + static void testCPU( String src, String cpu, String os, int spills, String stop ) { + CodeGen code = new CodeGen(src); + code.driver(CodeGen.Phase.RegAlloc,cpu,os); + int delta = spills>>3; + if( delta==0 ) delta = 1; + if( spills != -1 ) + assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); + if( stop != null ) + assertEquals(stop, code._stop.toString()); + } + + private static void testAllCPUs( String src, int spills, String stop ) { + testCPU(src,"x86_64_v2", "SystemV",spills,stop); + testCPU(src,"riscv" , "SystemV",spills,stop); + testCPU(src,"arm" , "SystemV",spills,stop); + } + + @Test public void testAlloc0() { + testCPU("return new u8[arg];","x86_64_v2", "SystemV",3,"return []u8;"); + testCPU("return new u8[arg];","riscv" , "SystemV",5,"return []u8;"); + testCPU("return new u8[arg];","arm" , "SystemV",5,"return []u8;"); + } + + @Test public void testBasic1() { + String src = "return arg | 2;"; + testCPU(src,"x86_64_v2", "SystemV",1,"return (ori,mov(arg));"); + testCPU(src,"riscv" , "SystemV",0,"return ( arg | #2 );"); + testCPU(src,"arm" , "SystemV",0,"return (ori,arg);"); + } + + @Test + public void testNewtonInteger() { + String src = +""" +// Newtons approximation to the square root +val sqrt = { int x -> + int guess = x; + while( 1 ) { + int next = (x/guess + guess)/2; + if( next == guess ) return guess; + guess = next; + } +}; +int cast_int = arg+2; +return sqrt(arg) + sqrt(cast_int); +"""; + testCPU(src,"x86_64_v2", "Win64" ,55,null); + testCPU(src,"riscv" , "SystemV",19,null); + testCPU(src,"arm" , "SystemV",19,null); + } + + @Test + public void testNewtonFloat() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/newtonFloat.smp")) + + "flt farg = arg; return test_sqrt(farg) + test_sqrt(farg+2.0);"; + testCPU(src,"x86_64_v2", "SystemV",39,null); + testCPU(src,"riscv" , "SystemV",17,null); + testCPU(src,"arm" , "SystemV",18,null); + } + + @Test + public void testAlloc2() { + String src = "int[] !xs = new int[3]; xs[arg]=1; return xs[arg&1];"; + testCPU(src,"x86_64_v2", "SystemV",-1,"return .[];"); + testCPU(src,"riscv" , "SystemV", 6,"return .[];"); + testCPU(src,"arm" , "SystemV", 6,"return .[];"); + } + + + + @Test + public void testArray1() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/array1.smp")); + testCPU(src,"x86_64_v2", "SystemV",-1,"return .[];"); + testCPU(src,"riscv" , "SystemV", 8,"return (add,.[],(mul,.[],1000));"); + testCPU(src,"arm" , "SystemV", 5,"return (add,.[],(mul,.[],1000));"); + } + + + @Test + public void testString() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/stringHash.smp")); + testCPU(src,"x86_64_v2", "SystemV", 9,null); + testCPU(src,"riscv" , "SystemV", 3,null); + testCPU(src,"arm" , "SystemV", 3,null); + } + + @Test + public void testCast() { + String src = "struct Bar { int x; }; var b = arg ? new Bar; return b ? b.x++ + b.x++ : -1;"; + testCPU(src,"x86_64_v2", "SystemV",2,null); + testCPU(src,"riscv" , "SystemV",2,null); + testCPU(src,"arm" , "SystemV",2,null); + } + + @Test + public void testFltArg() { + String src = "return {int i, flt f, int j->return i+f+j;};"; + testAllCPUs(src,0,null); + } + + @Test + public void testFlags1() { + String src = """ +bool b1 = arg == 1; +bool b2 = arg == 2; +if (b2) if (b1) return 1; +if (b1) return 2; +return 0; +"""; + testCPU(src,"x86_64_v2", "SystemV",0,"return Phi(Region,1,2,0);"); + testCPU(src,"riscv" , "SystemV",0,"return Phi(Region,1,2,0);"); + testCPU(src,"arm" , "SystemV",0,"return Phi(Region,1,2,0);"); + } + + @Test + public void testFlags2() { + String src = """ +bool b1 = arg == 1; +while (arg > 0) { + arg--; + if (b1) arg--; +} +return arg; +"""; + testCPU(src,"x86_64_v2", "SystemV",3,null); + testCPU(src,"riscv" , "SystemV",2,null); + testCPU(src,"arm" , "SystemV",2,null); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter21Test.java new file mode 100644 index 00000000..7f4898e0 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -0,0 +1,277 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.cpus.arm.arm; +import com.seaofnodes.simple.node.cpus.riscv.riscv; +import com.seaofnodes.simple.util.SB; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.Ignore; +import org.junit.Test; +import static org.junit.Assert.*; + +public class Chapter21Test { + + @Test + public void testJig() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/jig.smp")); + testCPU(src,"x86_64_v2", "Win64" ,-1,null); + testCPU(src,"riscv" , "SystemV",-1,null); + testCPU(src,"arm" , "SystemV",-1,null); + } + + static void testCPU( String src, String cpu, String os, int spills, String stop ) { + CodeGen code = new CodeGen(src).driver(CodeGen.Phase.Encoding,cpu,os); + int delta = spills>>3; + if( delta==0 ) delta = 1; + if( spills != -1 ) + assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); + if( stop != null ) + assertEquals(stop, code._stop.toString()); + } + + + @Test public void testBasic1() { + String src = "return arg | 2;"; + testCPU(src,"x86_64_v2", "SystemV",1,"return (ori,mov(arg));"); + testCPU(src,"riscv" , "SystemV",0,"return ( arg | #2 );"); + testCPU(src,"arm" , "SystemV",0,"return (ori,arg);"); + } + + @Test public void testInfinite() { + String src = "struct S { int i; }; S !s = new S; while(1) s.i++; return s.i;"; + testCPU(src,"x86_64_v2", "SystemV",0,"return Top;"); + testCPU(src,"riscv" , "SystemV",2,"return Top;"); + testCPU(src,"arm" , "SystemV",2,"return Top;"); + } + + @Test + public void testArray1() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/array1.smp")); + testCPU(src,"x86_64_v2", "SystemV",-1,"return .[];"); + testCPU(src,"riscv" , "SystemV", 7,"return (add,.[],(mul,.[],1000));"); + testCPU(src,"arm" , "SystemV", 5,"return (add,.[],(mul,.[],1000));"); + } + + @Test + public void testAntiDeps1() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/antiDep1.smp")); + testCPU(src,"x86_64_v2", "SystemV", 7,"return mov(mov(S));"); + testCPU(src,"riscv" , "SystemV",10,"return mov(mov(S));"); + testCPU(src,"arm" , "SystemV",10,"return mov(mov(S));"); + } + + @Test + public void testString() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/stringHash.smp")); + testCPU(src,"x86_64_v2", "SystemV", 9,null); + testCPU(src,"riscv" , "SystemV", 3,null); + testCPU(src,"arm" , "SystemV", 3,null); + } + + @Test public void testStringExport() throws IOException { + TestC.run("stringHash", 9); + } + + @Test public void testLoop2() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/loop2.smp")); + testCPU(src,"x86_64_v2", "Win64" ,0,"return (inc,Phi(Loop,0,inc));"); + testCPU(src,"riscv" , "SystemV",0,"return ( Phi(Loop,0,addi) + #1 );"); + testCPU(src,"arm" , "SystemV",0,"return (inc,Phi(Loop,0,inc));"); + } + + @Test public void testNewtonExport() throws IOException { + String result = """ +0 0.000000 (0) +1 1.000000 (0) +2 1.414214 (2.22045e-16) +3 1.732051 (0) +4 2.000000 (0) +5 2.236068 (0) +6 2.449490 (0) +7 2.645751 (0) +8 2.828427 (4.44089e-16) +9 3.000000 (0) +"""; + TestC.run("newtonFloat",result,34); + + EvalRisc5 R5 = TestRisc5.build("newtonFloat", 0, 10, false); + R5.fregs[riscv.FA0 - riscv.F_OFFSET] = 3.0; + int trap_r5 = R5.step(1000); + assertEquals(0,trap_r5); + // Return register A0 holds fib(8)==55 + assertEquals(1.732051,R5.fregs[riscv.FA0 - riscv.F_OFFSET], 0.00001); + + // arm + EvalArm64 A5 = TestArm64.build("newtonFloat", 0, 10, false); + A5.fregs[arm.D0 - arm.D_OFFSET] = 3.0; + int trap_arm = A5.step(1000); + assertEquals(0,trap_arm); + assertEquals(1.732051, A5.fregs[arm.D0 - arm.D_OFFSET], 0.00001); + } + + + @Test public void testSieve() throws IOException { + // The primes + int[] primes = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, }; + SB sb = new SB().p(primes.length).p("["); + for( int prime : primes ) + sb.p(prime).p(", "); + String sprimes = sb.p("]").toString(); + + // Compile, link against native C; expect the above string of primes to be printed out by C + TestC.run("sieve",sprimes, 257); + + // Evaluate on RISC5 emulator; expect return of an array of primes in + // the simulated heap. + EvalRisc5 R5 = TestRisc5.build("sieve", 100, 160, false); + int trap = R5.step(10000); + assertEquals(0,trap); + // Return register A0 holds sieve(100) + int ary = (int)R5.regs[riscv.A0]; + // Memory layout starting at ary(length,pad, prime1, primt2, prime3, prime4) + assertEquals(primes.length, R5.ld4s(ary)); + for( int i=0; i<primes.length; i++ ) + assertEquals(primes[i], R5.ld4s(ary + 4 + i*4)); + + // Evaluate on ARM5 emulator; expect return of an array of primes in + // the simulated heap. + EvalArm64 A5 = TestArm64.build("sieve", 100, 160, false); + int trap_arm = A5.step(10000); + assertEquals(0, trap_arm); + int ary_arm = (int)A5.regs[arm.X0]; + // Memory layout starting at ary(length,pad, prime1, primt2, prime3, prime4) + assertEquals(primes.length, A5.ld4s(ary_arm)); + for( int i = 0; i<primes.length; i++ ) + assertEquals(primes[i], A5.ld4s(ary_arm + 4 + i * 4)); + } + + @Test public void testFibExport() throws IOException { + String fib = "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]"; + TestC.run("fib", fib, 24); + + EvalRisc5 R5 = TestRisc5.build("fib", 9, 17, false); + int trap = R5.step(100); + assertEquals(0,trap); + // Return register A0 holds fib(8)==55 + assertEquals(55,R5.regs[riscv.A0]); + + // arm + EvalArm64 A5 = TestArm64.build("fib", 9, 17, false); + int trap_arm = A5.step(100); + assertEquals(0,trap_arm); + // Return register X0 holds fib(8)==55 + assertEquals(55, A5.regs[arm.X0]); + } + + @Test public void testPerson() throws IOException { + String person = "6\n"; + TestC.run("person", person, 0); + + // Memory layout starting at PS: + int ps = 1<<16; // Person array pointer starts at heap start + // Person[3] = { len,pad,P0,P1,P2 }; // sizeof = 4*8 + // P0 = { age } // sizeof=8 + int p0 = ps+4*8+0*8; + // P1 = { age } // sizeof=8 + int p1 = ps+4*8+1*8; + // P2 = { age } // sizeof=8 + int p2 = ps+4*8+2*8; + EvalRisc5 R5 = TestRisc5.build("person", ps, 0, false); + R5.regs[riscv.A1] = 1; // Index 1 + R5.st8(ps,3); // Length + R5.st8(ps+1*8,p0); + R5.st8(ps+2*8,p1); + R5.st8(ps+3*8,p2); + R5.st8(p0, 5); // age= 5 + R5.st8(p1,17); // age=17 + R5.st8(p2,60); // age=60 + + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals( 5+0,R5.ld8(p0)); + assertEquals(17+1,R5.ld8(p1)); + assertEquals(60+0,R5.ld8(p2)); + + EvalArm64 A5 = TestArm64.build("person", ps, 0, false); + A5.regs[arm.X1] = 1; // Index 1 + A5.st8(ps, 3); + A5.st8(ps+1*8,p0); + A5.st8(ps+2*8,p1); + A5.st8(ps+3*8,p2); + A5.st8(p0, 5); // age= 5 + A5.st8(p1,17); // age=17 + A5.st8(p2,60); // age=60 + + int trap_arm = A5.step(100); + assertEquals(0,trap_arm); + assertEquals( 5+0, A5.ld8(p0)); + assertEquals(17+1, A5.ld8(p1)); + assertEquals(60+0, A5.ld8(p2)); + } + + @Test public void testArgCount() throws IOException { + // Test passes more args than registers in Sys5, which is far far more + // than what Win64 allows - so Win64 gets a lot more spills here. + String arg_count = "191.000000\n"; + TestC.run("arg_count", arg_count, + TestC.CALL_CONVENTION.equals("Win64") ? 42 : 15); + + + EvalRisc5 R5 = TestRisc5.build("no_stack_arg_count", 0, 0, false); + + // Todo: handle stack(imaginary stack in emulator) + // pass in float arguments + R5.fregs[riscv.FA0 - riscv.F_OFFSET] = 1.1; + R5.fregs[riscv.FA1 - riscv.F_OFFSET] = 1.1; + R5.fregs[riscv.FA2 - riscv.F_OFFSET] = 1.1; + R5.fregs[riscv.FA3 - riscv.F_OFFSET] = 1.1; + R5.fregs[riscv.FA4 - riscv.F_OFFSET] = 1.1; + R5.fregs[riscv.FA5 - riscv.F_OFFSET] = 1.1; + R5.fregs[riscv.FA6 - riscv.F_OFFSET] = 1.1; + R5.fregs[riscv.FA7 - riscv.F_OFFSET] = 1.1; + + // a0 is passed in arg + R5.regs[riscv.A1] = 2; + R5.regs[riscv.A2] = 2; + R5.regs[riscv.A3] = 2; + R5.regs[riscv.A4] = 2; + R5.regs[riscv.A5] = 2; + R5.regs[riscv.A6] = 2; + R5.regs[riscv.A7] = 2; + + int trap = R5.step(100); + assertEquals(0,trap); + + double result = R5.fregs[riscv.FA0 - riscv.F_OFFSET]; + + assertEquals(22.8, result, 0.00001); + + // arm + EvalArm64 A5 = TestArm64.build("no_stack_arg_count", 0, 0, false); + + A5.fregs[arm.D0 - arm.D_OFFSET] = 1.1; + A5.fregs[arm.D1 - arm.D_OFFSET] = 1.1; + A5.fregs[arm.D2 - arm.D_OFFSET] = 1.1; + A5.fregs[arm.D3 - arm.D_OFFSET] = 1.1; + A5.fregs[arm.D4 - arm.D_OFFSET] = 1.1; + A5.fregs[arm.D5 - arm.D_OFFSET] = 1.1; + A5.fregs[arm.D6 - arm.D_OFFSET] = 1.1; + A5.fregs[arm.D7 - arm.D_OFFSET] = 1.1; + + A5.regs[arm.X1] = 2; + A5.regs[arm.X2] = 2; + A5.regs[arm.X3] = 2; + A5.regs[arm.X4] = 2; + A5.regs[arm.X5] = 2; + A5.regs[arm.X6] = 2; + A5.regs[arm.X7] = 2; + + int trap_arm = A5.step(100); + assertEquals(0,trap_arm); + + double result1 = A5.fregs[arm.D0 - arm.D_OFFSET]; + assertEquals(22.8, result1, 0.00001); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java new file mode 100644 index 00000000..13322d3d --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java @@ -0,0 +1,240 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import com.seaofnodes.simple.node.cpus.arm.arm; +import com.seaofnodes.simple.node.cpus.riscv.riscv; +import org.junit.Ignore; +import org.junit.Test; +import static org.junit.Assert.*; + +public class Chapter22Test { + + @Test @Ignore + public void testJig() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/jig.smp")); + //String src = Files.readString(Path.of("docs/examples/BubbleSort.smp")); + testCPU(src,"x86_64_v2", "Win64" ,-1,null); + testCPU(src,"riscv" , "SystemV",-1,null); + testCPU(src,"arm" , "SystemV",-1,null); + } + + static CodeGen testCPU( String src, String cpu, String os, int spills, String stop ) { + CodeGen code = new CodeGen(src).driver(CodeGen.Phase.Encoding,cpu,os); + int delta = spills>>3; + if( delta==0 ) delta = 1; + if( spills != -1 ) + assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); + if( stop != null ) + assertEquals(stop, code._stop.toString()); + return code; + } + + + static int testCPUSize( String src, String cpu, String os, int spills, String stop ) { + return testCPU(src,cpu,os,spills,stop)._encoding._bits.size(); + } + + // Should not fold away + @Test public void testSextFail() throws IOException { + String src = """ +struct Person { i32 age;}; +Person !p = new Person; +p.age = (arg<<17)>>17; +return 0; +"""; + assertEquals(46, testCPUSize(src, "x86_64_v2","Win64",2,"return 0;")); + assertEquals(60, testCPUSize(src, "riscv","SystemV",4,"return 0;")); + assertEquals(56, testCPUSize(src, "arm","SystemV",4,"return 0;")); + + // do assertEquals here + EvalRisc5 R5 = TestRisc5.build("sext_str_not_fold_away", 0, 4, false); + int trap = R5.step(100); + assertEquals(0,trap); + + EvalArm64 A5 = TestArm64.build("sext_str_not_fold_away", 0, 4, false); + trap = A5.step(100); + assertEquals(0,trap); + + } + + // Should not fold away + @Test public void testSextFail2() throws IOException { + String src = """ + + struct Person { i32 age;}; + Person !p = new Person; + p.age = (arg<<48)>>48; + return 0; + """; + + EvalRisc5 R5 = TestRisc5.build("sext_str_not_fold_away_2", 0, 4, false); + int trap = R5.step(100); + assertEquals(0,trap); + + EvalArm64 A5 = TestArm64.build("sext_str_not_fold_away_2", 0, 4, false); + int trap_arm = A5.step(100); + assertEquals(0,trap_arm); + + assertEquals(46, testCPUSize(src, "x86_64_v2","Win64",2,"return 0;")); + assertEquals(60, testCPUSize(src, "riscv","SystemV",4,"return 0;")); + assertEquals(56, testCPUSize(src, "arm","SystemV",4,"return 0;")); + + } + + // Should fold away + @Test public void testSextSuccess() throws IOException { + String src = """ +// Should fold away sign extend +struct Person { i8 age;}; +Person !p = new Person; +p.age = (arg<<48)>>48; +return 0; + """; + + EvalRisc5 R5 = TestRisc5.build("sext_str_fold_away", 0, 5, false); + int trap = R5.step(100); + assertEquals(0,trap); + + EvalArm64 A5 = TestArm64.build("sext_str_fold_away", 0, 5, false); + int trap_arm = A5.step(100); + assertEquals(0,trap_arm); + + assertEquals(41, testCPUSize(src, "x86_64_v2","Win64",2,"return 0;")); + assertEquals(56, testCPUSize(src, "riscv","SystemV",5,"return 0;")); + assertEquals(52, testCPUSize(src, "arm","SystemV",5,"return 0;")); + // do assertEquals here + } + + + // Int now is changed to 4 bytes. + @Test public void testPerson() throws IOException { + String person = "6\n"; + TestC.run("person", person, 0); + + // Memory layout starting at PS: + int ps = 1<<16; // Person array pointer starts at heap start + // Person[3] = { len,pad,P0,P1,P2 }; // sizeof = 4*8 + // P0 = { age } // sizeof=8 + int p0 = ps+4*8+0*8; + // P1 = { age } // sizeof=8 + int p1 = ps+4*8+1*8; + // P2 = { age } // sizeof=8 + int p2 = ps+4*8+2*8; + EvalRisc5 R5 = TestRisc5.build("person", ps, 0, false); + R5.regs[riscv.A1] = 1; // Index 1 + R5.st8(ps,3); // Length + R5.st8(ps+1*8,p0); + R5.st8(ps+2*8,p1); + R5.st8(ps+3*8,p2); + R5.st8(p0, 5); // age= 5 + R5.st8(p1,17); // age=17 + R5.st8(p2,60); // age=60 + + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals( 5+0,R5.ld8(p0)); + assertEquals(17+1,R5.ld8(p1)); + assertEquals(60+0,R5.ld8(p2)); + + EvalArm64 A5 = TestArm64.build("person", ps, 0, false); + A5.regs[arm.X1] = 1; // Index 1 + A5.st8(ps, 3); + A5.st8(ps+1*8,p0); + A5.st8(ps+2*8,p1); + A5.st8(ps+3*8,p2); + A5.st8(p0, 5); // age= 5 + A5.st8(p1,17); // age=17 + A5.st8(p2,60); // age=60 + + int trap_arm = A5.step(100); + assertEquals(0,trap_arm); + assertEquals( 5+0, A5.ld8(p0)); + assertEquals(17+1, A5.ld8(p1)); + assertEquals(60+0, A5.ld8(p2)); + } + + @Test + public void testCoRecur() { + String src = """ +struct A { B? b; C? c; i64 ax; val az = x*2; }; +struct B { A? a; C? c; f32 bx; val bz = x*3; }; +struct C { A? a; B? b; f64 cx; val cz = x*x; }; +A !aa = new A{ ax=17; }; +B !bb = new B{ bx=3.14; a = aa; }; +C !cc = new C{ cx=2.73; a = aa; b = bb; }; +aa.b = bb; +aa.c = cc; +bb.c = cc; +val x = 5; // aa.az; // Error to self-define forward ref +return cc.cz; +"""; + CodeGen code = new CodeGen(src).parse().opto().typeCheck(); + assertEquals("return 25;", code._stop.toString()); + assertEquals("25", Eval2.eval(code, 0)); + } + + @Test + public void testHelloWorld() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/helloWorld.smp")); + TestC.run(src,TestC.CALL_CONVENTION,null, null,null,"build/objs/helloWorld","","Hello, World!",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("helloWorld", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Hello, World!",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("helloWorld", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Hello, World!",arm._stdout.toString()); + } + + @Test + public void testFinalArray() { + String src = """ +int N=4; +i32[] !is = new i32[N]; +for( int i=0; i<N; i++ ) + is[i] = i*i; +val sum = { i32[~] is -> // final array + int sum=0; + for( int i=0; i<is#; i++ ) + sum += is[i]; + return sum; +}; +return sum(is); +"""; + CodeGen code = new CodeGen(src).parse().opto().typeCheck(); + assertEquals("return Phi(Loop,0,(Phi_sum+.[]));", code._stop.toString()); + assertEquals("14", Eval2.eval(code, 0)); + } + + + @Test @Ignore + public void testEcho() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/echo.smp")); + TestC.run(src,TestC.CALL_CONVENTION,null, null,null,"build/objs/echo","","",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("echo", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("echo", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + } + + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter23Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter23Test.java new file mode 100644 index 00000000..267bb3e0 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter23Test.java @@ -0,0 +1,244 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.cpus.riscv.riscv; +import com.seaofnodes.simple.type.TypeInteger; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.Ignore; +import org.junit.Test; +import static org.junit.Assert.*; + +public class Chapter23Test { + + @Test + public void testJig() throws IOException { + //String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/jig.smp")); + String src = Files.readString(Path.of("docs/examples/BubbleSort.smp")); + testCPU(src,"x86_64_v2", "Win64" ,-1,null); + testCPU(src,"riscv" , "SystemV",-1,null); + testCPU(src,"arm" , "SystemV",-1,null); + } + + + static CodeGen testCPU( String src, String cpu, String os, int spills, String stop ) { + CodeGen code = new CodeGen(src).driver(CodeGen.Phase.Encoding,cpu,os); + int delta = spills>>3; + if( delta==0 ) delta = 1; + if( spills != -1 ) + assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); + if( stop != null ) + assertEquals(stop, code._stop.toString()); + return code; + } + + @Test + public void testOr() throws IOException { + TestC.runS("or1","Or",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("or1", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Or",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("or1", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Or",arm._stdout.toString()); + } + + @Test + public void testAnd() throws IOException { + TestC.runS("and1","And",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("and1", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("And",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("and1", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("And",arm._stdout.toString()); + } + + @Test + public void testAndPtr() throws IOException { + String src = +""" +struct S { S? fld; }; +val ptr = arg == 1 ? null : new S{fld = arg==1 ? null : new S{fld = null;};}; +return ptr && ptr.fld ? "true" : "false"; + """; + CodeGen code = new CodeGen(src).parse().opto().typeCheck(); + assertEquals("[97-117][ 116,114,117,101]", Eval2.eval(code, 0)); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("ptrand", 1, 8, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("false",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("ptrand", 1, 8, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("false",arm._stdout.toString()); + } + + // conditional side effect + @Test + public void testCondSideEffAnd() throws IOException { + TestC.runS("and2","Effected",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("and2", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Effected",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("and2", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Effected",arm._stdout.toString()); + } + + + @Test + public void testCondSideEffOr() throws IOException { + TestC.runS("or2","Effected",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("or2", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Effected",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("or2", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Effected",arm._stdout.toString()); + } + + // test it with function calls + @Test + public void testFuncCall() throws IOException { + TestC.runS("and3","Or",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("and3", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Or",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("and3", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Or",arm._stdout.toString()); + } + + @Test + public void testFRefFields() { + String src = +""" +// A hypothetical scanner class +struct Scan { + int !x; + u8[~] buf; + // Skip whitespace + val skip = { Scan s -> + while( s.buf[s.x] <= ' ' ) + s.x++; + }; + // Peek a character; if matched consume it, else false. + val peek = { Scan s, u8 c -> + skip(s); + if( s.buf[s.x] != c ) return false; + s.x++; + return true; + }; +}; +Scan !s = new Scan{ buf = " q"; }; +return Scan.peek(s,'q'); + """; + + CodeGen code = new CodeGen(src).parse().opto().typeCheck(); + assertEquals("return Phi(Region,0,1);", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 0)); + testCPU(src,"x86_64_v2", "Win64" ,17,null); + }; + + @Test + public void testFRefFields2() { + String src = +""" +// A hypothetical scanner class +struct Scan { + int !x; + u8[~] buf; + // Skip whitespace + val skip = { -> + while( buf[x] <= ' ' ) + x++; + return self; + }; +}; +val s = new Scan{ buf = " q"; }; +return s.skip().x; + """; + + try { new CodeGen(src).parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Argument #0 isa *Scan {i64 x; *[]u8 buf; { *Scan -> *Scan {i64 !x; *[]u8 buf; {21} skip; } #21} skip; }, but must be a *Scan {i64 !x; *[]u8 buf; ... }",e.getMessage()); } + }; + + + @Test + public void testMethod() { + String src = +""" +// A hypothetical scanner class +struct Scan { + int !x; + u8[~] buf; + // Skip whitespace + val skip = { -> + while( buf[x] <= ' ' ) + x++; + }; + val require = { u8 ch -> + skip(); + buf[x++]==ch; + }; +}; +Scan !s = new Scan{ buf = " [1,2]"; }; +return s.require('['); + """; + + CodeGen code = new CodeGen(src).parse().opto().typeCheck(); + assertEquals("return (.[]==91);", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 0)); + testCPU(src,"x86_64_v2", "Win64" ,16,null); + }; + + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter24Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter24Test.java new file mode 100644 index 00000000..1970a228 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter24Test.java @@ -0,0 +1,340 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.cpus.riscv.riscv; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.Test; +import static org.junit.Assert.*; + +public class Chapter24Test { + + @Test + public void testJig() throws IOException { + //String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/jig.smp")); + String src = Files.readString(Path.of("docs/examples/BubbleSort.smp")); + testCPU(src,"x86_64_v2", "Win64" ,-1,null); + testCPU(src,"riscv" , "SystemV",-1,null); + testCPU(src,"arm" , "SystemV",-1,null); + } + + static CodeGen testCPU( String src, String cpu, String os, int spills, String stop ) { + CodeGen code = new CodeGen(src).driver(CodeGen.Phase.Encoding,cpu,os); + int delta = spills>>3; + if( delta==0 ) delta = 1; + if( spills != -1 ) + assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); + if( stop != null ) + assertEquals(stop, code._stop.toString()); + return code; + } + + @Test + public void testOr() throws IOException { + TestC.runS("or1","Or",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("or1", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Or",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("or1", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Or",arm._stdout.toString()); + } + + @Test + public void testAnd() throws IOException { + TestC.runS("and1","And",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("and1", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("And",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("and1", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("And",arm._stdout.toString()); + } + + @Test + public void testAndPtr() throws IOException { + String src = + """ + struct S { S? fld; }; + val ptr = arg == 1 ? null : new S{fld = arg==1 ? null : new S{fld = null;};}; + return ptr && ptr.fld ? "true" : "false"; + """; + CodeGen code = new CodeGen(src).parse().opto().typeCheck(); + assertEquals("[97-117][ 116,114,117,101]", Eval2.eval(code, 0)); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("ptrand", 1, 8, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("false",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("ptrand", 1, 8, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("false",arm._stdout.toString()); + } + + // conditional side effect + @Test + public void testCondSideEffAnd() throws IOException { + TestC.runS("and2","Effected",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("and2", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Effected",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("and2", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Effected",arm._stdout.toString()); + } + + + @Test + public void testCondSideEffOr() throws IOException { + TestC.runS("or2","Effected",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("or2", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Effected",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("or2", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Effected",arm._stdout.toString()); + } + + // test it with function calls + @Test + public void testFuncCall() throws IOException { + TestC.runS("and3","Or",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("and3", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Or",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("and3", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Or",arm._stdout.toString()); + } + + // test it with function calls + @Test + public void testStack1() throws IOException { + TestC.runS("stacked_r_1","In Range",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("stacked_r_1", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("In Range",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("stacked_r_1", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("In Range",arm._stdout.toString()); + } + + @Test + public void testStack2() throws IOException { + TestC.runS("stacked_r_2","In range",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("stacked_r_2", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("In range",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("stacked_r_2", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("In range",arm._stdout.toString()); + } + + @Test + public void testStack3() throws IOException { + TestC.runS("stacked_r_3","In range",3); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("stacked_r_3", 0, 3, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("In range",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("stacked_r_3", 0, 3, false); + int trap_1 = arm.step(100); + assertEquals(0,trap_1); + assertEquals(0,arm.regs[0]); + assertEquals("In range",arm._stdout.toString()); + } + + @Test + public void testStack4() throws IOException { + TestC.runS("stacked_r_4","Out of Range",0); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("stacked_r_4", 0, 2, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("Out of Range",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("stacked_r_4", 0, 2, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("Out of Range",arm._stdout.toString()); + } + + @Test + public void testStack5() throws IOException { + TestC.runS("stacked_r_5","In range",3); + + // Evaluate on RISC5 emulator + EvalRisc5 R5 = TestRisc5.build("stacked_r_5", 0, 5, false); + int trap = R5.step(100); + assertEquals(0,trap); + assertEquals(0,R5.regs[riscv.A0]); + assertEquals("In range",R5._stdout.toString()); + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("stacked_r_5", 0, 5, false); + trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); + assertEquals("In range",arm._stdout.toString()); + } + + + @Test + public void testFRefFields() { + String src = + """ + // A hypothetical scanner class + struct Scan { + int !x; + u8[~] buf; + // Skip whitespace + val skip = { Scan s -> + while( s.buf[s.x] <= ' ' ) + s.x++; + }; + // Peek a character; if matched consume it, else false. + val peek = { Scan s, u8 c -> + skip(s); + if( s.buf[s.x] != c ) return false; + s.x++; + return true; + }; + }; + Scan !s = new Scan{ buf = " q"; }; + return Scan.peek(s,'q'); + """; + + CodeGen code = new CodeGen(src).parse().opto().typeCheck(); + assertEquals("return Phi(Region,0,1);", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 0)); + testCPU(src,"x86_64_v2", "Win64" ,17,null); + }; + + @Test + public void testFRefFields2() { + String src = + """ + // A hypothetical scanner class + struct Scan { + int !x; + u8[~] buf; + // Skip whitespace + val skip = { -> + while( buf[x] <= ' ' ) + x++; + return self; + }; + }; + val s = new Scan{ buf = " q"; }; + return s.skip().x; + """; + + try { new CodeGen(src).parse().opto().typeCheck(); fail(); } + catch( Exception e ) { assertEquals("Argument #0 isa *Scan {i64 x; *[]u8 buf; { *Scan -> *Scan {i64 !x; *[]u8 buf; {21} skip; } #21} skip; }, but must be a *Scan {i64 !x; *[]u8 buf; ... }",e.getMessage()); } + }; + + + @Test + public void testMethod() { + String src = + """ + // A hypothetical scanner class + struct Scan { + int !x; + u8[~] buf; + // Skip whitespace + val skip = { -> + while( buf[x] <= ' ' ) + x++; + }; + val require = { u8 ch -> + skip(); + buf[x++]==ch; + }; + }; + Scan !s = new Scan{ buf = " [1,2]"; }; + return s.require('['); + """; + + CodeGen code = new CodeGen(src).parse().opto().typeCheck(); + assertEquals("return (.[]==91);", code._stop.toString()); + assertEquals("1", Eval2.eval(code, 0)); + testCPU(src,"x86_64_v2", "Win64" ,16,null); + }; + + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Compile.java b/chapter24/src/test/java/com/seaofnodes/simple/Compile.java new file mode 100644 index 00000000..088055f9 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Compile.java @@ -0,0 +1,65 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.FunNode; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import org.junit.Ignore; +import org.junit.Test; +import static org.junit.Assert.*; + +public class Compile { + + private static Process run(String simple, String c) throws IOException, InterruptedException { + boolean USE_WSL = System.getProperty("os.name").startsWith("Windows"); + CodeGen code = new CodeGen(simple); + code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched().regAlloc().encode(); + if (c != null) for (var n:code._start._outputs) if (n instanceof FunNode f && f._name.equals("main")) f._name = "simple_main"; + code.exportELF("test.o"); + var params = new ArrayList<String>(); + if (USE_WSL) params.add("wsl.exe"); + params.add("gcc"); + params.add("-o"); + params.add("test"); + if (c != null) { + Files.writeString(Path.of("test.c"), c); + params.add("test.c"); + } + params.add("test.o"); + Process p = Runtime.getRuntime().exec(params.toArray(String[]::new)); + assertEquals(0, p.waitFor()); + return Runtime.getRuntime().exec(USE_WSL ? new String[]{"wsl.exe", "./test"}:new String[]{"./test"}); + } + + @Test + @Ignore + public void testCompile() throws IOException, InterruptedException { + var p = run(""" + val testMy = { flt x -> + flt guess = x; + while( 1 ) { + flt next = (x/guess + guess)/2; + if( next == guess ) return guess; + guess = next; + } + }; + """,""" + + #include <stdio.h> + + extern double testMy(double); + + int main(int argc, char** argv) { + printf("%f\\n", testMy(2.0)); + return 0; + } + + """); + assertEquals(0, p.waitFor()); + assertEquals("1.414214\n", new String(p.getInputStream().readAllBytes(), StandardCharsets.UTF_8)); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter24/src/test/java/com/seaofnodes/simple/Eval2.java new file mode 100644 index 00000000..094b5143 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Eval2.java @@ -0,0 +1,469 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.print.IRPrinter; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.*; + +public abstract class Eval2 { + + // A mapping from Node ID to evaluation data Object. + // Data Objsts are a boxed Long or Double; or an Object[] of fields, which + // themselves are just more Objects. + private static class Frame { + private static int UID=1; + + private final IdentityHashMap<Node,Object> _data; + private Frame _prior; // Prior frame in this sequence, means when making a new frame we can find old stuff + private int _refcnt; // TODO: Use this in a sentence (free/recycle unused stack frames) + final int _uid = UID++; // Debugging aid + Frame(Frame prior) { + _prior = prior; + if( prior!=null ) prior._refcnt++; + _data = new IdentityHashMap<>(); + _refcnt = 1; + } + + // Dec ref count + void dec() { + assert _refcnt>0; + if( --_refcnt == 0 ) { + Frame prior = _prior; + _prior = null; + _data.clear(); + // TODO: FREE LIST? + if( prior!=null ) + prior.dec(); + } + } + + // Put a mapping from Node->Object + Node put(Node n, Object d) { + assert d!=null; + return put0(n,d); + } + // Put a mapping from Node->Object? + Node put0(Node n, Object d) { + assert _refcnt>0; + _data.put(n,d); + return n; + } + // Get a mapped Node, perhaps using the prior stack frame crawl + Object get(Node n) { + assert _refcnt>0; + Object d = _data.get(n); + return d != null ? d + : _prior == null ? null + : _prior.get(n); + } + + // Short debugging print + public String p() { + return "#"+_uid + (_prior==null ? "" : " >> " + _prior.p()); + } + // Long debugging print + @Override public String toString() { + String s = ""; + if( _prior != null ) s+= _prior+" << "; + s += "#"+_uid+"[ "; + for( Node n : _data.keySet() ) + s += n + ":" + _data.get(n) + ","; + s += "]"; + + return s; + } + } + + // Classic Closure; an environment (stack of frames) and an execution point + private static class Closure { + // Where to return too; either a CallEnd or a Function + final CFGNode _cc; + + // Stack frame at the execution point. Includes Closures which + // recursively include other stack frames + private Frame _frame; + + Closure(CFGNode cc, Frame frame) { + _cc = cc; // One of Fun, CallEnd or Stop (null) + _frame = frame; + assert _frame._refcnt >=0; + _frame._refcnt++; + } + + FunNode fun() { return (FunNode)_cc; } + CallEndNode cend() { return (CallEndNode)_cc; } + boolean isStop() { return _cc instanceof StopNode; } // or Stop + + // + void pushFrame() { + _frame = new Frame(_frame); + _frame._refcnt++; + } + + @Override public String toString() { + return _cc.toString(); + } + } + + // CodeGen has the linker tables + public static CodeGen CODE; + + // Current active Frame, to avoid having to pass it everywhere + public static Frame F; + + public static String eval( CodeGen code, long arg ) { return eval(code,arg,1000); } + public static String eval( CodeGen code, long arg, int timeout ) { + if( code._start.uctrl()==null ) return ""; // The empty program + SB trace = null; // = new SB(); // TRACE, set to null for off, new SB() for on + // Force local scheduling phase + code.driver(CodeGen.Phase.LocalSched); + // Set global, so don't have to pass everywhere + CODE = code; + + // Timer for when we run too long. Ticks once per backedge or function call + int loopCnt = 0; + + // Current value for each Node; boxed Long or Double; or an Object[] of + // fields, which themselves are just more Objects. + F = new Frame(null); + + // Start at the START + CFGNode BB = code._start, prior = null; + // Return from main hits Stop + F.put(BB,new Closure(code._stop,F)); + + + // ------------ + // Evaluate until exit or timeout. Each outer loop step computes + // all data nodes under some new Control. + while( true ) { + assert BB!=null; + traceCtrl(BB,trace); + if( trace!=null ) System.out.println(F.p()); + + // Parallel assign Phis + int i = BB instanceof RegionNode r + ? parallelAssignPhis(r,prior,arg,trace) + : 0; + + // Compute the data nodes until BB control + for( ; i < BB.nOuts(); i++ ) + if( !(BB.out(i) instanceof CFGNode) ) + step(BB.out(i), trace); + + // Find the next control target + prior = BB; + BB = BB.uctrl(); // Next unique control target + switch( prior ) { + case StartNode start: F = new Frame(F); break; // Frame for the call to main, as-if Called + case CallNode call : BB = call(call); break; + case IfNode iff : Object p = val(iff.pred()); BB = iff.cproj( p==null || (p instanceof Long x && x==0L) ? 1 : 0); break; + case ReturnNode ret : if( clj(ret.rpc()).isStop() ) return exit(ret); else BB = ret(ret); break; + case FunNode fun : if( loopCnt++ > timeout ) return null; break; // Timeout + case LoopNode loop : if( loopCnt++ > timeout ) return null; break; // Timeout + case CallEndNode cend: break; + case CProjNode cproj: break; + case RegionNode r : break; + default: throw Utils.TODO(); + } + assert !BB.isDead(); + } + } + + + // Phi cache; size is limited to number of Phis at a merge point + private static final Object[] PHICACHE = new Object[256]; + static int parallelAssignPhis(RegionNode r, CFGNode prior, long arg, SB trace) { + + // Compute input path on Phis for this Region + int path = r._inputs.find( prior ); + // Parameters read from prior frame, Phis from local frame + Frame frame = (r instanceof FunNode ? F._prior : F); + boolean isMain = r instanceof FunNode fun && fun.sig().isa(CodeGen.CODE._main); + + // Parallel assign Phis. First parallel read and cache + int i; + for( i = 0; i < r.nOuts(); i++ ) { + if( !(r.out(i) instanceof PhiNode phi) ) break; + if( isMain && phi instanceof ParmNode parm && parm._idx==2 ) + PHICACHE[i] = arg; // Reading the initial arguments to main() + else { + Node n = phi instanceof ParmNode parm + // RPC reads the Call directly; + // Parms may not be linked, so read call args directly + ? (parm._idx==0 ? prior : prior.in(parm._idx)) + // Phis read from path input + : phi.in(path); + PHICACHE[i] = frame.get(n); + } + } + // Parallel assign; might assign before read, so read from cache + for( int j=0; j < i; j++ ) + traceData(F.put0(r.out(j),PHICACHE[j]),trace); + // Return point in basic block past last Phi + return i; + } + + + // Make a call. + private static CFGNode call( CallNode call ) { + // Set up the Return PC and return frame (which is just the current frame). + // Really making a Continuation, but it's just a Closure + Closure cont = new Closure(call.cend(),F); + // Set the return continuation into the current frame RPC + F.put(call, cont ); + // Next Frame to use + F = new Frame(F); + // Target function and environment + return CODE.link(tfp(call.fptr())); + } + + private static CFGNode ret( ReturnNode ret ) { + // Fetch return expression value and continuation from current frame + Object rez = val(ret.expr()); + Closure cont = clj(ret.rpc()); + // Lower Frame reference count; might delete frame + F.dec(); // Lower ref count + // Install replacement Frame; set return result over the CallEnd + F = cont._frame; + F.put0(cont._cc,rez); // Set return value into CallEnd + return cont._cc; // Return CallEnd as the new control + } + + private static String exit( ReturnNode ret ) { + return prettyPrint(ret.expr()._type,val(ret.expr())); + } + + // Take a worklist step: one data op from the current Control is updated. + private static void step(Node n, SB trace) { + if( n instanceof PhiNode ) return; + // Compute new value + F.put0(n,compute(n)); + traceData(n,trace); + // Also do any following projections, which are not in the local schedule otherwise + if( n instanceof MultiNode ) + for( Node use : n._outputs ) + step(use,trace); + } + + // From here down shamelessly copied from Evaluator, written by @Xmilia + private static Object compute( Node n ) { + return switch( n ) { + case AddFNode adf -> d(adf.in(1)) + d(adf.in(2)); + case AddNode add -> x(add.in(1)) + x(add.in(2)); + case AndNode and -> x(and.in(1)) & x(and.in(2)); + case BoolNode.EQF eqf -> d(eqf.in(1)) == d(eqf.in(2)) ? 1L : 0L; + case BoolNode.LEF lef -> d(lef.in(1)) <= d(lef.in(2)) ? 1L : 0L; + case BoolNode.LTF ltf -> d(ltf.in(1)) < d(ltf.in(2)) ? 1L : 0L; + case BoolNode.EQ eq -> Objects.equals(val(eq.in(1)), val(eq.in(2))) ? 1L : 0L; // Bool EQ supports pointers, nil, and integers + case BoolNode.LE le -> x(le .in(1)) <= x(le .in(2)) ? 1L : 0L; + case BoolNode.LT lt -> x(lt .in(1)) < x(lt .in(2)) ? 1L : 0L; + case CastNode cast -> val(cast.in(1)); + case ConstantNode con -> con(con._con); + case DivFNode dvf -> d(dvf.in(2))==0 ? 0D : d(dvf.in(1)) / d(dvf.in(2)); + case DivNode div -> x(div.in(2))==0 ? 0L : x(div.in(1)) / x(div.in(2)); + case LoadNode ld -> load(ld); + case MinusFNode mnf -> - d(mnf.in(1)); + case MinusNode sub -> - x(sub.in(1)); + case MulFNode mlf -> d(mlf.in(1)) * d(mlf.in(2)); + case MulNode mul -> x(mul.in(1)) * x(mul.in(2)); + case NewNode alloc-> alloc(alloc); + case NotNode not -> x(not.in(1)) == 0 ? 1L : 0L; + case OrNode or -> x(or .in(1)) | x(or .in(2)); + case ProjNode proj -> proj._type instanceof TypeMem ? "$mem" : val(proj.in(0)); + case ReadOnlyNode read -> val(read.in(1)); + case SarNode sar -> x(sar.in(1)) >> x(sar.in(2)); + case MemMergeNode merge-> "$mem"; + case ShlNode shl -> x(shl.in(1)) << x(shl.in(2)); + case ShrNode shr -> x(shr.in(1)) >>>x(shr.in(2)); + case StoreNode st -> store(st); + case SubNode sub -> x(sub.in(1)) - x(sub.in(2)); + case SubFNode sbf -> d(sbf.in(1)) - d(sbf.in(2)); + case ToFloatNode toflt-> (double)x(toflt.in(1)); + case XorNode xor -> x(xor.in(1)) ^ x(xor.in(2)); + default -> throw Utils.TODO(); + }; + } + + // Fetch without unboxing, searching up-Frame + static Object val( Node n ) { return F.get(n); } + // Fetch and unbox as primitive long + static long x( Node n ) { Object d = F.get(n); return d==null ? 0 : (Long)d; } + // Fetch and unbox as primitive double + static double d( Node n ) { Object d = F.get(n); return d==null ? 0 : (Double)d; } + // Fetch and unbox a function constant + static TypeFunPtr tfp(Node n) { return (TypeFunPtr)F.get(n); } + // Fetch and unbox a closure + static Closure clj(Node n) { return (Closure)F.get(n); } + + // Java box ints and floats. Other things can just be null or some informative string + private static Object con( Type t ) { + return switch ( t ) { + case TypeInteger i -> i.isConstant() ? (Long )i.value() : "INT"; + case TypeFloat f -> f.isConstant() ? (Double)f.value() : "FLT"; + case TypeFunPtr tfp -> tfp; + case TypeMem mem -> "MEM"; + case TypeMemPtr tmp -> { + if( tmp._obj.isAry() ) { // Constant array ptr + TypeConAry con = (TypeConAry)tmp._obj.field("[]")._t; + Object[] xs = new Object[con.len()]; + for( int i=0; i<con.len(); i++ ) + xs[i] = con.at8(i); + yield xs; + + } else { + throw Utils.TODO(); // Constant non-array ptr + } + } + default -> null; + }; + } + + // Convert array size to array element count + private static int offToIdx( long off, TypeStruct t) { + off -= t.aryBase(); + int scale = t.aryScale(); + assert (off & ((1L << scale)-1)) == 0; + return (int)(off>>scale); + } + + // Builds and returns a pointer Object + private static Object alloc(NewNode alloc) { + TypeStruct type = alloc._ptr._obj; + if( type.isAry() ) { + long sz = (Long)val(alloc.in(1)); + long x = offToIdx(sz, type); + int n = (int)x; + if( n!=x || n<0 ) + throw new NegativeArraySizeException(""+n); + Object[] ary = new Object[n]; // Array body + var elem = type._fields[1]._t; + if (elem instanceof TypeInteger) { + Arrays.fill( ary, 0L ); + } else if (elem instanceof TypeFloat) { + Arrays.fill( ary, 0D ); + } else { + assert elem instanceof TypeMemPtr || elem instanceof TypeFunPtr; + } + return ary; + } + + int num = type._fields.length; + Object[] ptr = new Object[num]; + for( int i=0; i<num; i++ ) + ptr[i] = con(type._fields[i]._t.makeZero()); + return ptr; + } + + private static Object load( LoadNode ld ) { + Object f = val(ld.ptr()); + // Check for dense constant array + if( f instanceof TypeMemPtr tmp ) { + //assert tmp._obj._con != TypeConAry.BOT; + //if( ld._name.equals("#") ) + // return (long)tmp._obj._con.len(); + //int idx = offToIdx(x(ld.off()),tmp._obj); + //return tmp._obj._con.at(idx); + throw Utils.TODO(); + } + Object[] fs = (Object[])f; + if( ld._name.equals("#") ) + return (long)fs.length; + TypeMemPtr tmp = (TypeMemPtr)ld.ptr()._type; + int idx = tmp._obj.isAry() + ? offToIdx(x(ld.off()),tmp._obj) + : tmp._obj.find(ld._name); + return fs[idx]; + } + + private static Object store( StoreNode st ) { + if( st._name.equals("#") ) + return "$mem"; // Eval stores the length in the java object[], no need to set it now + TypeMemPtr tmp = (TypeMemPtr)st.ptr()._type; + Object[] fs = (Object[])val(st.ptr()); + int idx = tmp._obj.isAry() + ? offToIdx(x(st.off()),tmp._obj) + : tmp._obj.find(st._name); + Object val = val(st.val()); + fs[idx] = val; + return "$mem"; + } + + + // ------------------------------------------------------------------------ + private static final IdentityHashMap<Object,Object> VISIT = new IdentityHashMap<>(); + + + static void traceCtrl( CFGNode BB, SB sb ) { + if( sb==null ) return; + IRPrinter.printLine(BB,sb.p("--- ")); + System.out.print(sb); + sb.clear(); + } + static void traceData( Node n, SB sb ) { + if( sb==null ) return; + IRPrinter.printLine(n,sb).unchar(); + _print( n._type, F.get(n), sb.p('\t'), VISIT ); + System.out.println(sb); + sb.clear(); + VISIT.clear(); + } + + // Use type to print x as a string. Uses a new VISIT table so the debugger + // doesn't try to reuse VISIT if stopping mid-print. The trace code reuses + // VISIT endlessly for some minor speed hope + static String prettyPrint( Type t, Object x ) { return _print(t,x,new SB(), new IdentityHashMap<>()).toString(); } + static SB _print( Type t, Object x, SB sb, IdentityHashMap<Object,Object> visit ) { + if( x instanceof String s ) return sb.p(s); + if( x == null ) return sb.p("null"); + return switch( t ) { + case TypeInteger i -> sb.p( (Long)x); + case TypeFloat f -> sb.p((Double)x); + case TypeMemPtr tmp -> { + if( visit.containsKey(x) ) yield sb.p("$cyclic"); + visit.put(x,x); + assert !tmp.isFRef(); + + Object[] xs = (Object[])x; // Array of fields + if( tmp._obj.isAry() ) { + Type elem = tmp._obj._fields[1]._t; + if( elem == TypeInteger.U8 ) { + // Shortcut u8[] as a String + for( Object o : xs ) + sb.p((char)(long)(Long)o); + } else { + // Array of elements + elem.print(sb).p("[ "); + if( elem instanceof TypeConAry ) elem = TypeInteger.ZERO; + for( Object o : xs ) + _print( elem, o, sb, visit ).p( "," ); + sb.unchar().p("]"); + } + } else { + sb.p(tmp._obj._name).p("{"); + Field[] flds = tmp._obj._fields; + for( int i=0; i<flds.length; i++ ) + _print( flds[i]._t,xs[i], sb.p(flds[i]._fname).p("="), visit ).p(","); + sb.unchar().p("}"); + } + yield sb; + } + case TypeFunPtr tfp -> sb.p(x.toString()); + case TypeRPC rpc -> sb.p(x.toString()); + case TypeMem mem -> sb.p("$mem"); + case TypeTuple tt -> { + if( tt._types.length>1 && tt._types[1] instanceof TypeMemPtr ) + // Assume a NewNode + yield _print( tt._types[1], x, sb, visit ); + throw Utils.TODO(); + } + case Type tt -> { + if( tt == Type.NIL ) yield sb.p("null"); + throw Utils.TODO(); + } + }; + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/EvalArm64.java b/chapter24/src/test/java/com/seaofnodes/simple/EvalArm64.java new file mode 100644 index 00000000..078bc9e8 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/EvalArm64.java @@ -0,0 +1,769 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.node.cpus.arm.arm; +import com.seaofnodes.simple.util.Utils; +import java.io.ByteArrayOutputStream; + +public class EvalArm64 { + // Memory image, always 0-based + public final byte[] _buf; + + // GPRs + final long[] regs; + // FRs + final double[] fregs; + + int _pc; + + // Start of free memory for allocation + int _heap; + + // Standard out and err streams + ByteArrayOutputStream _stdout, _stderr; + + // Cycle counters + int _cycle; + + // flags + boolean N = false; + boolean Z = false; + boolean C = false; + boolean V = false; + + EvalArm64(byte[] buf, int stackSize) { + _buf = buf; + regs = new long[32]; + fregs = new double[32]; + // Stack grows down, heap grows up + regs[arm.RSP] = _heap = stackSize; + _pc = 0; + } + + // Little endian + public int ld1s(int x) { return _buf[x ] ; } + public int ld1z(int x) { return _buf[x ]&0xFF; } + public int ld2s(int x) { return ld1z(x) | ld1s(x+1)<< 8; } + public int ld2z(int x) { return ld1z(x) | ld1z(x+1)<< 8; } + public int ld4s(int x) { return ld2z(x) | ld2s(x+2)<<16; } + public long ld8 (int x) { return (long)ld4s(x)&0xFFFFFFFFL | ((long)ld4s(x+4))<<32; } + + + public float ld4f(int x) { return Float.intBitsToFloat(ld4s(x)); } + public double ld8f(int x) { return Double.longBitsToDouble(ld8(x)); } + + public void st1(int x, int val) { _buf[x] = (byte)val; } + public void st2(int x, int val) { st1(x,val); st1(x+1,val>> 8); } + public void st4(int x, int val) { st2(x,val); st2(x+2,val>>16); } + public void st8(int x, long val) { st4(x,(int)val); st2(x+4,(int)(val>>32)); } + + public int step(int maxops) { + int trap = 0; + long rval = 0; + double frval = 0; + int pc = _pc; + int cycle = _cycle; + boolean is_f = false; + outer: + for(int icount = 0; icount < maxops; icount++) { + int ir = 0; + rval = 0; + frval = 0; + cycle++; + if( pc >= _buf.length ) { + trap = 1 + 1; // Handle access violation on instruction read. + break; + } + if( (pc & 3)!=0 ) { + trap = 1; // Handle PC-misaligned access + break; + } + + // Load instruction from image buffer at PC + ir = ld4s( pc ); + + int rdid = ir & 0x1f; + // [31:24] + int opcode1 = (ir >> 24) & 0xFF; + + // for the opcode we just match for bits[31:24]; + switch( opcode1 ) { + case 0x14, 0x15, 0x16, 0x17: { //b + int imm26 = ir << 6 >> 6; + pc = pc + (imm26 * 4) - 4; + rdid = -1; + break; + } + case 0x1E: { // floats + is_f = true; + int rs1 = (ir >> 5) & 0x1F; + int rs2 = (ir >> 16) & 0x1F; + + int op = (ir >> 10) & 0x3F; + switch(op) { + case 16: frval = fregs[rs1]; break; // fmov + case 10:frval = fregs[rs1] + fregs[rs2]; break; // fadd + + case 6: if (fregs[rs2] == 0) frval = 0; else frval = fregs[rs1] / fregs[rs2]; break; // fdiv + case 8: { + // fcmp + double lhs = fregs[rs1]; + double rhs = fregs[rs2]; + + Z = (lhs == rhs); + N = (lhs < rhs); + C = lhs >= rhs; + V = Double.isNaN(lhs) || Double.isNaN(rhs); + rdid = -1; + + break; + } + case 2: frval = fregs[rs1] * fregs[rs2]; break; // fmul + case 14: frval = fregs[rs1] - fregs[rs2]; break; // fsub + default: trap = (2+1); + } + break; + } + + case 0x38: { + // STRB/LDRB(register) + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + // full opcode + opcode1 = (ir >> 21) & 0x7FF; + switch( ir >> 21 & 0x7 ) { + case 0x1 -> { // store + if( opcode1 == arm.OP_STORE_R_8 ) st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]); + else trap = (2+1); + rdid = -1; + } + case 0x3 -> { // load + if( opcode1 == arm.OP_LOAD_R_8 ) rval = ld1s((int)regs[rn] + (int)regs[rm]); + else trap = (2+1); + } + default -> trap = (2+1); + } + break; + } + case 0x39: { + // STRB/LDRB(immediate) + // str/ldr(immediate) + // rn + int base = ir >> 5 & 0x1F; + int imm = (ir >> 10) & 0xFFF; + rval = regs[base] + imm; + int opc = (ir >> 22) & 0x3; + // full opcode + opcode1 = (ir >> 22) & 0x3FF; + + switch(opc) { + case 0x0: { + // store + if(opcode1 == arm.OP_STORE_IMM_8) { + st1((int)rval, (int)regs[rdid]); + } else trap = (2+1); + rdid = -1; + + break; + } + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OP_LOAD_IMM_8) { + rval = ld1s((int)rval); + } else trap = (2+1); + rdid = -1; + break; + } + default: trap = (2+1); + } + break; + } + case 0x54: { + // b.cond + int imm19 = ir << 8 >> 13; + imm19 = pc + (imm19 * 4) - 4; + rdid = -1; + + switch(ir & 0xF) { + case 0x0: if(Z) pc = imm19; break; // eq + case 0x1: if(!Z) pc = imm19; break; // ne + case 0x2: if(C) pc = imm19; break; // cs + case 0x3: if(!C) pc = imm19; break; + case 0x4: if(N) pc = imm19; break; // mi + case 0x5: if(!N) pc = imm19; break; // pl + case 0x6: if(V) pc = imm19; break; // vs + case 0x7: if(!V) pc = imm19; break; // vc + case 0x8: if(C && !Z) pc = imm19; break; // hi + case 0x9: if(!C || Z) pc = imm19; break; // ls + case 0xA: if(N == V) pc = imm19; break; // ge + case 0xB: if(N != V) pc = imm19; break; // lt + case 0xC: if(!Z && N == V) pc = imm19; break; // gt + case 0xD: if(Z || N != V) pc = imm19; break; // le + case 0xE: pc = imm19; break; // always executed(al) + default: trap = (2+1); + } + break; + } + + case 0x5c: { + // ldr + is_f = true; + // address = delta + int address = ir << 8 >> 13; + address *= 4; + if(address >= _buf.length-3) trap = (5 + 1); + frval = ld8f(pc + address); + break; + } + + case 0x78: { + // STRH/LDRH(register) + int opc = ir >> 21 & 0x7; + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + // full opcode + opcode1 = (ir >> 21) & 0x7FF; + switch(opc) { + case 0x1: { + // store + if(opcode1 == arm.OP_STORE_R_16) { + st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]); + }else { + trap = (2+1); + } + rdid = -1; + break; + } + case 0x3: { + // load + if(opcode1 == arm.OP_LOAD_R_16) { + rval = ld1s((int)regs[rn] + (int)regs[rm]); + } else { + trap = (2+1); + } + break; + } + default: trap = (2+1); + } + break; + } + + case 0x79: { + // STRH/LDRH(immediate) + int base = ir >> 5 & 0x1F; + int imm = (ir >> 10) & 0xFFF; + imm *= 2; + rval = regs[base] + imm; + int opc = (ir >> 22) & 0x3; + // full opcode + opcode1 = (ir >> 22) & 0x3FF; + + switch(opc) { + case 0x0: { + // store + if(opcode1 == arm.OP_STORE_IMM_16) { + st2((int)rval, (int)regs[rdid]); + } else trap = (2+1); + rdid = -1; + + break; + } + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OP_LOAD_IMM_16) { + rval = ld2s((int)rval); + } else trap = (2+1); + rdid = -1; + break; + } + default: trap = (2+1); + } + break; + } + + case 0x8A: { // AND + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + rval = regs[rn] & regs[rm]; + break; + } + + case 0x8B: { + // add(shifted register) + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + long lhs = regs[rn]; + long rhs = regs[rm]; + rval = lhs + rhs; + break; + } + + case 0x90: { // adrp + int immhi = ( (ir& ~0x1F) << 8 ) >> 8; + int immlo = (ir>>29)& 3; + int imm = ((immhi<<2) | immlo) << 12; + rval = (pc & ~0xFFF) + imm; + break; + } + + case 0x91: { // add(immediate) + int rn = (ir >> 5) & 0x1F; + int immediate = ir << 10 >> 20; + // only hit it twice + rval = regs[rn] + immediate; + break; + } + case 0x92: { // and(immediate) + int imm12 = (ir >> 10) & 0x1FFF; + long immediate = arm.decodeImm12(imm12); + int rn = (ir >> 5) & 0x1F; + rval = regs[rn] & immediate; + break; + } + case 0x93: { + // asr(immediate) + int imm = (ir >> 16) & 0x3F; + int rn = (ir >> 5) & 0x1F; + rval = regs[rn] >> (imm); + break; + } + + case 0x94, 0x95, 0x96, 0x97: { // bl + rval = pc + 4; + regs[arm.X30] = rval; + int imm26 = (ir & 0x03FFFFFF); + int imm = (imm26 << 6) >> 6; + pc = pc + (imm << 2) ; + if( pc == Encoding.SENTINEL_CALLOC ) { + assert (_heap&7) == 0; // 8-byte aligned + long size = regs[arm.X0]*regs[arm.X1]; + size = (size+7) & -8; // 8-byte aligned + regs[arm.X0] = _heap; + _heap += (int)size; + pc = (int)rval; + rdid = -1; + } + if( pc == Encoding.SENTINEL_WRITE ) { + ByteArrayOutputStream baos = switch((int)regs[0]) { + case 1 -> _stdout==null ? (_stdout = new ByteArrayOutputStream()) : _stdout; + case 2 -> _stderr==null ? (_stderr = new ByteArrayOutputStream()) : _stderr; + default -> throw new IllegalArgumentException(); + }; + baos.write(_buf,(int)regs[1],(int)regs[2]); + regs[0] = regs[2]; + pc = (int)rval; + rdid = -1; + } + pc -= 4; + break; + } + + case 0x9A: { + // conditional select(csel) + int rm = (ir >> 16) & 0x1F; + int rn = (ir >> 5) & 0x1F; + boolean cond = switch ((ir >> 12) & 0xF) { + case 0x0 -> Z ; // eq + case 0x1 -> !Z ; // ne + case 0x2 -> C ; // cs + case 0x3 -> !C ; + case 0x4 -> N ; // mi + case 0x5 -> !N ; // pl + case 0x6 -> V ; // vs + case 0x7 -> !V ; // vc + case 0x8 -> ( C && !Z ) ; // hi + case 0x9 -> (!C || Z ) ; // ls + case 0xA -> ( N == V) ; // ge + case 0xB -> ( N != V) ; // lt + case 0xC -> (!Z && N == V) ; // gt + case 0xD -> ( Z || N != V ); // le + case 0xE -> true ; // always + case 0xF -> false ; // never + default -> throw Utils.TODO(); + }; + int reg = cond ? rn : rm; + rval = reg==31 ? 0 : regs[reg]; + if( cond ) rval++; + break; + } + case 0x9B: { // mul + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + rval = regs[rn] * regs[rm]; + break; + } + case 0x9E: { + // scvtf + is_f = true; + int rs1 = (ir >> 5) & 0x1F; + frval = (double)regs[rs1]; + break; + } + + case 0xAA: { + // MOV(register) + int rm = (ir >> 16) & 0x1F; + rval = regs[rm]; + break; + } + + case 0xB8: { + // LDR/STR (register + index) 32 bits + int opc = ir >> 21 & 0x7; + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + // full opcode + opcode1 = (ir >> 21) & 0x7FF; + switch(opc) { + case 0x1: { + if(opcode1 == arm.OP_STORE_R_32) { + st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]); + }else { + trap = (2+1); + } + // store(expected to store the length here) + + rdid = -1; + break; + } + case 0x3: { + // load + if( opcode1 == arm.OP_LOAD_R_32) { + rval = ld4s((int) (regs[rn] + regs[rm])); + } else { + trap = (2+1); + } + break; + } + default: trap = (2+1); + } + + break; + } + + case 0xB9: { + // str/ldr(immediate) 32 bits + int base = ir >> 5 & 0x1F; + int imm = (ir >> 10) & 0xFFF; + imm *= 4; + + rval = regs[base] + imm; + int opc = (ir >> 22) & 0x3; + + opcode1 = (ir >> 22) & 0x3FF; + switch(opc) { + case 0x0: { + // store + if(opcode1 == arm.OP_STORE_IMM_32) { + st4((int)rval, (int)regs[rdid]); + } else trap = (2+1); + + rdid = -1; + break; + } + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OP_LOAD_IMM_32) { + rval = ld4s((int) rval); + } else trap = (2+1); + break; + } + default: trap = (2+1); + } + break; + } + + case 0xBC: { + // LDR/STR (register + index) float 32 bits + int opc = ir >> 21 & 0x7; + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + is_f = true; + // full opcode + opcode1 = (ir >> 21) & 0x7FF; + switch(opc) { + case 0x1: { + if(opcode1 == arm.OPF_STORE_R_32) { + st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]); + }else { + trap = (2+1); + } + // store(expected to store the length here) + + rdid = -1; + break; + } + case 0x3: { + // load + if(opcode1 == arm.OPF_LOAD_R_32) { + frval = ld4f((int) (regs[rn] + regs[rm])); + } else { + trap = (2+1); + } + break; + } + default: trap = (2+1); + } + + break; + } + + case 0xBD: { + // LDR/STR(immediate) 32 bits floats + int base = ir >> 5 & 0x1F; + int imm = (ir >> 10) & 0xFFF; + + imm *= 4; + is_f = true; + rval = regs[base] + imm; + int opc = (ir >> 22) & 0x3; + // full opcode + opcode1 = (ir >> 22) & 0x3FF; + switch(opc) { + case 0x0: { + // store + if(opcode1 == arm.OPF_STORE_IMM_32) { + st4((int)rval, (int)regs[rdid]); + } else trap = (2+1); + + rdid = -1; + break; + } + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OPF_LOAD_IMM_32) { + frval = ld4s((int)rval); + } else trap = (2+1); + break; + } + default: trap = (2+1); + } + break; + } + + case 0xD2: { + // movz + // get immediate + rval = (ir >> 5) & 0x7FFF; + break; + } + + case 0xEB: { + // subs(shifted register) + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + long lhs = regs[rn]; + long rhs = regs[rm]; + rval = lhs - rhs; + + // set flags as a side effect + Z = (rval == 0); + N = (rval < 0); + C = lhs >= rhs; + + boolean sign_lhs = (lhs >>> 63) != 0; + boolean sign_rhs = (rhs >>> 63) != 0; + boolean sign_res = (rval >>> 63) != 0; + V = (sign_lhs != sign_rhs) && (sign_res != sign_lhs); + rdid = -1; + break; + } + + case 0xD3: { + // lsl(immediate) + int imm = (ir >> 16) & 0x3F; + int rn = (ir >> 5) & 0x1F; + rval = regs[rn] << (64 - imm); + break; + } + case 0xD6: { + if( (ir & 0xFFFF) != 0 ) throw Utils.TODO(); + if( ((ir>>16) & 0xFF) != 0x5F ) throw Utils.TODO(); // 0x3F is register call + rdid = -1; + int rn = ir << 22 >> 27; + assert rn == 0; + pc = (int)regs[30]; + // Return to zero breaks simulation + if( pc==0 ) break outer; + pc -= 4; // Undo post-increment + break; + } + + case 0xF1: { + // subs(immediate) + int rn = (ir >> 5) & 0x1F; + int immediate = ir << 10 >> 20; + long lhs = regs[rn]; + + rval = lhs - immediate; + + // set flags as a side effect + Z = (rval == 0); + N = (rval < 0); + C = lhs >= immediate; + + boolean sign_lhs = (lhs >>> 63) != 0; + boolean sign_rhs = (immediate >>> 63) != 0; + boolean sign_res = (rval >>> 63) != 0; + V = (sign_lhs != sign_rhs) && (sign_res != sign_lhs); + rdid = -1; + break; + } + case 0xF8: { + // LDR/STR (register + index) 64 bits + int opc = ir >> 21 & 0x7; + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + // full opcode + opcode1 = (ir >> 21) & 0x7FF; + switch(opc) { + case 0x1: { + if(opcode1 == arm.OP_STORE_R_64) { + st8((int)regs[rn] + (int)regs[rm], regs[rdid]); + }else { + trap = (2+1); + } + // store(expected to store the length here) + + rdid = -1; + break; + } + case 0x3: { + // load + if(opcode1 == arm.OP_LOAD_R_64) { + rval = ld8((int) (regs[rn] + regs[rm])); + } else { + trap = (2+1); + } + break; + } + default: trap = (2+1); + } + + break; + } + case 0xF9: { + // str/ldr(immediate) 64 bits + int base = ir >> 5 & 0x1F; + int imm = (ir >> 10) & 0xFFF; + + imm *= 8; + + rval = regs[base] + imm; + int opc = (ir >> 22) & 0x3; + // full opcode + opcode1 = (ir >> 22) & 0x3FF; + switch(opc) { + case 0x0: { + // store + if(opcode1 == arm.OP_STORE_IMM_64) { + st8((int)rval, regs[rdid]); + } else trap = (2+1); + + rdid = -1; + break; + } + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OP_LOAD_IMM_64) { + rval = ld8((int)rval); + } else trap = (2+1); + break; + } + default: trap = (2+1); + } + break; + } + + case 0xFC: { + // LDR/STR (register + index) float 64 bits + int opc = ir >> 21 & 0x7; + int rn = (ir >> 5) & 0x1F; + int rm = (ir >> 16) & 0x1F; + is_f = true; + // full opcode + opcode1 = (ir >> 21) & 0x7FF; + switch(opc) { + case 0x1: { + if(opcode1 == arm.OPF_STORE_R_64) { + st8((int)regs[rn] + (int)regs[rm], (int)regs[rdid]); + }else { + trap = (2+1); + } + // store(expected to store the length here) + + rdid = -1; + break; + } + case 0x3: { + // load + if(opcode1 == arm.OPF_LOAD_R_64) { + frval = ld8f((int) (regs[rn] + regs[rm])); + } else { + trap = (2+1); + } + break; + } + default: trap = (2+1); + } + + break; + } + case 0xFD: { + // LDR/STR(immediate) 64 bits floats + int base = ir >> 5 & 0x1F; + int imm = (ir >> 10) & 0xFFF; + + imm *= 4; + is_f = true; + rval = regs[base] + imm; + int opc = (ir >> 22) & 0x3; + // full opcode + opcode1 = (ir >> 22) & 0x3FF; + switch(opc) { + case 0x0: { + // store + if(opcode1 == arm.OPF_STORE_IMM_64) { + st8((int)rval, regs[rdid]); + } else trap = (2+1); + + rdid = -1; + break; + } + case 0x1: { + // LDR (immediate) + if(opcode1 == arm.OPF_LOAD_IMM_64) { + frval = ld8((int)rval); + } else trap = (2+1); + break; + } + default: trap = (2+1); + } + break; + } + + default: trap = (2+1); + } + + if(trap != 0) { + _pc = pc; + break; + } + if(rdid != -1) { + if(is_f) {fregs[rdid] = frval; is_f = false;} + else regs[rdid] = rval; + } + + pc += 4; + } + // Handle traps and interrupts. + if(trap != 0) { + return trap; + } + _cycle = cycle; + _pc = pc; + return 0; + } + + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/chapter24/src/test/java/com/seaofnodes/simple/EvalRisc5.java new file mode 100644 index 00000000..8c0a8792 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/EvalRisc5.java @@ -0,0 +1,368 @@ + package com.seaofnodes.simple; + +/** Simple RISC5 CPU Emulator + * + * Original works credit Charles Lohr. + * This is a complete rewrite in Java. + * + * Load code into memory and go! + */ + +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.node.cpus.riscv.riscv; +import com.seaofnodes.simple.util.Utils; +import java.io.ByteArrayOutputStream; +import java.util.Arrays; + +public class EvalRisc5 { + + // Memory image, always 0-based + public final byte[] _buf; + + // GPRs + final long[] regs; + // FRs + final double[] fregs; + // PC + int _pc; + + // Start of free memory for allocation + int _heap; + + // Standard out and err streams + ByteArrayOutputStream _stdout, _stderr; + + // Cycle counters + int _cycle; + + EvalRisc5( byte[] buf, int stackSize ) { + _buf = buf; + regs = new long[32]; + fregs = new double[32]; + // Stack grows down, heap grows up + regs[riscv.RSP] = _heap = stackSize; + _pc = 0; + } + + // Little endian + public int ld1s(int x) { return _buf[x ] ; } + public int ld1z(int x) { return _buf[x ]&0xFF; } + public int ld2s(int x) { return ld1z(x) | ld1s(x+1)<< 8; } + public int ld2z(int x) { return ld1z(x) | ld1z(x+1)<< 8; } + public int ld4s(int x) { return ld2z(x) | ld2s(x+2)<<16; } + public long ld8 (int x) { return (long)ld4s(x)&0xFFFFFFFFL | ((long)ld4s(x+4))<<32; } + + public float ld4f(int x) { return Float.intBitsToFloat(ld4s(x)); } + public double ld8f(int x) { return Double.longBitsToDouble(ld8(x)); } + + + public void st1(int x, int val) { _buf[x] = (byte)val; } + public void st2(int x, int val) { st1(x,val); st1(x+1,val>> 8); } + public void st4(int x, int val) {st2(x,val); st2(x+2,val>>16); } + public void st8(int x, long val) { st4(x,(int)val); st2(x+4,(int)(val>>32)); } + + // Note: only a few bits are used. (Machine = 3, User = 0) + // Bits 0..1 = privilege. + // Bit 2 = WFI (Wait for interrupt) + // Bit 3+ = Load/Store reservation LSBs. + int _extraflags; + + public int step( int maxops ) { + int trap = 0; + long rval = 0; + double frval = 0; + int pc = _pc; + int cycle = _cycle; + boolean is_f = false; + outer: + for( int icount = 0; icount < maxops; icount++ ) { + int ir = 0; + rval = 0; + cycle++; + + if( pc >= _buf.length ) { + trap = 1 + 1; // Handle access violation on instruction read. + break; + } + if( (pc & 3)!=0 ) { + trap = 1; // Handle PC-misaligned access + break; + } + // Load instruction from image buffer at PC + ir = ld4s( pc ); + int rdid = (ir >> 7) & 0x1f; + + switch( ir & 0x7f ) { + case 0x37: // LUI (0b0110111) + rval = ( ir & 0xfffff000 ); + break; + case 0x17: // AUIPC (0b0010111) + rval = pc + ( ir & 0xfffff000 ); + break; + case 0x6F: { // JAL (0b1101111) + int reladdy = ((ir & 0x80000000)>>11) | ((ir & 0x7fe00000)>>20) | ((ir & 0x00100000)>>9) | ((ir&0x000ff000)); + if( (reladdy & 0x00100000)!=0 ) reladdy |= 0xffe00000; // Sign extension. + rval = pc + 4; + pc = pc + reladdy - 4; + if( pc+4 == Encoding.SENTINEL_WRITE ) { + ByteArrayOutputStream baos = switch((int)regs[10]) { + case 1 -> _stdout==null ? (_stdout = new ByteArrayOutputStream()) : _stdout; + case 2 -> _stderr==null ? (_stderr = new ByteArrayOutputStream()) : _stderr; + default -> throw new IllegalArgumentException(); + }; + baos.write(_buf,(int)regs[11],(int)regs[12]); + regs[10] = regs[12]; + rdid = 0; + pc = (int)(rval - 4); // Unwind PC, as-if returned from write + } + break; + } + case 0x67: { // JALR (0b1100111) + int imm_se = ir >> 20; // Sign extend 12 bits + rval = pc + 4; + pc = ((int)regs[ (ir >> 15) & 0x1f ] + imm_se) & ~1; + // Return from top-level ; exit sim + if( pc==0 ) { + if( rdid!=0 ) regs[rdid] = rval; // Write PC into register before exit + break outer; + } + // Inline CALLOC effect + if( pc == Encoding.SENTINEL_CALLOC ) { + assert (_heap&7) == 0; // 8-byte aligned + int size = (int)(regs[10]*regs[11]); + size = (size+7) & -8; // 8-byte aligned + regs[10] = _heap; // Return next free address + _heap += size; + pc = (int)(rval - 4); // Unwind PC, as-if returned from calloc + } else + pc -= 4; + break; + } + case 0x63: { // Branch (0b1100011) + int immm4 = ((ir & 0xf00)>>7) | ((ir & 0x7e000000)>>20) | ((ir & 0x80) << 4) | ((ir >> 31)<<12); + if( (immm4 & 0x1000)!=0 ) immm4 |= 0xffffe000; + long rs1 = regs[(ir >> 15) & 0x1f]; + long rs2 = regs[(ir >> 20) & 0x1f]; + immm4 = pc + immm4 - 4; + rdid = 0; + if( switch( (ir >> 12) & 0x7 ) { + case 0 -> rs1 == rs2; + case 1 -> rs1 != rs2; + case 4 -> rs1 < rs2; + case 5 -> rs1 >= rs2; + case 6 -> Long.compareUnsigned(rs1,rs2) < 0; //BLTU + case 7 -> Long.compareUnsigned(rs1,rs2) >= 0; //BGEU + default -> { trap = (2+1); yield false; } + } ) pc = immm4; + break; + } + case 0x03: { // Load (0b0000011) + int rs1 = (int)regs[(ir >> 15) & 0x1f]; // Address chop to 32b + int imm = ir >> 20; + int imm_se = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0 ); + int rsval = rs1 + imm_se; + + if( rsval >= _buf.length-3 ) { + trap = (5+1); + rval = rsval; + } else { + switch( ( ir >> 12 ) & 0x7 ) { + //LB, LH, LW, LBU, LHU + case 0: rval = ld1s( rsval ); break; + case 1: rval = ld2s( rsval ); break; + case 2: rval = ld4s( rsval ); break; + case 3: rval = ld8 ( rsval ); break; + case 4: rval = ld1z( rsval ); break; + case 5: rval = ld2z( rsval ); break; + case 6: rval = ld4s( rsval ); break; + default: trap = (2+1); + } + } + break; + } + // floats + case 0x7: { + is_f = true; + int rs1 = (int)regs[(ir >> 15) & 0x1f]; // Address chop to 32b + int imm = ir >> 20; + int imm_se = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0 ); + int rsval = rs1 + imm_se; + + if( rsval >= _buf.length-3 ) { + trap = (5+1); + rval = rsval; + } else { + switch( ( ir >> 12 ) & 0x7 ) { + case 2: frval = ld4f( rsval ); break; + case 3: frval = ld8f( rsval ); break; + default: trap = (2+1); + } + } + break; + } + + case 0x23: { // Store 0b0100011 + int rs1 = (int)regs[(ir >> 15) & 0x1f]; // Address chop to 32b + long rs2 = regs[(ir >> 20) & 0x1f]; + int addy = ( ( ir >> 7 ) & 0x1f ) | ( ( ir & 0xfe000000 ) >> 20 ); + if( (addy & 0x800)!=0 ) addy |= 0xfffff000; + addy += rs1; + rdid = 0; + if( addy >= _buf.length-3 ) { + trap = (7+1); // Store access fault. + rval = addy; + } else { + switch( ( ir >> 12 ) & 0x7 ) { //SB, SH, SW + case 0: st1( addy, (int)rs2 ); break; + case 1: st2( addy, (int)rs2 ); break; + case 2: st4( addy, (int)rs2 ); break; + case 3: st8( addy, rs2 ); break; + default: trap = (2+1); + } + } + break; + } + case 0x13: // Op-immediate 0b0010011 + case 0x33: { // Op 0b0110011 + int imm = ir >> 20; + imm = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0); + long rs1 = regs[(ir >> 15) & 0x1f]; + boolean is_reg = (ir & 0x20)!=0; + long rs2 = is_reg ? regs[imm & 0x1f] : imm; + + // Insert the detection here + int rs1id = (ir >> 15) & 0x1f; + int funct3 = (ir >> 12) & 0x7; + + if( is_reg && ( ir & 0x02000000 )!=0 ) { + switch( (ir>>12)&7 ) { //0x02000000 = RV32M + case 0: rval = rs1 * rs2; break; // MUL + case 1: rval = (int)((long)((int)rs1) * (long)((int)rs2)) >> 32; break; // MULH + case 2: rval = (int)((long)((int)rs1) * (long)rs2) >> 32; break; // MULHSU + case 3: rval = (int)((long)rs1 * (long)rs2) >> 32; break; // MULHU + case 4: if( rs2 == 0 ) rval = -1; else rval = ((int)rs1 == Integer.MIN_VALUE && (int)rs2 == -1) ? rs1 : ((int)rs1 / (int)rs2); break; // DIV + case 5: if( rs2 == 0 ) rval = 0xffffffff; else rval = rs1 / rs2; break; // DIVU + case 6: if( rs2 == 0 ) rval = rs1; else rval = ((int)rs1 == Integer.MIN_VALUE && (int)rs2 == -1) ? 0 : ((int)((int)rs1 % (int)rs2)); break; // REM + case 7: if( rs2 == 0 ) rval = rs1; else rval = rs1 % rs2; break; // REMU + } + } else { + rval = switch( (ir >> 12) & 7 ) { // These could be either op-immediate or op commands. Be careful. + case 0 -> (is_reg && (ir & 0x40000000) != 0) ? (rs1 - rs2) : (rs1 + rs2); + case 1 -> rs1 << (rs2 & 0x3F); + case 2 -> (rs1 < rs2) ? 1 : 0; + case 3 -> (rs1 < rs2) ? 1 : 0; + case 4 -> rs1 ^ rs2; + case 5 -> (ir & 0x40000000) != 0 ? (rs1 >>> (rs2 & 0x3F)) : (rs1 >> (rs2 & 0x3F)); + case 6 -> rs1 | rs2; + case 7 -> rs1 & rs2; + default -> rval; + }; + } + break; + } + case 0x0f: // 0b0001111 + rdid = 0; // fencetype = (ir >> 12) & 0b111; We ignore fences in this impl. + break; + case 0x73: // Zifencei+Zicsr (0b1110011) + trap = (2+1); // Note micrrop 0b100 == undefined. + break; + + case 0x2f: { // RV32A (0b00101111) + long rs1 = regs[(ir >> 15) & 0x1f]; + long rs2 = regs[(ir >> 20) & 0x1f]; + int irmid = ( ir>>27 ) & 0x1f; + + // We don't implement load/store from UART or CLNT with RV32A here. + if( rs1 >= _buf.length-3 ) { + trap = (7+1); //Store/AMO access fault + rval = rs1; + } else { + rval = ld4s( (int)rs1 ); + + // Referenced a little bit of https://github.com/franzflasch/riscv_em/blob/master/src/core/core.c + boolean dowrite = true; + switch( irmid ) { + case 2: //LR.W (0b00010) + dowrite = false; + _extraflags = (_extraflags & 0x07) | (int)(rs1<<3); + break; + case 3: { //SC.W (0b00011) (Make sure we have a slot, and, it's valid) + boolean xflag = _extraflags >> 3 != ( rs1 & 0x1fffffff ); + rval = xflag ? 1 : 0; // Validate that our reservation slot is OK. + dowrite = !xflag; // Only write if slot is valid. + break; + } + case 0: rs2 += rval; break; // AMOADD.W (0b00000) + case 1: break; // AMOSWAP.W (0b00001) + case 4: rs2 ^= rval; break; // AMOXOR.W (0b00100) + case 8: rs2 |= rval; break; // AMOOR.W (0b01000) + case 12: rs2 &= rval; break; // AMOAND.W (0b01100) + case 16: rs2 = Math.min( rs2, rval ); break; //AMOMIN.W (0b10000) + case 20: rs2 = Math.max( rs2, rval ); break; //AMOMAX.W (0b10100) + case 24: rs2 = Math.min( rs2, rval ); break; //AMOMINU.W (0b11000) + case 28: rs2 = Math.max( rs2, rval ); break; //AMOMAXU.W (0b11100) + default: trap = (2+1); dowrite = false; break; //Not supported. + } + if( dowrite ) st4( (int)rs1, (int)rs2 ); + } + break; + } + + case 0x53: { + is_f = true; + int rs1 = (ir >> 15) & 0x1F; + int rs2 = (ir >> 20) & 0x1F; + double lhs = fregs[rs1]; + double rhs = fregs[rs2]; + int func5 = (ir >> 27) & 0x1F; + int func2 = (ir >> 25) & 0x3; + if( func2 != 1 ) throw Utils.TODO(); // 1==double + switch( func5 ) { + case 0: frval = lhs + rhs; break; // fadd.d + case 1: frval = lhs - rhs; break; // fsub.d + case 2: frval = lhs * rhs; break; // fmul.d + case 3: frval = lhs / rhs; break; // fdiv.d + case 5: frval = Math.min(lhs,rhs); break; // fmin.d, also used for move + case 20: + is_f = false; // Output into a GPR + rval = switch( (ir >> 12) & 7 ) { + case 0 -> lhs <= rhs ? 1 : 0; + case 1 -> lhs == rhs ? 1 : 0; + case 2 -> lhs < rhs ? 1 : 0; + default -> throw Utils.TODO(); + }; + break; + case 26: frval = (double)regs[rs1]; break; // fcvt.w.d + default: + trap = (2+1); // Fault: Invalid opcode. + throw Utils.TODO(); + } + break; + } + + default: trap = (2+1); // Fault: Invalid opcode. + } + + // If there was a trap, do NOT allow register writeback. + if( trap!=0 ) { + _pc = pc; + break; + } + + if( rdid!=0 || is_f) { + if(is_f) {fregs[rdid] = frval; is_f = false;} // Write back register. + else regs[rdid] = rval; // Write back register. + } + + pc += 4; + } + + // Handle traps and interrupts. + if( trap!=0 ) + return trap; + + _cycle = cycle; + _pc = pc; + return 0; + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/FuzzerWrap.java b/chapter24/src/test/java/com/seaofnodes/simple/FuzzerWrap.java new file mode 100644 index 00000000..d67b2065 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/FuzzerWrap.java @@ -0,0 +1,43 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.fuzzer.Fuzzer; +import java.util.Random; +import org.junit.Ignore; +import org.junit.Test; +import static org.junit.Assert.assertTrue; + +/** + * To use the fuzzer run the <code>fuzzPeeps</code> methods. + * This can be done from IntelliJ Gui or remove the `@Ignore` annotation and start the test case from the command line + * via <code>mvn clean test -Dtest=com.seaofnodes.simple.Fuzzer08Test#fuzzPeeps</code> + */ +public class FuzzerWrap { + + @Ignore + @Test + public void fuzzPeeps() { + var fuzzer = new Fuzzer(); + for (int i=0; i<1000000; i++) + fuzzer.fuzzPeeps(i); + assertTrue(fuzzer.noExceptions()); + } + + + @Test + public void fuzzPeepsSmall() { + Random R = new Random(System.currentTimeMillis()); + var fuzzer = new Fuzzer(); + for (int i=0; i<100; i++) + fuzzer.fuzzPeeps( R.nextLong()); + assertTrue(fuzzer.noExceptions()); + } + + @Test + @Ignore + public void fuzzPeepTiming() { + var fuzzer = new Fuzzer(); + int max_nid=0; + for (int i=0; i<1000000; i++) + max_nid = fuzzer.fuzzPeepTiming(i, max_nid); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Main.java b/chapter24/src/test/java/com/seaofnodes/simple/Main.java new file mode 100644 index 00000000..589c043b --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Main.java @@ -0,0 +1,18 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import java.nio.file.Files; +import java.nio.file.Path; + +public class Main { + // Compile and run a simple program + public static void main( String[] args ) throws Exception { + // First arg is file, 2nd+ args are program args + String src = Files.readString(Path.of(args[0])); + int arg = Integer.valueOf(args[1]); + CodeGen code = new CodeGen(src); + code.parse().opto().typeCheck().GCM().localSched(); + System.out.println(code._stop); + System.out.println(Eval2.eval(code,arg,100000)); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/MergeSortTest.java b/chapter24/src/test/java/com/seaofnodes/simple/MergeSortTest.java new file mode 100644 index 00000000..65eb525c --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/MergeSortTest.java @@ -0,0 +1,45 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.cpus.riscv.riscv; +import com.seaofnodes.simple.util.SB; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class MergeSortTest { + + @Test public void testMergeSort0() throws IOException { + int[] primes = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, }; + SB sb = new SB().p(primes.length).p("["); + for( int prime : primes ) + sb.p(prime).p(", "); + String sprimes = sb.p("]").toString(); + TestC.run("sort", sprimes, 40); + + + EvalRisc5 R5 = TestRisc5.build("src/test/java/com/seaofnodes/simple/progs", "sort", "merge_sort", 0, 36, false); + // Allocate an array of primes, filled in reverse order + int ps = R5._heap; + R5._heap += (primes.length+1)*8; // 25 primes, and length + R5.st4(ps,primes.length); + for( int i=0; i<primes.length; i++ ) + R5.st8(ps+(primes.length-1-i+1)*8,primes[i]); + // Pass array base when calling `merge_sort` + R5.regs[riscv.A0] = ps; // Array base to be sorted + + int trap = R5.step(100000); + assertEquals(0,trap); + + assertEquals(primes.length,R5.ld4s(ps)); + for( int i=0; i<primes.length; i++ ) + assertEquals(primes[i], R5.ld8(ps+(i+1)*8)); + + // TODO: replace with ARM Eval + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/sort.smp")); + Chapter21Test.testCPU(src,"arm", "SystemV",36,null); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/SchedulerTest.java b/chapter24/src/test/java/com/seaofnodes/simple/SchedulerTest.java new file mode 100644 index 00000000..ca29bf84 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/SchedulerTest.java @@ -0,0 +1,74 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.evaluator.Evaluator; +import com.seaofnodes.simple.node.StopNode; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class SchedulerTest { + + private static void assertObj(Object obj, String name, Object... fields) { + assertEquals(Evaluator.Obj.class, obj.getClass()); + var o = (Evaluator.Obj)obj; + assertEquals(name, o.struct()._name); + Assert.assertArrayEquals(fields, o.fields()); + } + + @Test + @Ignore + public void testJig() { + CodeGen code = new CodeGen(""" +struct S { + int f; +} +S !v=new S; +v.f = 2; +int i=v.f; +if (arg) v.f=1; +return i; +"""); + code.parse();//.opto(); + var eval = new Evaluator(code._stop); + assertEquals(2L, eval.evaluate(1, 10)); + } + + @Test + public void testStoreInIf() { + CodeGen code = new CodeGen(""" +struct S { + int f; +}; +S !v0=new S; +if(arg) v0.f=1; +return v0; +"""); + code.parse().opto(); + var eval = new Evaluator(code._stop); + assertObj(eval.evaluate(0, 10), "S", 0L); + assertObj(eval.evaluate(1, 10), "S", 1L); + } + + @Test + public void testStoreInIf2() { + CodeGen code = new CodeGen(""" +struct S { + int f; +}; +S !v=new S; +v.f = 2; +int i=new S.f; +i=v.f; +if (arg) v.f=1; +return i; +"""); + code.parse().opto(); + var eval = new Evaluator(code._stop); + assertEquals(2L, eval.evaluate(0, 10)); + assertEquals(2L, eval.evaluate(1, 10)); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Simple.java b/chapter24/src/test/java/com/seaofnodes/simple/Simple.java new file mode 100644 index 00000000..8b275389 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/Simple.java @@ -0,0 +1,289 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.print.*; +import com.seaofnodes.simple.util.Utils; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Collectors; + +public class Simple { + public static final String PORTS = "com.seaofnodes.simple.node.cpus"; + + static final int DUMP_AFTER_PARSE = 1<<0; + static final int DUMP_AFTER_OPTO = 1<<1; + static final int DUMP_AFTER_TYPE_CHECK = 1<<2; + static final int DUMP_AFTER_LOOP_TREE = 1<<3; + static final int DUMP_AFTER_SELECT = 1<<4; + static final int DUMP_AFTER_GCM = 1<<5; + static final int DUMP_AFTER_LOCAL_SCHED = 1<<6; + static final int DUMP_AFTER_REG_ALLOC = 1<<7; + static final int DUMP_AFTER_ENCODE = 1<<8; + + static final int DUMP_FINAL = 1<<16; + + static final int DUMP_DOT = 1<<29; + static final int DUMP_PASS_NAME = 1<<30; + static final int DUMP_AFTER_ALL = 0xff | DUMP_PASS_NAME; + static final int DUMP_DOT_AFTER_ALL = 0xff | DUMP_DOT; + + static final int DUMP_DISASSEMBLE = 1<<31; + + static void usage() { + System.out.println( +""" +simple [options] <input-file> ...args... +Options: + --dump - dump final intermediate representation + --dump-after-parse - dump intermediate representation after parse + --dump-after-opto - dump intermediate representation after opto pass + --dump-after-type-check - dump intermediate representation after type check pass + --dump-after-select - dump intermediate representation after instrution selection pass + --dump-after-gcm - dump intermediate representation after GCM pass + --dump-after-local-sched - dump intermediate representation after local scheduling pass + --dump-after-reg-alloc - dump intermediate representation after register allocation pass + --dump-after-encode - dump intermediate representation after encoding pass + --dump-after-all - dump intermediate representation after all passes + --dot - dump grapical representation of intermediate code into *.dot file(s) + -S - dump generated assembler code + --eval - evaluate the compiled code in emulator + --run - run the compiled code natively; this is the default + --dump-size - print the size of generated code + --dump-time - print compilation and execution times + --cpu <cpu-name> - use specific CPU (x86_64_v2, riscv, arm) + --abi <abi-name> - use speific ABI variant (SystemV) + --target - print native CPU and ABI + --version + --help +""" +); + System.exit(0); + } + + static void bad_usage() { bad("Invalid usage (use --help)"); } + static RuntimeException bad(String err) { + System.err.println("ERROR: "+err); + System.exit(1); + return new RuntimeException(err); + } + + static void target() { + System.out.print(TestC.CPU_PORT); + System.out.print("-"); + System.out.println(TestC.CALL_CONVENTION); + } + + static void dump(CodeGen code, int dump, int pass) { + if ((dump & pass) != 0) { + if ((dump & DUMP_DOT) != 0) { + String fn = switch (pass) { + case DUMP_AFTER_PARSE -> "01-parse.dot"; + case DUMP_AFTER_OPTO -> "02-opto.dot"; + case DUMP_AFTER_TYPE_CHECK -> "03-type_check.dot"; + case DUMP_AFTER_LOOP_TREE -> "04-loop_tree.dot"; + case DUMP_AFTER_SELECT -> "05-instr_select.dot"; + case DUMP_AFTER_GCM -> "06-gcm.dot"; + case DUMP_AFTER_LOCAL_SCHED -> "07-local_sched.dot"; + case DUMP_AFTER_REG_ALLOC -> "08-reg_allos.dot"; + case DUMP_AFTER_ENCODE -> "09-local_sched.dot"; + case DUMP_FINAL -> "10-final.dot"; + default -> throw Utils.TODO(); + }; + + try { + Files.writeString(Path.of(fn), + new GraphVisualizer().generateDotOutput(code._stop, null, null)); + } catch(IOException e) { throw bad("Cannot write DOT file"); } + } else { + if ((dump & DUMP_PASS_NAME) != 0) { + System.err.println(switch (pass) { + case DUMP_AFTER_PARSE -> "After Parse:"; + case DUMP_AFTER_OPTO -> "After OPTO:"; + case DUMP_AFTER_TYPE_CHECK -> "After Type Check:"; + case DUMP_AFTER_LOOP_TREE -> "After Loop Tree:"; + case DUMP_AFTER_SELECT -> "After Code Selection:"; + case DUMP_AFTER_GCM -> "After GCM:"; + case DUMP_AFTER_LOCAL_SCHED -> "After Local Scheduling:"; + case DUMP_AFTER_REG_ALLOC -> "After Register Allocation:"; + case DUMP_AFTER_ENCODE -> "After Encoding:"; + case DUMP_FINAL -> "Final:"; + default -> throw Utils.TODO(); + }); + } + + System.err.println(IRPrinter.prettyPrint(code._stop, 9999)); + } + } + } + + static void print_compilation_times(CodeGen code) { + double t, total = 0; + + total += t = code._tParse / 1e3; + System.out.printf( "Parsing Time: %.3f sec%n", t); + total += t = code._tOpto / 1e3; + System.out.printf( "Optimization Time: %.3f sec%n", t); + total += t = code._tTypeCheck / 1e3; + System.out.printf( "Type Checking Time: %.3f sec%n", t); + total += t = code._tLoopTree / 1e3; + System.out.printf( "Loop Tree Time: %.3f sec%n", t); + total += t = code._tInsSel / 1e3; + System.out.printf( "Code Selection Time: %.3f sec%n", t); + total += t = code._tGCM / 1e3; + System.out.printf( "GCM Time: %.3f sec%n", t); + total += t = code._tLocal / 1e3; + System.out.printf( "Local Scheduling Time: %.3f sec%n", t); + total += t = code._tRegAlloc / 1e3; + System.out.printf( "Register Allocation Time: %.3f sec%n", t); + total += t = code._tEncode / 1e3; + System.out.printf( "Encoding Time: %.3f sec%n", t); + System.out.printf( "TOTAL COMPILATION TIME: %.3f sec%n", total); + } + + static String getInput() { + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + return reader.lines().collect(Collectors.joining("\n")); + } + + public static void main(String[] args) throws Exception { + String input_filename = null; + boolean do_eval = false; + boolean do_run = true; + boolean do_codegen = false; + boolean do_print_size = false; + boolean do_print_time = false; + int dump = 0; + int first_arg = 0; + String src = null; + String cpu = null; + String abi = null; + + // Parse command line + int i; for( i = 0; i < args.length; i++ ) { + String arg = args[i]; + if( arg.charAt(0) != '-' ) { + input_filename = arg; + break; + } + + switch (arg) { + case "-": input_filename=""; break; + case "--dump": dump |= DUMP_FINAL; break; + case "--dump-after-parse": dump |= DUMP_AFTER_PARSE; break; + case "--dump-after-opto": dump |= DUMP_AFTER_OPTO; break; + case "--dump-after-type-check": dump |= DUMP_AFTER_TYPE_CHECK; break; + case "--dump-after-loop-tree": dump |= DUMP_AFTER_LOOP_TREE; break; + case "--dump-after-select": dump |= DUMP_AFTER_SELECT; break; + case "--dump-after-gcm": dump |= DUMP_AFTER_GCM; break; + case "--dump-after-local-sched": dump |= DUMP_AFTER_LOCAL_SCHED; break; + case "--dump-after-reg-alloc": dump |= DUMP_AFTER_REG_ALLOC; break; + case "--dump-after-encode": dump |= DUMP_AFTER_ENCODE; break; + case "--dump-after-all": dump |= DUMP_AFTER_ALL; break; + case "--dot": dump |= DUMP_DOT; break; + case "-S": dump |= DUMP_DISASSEMBLE; break; + case "--eval": do_eval = true ; do_run = false; break; + case "--run": do_run = true ; break; + case "--norun": do_run = false; break; + case "--dump-size": do_print_size = true; break; + case "--dump-time": do_print_time = true; break; + case "--cpu": if (cpu != null || i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage(); + cpu = args[++i]; + break; + case "--abi": if (abi != null || i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage(); + abi = args[++i]; + break; + case "--target": target(); break; + case "--version": throw Utils.TODO(); + case "--help": usage(); + default: bad_usage(); + } + } + + if (input_filename == null) throw bad("no input file' (use --help)"); + if( !input_filename.isEmpty() && !input_filename.endsWith(".smp") ) + throw bad("File extension must be .smp"); + String base = input_filename.substring(0,input_filename.length()-4); + + if (do_run || (dump & DUMP_DISASSEMBLE) != 0 || do_print_size) { + if (cpu == null) cpu = TestC.CPU_PORT; + if (abi == null) abi = TestC.CALL_CONVENTION; + do_codegen = true; + } + + // Read input file + try { + src = input_filename.isEmpty() ? getInput() : Files.readString(Path.of(input_filename)); + } catch( IOException e ) { throw bad("Cannot read input file: "+input_filename); } + + // Compilation pipeline + CodeGen code = new CodeGen(src); + + code.parse(); + dump(code, dump, DUMP_AFTER_PARSE); + + code.opto(); + dump(code, dump, DUMP_AFTER_OPTO); + + code.typeCheck(); + dump(code, dump, DUMP_AFTER_TYPE_CHECK); + + code.loopTree(); + dump(code, dump, DUMP_AFTER_LOOP_TREE); + + if (do_codegen) { + code.instSelect(cpu, abi, PORTS); + dump(code, dump, DUMP_AFTER_SELECT); + } + + code.GCM(); + dump(code, dump, DUMP_AFTER_GCM); + + code.localSched(); + dump(code, dump, DUMP_AFTER_LOCAL_SCHED); + + if (do_codegen) { + code.regAlloc(); + dump(code, dump, DUMP_AFTER_REG_ALLOC); + + code.encode(); + dump(code, dump, DUMP_AFTER_ENCODE); + + code.exportELF(base+".o"); + } + + dump(code, dump, DUMP_FINAL); + + if (do_codegen && (dump & DUMP_DISASSEMBLE) != 0) { + System.out.println(code.asm()); + } + + if (do_print_size) { + System.out.printf( "Code Size: %d%n", code._encoding._bits.size()); + } + + if (do_print_time) { + print_compilation_times(code); + } + + if (do_eval) { + // TODO: Support for evaluation of functions with different argument numbers and types + long t = System.currentTimeMillis(); + long arg = (i+1 < args.length) ? Integer.parseInt(args[i+1]) : 0; + System.out.println(Eval2.eval(code, arg, 100000)); + if (do_print_time) { + System.out.printf( "EXECUTION TIME: %.3f sec%n", + (System.currentTimeMillis() - t) / 1e3); + } + } + if (do_run) { + if ( !TestC.CPU_PORT.equals( cpu ) || !TestC.CALL_CONVENTION.equals( abi ) ) + throw bad("cannot run code on not native target"); + String exe = TestC.OS.startsWith("Windows") ? base+".exe" : base; + String result = TestC.gcc(base+".o", null, null, true, exe); + System.out.print(result); + } + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/TestArm64.java b/chapter24/src/test/java/com/seaofnodes/simple/TestArm64.java new file mode 100644 index 00000000..5d7d1361 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/TestArm64.java @@ -0,0 +1,42 @@ +package com.seaofnodes.simple; + + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.cpus.arm.arm; +import junit.framework.Assert; +import java.nio.file.Files; +import java.nio.file.Path; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +// Runs 32-bit ARM code in an emulator + +public class TestArm64 { + public static EvalArm64 build( String file, int arg, int spills, boolean print ) throws IOException { + return build("src/test/java/com/seaofnodes/simple/progs",file, arg, spills, print); + } + + // Compile and run a simple program + public static EvalArm64 build( String dir, String file, int arg, int spills, boolean print ) throws IOException { + // Compile and export Simple + String src = Files.readString(Path.of(dir+"/"+file+".smp")); + CodeGen code = new CodeGen(src).driver("arm", "SystemV",null); + if( print ) { code.print_as_hex(); System.out.print(code.asm()); } + + // Allocation quality not degraded + int delta = spills>>3; + if( delta == 0 ) delta =1; + if( spills != -1 ) assertEquals("Expect spills:", spills, code._regAlloc._spillScaled, delta); + + // Image + byte[] image = new byte[1<<20]; // A megabyte (1024*1024 bytes) + EvalArm64 ARM = new EvalArm64(image, 1<<16); + // Code at offset 0 + System.arraycopy(code._encoding.bits(), 0, image, 0, code._encoding.bits().length); + // Initial incoming int arg + ARM.regs[arm.X0] = arg; + // malloc memory starts at 64K and goes up + return ARM; + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/TestC.java b/chapter24/src/test/java/com/seaofnodes/simple/TestC.java new file mode 100644 index 00000000..dbe9f02f --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/TestC.java @@ -0,0 +1,122 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import static org.junit.Assert.*; + +// Call a C driver program, which calls a Simple-generated .o, and self-checks. +// Expects GCC from the default CLI, compiles C, compiles Simple, links and runs. +public abstract class TestC { + + public static final String OS = System.getProperty("os.name"); + public static final String CPU = System.getProperty("os.arch"); + + public static final String CALL_CONVENTION = OS.startsWith("Windows") ? "Win64" : "SystemV"; + public static final String CPU_PORT = switch( CPU ) { + case "amd64" -> "x86_64_v2"; + default -> throw Utils.TODO("Map Yer CPU Port Here"); + }; + + public static void run( String file, int spills ) throws IOException { run(file,"",spills); } + + public static void run( String file, String expected, int spills ) throws IOException { + run("src/test/java/com/seaofnodes/simple/progs",file,expected,spills); + } + + // Compile and run a simple program + public static void run( String dir, String file, TypeInteger arg, String expected, int spills, boolean standalone) throws IOException { + // Files + String cfile = dir+"/"+file+".c" ; + String sfile = dir+"/"+file+".smp"; + String efile = "build/objs/"+file; + + // Compile and export Simple + String src = Files.readString(Path.of(sfile)); + run(src,CALL_CONVENTION,arg, "",standalone? null: cfile,efile,"S",expected,spills); + } + public static void run(String dir, String file, String expected, int spills ) throws IOException { + run(dir, file,null, expected, spills, false); + } + + public static void runS(String file, String expected, int spills ) throws IOException { + run("src/test/java/com/seaofnodes/simple/progs", file, null, expected, spills, true); + } + + public static void runS(String file, TypeInteger arg, String expected, int spills ) throws IOException { + run("src/test/java/com/seaofnodes/simple/progs", file, arg, expected, spills, true); + } + + + public static void run( String src, String simple_conv, TypeInteger arg, String c_conv, String cfile, String efile, String xtn, String expected, int spills ) throws IOException { + String bin = efile+xtn; + String obj = bin+".o"; + String exe = OS.startsWith("Windows") ? bin+".exe" : bin; + // Compile simple, emit ELF + CodeGen code = new CodeGen(src, arg).driver( CPU_PORT, simple_conv, obj); + + String result = gcc(obj, c_conv, cfile, false, exe ); + assertEquals(expected,result); + + // Allocation quality not degraded + int delta = spills>>3; + if( delta==0 ) delta = 1; + if( spills != -1 ) + assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); + } + + public static String gcc( String obj, String c_conv, String cfile, boolean stdin, String... args ) throws IOException { + + // Compile the C program. Compiling code and constants in the low + // 2Gig. Pointers are 64b BUT since always in the low 2G all the + // high bits are zero - and Simple code can be emitted treating + // pointers as 4bytes. + var params = new Ary<>(String.class); + params.add("gcc"); + if( cfile!=null ) params.add(cfile); // Associated C driver, usually has a `main` + params.addAll(new String[] { + obj, + "-lm", // Picks up 'sqrt' for newtonFloat tests to compare + "-g", + "-o", + args[0], + }); + // Calling convention for C calls, if any + if( cfile!=null ) { + params.add("-D"); + params.add("CALL_CONV="+c_conv); + } + + // Run GCC to link (optionally compile C driver code) + Process gcc = new ProcessBuilder(params.asAry()).redirectErrorStream(true).start(); + int exit; + try { + boolean normal = gcc.waitFor(2, TimeUnit.SECONDS); + exit = normal ? gcc.exitValue() : -1; // no exit??? + } catch( InterruptedException e ) { + throw new IOException("interrupted"); + } + String result = new String(gcc.getInputStream().readAllBytes()); + if( exit!=0 ) { + System.err.println("gcc error code: "+exit); + System.err.println(result); + } + assertEquals( 0, exit ); + //assertTrue(result.isEmpty()); // No data in error stream + + // Execute results + ProcessBuilder smp = new ProcessBuilder(args); + if( stdin ) smp.redirectInput(ProcessBuilder.Redirect.INHERIT); + Process p = smp.start(); + try { exit = (byte)p.waitFor(); } catch( InterruptedException e ) { throw new IOException("interrupted"); } + result = new String(p.getInputStream().readAllBytes()); + if( exit!=0 ) + System.err.println("exec exit code: "+exit); + return result; + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/TestRisc5.java b/chapter24/src/test/java/com/seaofnodes/simple/TestRisc5.java new file mode 100644 index 00000000..041ed833 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/TestRisc5.java @@ -0,0 +1,50 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.FunNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.cpus.riscv.riscv; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import static org.junit.Assert.*; + +// Runs 32-bit R5 code in an emulator +public abstract class TestRisc5 { + + public static EvalRisc5 build( String file, int arg, int spills, boolean print ) throws IOException { + return build("src/test/java/com/seaofnodes/simple/progs",file, null, arg, spills, print); + } + + // Compile and run a simple program + public static EvalRisc5 build( String dir, String file, String main, int arg, int spills, boolean print ) throws IOException { + // Compile and export Simple + String src = Files.readString(Path.of(dir+"/"+file+".smp")); + CodeGen code = new CodeGen(src).driver("riscv", "SystemV",null); + if( print ) { code.print_as_hex(); System.out.print(code.asm()); } + + // Allocation quality not degraded + int delta = spills>>3; + if( delta==0 ) delta = 1; + if( spills != -1 ) + assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); + + // Image + byte[] image = new byte[1<<20]; // A megabyte (1024*1024 bytes) + EvalRisc5 R5 = new EvalRisc5(image, 1<<16); + // Code at offset 0 + System.arraycopy(code._encoding.bits(), 0, image, 0, code._encoding.bits().length); + // Initial incoming int arg + R5.regs[riscv.A0] = arg; + // malloc memory starts at 64K and goes up + + // Look up starting PC or zero if not given + if( main!=null ) + for( Node use : code._start._outputs ) + if( use instanceof FunNode fun && main.equals(fun._name) ) + R5._pc = code._encoding._opStart[fun._nid]; + + return R5; + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/TypeTest.java b/chapter24/src/test/java/com/seaofnodes/simple/TypeTest.java new file mode 100644 index 00000000..0fd56607 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/TypeTest.java @@ -0,0 +1,198 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.type.*; +import org.junit.Assert; +import org.junit.Test; +import static org.junit.Assert.assertSame; + +public class TypeTest { + + // Test basic properties and GLB + @Test + public void testTypeAdHoc() { + Assert.assertEquals( Type.BOTTOM, TypeInteger.TRUE.meet(TypeNil.NIL) ); + Assert.assertEquals( Type.BOTTOM, TypeInteger.TOP .meet(TypeNil.NIL) ); + + TypeStruct s1 = TypeStruct.make("s1",false, + Field.make("a", TypeInteger.BOT,-1, false, false), + Field.make("b", TypeInteger.BOT,-2, false, false) ); + TypeStruct s2 = TypeStruct.make("s2",false, + Field.make("a", TypeInteger.BOT,-3, false, false), + Field.make("b", TypeInteger.BOT,-4, false, false) ); + TypeStruct x1ro = (TypeStruct)s1.makeRO(); + TypeMemPtr p1 = TypeMemPtr.make(s1); + Assert.assertEquals(x1ro, ((TypeMemPtr)p1.glb(false))._obj); + Assert.assertNotEquals(s1, s1.dual()); + TypeStruct s1dglb = ((TypeMemPtr)p1.dual().glb(false))._obj; + Assert.assertTrue(x1ro.isa(s1dglb)); + + TypeMem m1 = TypeMem.make(2,TypeNil.NIL); + TypeMem m2 = TypeMem.make(3,TypeInteger.U16); + TypeMem m3 = TypeMem.make(4,TypeFloat.F64); + TypeMem m4 = TypeMem.make(5,TypeInteger.BOT); + + Assert.assertNotEquals(m1, m2); + Assert.assertNotEquals(m2, m3); + Assert.assertNotEquals(m3, m4); + + Assert.assertEquals(TypeStruct.BOT, s1.meet(s2)); + Assert.assertEquals(TypeMem .BOT, m1.meet(m2)); + Assert.assertEquals(TypeMem.make(1,Type.BOTTOM), m1.meet(m3)); + Assert.assertEquals(TypeMem .BOT, m3.meet(m4)); + + Assert.assertEquals(TypeMem.make(2,Type.BOTTOM), m1.glb(false)); + Assert.assertEquals(TypeMem.make(2,Type.XNIL), m1.dual()); + Assert.assertEquals(m4.dual(), m4.glb(false).dual()); + + TypeMemPtr ptr1 = TypeMemPtr.make(s1); + Assert.assertEquals(s1, ptr1._obj); + TypeMemPtr ptr2 = TypeMemPtr.make(s2); + Assert.assertEquals(s2, ptr2._obj); + + TypeMemPtr ptr1nil = TypeMemPtr.makeNullable(s1); + Assert.assertEquals(s1, ptr1nil._obj); + Assert.assertTrue( ptr1nil.nullable() ); + Assert.assertNotNull( ptr1nil._obj ); + TypeMemPtr ptr2nil = TypeMemPtr.makeNullable( s2); + Assert.assertEquals(s2, ptr2nil._obj); + + Assert.assertNotEquals(ptr1, ptr2); + Type p1glb = ptr1.glb(false); + Assert.assertNotEquals(ptr1, p1glb ); + Type p1nro = ptr1nil.makeRO(); + Assert.assertEquals(p1nro, p1glb); + + Assert.assertEquals(ptr1, ptr1.dual().dual()); + Assert.assertTrue(p1glb.makeRO().isa( ptr1.dual().glb(false))); + Assert.assertEquals(TypeMemPtr.makeNullable(TypeStruct.BOT), ptr1.meet(ptr2nil)); + Assert.assertEquals(p1glb, ptr1.meet(TypeNil.NIL).makeRO()); + + TypeMemPtr TOP = TypeMemPtr.TOP; + TypeMemPtr BOT = TypeMemPtr.makeNullable(TypeStruct.BOT); + TypeMemPtr PTR = TypeMemPtr.make(TypeStruct.BOT); + Type NULL = TypeNil.NIL; + Type PTR_meet_NULL = NULL.meet(PTR); + Assert.assertEquals(BOT, PTR_meet_NULL); + Type ptr1_meet_ptr2 = ptr1.meet(ptr2); + Assert.assertEquals(PTR, ptr1_meet_ptr2); + Type NULL_join_ptr1 = NULL.join(ptr1); + Assert.assertEquals(TypePtr.XNPTR, NULL_join_ptr1); + Type NULL_join_PTR = PTR.join(NULL); + Assert.assertEquals(TypePtr.XNPTR, NULL_join_PTR); + Type ptr1_dual = ptr1.dual(); + Type nullableptr1_dual = ptr1nil.dual(); + + // Cyclic check + TypeStruct S1 = ((TypeMemPtr)TypeStruct.SFLT2.field("s1")._t)._obj; + Assert.assertFalse(s1.isFinal()); + Type s1ro = S1.makeRO(); + Type s1ro2 = S1.makeRO(); + Assert.assertSame(s1ro,s1ro2); + Assert.assertTrue(s1ro.isFinal()); + + Assert.assertFalse(S1.isConstant()); + Type s1glb = S1.field("s2")._t.glb(false); + Type s1glb2 = S1.field("s2")._t.glb(false); + Assert.assertSame(s1glb,s1glb2); + } + + // Test theoretical properties. + // This is a symmetric complete bounded (ranked) lattice. + // Also, the meet is commutative and associative. + // The lattice has a dual (symmetric), and join is ~(~x meet ~y). + // See https://en.wikipedia.org/wiki/Lattice_(order). + @Test + public void testLatticeTheory() { + Type[] ts = Type.gather(); + + // Confirm commutative & complete + for( Type t0 : ts ) + for( Type t1 : ts ) { + check_commute (t0,t1); + check_symmetric(t0,t1); + } + + // Confirm associative + for( Type t0 : ts ) + for( Type t1 : ts ) + for( Type t2 : ts ) + assoc(t0,t1,t2); + + // Confirm symmetry. If A isa B, then A.join(C) isa B.join(C) + for( Type t0 : ts ) + for( Type t1 : ts ) + if( t0.isa(t1) ) + for( Type t2 : ts ) { + Type t02 = t0.join(t2); + Type t12 = t1.join(t2); + Type mt = t02.meet(t12); + assertSame(mt,t12); + } + } + + // By design in meet, args are already flipped to order _type, which forces + // symmetry for things with badly ordered _type fields. The question is + // still interesting for other orders. + private static void check_commute( Type t0, Type t1 ) { + if( t0==t1 ) return; + if( t0.is_simple() && !t1.is_simple() ) return; // By design, flipped the only allowed order + Type mta = t0.meet(t1); + Type mtb = t1.meet(t0); // Reverse args and try again + assertSame(mta,mtb); + } + + // A & B = MT + // Expect: ~A & ~MT == ~A + // Expect: ~B & ~MT == ~B + private static void check_symmetric( Type t0, Type t1 ) { + if( t1==t0 ) return; + Type mt = t0.meet(t1); + Type dm = mt.dual(); + Type d0 = t0.dual(); + Type d1 = t1.dual(); + Type ta = dm.meet(d1); + Type tb = dm.meet(d0); + assertSame(ta,d1); + assertSame(tb,d0); + } + + private static void assoc( Type t0, Type t1, Type t2 ) { + Type t01 = t0 .meet(t1 ); + Type t12 = t1 .meet(t2 ); + Type t01_2 = t01.meet(t2 ); + Type t0_12 = t0 .meet(t12); + assertSame(t01_2,t0_12); + } + + // Test cyclic types and meets + @Test + public void testCyclic0() { + Type d0 = TypeStruct.SFLT2.dual(); + Type d1 = d0.dual(); + assertSame(TypeStruct.SFLT2,d1); + } + + @Test + public void testGLB() { + Type[] ts = Type.gather(); + for( Type t0 : ts ) + if( !(t0 instanceof Field || t0 instanceof TypeStruct || t0 instanceof TypeTuple || t0 instanceof TypeConAry ) ) + Assert.assertTrue(t0.isa(t0.glb(false))); + } + + @Test + public void testList() { + TypeStruct list = TypeStruct.open("List"); + TypeMemPtr plist = TypeMemPtr.makeNullable(list); + list = list.add(Field.make("next", plist, 2, false, false ) ); + list = list.add(Field.make("x", TypeInteger.BOT, 3, false, false)); + // Make a cyclic type + list = list.close(); + // Fields are mutable + Assert.assertFalse(list.isFinal()); + TypeStruct flist = (TypeStruct)list.makeRO(); + Assert.assertTrue(flist.isFinal()); + Assert.assertNotSame( list, flist ); + + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java new file mode 100644 index 00000000..911acc5c --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java @@ -0,0 +1,382 @@ +package com.seaofnodes.simple.evaluator; + +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; +import java.util.*; + +public class Evaluator { + + private static final Object MEMORY = new Object(); + + public record Obj(TypeStruct struct, Object[] fields) { + private void init(IdentityHashMap<Obj, Integer> objs) { + var oid = objs.get(this); + if (oid != null) { + if (oid != 0) objs.put(this, 0); + return; + } + objs.put(this, -1); + for (var obj : fields) { + if (obj instanceof Obj o) o.init(objs); + } + } + private static int p(StringBuilder sb, IdentityHashMap<Obj, Integer> objs, int id, String indentation, String step, String sep, Object obj) { + if (obj instanceof Obj o) return o.p(sb, objs, id, indentation, step, sep); + sb.append(obj); + return id; + } + private int p(StringBuilder sb, IdentityHashMap<Obj, Integer> objs, int id, String indentation, String step, String sep) { + var cid = objs.get(this); + assert cid != null; + if (cid > 0) { + sb.append("obj@").append(cid); + return id; + } + if (struct._name.equals("[u8]")) { + sb.append('"'); + for (int i=struct._fields.length-1; i<fields.length; i++) { + var v = fields[i]; + if (v == null) v = 0; + assert v instanceof Number; + var n = ((Number)v).byteValue() & 0xFF; + if (n >= 0x20 && n < 0x80) { + if (n == 0x22 || n == 0x5C) sb.append("\\"); + sb.append((char)n); + } else { + sb.append("\\x").append("0123456789abcdef".charAt(n >> 4)).append("0123456789abcdef".charAt(n & 0xF)); + } + } + sb.append('"'); + return id; + } + sb.append("Obj<").append(struct._name).append(">"); + if (cid == 0) { + cid = id++; + objs.put(this, cid); + sb.append("@").append(cid); + } + sb.append("{"); + if (struct._fields.length == 0) { + assert !struct.isAry(); + sb.append("}"); + return id; + } + String nextIndent = indentation + step; + int e = struct._fields.length - 1; + for(int i=0; i<e; i++) { + sb.append(nextIndent).append(struct._fields[i]._fname).append("="); + id = p(sb, objs, id, nextIndent, step, sep, fields[i]); + sb.append(sep); + } + sb.append(nextIndent).append(struct._fields[e]._fname).append("="); + if (struct.isAry()) { + sb.append("["); + if (fields.length > e) { + String innerIndent = nextIndent + step; + sb.append(innerIndent); + id = p(sb, objs, id, nextIndent, step, sep, fields[e]); + for (int i = e+1; i < fields.length; i++) { + sb.append(sep).append(innerIndent); + id = p(sb, objs, id, nextIndent, step, sep, fields[i]); + } + sb.append(nextIndent); + } + sb.append("]"); + } else { + id = p(sb, objs, id, nextIndent, step, sep, fields[e]); + } + sb.append(indentation).append("}"); + return id; + } + private StringBuilder p(StringBuilder sb, String indentation, String step, String sep) { + var objs = new IdentityHashMap<Obj, Integer>(); + init(objs); + p(sb, objs, 1, indentation, step, sep); + return sb; + } + @Override + public String toString() { + if (struct._name.equals("[u8]")) { + var sb = new StringBuilder(); + for (int i=struct._fields.length-1; i<fields.length; i++) { + var v = fields[i]; + if (v == null) v = 0; + assert v instanceof Number; + var n = ((Number)v).byteValue() & 0xFF; + sb.append((char)n); + } + return sb.toString(); + } + return p(new StringBuilder(), "", "", ",").toString(); + } + public String pretty() { + return p(new StringBuilder(), "\n", " ", "").toString(); + } + } + + private static int getFieldIndex(TypeStruct struct, MemOpNode memop, long off) { + int idx = struct.find(memop._name); + if( idx >= 0 ) return idx; + throw new AssertionError("Field "+memop._name+" not found in struct " + struct._name); + } + + public enum Status { + TIMEOUT, + FALLTHROUGH + } + + /** + * Find the start node from some node in the graph or null if there is no start node + */ + private static StartNode findStart(BitSet visit, Node node) { + if (node == null) return null; + if( visit.get(node._nid) ) return null; + visit.set(node._nid); + StartNode start = node instanceof StartNode ? (StartNode) node : null; + for( Node def : node._inputs ) { + var res = findStart(visit,def); + if( res != null ) start = res; + } + for( Node use : node._outputs ) { + var res = findStart(visit,use); + if( res != null ) start = res; + } + return start; + } + + private final Object[] values; + private final ArrayList<Object> phiCache = new ArrayList<>(); + private final StartNode start; + private final Scheduler.Block startBlock; + + public Evaluator(Node graph) { + var visited = new BitSet(); + this.start = findStart(visited, graph); + if (this.start == null) { + this.values = null; + this.startBlock = null; + return; + } + this.startBlock = Scheduler.schedule(this.start); + this.values = new Object[visited.length()]; + } + + private long div(DivNode div) { + long in2 = vall(div.in(2)); + return in2 == 0 ? 0 : vall(div.in(1)) / in2; + } + private double div(DivFNode div) { + double in2 = vald(div.in(2)); + return in2 == 0 ? 0 : vald(div.in(1)) / in2; + } + + private static long offToIdx(long off, TypeStruct t) { + off -= t.aryBase(); + int scale = t.aryScale(); + long mask = (1L << scale)-1; + assert (off & mask) == 0; + return off>>scale; + } + + private Object alloc(NewNode alloc) { + TypeStruct type = alloc._ptr._obj; + Object[] body=null; + int num; + if( type.isAry() ) { + long sz = (Long)val(alloc.in(1)); + long n = offToIdx(sz, type); + if( n < 0 ) + throw new NegativeArraySizeException(""+n); + body = new Object[(int)n+1]; // Array body + var elem = type._fields[1]._t; + if (elem instanceof TypeInteger) { + for (int i=0; i<n; i++) body[i+1] = 0L; + } else if (elem instanceof TypeFloat) { + for (int i = 0; i < n; i++) body[i+1] = 0D; + } else { + assert elem instanceof TypeMemPtr; + } + // Length value + body[0] = vall(alloc.in(2+2)); + } else { + body = new Object[num = type._fields.length]; + for( int i=0; i<num; i++ ) + body[i] = switch( alloc._ptr._obj._fields[i]._t ) { + case TypeInteger ti -> 0L; + case TypeFloat tf -> 0; + default -> null; + }; + } + Object[] mems = new Object[type._fields.length+2]; + // mems[0] is control + mems[1] = new Obj(type,body); // the ref + // mems[2+...] are memory aliases + return mems; + } + + private Object load(LoadNode load) { + var from = (Obj)val(load.ptr()); + var off = vall(load.off()); + var idx = getFieldIndex(from.struct, load, (Long)off); + if( idx==from.struct._fields.length-1 && from.struct.isAry() ) { + long len = from.fields.length - from.struct._fields.length + 1; + long i = offToIdx(off, from.struct); + if( i < 0 || i >= len ) + throw new ArrayIndexOutOfBoundsException("Array index out of bounds " + i + " < " + len); + return from.fields[(int)i+from.struct._fields.length-1]; + + } else + return from.fields[idx]; + } + + private Object store(StoreNode store) { + var to = (Obj)val(store.ptr()); + var off = vall(store.off()); + var val = val(store.val()); + var idx = getFieldIndex(to.struct, store, (Long)off); + if( idx==to.struct._fields.length-1 && to.struct.isAry() ) { + long len = to.fields.length - to.struct._fields.length + 1; + long i = offToIdx(off, to.struct); + if( i < 0 || i >= len ) + throw new RuntimeException("Array index out of bounds " + off + " <= " + len); + to.fields[(int)i+to.struct._fields.length-1] = val; + } else + to.fields[idx] = val; + return null; + } + + private static boolean isTrue(Object obj) { + if (obj == null) return false; + if (obj instanceof Number n) return n.longValue() != 0; + return true; + } + + private Object val(Node node) { + return values[node._nid]; + } + + private long vall(Node node) { + var v = val(node); + if (v instanceof Number n) return n.longValue(); + throw new AssertionError("Not a long " + v); + } + private double vald(Node node) { + var v = val(node); + if (v instanceof Number n) return n.doubleValue(); + if( v == null ) return 0; + throw new AssertionError("Not a double " + v); + } + + private Object cons(ConstantNode cons) { + var type = cons.compute(); + if (type instanceof TypeInteger i) return i.isConstant() ? i.value() : Integer.MAX_VALUE; + if (type instanceof TypeFloat i) return i.value(); + return null; + } + + private Object exec(Node node) { + return switch (node) { + case ConstantNode cons -> cons(cons); + case AddNode add -> vall(add.in(1)) + vall(add.in(2)); + case AddFNode add -> vald(add.in(1)) + vald(add.in(2)); + case BoolNode.EQF eq -> vald(eq.in(1)) == vald(eq.in(2)) ? 1L : 0L; + case BoolNode.LEF le -> vald(le.in(1)) <= vald(le.in(2)) ? 1L : 0L; + case BoolNode.LTF lt -> vald(lt.in(1)) < vald(lt.in(2)) ? 1L : 0L; + case BoolNode.EQ eq -> Objects.equals(val(eq.in(1)), val(eq.in(2))) ? 1L : 0L; + case BoolNode.LE le -> vall(le.in(1)) <= vall(le.in(2)) ? 1L : 0L; + case BoolNode.LT lt -> vall(lt.in(1)) < vall(lt.in(2)) ? 1L : 0L; + case DivNode div -> div(div); + case DivFNode div -> div(div); + case MinusNode minus -> -vall(minus.in(1)); + case MinusFNode minus -> -vald(minus.in(1)); + case MulNode mul -> vall(mul.in(1)) * vall(mul.in(2)); + case MulFNode mul -> vald(mul.in(1)) * vald(mul.in(2)); + case NotNode not -> isTrue(val(not.in(1))) ? 0L : 1L; + case SubNode sub -> vall(sub.in(1)) - vall(sub.in(2)); + case SubFNode sub -> vald(sub.in(1)) - vald(sub.in(2)); + case ShlNode shl -> vall(shl.in(1)) << vall(shl.in(2)); + case ShrNode shr -> vall(shr.in(1)) >>> vall(shr.in(2)); + case SarNode sar -> vall(sar.in(1)) >> vall(sar.in(2)); + case AndNode and -> vall(and.in(1)) & vall(and.in(2)); + case OrNode or -> vall(or .in(1)) | vall(or .in(2)); + case XorNode xor -> vall(xor.in(1)) ^ vall(xor.in(2)); + case CastNode cast -> val(cast.in(1)); + case ToFloatNode cast -> (double)vall(cast.in(1)); + case LoadNode load -> load(load); + case StoreNode store -> store(store); + case NewNode alloc -> alloc(alloc); + case CProjNode cproj -> ((Object[])val(cproj.ctrl()))[cproj._idx]; + case ProjNode proj -> ((Object[])val( proj.in(0) ))[ proj._idx]; + case MemMergeNode mem -> null; + case ReadOnlyNode ro -> val(ro.in(1)); + case CallNode call -> Utils.TODO(); // should not reach here, go the IfNode route + default -> throw new AssertionError("Unexpected node " + node); + }; + } + + /** + * Run the graph until either a return is found or the number of loop iterations are done. + */ + public Object evaluate(long parameter, int loops) { + if (start == null) return Status.TIMEOUT; + var s = new Object[start.compute()._types.length]; + s[1] = MEMORY; + s[2] = parameter; + values[start._nid] = s; + int i=0; + Scheduler.Block block = this.startBlock; + for(;;) { + for(; i<block.nodes().length;i++) values[block.nodes()[i]._nid] = exec(block.nodes()[i]); + i=0; + switch (block.exit()) { + case null: + return Status.FALLTHROUGH; + case ReturnNode ret : return val(ret .expr()); + case IfNode ifn: + block = block.next()[isTrue(val(ifn.in(1))) ? 0 : 1]; + if (block == null) return Status.FALLTHROUGH; + break; + case RegionNode region: + if (loops-- <= 0) return Status.TIMEOUT; + int exit = block.exitId(); + assert exit > 0 && region.nIns() > exit; + block = block.next()[0]; + assert block != null; + for (; i < block.nodes().length; i++) { + if (!(block.nodes()[i] instanceof PhiNode phi)) break; + var val = region instanceof FunNode fun && "main".equals(fun._name) && ((ParmNode)phi)._idx==2 && exit==1 + ? parameter + : val(phi.in(exit)); + phiCache.add(val); + } + for (i=0; i<phiCache.size(); i++) { + values[block.nodes()[i]._nid] = phiCache.get(i); + } + phiCache.clear(); + break; + default: + throw Utils.TODO("Unexpected control node " + block.exit()); + } + } + } + + public static Object evaluate(StopNode graph) { + return evaluate(graph, 0); + } + + public static Object evaluate(StopNode graph, long parameter) { + return evaluate(graph, parameter, 1000); + } + + public static Object evaluate(StopNode graph, long parameter, int loops) { + var res = evaluateWithResult(graph, parameter, loops); + if (res == Status.TIMEOUT) throw new RuntimeException("Timeout"); + return res; + } + + public static Object evaluateWithResult(StopNode graph, long parameter, int loops) { + return new Evaluator(graph).evaluate(parameter, loops); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java b/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java new file mode 100644 index 00000000..c837bd6f --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java @@ -0,0 +1,605 @@ +package com.seaofnodes.simple.evaluator; + +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.Utils; +import java.util.*; + +/** + * A late scheduler for test cases. + * <br> + * <br> + * This scheduler is used for tests and is not the final scheduler. + * <br> + * <br> + * The scheduler schedules not as late as possible. Since it is just for test cases this is fine. + * A better scheduler will try to place nodes outside of loops. Due to the schedule late strategy + * this scheduler might place initialization code in loops. + * <br> + * We schedule late here since memory edges have some implicit information. There can only be one + * memory edge (for a field) at a time. However, before <code>if</code> statements this might split. + * When scheduling early a store might be moved out of the loop but then there are two edges alive. + * The one through the store node and the adjacent one. This is an invalid schedule and instead of + * handling this case a late scheduler does not have this problem as memory edges are combined + * through phi nodes. + * <br> + * <br> + * A bit about this scheduler. It first discovers all alive nodes and allocates side data for them. + * Then the control flow graph is build. Then, all phis are placed and finally all the remaining nodes + * in an order where a node is placed when all alive uses are placed. Finally, the output is produced. + */ +public class Scheduler { + + /** + * A basic block with a schedule of the containing nodes. + * + * @param nodes The nodes in the final schedule of this block + * @param exit The exit node of this block. + * @param exitId In case the next block is a region this gives the entry id into the region. + * @param next The next blocks. + */ + public record Block(Node[] nodes, Node exit, int exitId, Block[] next) {} + + /** + * Definition of a block in the building process. + */ + private static class BasicBlock { + + /** + * Dominator of this block + */ + final BasicBlock dom; + /** + * Id of this block where <code>a.depth < b.depth</code> means that a is before b or + * both are in different branches. + */ + final int depth; + /** + * Previous blocks + */ + final BasicBlock[] prev; + /** + * Entry to this block + */ + final Node entry; + /** + * Schedules node in reverse order. + */ + final ArrayList<Node> reverseSchedule = new ArrayList<>(); + + /** + * Initialize the block. + * @param entry The node that started this block + * @param depth The depth of this node. All previous nodes need to have a lower value. + * @param prev The previous blocks. + */ + BasicBlock(Node entry, int depth, BasicBlock... prev) { + BasicBlock dom = null; + int max = -1; + for(var bb: prev) { + max = Math.max(max, bb.depth); + dom = dom==null?bb:dom(dom, bb); + } + assert depth > max; + this.dom = dom; + this.depth = depth; + this.entry = entry; + this.prev = prev; + } + BasicBlock(Node entry, BasicBlock prev) { + this(entry,prev.depth+1,prev); + } + + } + + /** + * Ancillary data for nodes used during the scheduling process. + */ + private static class NodeData { + + /** + * The node this ancillary data is used for. + */ + final Node node; + + /** + * Number of alive users not yet scheduled. + */ + int users = 1; + + /** + * Block into which the node should be placed so far. + * This will be updated with every placed use. + */ + BasicBlock block; + + /** + * Initialize ancillary data for a node + * @param node The node this ancillary data is associated with. + */ + NodeData(Node node) { + this.node = node; + } + + } + + /** + * Ancillary data for nodes. + */ + private final IdentityHashMap<Node, NodeData> data = new IdentityHashMap<>(); + /** + * List of nodes which can be placed since all users are placed. + */ + private final Stack<NodeData> scheduleQueue = new Stack<>(); + + /** + * Get the ancillary data for an alive node. + * @param node The node for which the ancillary data is requested. + * @return The ancillary data for the node. + */ + NodeData d(Node node) { + return od(node).orElseThrow(AssertionError::new); + } + + /** + * Get the ancillary data for a potentially dead node. + * @param node The node for which the ancillary data is requested. + * @return The ancillary data for the node an alive node or + * <code>Optional.empty()</code> for <code>null</code> or dead nodes. + */ + Optional<NodeData> od(Node node) { + return Optional.ofNullable(data.get(node)); + } + + /** + * Checks a node for validity + * @param data The node to check. + * @return true if all placed inputs are before this node. + */ + private boolean isValid(NodeData data) { + return data.node._inputs.stream() + .map(i->i==null?null:d(i)) + .map(d->d==null||d.users>0?null:d.block) + .allMatch(d->d==null||dom(d, data.block)==d); + } + + /** + * Checks that node is not XCtrl. + * @param node The node to check. + * @return true if the node is not XCtrl. + */ + private static boolean isNotXCtrl(Node node) { + return !(node instanceof ConstantNode c && c.compute() == Type.XCONTROL) && !(node instanceof XCtrlNode); + } + + /** + * Return the dominator of <code>a</code> and <code>b</code> + * @param a Block a + * @param b Block b + * @return The dominator of <code>a</code> and <code>b</code> + */ + private static BasicBlock dom(BasicBlock a, BasicBlock b) { + while (a!=b) { + if (a.depth >= b.depth) a=a.dom; + if (b.depth > a.depth) b=b.dom; + } + return a; + } + + /** + * Return if a is before b. + * @param a Block a + * @param b Block b + * @return true is a is before b. + */ + private static boolean isBefore(BasicBlock a, BasicBlock b) { + while (b.depth > a.depth) { + while (b.dom.depth > a.depth) b = b.dom; + for (int i=0; i<b.prev.length-1; i++) { + if (isBefore(a, b.prev[i])) return true; + } + b = b.prev[b.prev.length-1]; + } + return a == b; + } + + /** + * Is node placed during the control flow graph build. + * @param data Node to check. + * @return true if node is placed during the control flow graph build. + */ + private static boolean isPinnedNode(NodeData data) { + return data.node instanceof CFGNode || data.node instanceof PhiNode; + } + + /** + * Refine placement of a node. + * @param data The node to refine. + * @param block The block before the node should be scheduled. + */ + private void refinePlacement(NodeData data, BasicBlock block) { + assert !isPinnedNode(data); + data.block = data.block == null ? block : dom(data.block, block); + assert isValid(data); + } + + /** + * Refine placement if before is happening before data + * @param data The node for which the placement should be refined. + * @param before The node before which the data node should be placed. + */ + private void optionalRefinePlacement(NodeData data, Node before) { + od(before).ifPresent(d->{ + // before might be in a different branch. So check this case with isBefore + // and only refine the placement if it is not in a different branch. + if (isBefore(d.block, data.block)) refinePlacement(data, d.block); + }); + } + + /** + * Schedule all nodes not yet scheduled. + */ + private void doSchedule() { + while (!scheduleQueue.isEmpty()) { + var data = scheduleQueue.pop(); + assert !isPinnedNode(data); + + assert data.block != null; + assert data.users == 0; + + if (data.node instanceof MemOpNode l && l._isLoad) { + assert isValid(data); + // Handle anti-deps of load nodes. + // At this point all anti-dep nodes are scheduled, + // but they did not refine the placement + // so do that now. + var mem = data.node.in(1); + for(var out : mem._outputs) { + if (out instanceof PhiNode p) { + var r = p.in(0); + for (int i = 1; i < p.nIns(); i++) { + if (p.in(i) == mem) optionalRefinePlacement(data, r.in(i)); + } + } else if (!(out instanceof MemOpNode ld && ld._isLoad)) { + optionalRefinePlacement(data, out); + } + } + } + + assert isValid(data); + data.block.reverseSchedule.add(data.node); + + for(var in:data.node._inputs) { + if (in!=null) update(d(in), data.block); + } + if (data.node instanceof MemOpNode s && !s._isLoad) { + // Store nodes have anti-deps to load nodes. + // So decrease the uses of these loads when the store is placed. + for (var out: ((Node)s).in(1)._outputs) { + if (out instanceof MemOpNode ld && ld._isLoad) od(out).ifPresent(this::decUsers); + } + } + } + + // Now all nodes should be placed and have a block assigned + assert this.data.values().stream().noneMatch(d->d.block==null); + } + + /** + * Decrement the not-yet-placed users of a block. + * @param data The node for which the users should be decremented. + */ + private void decUsers(NodeData data) { + assert data.users > 0; + if (--data.users == 0) { + assert data.block != null; + assert isValid(data); + + // When all users are gone this node can be scheduled. + scheduleQueue.push(data); + } + } + + /** + * Update the placement of a node + * @param data The node to update + * @param block The block before which the node should happen. + */ + private void update(NodeData data, BasicBlock block) { + assert block != null; + if (data.users == 0) { + assert isPinnedNode(data); + return; + } + refinePlacement(data, block); + decUsers(data); + } + + /** + * Checks if a CFG node is ready to be placed. This is used for regions joining branches. + * @param node The CFG node to check + * @return true if all parents of a CFG node are placed. + */ + private boolean isCFGNodeReady(Node node) { + if (node instanceof LoopNode l) { + assert d(l.in(1)).block != null; + } else if (node instanceof RegionNode r) { + for(int i=1; i<r.nIns(); i++) { + if (od(r.in(i)).map(d->d.block==null).orElse(false)) return false; + } + } else if (node instanceof XCtrlNode) { + return false; + } else { + assert d(node.in(0)).block != null; + } + return true; + } + + /** + * Schedule all phi nodes. + * @param phiQueue List of all the phi nodes to schedule. + */ + private void schedulePhis(Stack<NodeData> phiQueue) { + while(!phiQueue.empty()) { + var data = phiQueue.pop(); + var phi = (PhiNode) data.node; + var r = phi.in(0); + data.block = d(r).block; + for(int i=1; i<phi.nIns(); i++) { + var in = phi.in(i); + od(r.in(i)).ifPresent(d->update(d(in), d.block)); + } + } + } + + /** + * Build the control flow graph. + * @param start The start node. + */ + private void doBuildCTF(StartNode start) { + var queue = new Stack<NodeData>(); + var phiQueue = new Stack<NodeData>(); + queue.push(d(start)); + while (!queue.isEmpty()) { + var data = queue.pop(); + var node = data.node; + assert node instanceof CFGNode; + BasicBlock block = switch (node) { + case StartNode s -> new BasicBlock(s, 0); + case LoopNode l -> new BasicBlock(l, d(l.in(1)).block); + case RegionNode r -> { + var prev = new ArrayList<BasicBlock>(); + int depth = 0; + for(int i=1; i<r.nIns(); i++) { + if( !od(r.in(i)).isPresent() ) continue; + BasicBlock bb = d(r.in(i)).block; + prev.add(bb); + depth = Math.max(depth,bb.depth); + } + yield new BasicBlock(r, depth+1, prev.toArray(BasicBlock[]::new)); + } + case IfNode i -> d(i.in(0)).block; + case ReturnNode ret -> d(ret .in(0)).block; + case CallNode call -> throw Utils.TODO(); + default -> new BasicBlock(node, d(node.in(0)).block); + }; + data.block = block; + if (node instanceof RegionNode r) { + // Regions might have phis which need to be scheduled. + // Put them on a list for later scheduling. + for (var out:r._outputs) { + if (out instanceof PhiNode p) { + var d = this.data.get(p); + if (d!=null) { + d.users=0; + phiQueue.push(d); + } + } + } + } + if( node instanceof FunNode fun ) { + // Cannot find CFG user from fun via a naive search, because always find + // Return but Return is not always the one CFG user. + CFGNode n = fun.uctrl(); + assert isCFGNodeReady(n) && d(n).block==null; + queue.push(d(n)); + } else if( !(node instanceof ReturnNode) ) { + for (Node n : node._outputs) + if(n instanceof CFGNode && isCFGNodeReady(n) && d(n).block == null) + queue.push(d(n)); + } + var b = block; + for(var in:data.node._inputs) od(in).ifPresent(d->update(d, b)); + } + + // Schedule all phi nodes. + schedulePhis(phiQueue); + } + + /** + * Mark a node alive and create ancillary data for it. + * @param queue List into which this node should be placed if it needs to be visited. + * @param node Node which should be marked alive. + * @param cfg If this node is a CFG node. + */ + private void markAlive(Stack<NodeData> queue, Node node, boolean cfg) { + var nd = od(node).orElse(null); + if (nd != null) { + // Node was already visited, just increase the users. + if (nd.users>0) nd.users++; + return; + } + assert node instanceof CFGNode == cfg; + assert isNotXCtrl(node); + nd = new NodeData(node); + if (cfg) nd.users=0; + data.put(node, nd); + queue.push(nd); + } + + /** + * Mark all alive nodes. + * First all CFG nodes are marked, then all other nodes. + * @param node THe start node. + */ + private void doMarkAlive(Node node) { + var cfgQueue = new Stack<NodeData>(); + var dataQueue = new Stack<NodeData>(); + var mem = new Stack<NodeData>(); + markAlive(cfgQueue, node, true); + // Mark all CFG nodes. + while (!cfgQueue.isEmpty()) { + var data = cfgQueue.pop(); + node = data.node; + assert node instanceof CFGNode; + if (!(node instanceof ReturnNode) ) { + for (var out : node._outputs) if (out!=null && out instanceof CFGNode && isNotXCtrl(out)) markAlive(cfgQueue, out, true); + } + for (var in : node._inputs) if(in!=null && !(in instanceof CFGNode) && isNotXCtrl(in)) markAlive(dataQueue, in, false); + } + // Mark all other nodes. + while (!dataQueue.isEmpty()) { + var data = dataQueue.pop(); + node = data.node; + assert !(node instanceof CFGNode); + if (node instanceof PhiNode phi) { + var r = phi.in(0); + for (int i=1; i<phi.nIns(); i++) { + if (od(r.in(i)).isPresent()) markAlive(dataQueue, phi.in(i), false); + } + } else { + for (var in : node._inputs) if (in != null && !(in instanceof CFGNode)) markAlive(dataQueue, in, false); + } + if (node instanceof MemOpNode s && !s._isLoad) mem.push(data); + } + // Handle store nodes and increase load with an anti-dep to the store. + while (!mem.isEmpty()) { + var data = mem.pop(); + node = data.node; + for(var out:node.in(1)._outputs) { + if (out instanceof MemOpNode ld && ld._isLoad) od(out).ifPresent(d->d.users++); + } + } + } + + /** + * Helper function to append the nodes of a block to an array of nodes + * @param arr The array the nodes of a block should be appended to. + * @param node A potentially separator node + * @param block The block from which the nodes should be appended. + * @return The combined new array. + */ + private static Node[] appendNodes(Node[] arr, Node node, BasicBlock block) { + var idx = arr.length; + arr = Arrays.copyOf(arr, arr.length+block.reverseSchedule.size()+(node==null?0:1)); + if (node != null) arr[idx++] = node; + for(int i=block.reverseSchedule.size()-1;i>=0;i--) { + arr[idx++] = block.reverseSchedule.get(i); + } + return arr; + } + + /** + * Find the CFG output of a node + * @param node The node + * @return The CFG output of the node. + */ + private static CFGNode findSingleCFGOut(Node node) { + if (node instanceof StartNode) { + for(var n:node._outputs) + if (n instanceof FunNode fun && "main".equals(fun._name) ) + return fun; + return null; + } + if( node instanceof FunNode fun ) return fun.uctrl(); + assert node._outputs.stream().filter(x -> x instanceof CFGNode).limit(2).count()<=1; + for(var n:node._outputs) if(n instanceof CFGNode cfg) return cfg; + return null; + } + + /** + * Build the final data structure after all the scheduling happened. + * @param start The start node + * @return The final schedule. + */ + private Block build(Node start) { + var blocks = new IdentityHashMap<Node, Block>(); + var queue = new Stack<NodeData>(); + queue.push(d(start)); + + // Visit all CFG nodes and create blocks for them. + // This can combine blocks. + while(!queue.isEmpty()) { + var data = queue.pop(); + var first = data.node; + Node prev; + var last = first; + Node[] arr = new Node[0]; + if (first instanceof RegionNode) { + var nodes = new ArrayList<Node>(); + for(var out: first._outputs) { + if (out instanceof PhiNode) { + if(od(out).isPresent()) nodes.add(out); + } + } + arr = nodes.toArray(arr); + } + arr = appendNodes(arr, null, data.block); + assert !(first instanceof IfNode); + for(;;) { + prev = last; + last = findSingleCFGOut(last); + if (last == null) break; + if (last instanceof RegionNode) { + if (blocks.get(last) == null && last != first) + queue.push(d(last)); + break; + } + if (last instanceof ReturnNode) break; + if (last instanceof IfNode if_) { + for(var out:if_._outputs) if (out instanceof CFGNode && blocks.get(out) == null) queue.push(d(out)); + break; + } + data = d(last); + arr = appendNodes(arr, data.node, data.block); + } + blocks.put(first, switch(last) { + case null -> new Block(arr, null, -1, new Block[0]); + case IfNode i -> new Block(arr, i, -1, new Block[2]); + case RegionNode r -> new Block(arr, r, r._inputs.find(prev), new Block[1]); + case ReturnNode r -> new Block(arr, r , -1, new Block[0]); + default -> throw new AssertionError("Unexpected block exit node"); + }); + } + // Update the next pointer of all blocks. + for (var block: blocks.values()) { + switch(block.exit) { + case null: break; + case IfNode i: + for(var out:i._outputs) if (out instanceof CProjNode p) block.next[p._idx] = blocks.get(p); + break; + case RegionNode r: + block.next[0] = blocks.get(r); + break; + default: + assert block.exit instanceof ReturnNode; + } + } + // And return the block for the start node. + return blocks.get(start); + } + + /** + * Create a schedule for the program reachable from start. + * @param start The start node + * @return The final schedule. + */ + public static Block schedule(StartNode start) { + var scheduler = new Scheduler(); + scheduler.doMarkAlive(start); + scheduler.doBuildCTF(start); + scheduler.doSchedule(); + return scheduler.build(start); + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java new file mode 100644 index 00000000..77e61b42 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java @@ -0,0 +1,174 @@ +package com.seaofnodes.simple.fuzzer; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.Eval2; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.Node; +import java.util.ArrayList; +import java.util.Objects; +import java.util.Random; +import java.util.function.Consumer; + +/** + * Implementation of the fuzzer. + * Random testcases are generated using the ScriptGenerator. + * This will generate a script similar to how the parser parses it but instead of parsing it will + * randomly choose a variation the parser would parse and generate it. + * These scripts are the parsed by the parser and all exceptions are caught and filtered + * to only show one occurrence of one problem. This includes script which generate different + * results when the compiled graph with and without peeps is executed. + * To aid debugging scripts that cause errors are then reduced by applying rules and checking + * that the same issue persists. + */ +public class Fuzzer { + + private static final int EVAL_TIMEOUT = 10000; + + /** + * List of exceptions already encountered. + * This is used to filter new exceptions and discard them if they are already found. + */ + private final ArrayList<Throwable> exceptions = new ArrayList<>(); + + /** + * Filter and record an exception in a script. + * @param e The exception caused by the script + * @param script The script causing the exception + * @param reproducer Reproducer which should be used to reproduce the test case. + */ + private void recordException(Throwable e, String script, Consumer<String> reproducer, long seed) { + for (var ex : exceptions) { + if (FuzzerUtils.isExceptionFromSameCause(ex, e)) return; + } + exceptions.add(e); + System.out.println("========== Stack =========="); + e.printStackTrace(System.out); + System.out.println("========== Seed =========="); + System.out.println(seed); + //System.out.println("========== Code ==========="); + //System.out.println(script); + System.out.println("========= Reduced ========="); + System.out.println(Reducer.reduce(script, e, reproducer)); + System.out.println("==========================="); + System.out.flush(); + } + + private static boolean neq(Object a, Object b) { + if (Objects.equals(a, b)) return false; + return true; + } + + /** + * Check that two graphs result in the same output when supplied with a value + * @param e1 Evaluator for the first graph + * @param e2 Evaluator for the second graph + * @param in The input value to both graphs to test for an equal output + */ + private static void checkGraphs(CodeGen code1, CodeGen code2, long in) { + var r1 = Eval2.eval(code1, in, EVAL_TIMEOUT); + var r2 = Eval2.eval(code2, in, EVAL_TIMEOUT); + if( r1 == null || r2 == null ) return; // Timeout test invalid + if( neq(r1, r2) ) + throw new RuntimeException("Different calculations values " + r1 + " vs " + r2); + } + + /** + * Run checks for script. Compile the script with peeps enabled and disabled. + * Check that exceptions raised in the parser by both methods are the same and only happens if the script may be invalid. + * If the script was successfully parsed check that both version behave the same. + * @param script The script to test + * @param valid If the script is definitely valid. If not some exceptions may be suppressed. + */ + private static void runCheck(String script, boolean valid) { + CodeGen code1; + try { + code1 = FuzzerUtils.parse(script, 123, true); + } catch (RuntimeException e1) { + try { + FuzzerUtils.parse(script, 456, false); + } catch (RuntimeException e2) { + if (FuzzerUtils.isExceptionFromSameCause(e1, e2)) { + if (!valid || e1.getClass() == Parser.ParseException.class) return; + } else { + e1.addSuppressed(e2); + } + } + throw e1; + } + CodeGen code2 = FuzzerUtils.parse(script, 456, false); + checkGraphs(code1, code2, 0); + checkGraphs(code1, code2, 1); + checkGraphs(code1, code2, 10); + } + + /** + * Check that the script does not result in exceptions. + * @param script The script to test. + * @param valid If the script is valid or if it might contain syntax errors. + */ + private void check(String script, boolean valid, long seed) { + try { + runCheck(script, valid); + } catch (Throwable e) { + recordException(e, script, s->runCheck(s, valid), seed); + } + } + + /** + * Run one test with the given seed, and check for peephole counts. + * @param seed The seed to use for generating this test case + */ + public int fuzzPeepTiming(long seed, int max_nids) { + var rand = new Random(seed); + var sb = new StringBuilder(); + new ScriptGenerator(rand, sb, true).genProgram(); + try { + var code = new CodeGen(sb.toString()); + + code.parse(); + int nids = code.UID(); + if( nids <= max_nids ) return max_nids; // Smaller, looking for trends as we grow + int parse_peeps= code._iter_cnt; + int parse_nops = code._iter_nop_cnt; + double parse_nop_ratio = (double)parse_nops/parse_peeps; + double parse_peeps_per_node = (double)parse_peeps/nids; + + code.opto(); + int iter_peeps= code._iter_cnt; + int iter_nops = code._iter_nop_cnt; + double iter_nop_ratio = (double)iter_nops/iter_peeps; + double iter_peeps_per_node = (double)iter_peeps/nids; + + System.out.printf("%6d | Parsing: peeps: %5d, nops: %5d, ratio: %5.3f, last UID: %5d ps/node: %5.3f | Iter: peeps: %6d, nops: %6d, ratio: %5.3f, ps/node: %5.3f\n", + seed, + parse_peeps,parse_nops,parse_nop_ratio,nids,parse_peeps_per_node, + iter_peeps , iter_nops, iter_nop_ratio, iter_peeps_per_node); + return nids; + } catch (Throwable e) { + // ignore exceptions, let the normal fullPeeps catch and reduce, + // we're interested in valid program optimizations + } + return max_nids; + } + + + /** + * Run one test with the given seed. + * @param seed The seed to use for generating this test case + */ + public void fuzzPeeps(long seed) { + var rand = new Random(seed); + var sb = new StringBuilder(); + var valid = new ScriptGenerator(rand, sb, true).genProgram(); + check(sb.toString(), valid, seed); + } + + + /** + * Check that no exceptions happened. + * @return true if no exception happened + */ + public boolean noExceptions() { + return exceptions.isEmpty(); + } +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java new file mode 100644 index 00000000..e08b73fc --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java @@ -0,0 +1,111 @@ +package com.seaofnodes.simple.fuzzer; + +import com.seaofnodes.simple.IterPeeps; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.StopNode; +import com.seaofnodes.simple.type.TypeInteger; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.util.BitSet; + +/** + * Some utilities for the fuzzer. + */ +class FuzzerUtils { + + /** + * Get the val of a private field + */ + @SuppressWarnings("unchecked") + public static <T> T getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException { + return (T) (obj instanceof Class<?> clz ? getField(clz, name).get(null) : getField(obj.getClass(), name).get(obj)); + } + + /** + * Get access to a private field + */ + public static Field getField(Class<?> clz, String name) throws NoSuchFieldException { + var field = clz.getDeclaredField(name); + try { + field.setAccessible(true); + } catch (Throwable e) { + // Intentionally left empty + } + return field; + } + + /** + * Try to rethrow an exception or create a runtime exception and throw it. + */ + public static RuntimeException rethrow(Throwable e) { + if (e instanceof RuntimeException re) return re; + if (e instanceof Error er) throw er; + return new RuntimeException(e); + } + + /** + * Some problems might trigger debug output. Suppress this output with a null print stream during fuzzing. + */ + public static final PrintStream NULL_PRINT_STREAM = new PrintStream(OutputStream.nullOutputStream()); + + /** + * Check that the messages are similar. + */ + private static boolean similarMessages(String a, String b) { + if (a == null || b == null) return true; + a = a.replaceAll("'\\w+'", "'normalized'").replaceAll("variable \\w+", "variable normalized"); + b = b.replaceAll("'\\w+'", "'normalized'").replaceAll("variable \\w+", "variable normalized"); + return a.equals(b); + } + + /** + * Check if both stack traces have the same first entry. Empty stack traces can happen with NPE optimization + * and allow the other to be any stack trace. + */ + private static boolean sameStackTraceOrigin(StackTraceElement[] a, StackTraceElement[] b) { + if (a == null || a.length == 0 || b == null || b.length == 0) return true; // One or both stack traces are missing. + return a[0].equals(b[0]); + } + + /** + * Checks if two exceptions are caused by the same problem. + */ + public static boolean isExceptionFromSameCause(Throwable a, Throwable b) { + if (a == null || b == null) return a == b; // Handle the null case + if (a.getClass() != b.getClass()) return false; // Different classes + if (!similarMessages(a.getMessage(), b.getMessage())) return false; // Different messages. Null is allowed as wildcard + var s1 = a.getStackTrace(); + var s2 = b.getStackTrace(); + if (!sameStackTraceOrigin(s1, s2)) return false; // Different stack trace origins + if (!isExceptionFromSameCause(a.getCause(), b.getCause())) return false; // Different causes + var o1 = a.getSuppressed(); + var o2 = b.getSuppressed(); + if (o1 == null || o2 == null || o1.length != o2.length) return o1 == o2; // Different suppression + for (int i=0; i<o1.length; i++) { + if (!isExceptionFromSameCause(o1[i], o2[i])) return false; // Different suppression + } + return true; + } + + /** + * Parse script with peepholes enabled or disabled + */ + public static CodeGen parse(String script, long workListSeed, boolean reset) { + var err = System.err; + var out = System.out; + try { + System.setErr(NULL_PRINT_STREAM); + System.setOut(NULL_PRINT_STREAM); + var code = new CodeGen(script, TypeInteger.BOT, workListSeed, reset); + return code.driver(CodeGen.Phase.LocalSched); + } finally { + System.setErr(err); + System.setOut(out); + } + } + +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Reducer.java b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Reducer.java new file mode 100644 index 00000000..f6e12e11 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Reducer.java @@ -0,0 +1,177 @@ +package com.seaofnodes.simple.fuzzer; + +import java.util.Arrays; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This class is used to reduce test cases created by the fuzzer. + * It applies rewrite rules to the test case and checks that the + * test still produces the same exception. + * This is done in a fixpoint iteration until every rewrite produces + * no or a different exception. + */ +public class Reducer { + + private interface Replacer extends BiConsumer<StringBuilder, Matcher> {} + + /** + * Holder for the rewrite rules + */ + private record Replace(Pattern pattern, boolean iterate, Replacer... replacements) { + Replace(Pattern p, Object... replacements) { + this(p, replacements[0] == Boolean.TRUE, Arrays.stream(replacements).filter(o->!(o instanceof Boolean)).map(Replace::from).toArray(Replacer[]::new)); + } + private static Replacer from(Object o) { + if (o instanceof Replacer r) return r; + if (o instanceof Integer i) return (s, m)->s.append(m.group(i)); + if (o instanceof String r) return (s, m)->s.append(r); + throw new IllegalArgumentException(); + } + } + + /** + * List of rewrite rules. + */ + private static final Replace[] REPLACEMENTS = { + new Replace(Pattern.compile("\\b(?:[^\\W0]|\\w\\w+)\\b"), "0", "1"), + new Replace(Pattern.compile("(?<=\\n|^)[^\\n]+(?=\\n|$)"), true, ""), + new Replace(Pattern.compile("(?<=[+\\-*/<>=(])--"), ""), + new Replace(Pattern.compile("\\b--"), "+"), + new Replace(Pattern.compile("[-!]"), ""), + new Replace(Pattern.compile("\\b\\+-"), "-"), + new Replace(Pattern.compile("(?<![+\\-*/<>=&|])(?:-|\\*|/|>=|<=|>>>|>>|>|<<|<|!=|==|&&|\\|\\||&|\\||^)(?![+*/<>=&|])"), "+"), + new Replace(Pattern.compile("\\?([^;]+):"), "+"), + new Replace(Pattern.compile("\\{((?:[^{}]|\\{})+)(?:\\n[ \\t]*)?}"), "", "{}", 1), + new Replace(Pattern.compile("(?<=\\n|^)([ \\t]*)\\{\\n(.*?)\\n\\1}", Pattern.DOTALL), 2), + new Replace(Pattern.compile("\\(([^()]+)\\)"), 1), + new Replace(Pattern.compile("\\d+ ?\\+ ?"), ""), + new Replace(Pattern.compile(" ?\\+ ?\\d+"), ""), + new Replace(Pattern.compile("\\n\\n+"), "\n"), + new Replace(Pattern.compile("^\\n+|\\n+$"), ""), + new Replace(Pattern.compile("else *"), ""), + new Replace(Pattern.compile("\\bif\\([^()]+\\) *"), ""), + new Replace(Pattern.compile("\\bwhile\\([^()]+\\) *"), ""), + new Replace(Pattern.compile("\\bstruct \\w+ \\{[^{}]*}"), "") + }; + + /** + * Predicate to test if the reduced script generates the same error. + */ + private final Predicate<String> tester; + + /** + * Create a reducer with a test function. + * @param tester Test function which returns true when the same issue is found in the script. + */ + private Reducer(Predicate<String> tester) { + this.tester = tester; + } + + /** + * Rewrites the script with one rewrite rule. + */ + private String doReplacement(String script, Pattern pattern, Replacer[] replacements) { + var matcher = pattern.matcher(script); + var sb = new StringBuilder(); + var last = 0; + var skip = 0; + outer: + while (matcher.find(last + skip)) { + sb.append(script, last, matcher.start()); + last = matcher.end(); + skip = last == matcher.start() ? 1 : 0; + var pos = sb.length(); + for (var replacement : replacements) { + replacement.accept(sb, matcher); + var tail = sb.length(); + sb.append(script, last, script.length()); + if (tester.test(sb.toString())) { + sb.setLength(tail); + continue outer; + } + sb.setLength(pos); + } + last = matcher.start(); + skip = 1; + } + sb.append(script, last, script.length()); + return sb.toString(); + } + + /** + * Clean up variable names from the random ones generated by the fuzzer. + */ + private String cleanVariables(String script) { + var matcher = Pattern.compile("\\b([0-9a-zA-Z_]+) !?([0-9a-zA-Z_]+)").matcher(script); + int[] num = {0, 0}; + while (matcher.find()) { + var type = matcher.group(1); + var var = matcher.group(2); + if (type.equals("new")) continue; + String prefix = "v"; + int t = 0; + if (type.equals("struct")) { + t = 1; + prefix = "s"; + } + if (var.matches(prefix+"\\d+")) continue; + while (script.contains(prefix+num[t])) num[t]++; + var n = script.replaceAll("\\b"+var+"\\b", prefix + num[t]); + if (tester.test(n)) { + script = n; + } + } + return script; + } + + /** + * Run all rewrite rules once. + */ + private String doAllReplacements(String script) { + for (var replace: REPLACEMENTS) { + String old; + do { + old = script; + script = doReplacement(script, replace.pattern, replace.replacements); + } while (replace.iterate && !old.equals(script)); + } + return script; + } + + /** + * Reduce the script to a minimal version which produces the same problem with a test function. + * @param tester Test function which returns true when the same issue is found in the script. + */ + public static String reduce(String script, Predicate<String> tester) { + var reducer = new Reducer(tester); + String old; + do { + old = script; + script = reducer.doAllReplacements(script); + script = reducer.cleanVariables(script); + } while (!script.equals(old)); + return script; + } + + /** + * Reduce the script to a minimal version which produces the same problem with a reproducer. + * @param ex The exception originally caused by the script + * @param reproducer Test function which throws an exception which will be checked against ex. + */ + public static String reduce(String script, Throwable ex, Consumer<String> reproducer) { + return reduce(script, s->{ + Throwable nex = null; + try { + reproducer.accept(s); + } catch (Throwable e) { + nex = e; + } + return FuzzerUtils.isExceptionFromSameCause(nex, ex); + }); + } + +}
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java new file mode 100644 index 00000000..dde5a1dc --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java @@ -0,0 +1,938 @@ +package com.seaofnodes.simple.fuzzer; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.node.ScopeNode; +import com.seaofnodes.simple.type.TypeInteger; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.function.Predicate; +import static com.seaofnodes.simple.Parser.KEYWORDS; + + +/** + * Generate a pseudo random script. + * This generator will generate the same script for two random number generators initialized with the same seed. + * To generate valid code it implements the parser but instead of parsing it emits the statements and expressions. + * It is guaranteed to terminate. + */ +public class ScriptGenerator { + + private static final int MAX_STATEMENTS_PER_BLOCK = 5; + private static final int MAX_NAME_LENGTH = 10; + private static final int MAX_BLOCK_DEPTH = 4; + private static final int MAX_EXPRESSION_DEPTH = 10; + + /** + * Number of spaces per indentation + */ + private static final int INDENTATION = 4; + /** + * Valid characters for identifiers. The last 10 are not valid for the first character. + */ + private static final String VAR_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"; + + /** + * Flag for a statement that it does not pass on control flow to the next statement. + */ + private static final int FLAG_STOP = 0x01; + /** + * Flag for a statement that it contains a final if statement without an else branch. + */ + private static final int FLAG_IF_WITHOUT_ELSE = 0x02; + + private static class Type { + final String name; + Type(String name) {this.name=name;} + boolean isa(Type other) { return this == other; } + } + + private static class TypeStruct extends Type { + record Field (String name, Type type, TypeStruct struct) {} + Field[] fields; + final TypeNullable nullable = new TypeNullable(this); + TypeStruct(String name) { + super(name); + } + boolean isa(Type other) { return this == other || other == nullable; } + } + + private static class TypeNullable extends Type { + + final Type base; + + TypeNullable(Type base) { + super(base.name+"?"); + this.base = base; + } + + } + + private static final Type TYPE_FLT = new Type("flt"); + + private static class TypeInt extends Type { + + TypeInt(String name) { + super(name); + } + + @Override + boolean isa(Type other) { + return super.isa(other) || other == TYPE_FLT || other instanceof TypeInt; + } + } + + private static final List<TypeInt> INTTYPES = new ArrayList<>(); + + static { + for( var e : Parser.TYPES.entrySet() ) { + if( e.getValue() instanceof TypeInteger ) { + INTTYPES.add(new TypeInt(e.getKey())); + } + } + } + + private static final Type TYPE_INT = INTTYPES.stream().filter(t->t.name.equals("int")).findAny().get(); + private static final Type TYPE_BOOL = INTTYPES.stream().filter(t->t.name.equals("bool")).findAny().get(); + + private static class Variable { + final String name; + final Type declared; + final Variable shadowing; + Type type; + boolean shadowed = false; + + Variable(String name, Type type, Variable var) { + this.name = name; + this.declared = type; + this.type = type; + this.shadowing = var; + } + } + + /** + * The random number generator used for random decisions. + */ + private final Random random; + /** + * Indentation depth. + */ + private int indentation = 0; + /** + * Output string builder + */ + private final StringBuilder sb; + /** + * Number of nested loops + */ + private int loopDepth = 0; + /** + * Current scope start in the variables list. + */ + private int currScopeStart = 0; + /** + * The depth of blocks allowed. + */ + private int depth = MAX_BLOCK_DEPTH; + /** + * Current variables in scope. + */ + private final ArrayList<Variable> variables = new ArrayList<>(); + /** + * All defined structs. + */ + private final ArrayList<TypeStruct> structs = new ArrayList<>(); + /** + * All forward declared structs + */ + private final ArrayList<TypeStruct> forwardStructs = new ArrayList<>(); + /** + * Allow to declare structs. + */ + private boolean allowStructs = true; + /** + * If this needs to generate valid scripts or is also allowed to generate invalid ones. + */ + private boolean generateValid; + /** + * If this script might be invalid. + */ + private boolean maybeInvalid = false; + + + /** + * + * @param random the random number generator. + * @param sb the script will be written to this string builder. + * @param generateValid if the script should be guaranteed valid or if it is allowed to contain bugs. + */ + public ScriptGenerator(Random random, StringBuilder sb, boolean generateValid) { + this.random = random; + this.sb = sb; + this.generateValid = generateValid; + } + + /** + * Random number with log distribution + * @param max The maximum value + * @return A random number in the range [0, max) with higher numbers being more uncommon. + */ + private int randLog(int max) { + max--; + int n = 1<<max; + var num = random.nextInt(n); + for (int i=max-1; i>=0; i--) { + if ((num & (1<<i))!=0) return max-i-1; + } + return max; + } + + /** + * Helper function to print indentation. + * @return sb for chaining + */ + private StringBuilder printIndentation() { + return sb.repeat(' ', indentation); + } + + /** + * Generate a random name for variables. This might be invalid when it is a keyword. + * @return The random name generated + */ + private StringBuilder getRandomName() { + int len = random.nextInt(MAX_NAME_LENGTH) + 1; + StringBuilder sb = new StringBuilder(len); + sb.append(VAR_CHARS.charAt(random.nextInt(VAR_CHARS.length()-10))); + for (int i=1; i<len; i++) + sb.append(VAR_CHARS.charAt(random.nextInt(VAR_CHARS.length()))); + return sb; + } + + /** + * Should invalid code be generated? + * @return True if invalid code should be generated + */ + private boolean generateInvalid() { + if (generateValid || random.nextInt(1000)>2) return false; + maybeInvalid = true; + return true; + } + + /** + * Lookup a variable by name + * @param name name of the variable + * @return The index of the variable in variables or -1 + */ + private int lookup(String name) { + for (int i=variables.size()-1; i>=0; i--) { + if (variables.get(i).name.equals(name)) return i; + } + return -1; + } + + /** + * Lookup a variable by name + * @param name name of the variable + * @return THe variable of null if not found + */ + private Variable lookupVar(String name) { + int idx = lookup(name); + return idx == -1 ? null : variables.get(idx); + } + + /** + * Add a variable to the current scope + * @param name The name of the variable + * @param type The declared type of the variable + */ + private void addVariable(String name, Type type) { + var old = lookupVar(name); + variables.add(new Variable(name, type, old)); + if (old != null) old.shadowed = true; + } + + /** + * Pop variables to level to + * @param to Level until which variables should be popped + */ + private void popVariables(int to) { + while (variables.size() > to) { + var v = variables.removeLast(); + if (v.shadowing != null) v.shadowing.shadowed = false; + } + } + + /** + * Get a random visible variable patching pred + * @param pred The predicate the variable needs to match + * @return A random visible variable matching pred or null if no variable mached pred. + */ + private Variable findVisibleVariablesMatching(Predicate<Variable> pred) { + int num=0; + for (var v:variables) { + if (!v.shadowed && pred.test(v)) num++; + } + if (num == 0) return null; + num = random.nextInt(num); + for (var v:variables) { + if (!v.shadowed && pred.test(v) && num-- == 0) return v; + } + throw new AssertionError(); + } + + /** + * Get a structure by name + * @param name Name of the structure + * @return The structure of null + */ + private TypeStruct getStruct(String name) { + for (var s:structs) { + if (s.name.equals(name)) return s; + } + for (var s:forwardStructs) if (s.name.equals(name)) return s; + return null; + } + + /** + * Generate a variable name. This might be new random name or a name from an outer scope. + * If the program is allowed to be invalid this can return keywords and already used variable names in the current scope. + * @return The variable name. + */ + private String getVarName() { + if (currScopeStart > 0 && random.nextInt(10) > 7) { + // Use a variable outside the current scope. + var v = variables.get(random.nextInt(currScopeStart)); + if (lookup(v.name) < currScopeStart) return v.name; + if (!generateValid) { + maybeInvalid = true; + return v.name; + } + } + // Generate a new random variable name + StringBuilder sb = getRandomName(); + var v = sb.toString(); + if (!generateValid && (KEYWORDS.contains(v) || lookup(v) >= currScopeStart)) { + maybeInvalid = true; + return v; + } + while (KEYWORDS.contains(v) || lookup(v) >= currScopeStart) { + sb.append(VAR_CHARS.charAt(random.nextInt(VAR_CHARS.length()))); + v = sb.toString(); + } + return v; + } + + private <T> T randFromList(List<T> list) { + return list.get(random.nextInt(list.size())); + } + + /** + * Get a random structure name + * @return A random structure name + */ + private String getStructName() { + if (!structs.isEmpty() && generateInvalid()) return randFromList(structs).name; + if (!forwardStructs.isEmpty() && generateInvalid()) return randFromList(forwardStructs).name; + + // Generate a new random struct name + StringBuilder sb = getRandomName(); + var v = sb.toString(); + if (!generateValid && (KEYWORDS.contains(v) || getStruct(v) != null)) { + maybeInvalid = true; + return v; + } + while (KEYWORDS.contains(v) || getStruct(v) != null) { + sb.append(VAR_CHARS.charAt(random.nextInt(VAR_CHARS.length()))); + v = sb.toString(); + } + return v; + } + + public TypeInt getIntType() { + return randFromList(INTTYPES); + } + + /** + * Get a random type + * @return A random type + */ + private Type getType(boolean allowForward) { + int t = random.nextInt(10); + if( t<5 || structs.isEmpty() ) return getIntType(); + if( t<7 ) return TYPE_FLT; + if (allowForward && random.nextInt(10)==0) { + int i=random.nextInt(forwardStructs.size()+1); + if (i>0) return forwardStructs.get(i-1).nullable; + var name = getStructName(); + var struct = new TypeStruct(name); + forwardStructs.add(struct); + return struct.nullable; + } + TypeStruct struct = randFromList(structs); + if (random.nextBoolean()) return struct.nullable; + return struct; + } + + private Type getType() { + return getType(false); + } + + /** + * Generates a program and writes it into the string builder supplied in the constructor. + * @return If the program is allowed to be invalid returns if something potentially invalid was generated. + */ + public boolean genProgram() { + var oldGenerateValid = generateValid; + if (!generateValid && random.nextBoolean()) generateValid = true; + this.maybeInvalid = false; + addVariable(ScopeNode.ARG0, TYPE_INT); + currScopeStart = variables.size(); + if ((genStatements() & FLAG_STOP) == 0) { + if (generateValid || random.nextInt(10)<7) { + genReturn(); + } else { + this.maybeInvalid = true; + } + } + generateValid = oldGenerateValid; + return !this.maybeInvalid; + } + + /** + * Generate a list of statements. + * @return flags FLAG_STOP and FLAG_IF_WITHOUT_ELSE for the last statement generated + */ + public int genStatements() { + var num = random.nextInt(MAX_STATEMENTS_PER_BLOCK * (depth+1)); + for (int i=0; i<num; i++) { + printIndentation(); + var stop = genStatement(); + sb.append("\n"); + if ((stop & FLAG_STOP) != 0) return stop; + } + return 0; + } + + /** + * Generate a single statement + * @return flags FLAG_STOP and FLAG_IF_WITHOUT_ELSE for the generated statement + */ + public int genStatement() { + return switch (random.nextInt(12)) { + case 0 -> allowStructs || generateInvalid() ? genStruct() : genAssignment(); + case 1 -> genBlock(); + case 2 -> genIf(); + case 3 -> genCountedLoop(); + case 4 -> genWhile(); + case 5, 6 -> genDecl(); + case 7, 8, 9 -> genAssignment(); + case 10 -> genNullCheck(); + default -> genExit(); + }; + } + + /** + * Generate a new structure + * @return 0 + */ + public int genStruct() { + int idx = random.nextInt(forwardStructs.size()+10); + TypeStruct struct; + if (idx < 10) { + var name = getStructName(); + struct = new TypeStruct(name); + forwardStructs.add(struct); + } else { + struct = forwardStructs.get(idx-10); + } + var fields = new TypeStruct.Field[generateInvalid() ? 0 : random.nextInt(10)]; + sb.append("struct ").append(struct.name).append(" {\n"); + indentation += INDENTATION; + for (int i=0; i<fields.length; i++) { + var fieldName = getRandomName(); + var type = getType(true); + printIndentation().append(type.name).append(" ").append(fieldName).append(";\n"); + fields[i] = new TypeStruct.Field(fieldName.toString(), type, struct); + } + indentation -= INDENTATION; + printIndentation().append("};"); + struct.fields = fields; + forwardStructs.remove(struct); + structs.add(struct); + return 0; + } + + /** + * Generate a statement for if, else and while blocks. + * This is special since it disallows declarations and prefers to generate blocks. + * @return flags FLAG_STOP and FLAG_IF_WITHOUT_ELSE for the generated statement + */ + public int genStatementBlock() { + var oldAllowStructs = allowStructs; + allowStructs = false; + indentation += INDENTATION; + int res; + if (depth == 0) { + res = random.nextBoolean() ? genAssignment() : genExit(); + } else { + depth--; + res = switch (random.nextInt(12)) { + case 1, 2, 3, 4, 5 -> { + depth++; + indentation -= INDENTATION; + var ret = genBlock(); + indentation += INDENTATION; + depth--; + yield ret; + } + case 6 -> genIf(); + case 7 -> genCountedLoop(); + case 8 -> genWhile(); + case 9 -> genAssignment(); + case 10 -> genNullCheck(); + default -> genExit(); + }; + depth++; + } + indentation -= INDENTATION; + allowStructs = oldAllowStructs; + return res; + } + + /** + * Generate an exit. This can be return or break and continue when in a loop. + * @return FLAG_STOP + */ + public int genExit() { + if (loopDepth == 0 && generateValid) return genReturn(); + return switch (random.nextInt(7)) { + case 0,1,2 -> { + if (loopDepth == 0) maybeInvalid = true; + sb.append("continue;"); + yield FLAG_STOP; + } + case 3,4,5 -> { + if (loopDepth == 0) maybeInvalid = true; + sb.append("break;"); + yield FLAG_STOP; + } + default -> genReturn(); + }; + } + + /** + * Generate a block statement. After a certain depth only empty blocks are generated to ensure termination of the generator. + * @return flag FLAG_STOP for the generated statement + */ + public int genBlock() { + if (depth == 0) { + sb.append("{}"); + return 0; + } + var oldAllowStructs = allowStructs; + var oldCSS = currScopeStart; + allowStructs = false; + currScopeStart = variables.size(); + depth--; + sb.append("{\n"); + indentation += INDENTATION; + var stop = genStatements(); + indentation -= INDENTATION; + printIndentation().append("}"); + popVariables(currScopeStart); + depth++; + currScopeStart = oldCSS; + allowStructs = oldAllowStructs; + return stop & ~FLAG_IF_WITHOUT_ELSE; + } + + /** + * Generate an if statement with an optional else block. + * @return flags FLAG_STOP and FLAG_IF_WITHOUT_ELSE for the generated statement + */ + public int genIf() { + sb.append("if("); + genExpression(TYPE_BOOL, true, true); + sb.append(") "); + var stop = genStatementBlock(); + if ((stop & FLAG_IF_WITHOUT_ELSE) == 0 && random.nextInt(10) > 3) { + sb.append("\n"); + printIndentation().append("else "); + stop &= genStatementBlock(); + } else { + stop = FLAG_IF_WITHOUT_ELSE; + } + return stop; + } + + /** + * Generate a block with a null check + * if (nullable) { handle_nullable_as_non_nullable; } + */ + public int genNullCheck() { + var v = findVisibleVariablesMatching(va->va.declared instanceof TypeNullable); + if (v == null) return genIf(); + var n = (TypeNullable)v.declared; + boolean negate = random.nextBoolean(); + sb.append("if("); + if (negate) sb.append("!"); + sb.append(v.name).append(")"); + if (!negate) v.type = n.base; + var stop = genStatementBlock(); + v.type = n; + if ((stop & FLAG_IF_WITHOUT_ELSE) == 0 && random.nextInt(10) > 3) { + sb.append("\n"); + printIndentation().append("else "); + if (negate) v.type = n.base; + stop &= genStatementBlock(); + v.type = n; + } else { + stop = FLAG_IF_WITHOUT_ELSE; + } + return stop; + } + + /** + * Generate a while loop. + * @return 0 + */ + public int genWhile() { + sb.append("while("); + genExpression(TYPE_BOOL, true, true); + sb.append(") "); + loopDepth++; + genStatementBlock(); + loopDepth--; + return 0; + } + + /** + * Generate a counted loop of the form + * <code> + * { + * int varname = start_expr; + * while (varname < end_expr) loop_body; + * } + * </code> + * @return 0 + */ + public int genCountedLoop() { + if (depth == 0) return genWhile(); + var oldCSS = currScopeStart; + currScopeStart = variables.size(); + sb.append("{\n"); + indentation += INDENTATION; + String name = getVarName(); + printIndentation().append("int ").append(name).append("="); + genExpression(TYPE_INT, true, false); + sb.append(";\n"); + addVariable(name, TYPE_INT); + printIndentation().append("while(").append(name).append("<"); + genShift(TYPE_INT, true, false, MAX_EXPRESSION_DEPTH); + sb.append(") {\n"); + indentation += INDENTATION; + depth--; + loopDepth++; + printIndentation().append(name).append("=").append(name).append("+"); + genExpression(TYPE_INT, true, false); + sb.append(";\n"); + genStatements(); + loopDepth--; + depth++; + indentation -= INDENTATION; + printIndentation().append("}\n"); + indentation -= INDENTATION; + printIndentation().append("}"); + popVariables(currScopeStart); + currScopeStart = oldCSS; + return 0; + } + + /** + * Generate a declaration statement. + * @return 0 + */ + public int genDecl() { + var type = getType(); + var name = getVarName(); + // Always make them mutable + sb.append(generateInvalid() ? getRandomName() : type.name).append(" !").append(name); + if (!(type instanceof TypeNullable) || random.nextBoolean()) { + sb.append("="); + genExpression(type, true, type==TYPE_BOOL); + } + sb.append(";"); + addVariable(name, type); + return 0; + } + + /** + * Generate an assignment statement. + * @return 0 + */ + public int genAssignment() { + Type type; + Type declared; + if (generateInvalid()) { + sb.append(getRandomName()); + type = getType(); + declared = type; + } else { + var v = findVisibleVariablesMatching(va->true); + if (v == null) return genDecl(); + sb.append(v.name); + type = v.type; + declared = v.declared; + } + if (generateInvalid()) { + var name = getRandomName(); + sb.append(".").append(name); + declared = getType(); + } else if (type instanceof TypeStruct s && s.fields.length > 0 && random.nextBoolean()) { + var field = s.fields[random.nextInt(s.fields.length)]; + sb.append(".").append(field.name); + declared = field.type; + } + sb.append("="); + genExpression(declared, true, declared==TYPE_BOOL); + sb.append(";"); + return 0; + } + + /** + * Generate a return statement. + * @return FLAG_STOP + */ + public int genReturn() { + var type = getType(); + sb.append("return "); + genExpression(type, true, false); + sb.append(";"); + return FLAG_STOP; + } + + public void genExpression(Type type, boolean change, boolean preferLogical) { + genExpression(type, change, preferLogical, MAX_EXPRESSION_DEPTH); + } + + public void genExpression(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + if (d > 0 && random.nextInt(10)==0) { + genLogical(TYPE_INT, true, true, d); + sb.append("?"); + genExpression(type, true, preferLogical, d-1); + sb.append(":"); + genExpression(type, false, preferLogical, d-1); + } else { + genLogical(type, false, preferLogical, d); + } + } + + public void genLogical(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + genBitwise(type, false, preferLogical, d); + while (d-->0 && random.nextInt(preferLogical?5:50) == 0) { + sb.append(random.nextBoolean()?"&&":"||"); + genBitwise(type, true, preferLogical, d); + } + } + + public void genBitwise(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + genComparison(type, false, preferLogical, d); + while (type instanceof TypeInt && d-->0 && random.nextInt(preferLogical?50:5)==0) { + sb.append("&|^".charAt(random.nextInt(3))); + genComparison(type, true, preferLogical, d); + } + } + + public void genComparison(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + if (d > 0 && type instanceof TypeInt && random.nextInt(preferLogical?5:50)==0) { + type = getType(); + genComparison(type, true, preferLogical, d-1); + sb.append(random.nextBoolean()?"==":"!="); + } + genChaining(type, false, preferLogical, d); + } + + public void genChaining(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + if (d>0 && type instanceof TypeInt && random.nextInt(preferLogical?5:50)==0) { + genShift(TYPE_INT, true, false, d); + char c = random.nextBoolean()?'>':'<'; + sb.append(c); + if (random.nextInt(4)==0) sb.append('='); + genShift(TYPE_INT, true, false, --d); + while (d-->0 && random.nextInt(preferLogical?5:50)==0) { + if (generateInvalid()) c = c=='>' ? '<' : '>'; + sb.append(c); + if (random.nextInt(4)==0) sb.append('='); + genShift(TYPE_INT, true, false, d); + } + } else { + genShift(type, false, preferLogical, d); + } + } + + private static final String[] SHIFTS = {">>", ">>>", "<<"}; + + public void genShift(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + genAddition(type, false, preferLogical, d); + while (d-- > 0 && type instanceof TypeInt && random.nextInt(50)==0) { + sb.append(SHIFTS[random.nextInt(3)]); + genAddition(type, true, preferLogical, d); + } + } + + public void genAddition(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + genMultiplication(type, false, preferLogical, d); + while (d-- > 0 && (type instanceof TypeInt || type==TYPE_FLT) && random.nextInt(50)==0) { + sb.append(random.nextBoolean()?" + ":" - "); + genMultiplication(type, true, preferLogical, d); + } + } + + public void genMultiplication(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + genUnary(type, false, preferLogical, d); + while (d-- > 0 && (type instanceof TypeInt || type==TYPE_FLT) && random.nextInt(50)==0) { + sb.append(random.nextBoolean()?'*':'/'); + genUnary(type, true, preferLogical, d); + } + } + + /** + * Generate a unary expression. + */ + public void genUnary(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + if (!(type instanceof TypeInt) && type != TYPE_FLT) { + genSuffix(type, false, preferLogical, d); + return; + } + while (d>0 && random.nextInt(5)==0) { + d--; + boolean what = type instanceof TypeInt && random.nextInt(preferLogical?2:20) == 0; + sb.append(what?'!':'-'); + } + if (random.nextInt(10)==0) { + var t = type; + var v = findVisibleVariablesMatching(va->va.type.isa(t)); + if (v != null) { + sb.append(random.nextBoolean()?"--":"++").append(v.name); + return; + } + } + genSuffix(type, false, preferLogical, d); + } + + public TypeStruct.Field getField(Type type) { + int n=0; + for (var s: structs) { + for (var f: s.fields) { + if (f.type.isa(type)) n++; + } + } + if (n==0) return null; + n = random.nextInt(n); + for (var s: structs) { + for (var f: s.fields) { + if (f.type.isa(type)) if (n--==0) return f; + } + } + throw new AssertionError(); + } + + public void genSuffix(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + if (d > 0 && random.nextBoolean() && genField(type, d-1)) return; + if (d > 0 && random.nextInt(10) == 0) { + if (random.nextBoolean() && genField(type, d-1)) return; + var t = type; + var v = findVisibleVariablesMatching(va -> va.type.isa(t)); + if (v != null) { + sb.append(v.name).append(random.nextBoolean() ? "--" : "++"); + return; + } + } + genPrimary(type, false, preferLogical, d); + } + + public boolean genField(Type type, int d) { + if (generateInvalid()) { + var field = getRandomName(); + var t = getType(); + genSuffix(t, true, false, d); + sb.append(".").append(field); + } else { + var field = getField(type); + if (field == null) return false; + genSuffix(field.struct, true, false, d); + sb.append(".").append(field.name); + } + return true; + } + + /** + * Generate a primary expression. + */ + public void genPrimary(Type type, boolean change, boolean preferLogical, int d) { + if (change && generateInvalid()) type = getType(); + var rand = random.nextInt(10); + if (d > 0 && rand == 0) { + sb.append("("); + genExpression(type, false, preferLogical, d-1); + sb.append(")"); + } else if (rand < 6) { + genVariable(type); + } else { + genConst(type); + } + } + + /** + * Generate a constant. + */ + public void genConst(Type type) { + if (generateInvalid()) type = getType(); + if (type instanceof TypeInt || (type == TYPE_FLT && random.nextBoolean())) { + var rand = random.nextInt(10); + switch (rand) { + case 0 -> sb.append("true"); + case 1 -> sb.append("false"); + default -> sb.append(random.nextInt(1<<(rand-2))); + } + } else if (type == TYPE_FLT) { + sb.append(random.nextFloat()); + } else if (type instanceof TypeNullable n) { + if ((n.base instanceof TypeStruct s && s.fields == null) || random.nextBoolean()) { + sb.append("null"); + } else { + sb.append("new ").append(generateInvalid() ? getRandomName() : n.base.name); + } + } else { + sb.append("new ").append(generateInvalid() ? getRandomName() : type.name); + } + } + + /** + * Generate a variable. If there are none generate a number instead. + * If the program is allowed to be invalid a random name can be generated in some cases. + */ + public void genVariable(Type type) { + if (generateInvalid()) { + sb.append(getRandomName()); + return; + } + if (generateInvalid()) type = getType(); + var t = type; + var v = findVisibleVariablesMatching(va->va.type.isa(t)); + if (v == null) genConst(type); + else sb.append(v.name); + } + +}
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/and1.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/and1.smp new file mode 100644 index 00000000..ef4c904f --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/and1.smp @@ -0,0 +1,10 @@ +// -*- mode: java; -*- +int a = 1; +int b = 1; + +if(a && b) { + sys.io.p("And"); +} else { + sys.io.p("Or"); +} +return 0; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/and2.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/and2.smp new file mode 100644 index 00000000..2a463c94 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/and2.smp @@ -0,0 +1,16 @@ +// -*- mode: java; -*- +int a = 1; +int b = 1; + +int x=1; +int y=1; +int z=0; + +int g = x++ && y++ && z++; + +if(x == 2 && y == 2 && z == 1 && g == 0) { + sys.io.p("Effected"); +} else { + sys.io.p("Not effected"); +} +return 0; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/and3.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/and3.smp new file mode 100644 index 00000000..aadbdfed --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/and3.smp @@ -0,0 +1,14 @@ +// -*- mode: java; -*- +int a = 1; +int b = 1; + +var sq = { int x -> + x*x; +}; + +if(a && sq(0)) { + sys.io.p("And"); +} else { + sys.io.p("Or"); +} +return 0; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/antiDep1.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/antiDep1.smp new file mode 100644 index 00000000..b18dfd16 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/antiDep1.smp @@ -0,0 +1,11 @@ +// -*- mode: java; -*- +struct S { int f; }; +var v0 = new S; +S? v1; +if (arg) v1 = new S; +if (v1) { + v0.f = v1.f; +} else { + v0.f = 2; +} +return v0; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/arg_count.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/arg_count.c new file mode 100644 index 00000000..e247e28a --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/arg_count.c @@ -0,0 +1,10 @@ +#include <stdio.h> + +__attribute__ ((CALL_CONV)) +extern double addAll( long long i0, double f1, long long i2, double f3, long long i4, double f5, long long i6, double f7, long long i8, double f9, long long i10, double f11, long long i12, double f13, long long i14, double f15, long long i16, double f17, long long i18, double f19 ); + +int main() { + double result = addAll( 0, 1.1, 2, 3.1, 4, 5.1, 6, 7.1, 8, 9.1, 10, 11.1, 12, 13.1, 14, 15.1, 16, 17.1, 18, 19.1 ); + printf("%f\n", result); + return 0; +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/arg_count.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/arg_count.smp new file mode 100644 index 00000000..6b6bc0ae --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/arg_count.smp @@ -0,0 +1,6 @@ +// -*- mode: java; -*- +val addAll = { int i0, flt f1, int i2, flt f3, int i4, flt f5, int i6, flt f7, int x8, flt f9, int i10, flt f11, int i12, flt f13, int i14, flt f15, int x16, flt f17 int x18, flt f19 -> + return + i0 + f1+ i2+ f3+ i4+ f5+ i6+ f7+ x8 +f9 + + i10+f11+i12+f13+i14+f15+x16+f17+x18+f19 ; +}; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/array1.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/array1.smp new file mode 100644 index 00000000..6b10f92c --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/array1.smp @@ -0,0 +1,9 @@ +// -*- mode: java; -*- +int[] !ary = new int[arg]; +// Fill [0,1,2,3,4,...] +for( int i=0; i<ary#; i++ ) + ary[i] = i; +// Fill [0,1,3,6,10,...] +for( int i=0; i<ary#-1; i++ ) + ary[i+1] += ary[i]; +return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6 diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/brain_fuck.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/brain_fuck.c new file mode 100644 index 00000000..127cbe73 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/brain_fuck.c @@ -0,0 +1,18 @@ +#include <stdio.h> +#include <stdbool.h> + +typedef struct AryInt { + unsigned int len; + unsigned char data[]; +} AryInt; + +__attribute__ ((CALL_CONV)) +extern AryInt* brain_fuck(); + +int main() { + AryInt* ps = brain_fuck(); + + printf("%.*s", ps->len, ps->data); + + return 0; +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/brain_fuck.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/brain_fuck.smp new file mode 100644 index 00000000..ed90cb84 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/brain_fuck.smp @@ -0,0 +1,46 @@ +// -*- mode: java; -*- +val brain_fuck = { -> + u8[] !program = new u8[106];program[0] = 43;program[1] = 43;program[2] = 43;program[3] = 43;program[4] = 43;program[5] = 43;program[6] = 43;program[7] = 43;program[8] = 91;program[9] = 62;program[10] = 43;program[11] = 43;program[12] = 43;program[13] = 43;program[14] = 91;program[15] = 62;program[16] = 43;program[17] = 43;program[18] = 62;program[19] = 43;program[20] = 43;program[21] = 43;program[22] = 62;program[23] = 43;program[24] = 43;program[25] = 43;program[26] = 62;program[27] = 43;program[28] = 60;program[29] = 60;program[30] = 60;program[31] = 60;program[32] = 45;program[33] = 93;program[34] = 62;program[35] = 43;program[36] = 62;program[37] = 43;program[38] = 62;program[39] = 45;program[40] = 62;program[41] = 62;program[42] = 43;program[43] = 91;program[44] = 60;program[45] = 93;program[46] = 60;program[47] = 45;program[48] = 93;program[49] = 62;program[50] = 62;program[51] = 46;program[52] = 62;program[53] = 45;program[54] = 45;program[55] = 45;program[56] = 46;program[57] = 43;program[58] = 43;program[59] = 43;program[60] = 43;program[61] = 43;program[62] = 43;program[63] = 43;program[64] = 46;program[65] = 46;program[66] = 43;program[67] = 43;program[68] = 43;program[69] = 46;program[70] = 62;program[71] = 62;program[72] = 46;program[73] = 60;program[74] = 45;program[75] = 46;program[76] = 60;program[77] = 46;program[78] = 43;program[79] = 43;program[80] = 43;program[81] = 46;program[82] = 45;program[83] = 45;program[84] = 45;program[85] = 45;program[86] = 45;program[87] = 45;program[88] = 46;program[89] = 45;program[90] = 45;program[91] = 45;program[92] = 45;program[93] = 45;program[94] = 45;program[95] = 45;program[96] = 45;program[97] = 46;program[98] = 62;program[99] = 62;program[100] = 43;program[101] = 46;program[102] = 62;program[103] = 43;program[104] = 43;program[105] = 46; + int d = 0; + u8[] !output = new u8[0]; + u8[] !data = new u8[100]; + + for( int pc = 0; pc < program#; pc++ ) { + var command = program[pc]; + if (command == 62) { + d++; + } else if (command == 60) { + d--; + } else if (command == 43) { + data[d]++; + } else if (command == 45) { + data[d]--; + } else if (command == 46) { + // Output a byte; increase the output array size + var old = output; + output = new u8[output# + 1]; + for( int i = 0; i < old#; i++ ) + output[i] = old[i]; + output[old#] = data[d]; // Add the extra byte on the end + } else if (command == 44) { + data[d] = 42; + } else if (command == 91) { + if (data[d] == 0) { + for( int d = 1; d > 0; ) { + command = program[++pc]; + if (command == 91) d++; + if (command == 93) d--; + } + } + } else if (command == 93) { + if (data[d]) { + for( int d = 1; d > 0; ) { + command = program[--pc]; + if (command == 93) d++; + if (command == 91) d--; + } + } + } + } + return output; +}; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/echo.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/echo.smp new file mode 100644 index 00000000..8eafd73b --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/echo.smp @@ -0,0 +1,3 @@ +// -*- mode: java; -*- +// Echo stdin to stdout. +return sys.io.p( sys.io.stdin() ); diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/fib.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/fib.c new file mode 100644 index 00000000..263d2f13 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/fib.c @@ -0,0 +1,16 @@ +#include <stdio.h> +#include <stdbool.h> + + +__attribute__ ((CALL_CONV)) +extern int fib(int x); + +int main() { + printf("["); + for (int i = 0; i < 10; i++) { + printf("%d", fib(i)); + if (i < 9) printf(", "); + } + printf("]"); + return 0; +}
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/fib.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/fib.smp new file mode 100644 index 00000000..1512541b --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/fib.smp @@ -0,0 +1,11 @@ +// -*- mode: java; -*- +val fib = {int n -> + int f1=1; + int f2=1; + while( n-- > 1 ){ + int temp = f1+f2; + f1=f2; + f2=temp; + } + return f2; +};
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/helloWorld.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/helloWorld.smp new file mode 100644 index 00000000..07ff935f --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/helloWorld.smp @@ -0,0 +1,3 @@ +// -*- mode: java; -*- +sys.io.p("Hello, World!"); +return 0; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/jig.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/jig.smp new file mode 100644 index 00000000..001e8eae --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/jig.smp @@ -0,0 +1,19 @@ +// -*- mode: java; -*- +//2298769344378917493 +//========= Reduced ========= +struct s0 { + bool v1; + i16 v2; + int v3; + i8 v4; + byte v5; +}; +while(new s0.v3) + while(new s0.v5<<new s0.v4) {} +if(0) { + if(0) { + flt !P5ZUD4=new s0.v2; + } + while(0) {} +} +return new s0.v1; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/large.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/large.smp new file mode 100644 index 00000000..7f151f60 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/large.smp @@ -0,0 +1,5344 @@ + +struct stbi_io_callbacks { + { i64 u8[] int -> int } read = "C"; // fill 'data' with 'size' bytes. return number of bytes actually read + { i64 int -> int } skip = "C"; // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + { i64 -> int } eof = "C"; // returns nonzero if we are at end of file/data +}; + +struct stbi__context { + u32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + u8[]io_user_data; + + int read_from_callbacks; + int buflen; + u8[] buffer_start; + int callback_already_read; + + u8[] img_buffer; + int img_buffer_end; + u8[] img_buffer_original; + int img_buffer_original_end; +}; + +{ stbi__context -> u8 } stbi__get8 = "C"; + +val sample = { stbi__context s, int pal_len -> + var palette = new u8[1024]; + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + for (int i=0; i < pal_len; ++i) { + palette[i*4+3] = 0; + + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + for (int j=0; j < pal_len; ++j) { + palette[j*4+3] = 0; + + palette[j*4+0] = stbi__get8(s); + palette[j*4+1] = stbi__get8(s); + palette[j*4+2] = stbi__get8(s); + palette[j*4+3] = 255; + } + } + + return palette; +}; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/loop2.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/loop2.c new file mode 100644 index 00000000..934f2d89 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/loop2.c @@ -0,0 +1,7 @@ + +__attribute__ ((CALL_CONV)) +extern int loop2(); + +int main() { + return loop2(); +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/loop2.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/loop2.smp new file mode 100644 index 00000000..01ec827e --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/loop2.smp @@ -0,0 +1,10 @@ +// -*- mode: java; -*- +int i = 0; +while(true) { + i += 1; + if( i==0 ) continue; + if( i==1 ) continue; + if( i==2 ) break; + continue; +} +return i; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/newtonFloat.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/newtonFloat.c new file mode 100644 index 00000000..7e7e796d --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/newtonFloat.c @@ -0,0 +1,16 @@ +#include <stdio.h> +#include <math.h> +#include <stdlib.h> + +extern double test_sqrt(double); + +int main( int argc, char** argv ) { + for( int i=0; i<10; i++ ) { + double d = test_sqrt((double)i), expect = sqrt((double)i); + double delta = fabs(d-expect); + printf("%d %f (%g)\n",i,d,delta); + if( delta > 1e-15 ) + return 1; + } + return 0; +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/newtonFloat.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/newtonFloat.smp new file mode 100644 index 00000000..be2dffec --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/newtonFloat.smp @@ -0,0 +1,12 @@ +// -*- mode: java; -*- +// Newtons approximation to the square root +val test_sqrt = { flt x -> + flt epsilon = 1e-15; + flt guess = x; + while( 1 ) { + flt next = (x/guess + guess)/2; + if( guess-epsilon <= next & next <= guess+epsilon ) return guess; + //if( guess==next ) return guess; + guess = next; + } +}; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/no_stack_arg_count.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/no_stack_arg_count.smp new file mode 100644 index 00000000..20a05445 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/no_stack_arg_count.smp @@ -0,0 +1,6 @@ +// -*- mode: java; -*- +val addAll = { int i0, flt f1, int i2, flt f3, int i4, flt f5, int i6, flt f7, int x8, flt f9, int i10, flt f11, int i12, flt f13, int i14, flt f15 -> + return + i0 + f1+ i2+ f3+ i4+ f5+ i6+ f7+ x8 +f9 + + i10+f11+i12+f13+i14+f15; +}; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/or1.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/or1.smp new file mode 100644 index 00000000..f5f526c3 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/or1.smp @@ -0,0 +1,12 @@ +// -*- mode: java; -*- +int a = 1; +int b = 0; + +if(a++ || b++ ) { + if(b == 0 && a == 2) { + sys.io.p("Or"); + } +} else{ + sys.io.p("And"); +} +return 0; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/or2.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/or2.smp new file mode 100644 index 00000000..ac688b5a --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/or2.smp @@ -0,0 +1,23 @@ +// -*- mode: java; -*- +int a = 1; +int b = 1; + +int x = -1; +int y=1; +int z= -1; + +int g = x++ || y++ || z++; + +int switch = 0; +if(x == 4 || y == 4 || z == 4) { + switch = -1; +} else { + switch = 1; +} +int cd = 1; +if((x == 0 && y == 1 && z==-1) && switch && g) { + sys.io.p("Effected"); +} else { + sys.io.p("Not effected"); +} +return 0; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/person.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/person.c new file mode 100644 index 00000000..df95e1ca --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/person.c @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> + +typedef struct Person { + int age; +} Person; + +typedef struct PersonArray { + unsigned int length; + int pad; + Person* data[]; +} PersonArray; + +__attribute__ ((CALL_CONV)) +extern void fcn(PersonArray* people, int index); + +int main() { + Person base[5] = {{25},{1},{18},{45},{60}}; + unsigned char buf[8+8*5]; + PersonArray* people_array = (PersonArray*)buf; + people_array->length=5; + for (int i=0; i<people_array->length; i++) people_array->data[i] = &base[i]; + + fcn(people_array, 1); + fcn(people_array, 1); + fcn(people_array, 1); + fcn(people_array, 1); + fcn(people_array, 1); + + printf("%d\n", people_array->data[1]->age); // expected: 6 + + return 0; +}
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/person.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/person.smp new file mode 100644 index 00000000..507fb83b --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/person.smp @@ -0,0 +1,9 @@ +// -*-java-*- +struct Person { + i32 age; +}; + +val fcn = { Person?[] ps, int x -> + if( ps[x] ) + ps[x].age++; +};
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/print.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/print.smp new file mode 100644 index 00000000..3bb86268 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/print.smp @@ -0,0 +1,8 @@ +int x = 1; + +int y = 2; +if(x == 1) { +y = 1; +} + +return y;
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/ptrand.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/ptrand.smp new file mode 100644 index 00000000..9d7bce88 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/ptrand.smp @@ -0,0 +1,10 @@ +struct S { S? fld; }; + +val ptr = arg == 1 ? null : new S{fld = arg==1 ? null : new S{fld = null;};}; +if( ptr && ptr.fld ) { + sys.io.p("true"); +} else { + sys.io.p("false"); +} + +return 0; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/riscv_load.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/riscv_load.smp new file mode 100644 index 00000000..67369feb --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/riscv_load.smp @@ -0,0 +1,4 @@ +struct Person { i32 age;}; +Person !p = new Person; +p.age += arg; +return p.age; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_1.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_1.smp new file mode 100644 index 00000000..cfb3fbcc --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_1.smp @@ -0,0 +1,4 @@ +struct Person {i64 age;} +Person !p = new Person; +p.age += arg; +return p.age; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_fold_away.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_fold_away.smp new file mode 100644 index 00000000..0cf70392 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_fold_away.smp @@ -0,0 +1,5 @@ +// Should fold away sign extend +struct Person { i8 age;}; +Person !p = new Person; +p.age = (arg<<48)>>48; +return 0;
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away.smp new file mode 100644 index 00000000..48cc6409 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away.smp @@ -0,0 +1,4 @@ +struct Person { i32 age;}; +Person !p = new Person; +p.age = (arg<<17)>>17; +return 0;
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away_2.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away_2.smp new file mode 100644 index 00000000..3120429b --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/sext_str_not_fold_away_2.smp @@ -0,0 +1,4 @@ +struct Person { i32 age;}; +Person !p = new Person; +p.age = (arg<<48)>>48; +return 0;
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/sieve.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/sieve.c new file mode 100644 index 00000000..cac4cfa3 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/sieve.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdbool.h> + +typedef struct AryInt { + unsigned int len; + unsigned int data[]; +} AryInt; + +__attribute__ ((CALL_CONV)) +extern AryInt *sieve(int N); + +int main() { + AryInt* ps = sieve(100); + printf("%d[",ps->len); + for( int i=0; i<ps->len; i++ ) + printf("%d, ",ps->data[i]); + printf("]"); + return 0; +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/sieve.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/sieve.smp new file mode 100644 index 00000000..569dbb96 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/sieve.smp @@ -0,0 +1,31 @@ +// -*- mode: java; -*- +val sieve = { int N -> + // The main Sieve array + bool[] !ary = new bool[N]; + // The primes less than N + u32[] !primes = new u32[N>>1]; + // Number of primes so far, searching at index p + int nprimes = 0, p=2; + // Find primes while p^2 < N + while( p*p < N ) { + // skip marked non-primes + while( ary[p] ) p++; + // p is now a prime + primes[nprimes++] = p; + // Mark out the rest non-primes + for( int i = p + p; i < ary#; i+= p ) + ary[i] = true; + p++; + } + + // Now just collect the remaining primes, no more marking + for( ; p < N; p++ ) + if( !ary[p] ) + primes[nprimes++] = p; + + // Copy/shrink the result array + u32[] !rez = new u32[nprimes]; + for( int j=0; j < nprimes; j++ ) + rez[j] = primes[j]; + return rez; +}; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/sort.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/sort.c new file mode 100644 index 00000000..ad76cc7f --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/sort.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdlib.h> + +// Test wrapper to call `sort.smp` + +typedef struct AryInt { + unsigned int len; + long long data[]; +} AryInt; + +__attribute__ ((CALL_CONV)) +extern AryInt* merge_sort(AryInt*); + + +long long primes[] = { 25, 97, 89, 83, 79, 73, 71, 67, 61, 59, 53, 47, 43, 41, 37, 31, 29, 23, 19, 17, 13, 11, 7, 5, 3, 2 }; + +int main() { + AryInt *as = (AryInt*)primes; + + merge_sort(as); + + printf("%d[",as->len); + for( int i=0; i<as->len; i++ ) + printf("%d, ",as->data[i]); + printf("]"); + + return 0; +}
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/sort.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/sort.smp new file mode 100644 index 00000000..ae3f4f23 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/sort.smp @@ -0,0 +1,38 @@ +// -*- mode: java; -*- +// based on the top-down version from https://en.wikipedia.org/wiki/Merge_sort + +val merge_sort = { int[] a -> + int[] !b = new int[a#]; + copy_array (a, 0, a#, b); + split_merge(a, 0, a#, b); +}; + +val split_merge = { int[] b, int begin, int end, int[] a -> + if (end - begin <= 1) + return 0; + int middle = (end + begin) / 2; + split_merge(a, begin, middle, b); + split_merge(a, middle, end, b); + merge(b, begin, middle, end, a); + return 0; +}; + +val merge = { int[] b, int begin, int middle, int end, int[] a -> + int i = begin, j = middle; + + for (int k = begin; k < end; k++) { + // && and || + bool cond = false; + if (i < middle) { + if (j >= end) cond = true; + else if (a[i] <= a[j]) cond = true; + } + if (cond) b[k] = a[i++]; + else b[k] = a[j++]; + } +}; + +val copy_array = { int[] a, int begin, int end, int[] b -> + for (int k = begin; k < end; k++) + b[k] = a[k]; +}; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_1.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_1.smp new file mode 100644 index 00000000..43d7a5d1 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_1.smp @@ -0,0 +1,9 @@ +// -*- mode: java; -*- +int something_specific = 11; + +if (10 < something_specific < 20) { + sys.io.p("In Range"); +} else { + sys.io.p("Out of Range"); +} +return 0; diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_2.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_2.smp new file mode 100644 index 00000000..a867267e --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_2.smp @@ -0,0 +1,9 @@ +// -*- mode: java; -*- +int score = 75; + +if (60 <= score < 90) { + sys.io.p("In range"); +} else { +sys.io.p("Out of range"); +} +return 0;
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_3.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_3.smp new file mode 100644 index 00000000..43d7c3ac --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_3.smp @@ -0,0 +1,10 @@ +// -*- mode: java; -*- +var sq = { int x -> + x*x; +}; + +int score = 5; + +val str = (sq(2) <= score < sq(3)) ? "In range" : "Out of range"; +sys.io.p(str); +return 0;
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_4.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_4.smp new file mode 100644 index 00000000..029245ed --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_4.smp @@ -0,0 +1,9 @@ +// -*- mode: java; -*- +int something_specific = 9; + +if (10 < something_specific < 20) { + sys.io.p("In Range"); +} else { + sys.io.p("Out of Range"); +} +return 0;
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_5.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_5.smp new file mode 100644 index 00000000..13a3dbff --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/stacked_r_5.smp @@ -0,0 +1,14 @@ +// -*- mode: java; -*- +var sq = { int x -> + x*x; +}; + +int score = 5; + +if (sq(2) <= score < sq(3)) { +sys.io.p("In range"); +} else { +sys.io.p("Out of range"); +} + +return 0;
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/store_peep.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/store_peep.smp new file mode 100644 index 00000000..c3feddd5 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/store_peep.smp @@ -0,0 +1,3 @@ +i64 a = 123456789012345; +i32 b = a; // truncate high order bits +return b;
\ No newline at end of file diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/stringHash.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/stringHash.c new file mode 100644 index 00000000..2c6d0fa9 --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/stringHash.c @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <stdbool.h> + +typedef struct ArrayU8 { + unsigned int length; + unsigned char data[]; +} ArrayU8; +typedef struct String { + ArrayU8 * cs; + long long _hashCode; +} String; + + +__attribute__ ((CALL_CONV)) +extern bool equals(String*st1, String*st2); + +int main() { + String test1 = {.cs=(ArrayU8*)"\x04\x00\x00\x00test"}; + String test2 = {.cs=(ArrayU8*)"\x05\x00\x00\x00test1"}; + + if( equals(&test1, &test2) ) { + printf("Expected test1 and test2 unequal"); + return 1; + } + if( !equals(&test2, &test2) ) { + printf("Expected test2 and test2 equal"); + return 1; + } + return 0; +} diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/stringHash.smp b/chapter24/src/test/java/com/seaofnodes/simple/progs/stringHash.smp new file mode 100644 index 00000000..3fa2174c --- /dev/null +++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/stringHash.smp @@ -0,0 +1,30 @@ +// -*- mode: java; -*- +struct String { + u8[] cs; + int _hashCode; +}; + +// Compare two Strings +val equals = { String self, String s -> + if( self == s ) return true; + if( self.cs# != s.cs# ) return false; + for( int i=0; i< self.cs#; i++ ) + if( self.cs[i] != s.cs[i] ) + return false; + return true; +}; + +// Return the String hashCode (cached, and never 0) +val hashCode = { String self -> + self._hashCode + ? self._hashCode + : (self._hashCode = _hashCodeString(self)); +}; + +val _hashCodeString = { String self -> + int hash=0; + for( int i=0; i< self.cs#; i++ ) + hash = hash*31 + self.cs[i]; + if( !hash ) hash = 123456789; + return hash; +}; |
