From 8255a58d172332820ace6ec8f4c0635c10fd8bce Mon Sep 17 00:00:00 2001 From: David Noble Date: Sat, 21 Sep 2019 15:32:54 -0700 Subject: [PATCH] Progressed on RowReader --- .../serialization/hybridrow/RowBuffer.java | 2 +- .../serialization/hybridrow/RowCursors.java | 8 +- .../serialization/hybridrow/io/RowReader.java | 91 +++++++++++++++++- .../hybridrow/layouts/LayoutBuilder.java | 61 ++++++++---- .../hybridrow/layouts/LayoutFloat64.java | 2 +- .../hybridrow/layouts/LayoutInt64.java | 2 +- .../hybridrow/layouts/LayoutUDT.java | 4 +- .../hybridrow/layouts/LayoutUInt32.java | 6 ++ .../hybridrow/layouts/LayoutUInt8.java | 6 ++ .../hybridrow/io/RowReaderTest.java | 50 +++++++--- layout.xlsx | Bin 0 -> 24790 bytes 11 files changed, 184 insertions(+), 48 deletions(-) create mode 100644 layout.xlsx diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/RowBuffer.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/RowBuffer.java index f7de015..7eb6606 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/RowBuffer.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/RowBuffer.java @@ -1215,7 +1215,7 @@ public final class RowBuffer { * Produce a new scope from the current iterator position. * * @param edit An initialized iterator pointing at a scope. - * @param immutable True if the new scope should be marked immutable (read-only). + * @param immutable {@code true} if the new scope should be marked immutable (read-only). * @return A new scope beginning at the current iterator position. */ public RowCursor sparseIteratorReadScope(@Nonnull final RowCursor edit, boolean immutable) { diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/RowCursors.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/RowCursors.java index 6ddba18..3e737c9 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/RowCursors.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/RowCursors.java @@ -108,13 +108,17 @@ public final class RowCursors { } public static void skip( - @Nonnull final RowCursor edit, @Nonnull final RowBuffer row, @Nonnull final RowCursor childScope) { + @Nonnull final RowCursor edit, @Nonnull final RowBuffer buffer, @Nonnull final RowCursor childScope) { + + checkNotNull(edit, "expected non-null edit"); + checkNotNull(buffer, "expected non-null buffer"); + checkNotNull(childScope, "expected non-null childScope"); checkArgument(childScope.start() == edit.valueOffset()); if (!(childScope.cellType() instanceof LayoutEndScope)) { //noinspection StatementWithEmptyBody - while (row.sparseIteratorMoveNext(childScope)) { + while (buffer.sparseIteratorMoveNext(childScope)) { } } diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/io/RowReader.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/io/RowReader.java index 2ff162b..3c8b872 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/io/RowReader.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/io/RowReader.java @@ -3,6 +3,7 @@ package com.azure.data.cosmos.serialization.hybridrow.io; +import com.azure.data.cosmos.core.Json; import com.azure.data.cosmos.core.Out; import com.azure.data.cosmos.core.Utf8String; import com.azure.data.cosmos.serialization.hybridrow.Float128; @@ -41,10 +42,15 @@ import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutVarInt; import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutVarUInt; import com.azure.data.cosmos.serialization.hybridrow.layouts.TypeArgumentList; import com.azure.data.cosmos.serialization.hybridrow.schemas.StorageKind; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; import io.netty.buffer.ByteBuf; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.io.IOException; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.util.List; @@ -65,6 +71,7 @@ import static com.google.common.base.Strings.lenientFormat; * Modifying a {@link RowBuffer} invalidates any reader or child reader associated with it. In general{@link RowBuffer}s * should not be mutated while being enumerated. */ +@JsonSerialize(using = RowReader.JsonSerializer.class) public final class RowReader { private int columnIndex; @@ -818,7 +825,10 @@ public final class RowReader { * @param value On success, receives the value, undefined otherwise. * @return {@link Result#SUCCESS} if the read is successful, an error {@link Result} otherwise. */ - public Result readUInt8(Out value) { + @Nonnull + public Result readUInt8(@Nonnull Out value) { + + checkNotNull(value, "expected non-null value"); switch (this.state) { @@ -839,6 +849,32 @@ public final class RowReader { } } + /** + * Returns a string representation of the object. In general, the + * {@code toString} method returns a string that + * "textually represents" this object. The result should + * be a concise but informative representation that is easy for a + * person to read. + * It is recommended that all subclasses override this method. + *

+ * The {@code toString} method for class {@code Object} + * returns a string consisting of the name of the class of which the + * object is an instance, the at-sign character `{@code @}', and + * the unsigned hexadecimal representation of the hash code of the + * object. In other words, this method returns a string equal to the + * value of: + *

+ *
+     * getClass().getName() + '@' + Integer.toHexString(hashCode())
+     * 
+ * + * @return a string representation of the object. + */ + @Override + public String toString() { + return Json.toString(this); + } + /** * Read the current field as a fixed length {@link UnixDateTime} value. * @@ -999,7 +1035,8 @@ public final class RowReader { * @param value On success, receives the value, undefined otherwise * @return {@link Result#SUCCESS} if the read is successful, an error {@link Result} otherwise. */ - private Result readPrimitiveValue(Out value) { + @Nonnull + private Result readPrimitiveValue(@Nonnull Out value) { final LayoutColumn column = this.columns.get(this.columnIndex); final LayoutType type = this.columns.get(this.columnIndex).type(); @@ -1017,9 +1054,8 @@ public final class RowReader { case VARIABLE: return type.>typeAs().readVariable(this.row, this.cursor, column, value); default: - assert false : lenientFormat("expected FIXED or VARIABLE column storage, not %s", storage); - value.set(null); - return Result.FAILURE; + String message = lenientFormat("expected FIXED or VARIABLE column storage, not %s", storage); + throw new IllegalStateException(message); } } @@ -1115,11 +1151,30 @@ public final class RowReader { DONE; public static final int BYTES = Byte.BYTES; + private final String friendlyName; + + States() { + this.friendlyName = this.name().toLowerCase(); + } + + public String friendlyName() { + return this.friendlyName; + } public static States from(byte value) { return values()[value]; } + /** + * Returns the friendly name of this enum constant, as returned by {@link #friendlyName()}. + * + * @return the friendly name of this enum constant + */ + @Override + public String toString() { + return this.friendlyName; + } + public byte value() { return (byte) this.ordinal(); } @@ -1186,4 +1241,30 @@ public final class RowReader { return this; } } + + static final class JsonSerializer extends StdSerializer { + + JsonSerializer() { + super(RowReader.class); + } + + @Override + public void serialize(RowReader value, JsonGenerator generator, SerializerProvider provider) throws IOException { + generator.writeStartObject(); + generator.writeStringField("path", value.path().toUtf16()); + generator.writeStringField("state", value.state == null ? null : value.state.friendlyName); + generator.writeObjectFieldStart("span"); + generator.writeNumberField("start", value.cursor.start()); + generator.writeNumberField("end", value.cursor.endOffset()); + generator.writeEndObject(); + LayoutColumn column = value.columns.get(value.columnIndex); + generator.writeObjectFieldStart("column"); + generator.writeStringField("fullPath", column.fullPath().toUtf16()); + generator.writeStringField("type", column.type().name()); + generator.writeNumberField("index", column.index()); + generator.writeNumberField("offset", column.offset()); + generator.writeEndObject(); + generator.writeEndObject(); + } + } } \ No newline at end of file diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutBuilder.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutBuilder.java index cd976ac..99a0f1e 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutBuilder.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutBuilder.java @@ -6,10 +6,12 @@ package com.azure.data.cosmos.serialization.hybridrow.layouts; import com.azure.data.cosmos.serialization.hybridrow.SchemaId; import com.azure.data.cosmos.serialization.hybridrow.schemas.StorageKind; +import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Stack; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; public final class LayoutBuilder { private LayoutBit.Allocator bitAllocator; @@ -36,27 +38,37 @@ public final class LayoutBuilder { this.reset(); } - public void addFixedColumn(String path, LayoutType type, boolean nullable, int length) { + public void addFixedColumn(@Nonnull String path, @Nonnull LayoutType type, boolean nullable, int length) { + checkNotNull(path, "expected non-null path"); + checkNotNull(type, "expected non-null type"); checkArgument(length >= 0); checkArgument(!type.isVarint()); - LayoutColumn column; + final LayoutColumn column; + if (type.isNull()) { checkArgument(nullable); - LayoutBit nullBit = this.bitAllocator.allocate(); - column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), - this.fixedCount, 0, nullBit, LayoutBit.INVALID, 0); + LayoutBit boolBit = this.bitAllocator.allocate(); + LayoutBit nullBit = LayoutBit.INVALID; + int offset = 0; + column = new LayoutColumn( + path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), this.fixedCount, offset, + boolBit, nullBit, 0); } else if (type.isBoolean()) { LayoutBit nullBit = nullable ? this.bitAllocator.allocate() : LayoutBit.INVALID; - LayoutBit boolbit = this.bitAllocator.allocate(); - column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), - this.fixedCount, 0, nullBit, boolbit, 0); + LayoutBit boolBit = this.bitAllocator.allocate(); + int offset = 0; + column = new LayoutColumn( + path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), this.fixedCount, offset, + nullBit, boolBit, 0); } else { + LayoutBit boolBit = LayoutBit.INVALID; LayoutBit nullBit = nullable ? this.bitAllocator.allocate() : LayoutBit.INVALID; - column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), - this.fixedCount, this.fixedSize, nullBit, LayoutBit.INVALID, length); - + int offset = this.fixedSize; + column = new LayoutColumn( + path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), this.fixedCount, offset, + nullBit, boolBit, length); this.fixedSize += type.isFixed() ? type.size() : length; } @@ -74,31 +86,40 @@ public final class LayoutBuilder { this.scope.push(column); } - public void addSparseColumn(String path, LayoutType type) { + public void addSparseColumn(@Nonnull final String path, @Nonnull final LayoutType type) { - LayoutColumn column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.SPARSE, this.parent(), - this.sparseCount, -1, LayoutBit.INVALID, LayoutBit.INVALID, 0); + checkNotNull(path, "expected non-null path"); + checkNotNull(type, "expected non-null type"); + + final LayoutColumn column = new LayoutColumn( + path, type, TypeArgumentList.EMPTY, StorageKind.SPARSE, this.parent(), this.sparseCount, -1, + LayoutBit.INVALID, LayoutBit.INVALID, 0); this.sparseCount++; this.sparseColumns.add(column); } - public void addTypedScope(String path, LayoutType type, TypeArgumentList typeArgs) { + public void addTypedScope( + @Nonnull final String path, @Nonnull final LayoutType type, @Nonnull final TypeArgumentList typeArgs) { - LayoutColumn col = new LayoutColumn(path, type, typeArgs, StorageKind.SPARSE, this.parent(), this.sparseCount, - -1, LayoutBit.INVALID, LayoutBit.INVALID, 0); + final LayoutColumn column = new LayoutColumn( + path, type, typeArgs, StorageKind.SPARSE, this.parent(), this.sparseCount, -1, LayoutBit.INVALID, + LayoutBit.INVALID, 0); this.sparseCount++; - this.sparseColumns.add(col); + this.sparseColumns.add(column); } public void addVariableColumn(String path, LayoutType type, int length) { + checkNotNull(path, "expected non-null path"); + checkNotNull(type, "expected non-null type"); checkArgument(length >= 0); checkArgument(type.allowVariable()); - LayoutColumn column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.VARIABLE, this.parent(), - this.varCount, this.varCount, this.bitAllocator.allocate(), LayoutBit.INVALID, length); + final LayoutColumn column = new LayoutColumn( + path, type, TypeArgumentList.EMPTY, StorageKind.VARIABLE, this.parent(), this.varCount, this.varCount, + this.bitAllocator.allocate(), LayoutBit.INVALID, length); this.varCount++; this.varColumns.add(column); diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutFloat64.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutFloat64.java index 1dcfe92..6cfb1ca 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutFloat64.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutFloat64.java @@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument; public final class LayoutFloat64 extends LayoutTypePrimitive { public LayoutFloat64() { - super(LayoutCode.FLOAT_64, Double.BYTES / Byte.SIZE); + super(LayoutCode.FLOAT_64, Double.BYTES); } public boolean isFixed() { diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutInt64.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutInt64.java index 974e65f..815a97d 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutInt64.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutInt64.java @@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument; public final class LayoutInt64 extends LayoutTypePrimitive { public LayoutInt64() { - super(LayoutCode.INT_64, Long.BYTES / Byte.SIZE); + super(LayoutCode.INT_64, Long.BYTES); } public boolean isFixed() { diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUDT.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUDT.java index a18ad2f..bb5da7d 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUDT.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUDT.java @@ -33,9 +33,9 @@ public final class LayoutUDT extends LayoutPropertyScope { @Override @Nonnull - public TypeArgumentList readTypeArgumentList(@Nonnull RowBuffer row, int offset, @Nonnull Out lenInBytes) { + public TypeArgumentList readTypeArgumentList(@Nonnull RowBuffer row, int offset, @Nonnull Out lengthInBytes) { SchemaId schemaId = row.readSchemaId(offset); - lenInBytes.set(SchemaId.BYTES); + lengthInBytes.set(SchemaId.BYTES); return new TypeArgumentList(schemaId); } diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUInt32.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUInt32.java index 62df625..af9787a 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUInt32.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUInt32.java @@ -11,6 +11,7 @@ import com.azure.data.cosmos.serialization.hybridrow.RowCursor; import javax.annotation.Nonnull; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; public final class LayoutUInt32 extends LayoutTypePrimitive { @@ -31,6 +32,11 @@ public final class LayoutUInt32 extends LayoutTypePrimitive { @Nonnull public Result readFixed(@Nonnull RowBuffer buffer, @Nonnull RowCursor scope, @Nonnull LayoutColumn column, @Nonnull Out value) { + checkNotNull(buffer, "expected non-null buffer"); + checkNotNull(scope, "expected non-null scope"); + checkNotNull(column, "expected non-null column"); + checkNotNull(value, "expected non-null value"); + checkArgument(scope.scopeType() instanceof LayoutUDT); if (!buffer.readBit(scope.start(), column.nullBit())) { diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUInt8.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUInt8.java index 36280c0..1d678a5 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUInt8.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutUInt8.java @@ -11,6 +11,7 @@ import com.azure.data.cosmos.serialization.hybridrow.RowCursor; import javax.annotation.Nonnull; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; public final class LayoutUInt8 extends LayoutTypePrimitive { @@ -31,6 +32,11 @@ public final class LayoutUInt8 extends LayoutTypePrimitive { @Nonnull public Result readFixed(@Nonnull RowBuffer buffer, @Nonnull RowCursor scope, @Nonnull LayoutColumn column, @Nonnull Out value) { + checkNotNull(buffer, "expected non-null buffer"); + checkNotNull(scope, "expected non-null scope"); + checkNotNull(column, "expected non-null column"); + checkNotNull(value, "expected non-null value"); + checkArgument(scope.scopeType() instanceof LayoutUDT); if (!buffer.readBit(scope.start(), column.nullBit())) { diff --git a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/io/RowReaderTest.java b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/io/RowReaderTest.java index 52d4916..1e13e0d 100644 --- a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/io/RowReaderTest.java +++ b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/io/RowReaderTest.java @@ -73,21 +73,45 @@ public class RowReaderTest { private static Result visitFields(RowReader reader, int level) { + Out out = new Out(); + while (reader.read()) { - final Utf8String path = reader.path(); + Utf8String path = reader.path(); LayoutType type = reader.type(); - if (type == null) { - fail(lenientFormat("path: %s, type: null", path)); + if (path.isNull() || type == null) { + fail(lenientFormat("path: %s, type: %s", path, type)); } - System.out.println(lenientFormat("%s%s:\"%s\"", Strings.repeat(" ", level), path, type.layoutCode())); - Out out = new Out(); + System.out.println(lenientFormat("%s%s : %s", Strings.repeat(" ", level), path, type.name())); + + Result result = Result.SUCCESS; + out.set(null); switch (type.layoutCode()) { + case INT_32: { + result = reader.readInt32(out); + break; + } + case INT_64: { + result = reader.readInt64(out); + break; + } + case UINT_8: { + result = reader.readUInt8(out); + break; + } + case UINT_32: { + result = reader.readUInt32(out); + break; + } case UINT_64: { - Result result = reader.readUInt64(out); + result = reader.readUInt64(out); + break; + } + case GUID: { + result = reader.readGuid(out); break; } case NULL: @@ -95,11 +119,7 @@ public class RowReaderTest { case BOOLEAN_FALSE: case INT_8: case INT_16: - case INT_32: - case INT_64: - case UINT_8: case UINT_16: - case UINT_32: case VAR_INT: case VAR_UINT: case FLOAT_32: @@ -108,7 +128,6 @@ public class RowReaderTest { case DECIMAL: case DATE_TIME: case UNIX_DATE_TIME: - case GUID: case UTF_8: case BINARY: { break; @@ -155,11 +174,7 @@ public class RowReaderTest { case TYPED_TUPLE_SCOPE: case IMMUTABLE_TYPED_TUPLE_SCOPE: { - Result result = reader.readScope(null, (RowReader child, Object ignored) -> visitFields(child, level + 1)); - - if (result != Result.SUCCESS) { - return result; - } + result = reader.readScope(null, (RowReader child, Object ignored) -> visitFields(child, level + 1)); break; } case END_SCOPE: @@ -173,6 +188,9 @@ public class RowReaderTest { break; } } + if (result != Result.SUCCESS) { + return result; + } } return Result.SUCCESS; diff --git a/layout.xlsx b/layout.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..67d1a45e728032798295755194b43f4b93299e45 GIT binary patch literal 24790 zcmeFYV{~O*w=SBh*sR#LQ>nOO+qP}HVpVKbY}+;~wr%^a-2-f&c;nA^;M&31j{B1qdh!3pMG&}Ju6mI? zyvhYEq|Jo{OY#>_*1havvFu=xHiP&D4yG2>sGx1hvKSV2ZH)99uQ`24GhKr`G`8oY zwp@7X%P+MchRk~wVHpv^4Xizjb2-xF>d$HM1Pj9BZRAy8nHXUyN>JNo5I0AtD}E~7 zUmvsPTlTvTeAsidyLA3+BBNHy5xA~R?x!OK4c8b{FE7~a!jvk;`}`DpR2#vgKFlEa zGuk+i7=P=edSe*RO~aOVM}%#WJ*k)yET|J|3ZJRKTmIkdjjfB1WXd z;)s7eMj9T^BNhzd@HyC?FjQGDxB5CkDEE)K-ir|u@Y3q zw|;vbm9?KFZbQEA{|9-g$>)5**a0L-9^3^+GfEqz&8OqI>KVENh=h~`XEriuBiOyz z>nf^-@-$yz+(5W@BiDh|ARaAUqUa9k(BPChY36vc?lZ4pI!Zp zz$fm^E7C%s;N>H_0$&&LhZt+MgA5x%0n;B?*t^Z^Wq5g&Gva8F;BJe#Gz(P{Q}_AXgi%$3}!EsC@Bdp+aDa*sg^ zg4;(-MR^l8(@MPzJ9a`>Z3BzWYk|}bAwOZ!Ok#yHy zR>+=`!HXfkFucMwz&`fho8-;(NEr$s83hIc!UTf&;$lJfPoFqj+nMWGTbqCEasR7l zz5q5lfbRe7Piw5ScrQId-?`s9!RTs!S#z*OGq~VFNjV;V?o7T#YTW2U!TOp^m7{J^ z;+E~&?|Uy!#^qJx`A}z=zb*y%;&KQF;dEHaR4!bcnybF}bLD@_oC|e+`f1v_R(bX- z*?S1oABqZ~2}4oad()9%gr(>A-XCn`UuDl=56FyYrT!_G-7{^D-fRFzAv-r(V4Qv@~II8v05 z&FYFI=_FGZHFdERQs2QGx72E7Wt5nP#jb@EL=~sfV-tbS$LKe*E99P$B0BDpi_J_> zp6y#mA{ncS$G>HgZB)KNB7j9TfTI&UfFb}U{VRt`6_>4+e;{~j>%8+$w(!ZZs`I6F zS6f*4B2jLQH!ZfbU8!_gc*MJhGU(ADSF8S|Cm zHe32=n%FxYMCma!rrO7B5U%j>fwpN6(N!S2;pSro;w-7bO8#)pUa#eQ)OWc^SvLC# zugmsBS(QJvH>hfBMGpB^Wi;8^N`+~kaynfVroYj(DfviE0i)y{nRHFwYWW6x9g_fu zln9Z-w{O($ty^?uu_EOU++INw<_Cnp_)S_IS`Y99Lbm=s)GB0EW2bK)t-x1xb^t8` z_Kj;9Zf9nmvU=hSA?2>sKJC)g!ZUHh!~EQK-mh!_zG`2uRPn?hZ+zXkELU14JYn5$ z-ty8Zt{Jg{AI#v=s`(srIRMr81OjJ+qh`{sXW#5Yj(*jy`@>HAf?BGdJCchL14IiU zC?xUMR3{dx7dJ-#8v=NfVc?of4J)loZQINeWfM~a{m*3*AGv>_87Gm7XGyt4I^`b zvtDHU17%=#NVxHwV1WwDgbmbZBV?o{f^=f2itQ%L4W094h-}8>PHgU%@naW9G;^9qdxp09>C0bV zOCL#dL*F~orUyWa{`cJ=Q}T^R3vjPP#sCBa`%e$sJGfdH+JEcFJec{DrITxTIBQ9RJjzR5*`#vEyt2J=0H}#%z43kJ-U{9DD;JrgJO@aN+5c` z-PJ`Hmo7a_6x{?qsqdGN<|=oU1FSIattj)!k@rede{y*rwjei@$*-0tlz}I~^8q|| zhD@-B83_IIFCpY-M?~WT`}r8|MA$hGzanixw87#6f_td2QZAEpcLwxi(34!hamb`dk#{=9ycFrVBjcE}UwNg2Y(+*q z_HmY4T+pH<#Sirpel9!UGB7b?%?**5RebAg^&IvHrYfTIV@avMW&eU}^AnkR>n&W?8NJ+1b-61nyJ@;m8W3)H5S7ulxDJ2pyppTY0tm9ER579qXda-4j>lDH^&%Cvyq0(i{^ii8&9|1dM- zg3F^7iZ30(k`Atw8wd=o(E&4t^QGZkM9W5U(ZVw&gzLFh#rPo=0Yo6ab;FBLO=a-Ob;KmacHN-%y(9#0K^|a5p@*EE7m6!5%OZTKL+uD@ zVVvS!aTQHKeV{DQ;=jr&?|eS$)?gH|n_w{B@p5vd<#AIW#~)|)HM7~-2b=l@p7onE z8S(0HUV}d;V`fBzpuIQU?CcLZG!&oaG1`~X=7=%0uLccS)zeu=rSIOrJ+km&aNCEd zdsC>xsOu5_OGQRTA@;+d;eTkWH(dYr-4}$Zg?2`Y3n~dFgkquHF$*_D&${9|R!N{; zoF<<=-ebvuQf`b63UW13M+*^(h5w}#5n*!2&eVdwA2PW>+hrDY}iS}4y~gHRUxuGXw-b9wsef$nCD zLNx*7;Wcwb`i+sRjixLWYwYE*+pCM!cdLw+>WWj)d+GL4e6G~g)!vELphR8ANCcyQ zk&N!};M(2++suF8h?`bkUKlh_t<*|G7zMM21N)mb;p5o2>XX`C8ByOS zgdV2#(ShVm7_wJoss#6Y0ZPh;PWa`)dkAR(u}8a&iS3%UjB|Qw;TTFt2>aOGXHV7{owDb(CLNV`aZ#%&+BXffYsk%6U$x*iVi(L5*_p4s>}6z2>XukFi8&id@bG3F$EIHL}dp z5<6pPT&S7H>BOA)cXm(1sWCRy7GXGEgUv-DWfC=}NXUweuc~V;zkm+}3=1#~l|pu+ z8W1MTJNjCrXirh|ReW=scvBCU$l!=%>k<>j5Iuw9Z6ZB1_|6T=+~K229sao4ZuxY3 zjV6+!{$|wsH=S%Jg;;H{V8L6+z3kBx=IgTwlubq$R@(WbBMbO*wy^?obR%=7#nIxy z`Qrg0CQZ4ptOuK8?u6jhFe9-=VV|m2%6C)h9wM{)!mDOb&U87l$@Ho{_GoS1O| z3S>K1_mW_z+2H{5ayiF!F!$7A2~k1=H(Ehem1+j*p<+H?sAM>V@mK{#Ck;cQw~&6g ztn6g-)G-E)GO6StSfhZluv8TIoV%a@%I6c_+1`>k9amw#`L}KGlqJuf>Jf}u!RwN=i zbyZOnszWW5JOg(>4(xH$Q5=Y$skmw=k8r(6O!Tzv885hA~R0`c$5 zU%TAEW+>6NGkzYrREuLrqR>g=G+C-SxIH+vJ+1`Dy(~g-Ye{>x$(ftd@0`h=NQh zBOsSH1K*f3%v--`nCF7`7ek&mJ@ZMf{(a#7VVB#asQJbp?j$kD6=&|c`P$Rue6J3t ze@?X_8nm|S9Bgj6A5>`g{71Q(>G6F~Ey$jC{3h$a?P(vDW0h8bgamN=Nc2xnf7~G2 zn;058*#E~q;KIbP6X2JMI33`ce@(i4lG;?`6c$*emp z%(>J_D35K9E)T_#w-C-uB#t*|Sa5IKA2;x$&}T0cxX4k~LgB^W=W8E|WdT9GCgj!) z4BI2m@_idi?fu^OSaBXgh3*jnj9}ZWT;AdP!1d~cM^zcey!PQ)x_=vd7aBsl6gUu2 zKmNy?gwMNU2NOd}L%PpzhR^f0>R1>SD@q626Az5N^9##%6v^7gghlKsu|awqc3u66 ztP&GrOe+@hR}!{cIr7}RL_TY-xapt3ux&R{ki@lzcvEC!3q)nR#HkiyYEH0W!f$N_ z1@{?VZr2W%(``v^!b#BGF$vo3GFMz_;R{K`GYQ`2KggLqq($Pw5e*@&9-*mU#FsO@ z><}%7AO;qI9|bJ36YxaYmMKyDAOfQsJB@z$u9Jojh;$QWq7Go=_^&0QQsv2&p%cYC zX!+^MxO*}Z5S_rri+Q^jwMuU?MDxLhldmfmSCM2_ZTD331qU3+o#7BHUFl{paNusa zPv4UxA$gfRlDzJtHPE3>DUk~7f~oRbWxX>tN$7Z}Oxa%@c9~7%L-?z?=V=2MY7E>S zzp8cAPZxYKVfKs9uU}w4j<@=)3oG+9o86*(t~i3aHmR*y(}YtT6)>Nr;9VJr2h+SE z2wlNT!L88~lx|dDd_13pqOIODFMg^e({N)hBOq$m7)TpXXXf0r^v$6AAQE{E#-Fz> zhGIhYH*Cp?oV2Sw-`}rxCa}G6q5g=Yg)deia#8uq=i3tcb$n*aj~PJ5Wa z4x^oSmoRBL9kGC0D8==YKJ_p0J@%kmOx_MCm~FUcT+QC^G2(Uy(@kOMOwn9U3lTD$ z_Dd2mgS}p)a0G(U&iMXS zcxVoOm0^ZUob?NJVj(|`#PIN;(^U$=R^0KZO(9vGwI&BBR@G!%`ziYS~Ly$H1G{<`hIDJyE)zlA*$8M~3!k$mNb6KMIDO%=Y%^Jt*_Uy`hZL41>XkSmnr&NB9x}$I zs7V+#e#6zyv`~p#1s5jLEdAUdN2+g`lV#6R*Dg^JGg8J)rOhct(4aAoE)*IO{E1@u z2WnjBYh{0ry$%$dRTII;7iZ9QC5*6S9nodA;rLLrjDKk@CaX+2s7%QmC1$G$+3rHo zTYmfIvU|57*tQ$QyTlu4gdMl9|E-`lxi!2TYCKuUEtaV$`HPGm9TR?(gZyH%t*e=% zX>priE)7w*LrnzzG`%0%CN;-c!n10Bb8^sMM(HNKCM-LqqX>9Jb3sC~Mqg4=`N>`m ztH(Mshz3d`X7fkn1N5GG7qBLxzv^f?@{LXyq8U~X&bkR0Xw^XiaqJqgQo~>j(Mj%c zy)@c1-tn-^Q`k9{RLVXG+-ln?KdJCiZ4n$e23;7th)e@l(PcBF@O(Gr%Wd9@`_^$v zi5IcE+wdZy+JM>jSrKzpROqO{BSU<`{Oyj$7<^MJzeVppI&bL=o6NU{PP4^D60wKL zIOQZ6WOTEHl#fnHQ{kaYFQ#;5AJcLs6$9V3Nw2cv%?{gxneG|q_fa1Gb%;F-;@E*L zx#Is@O_^u)Dn(;gZcf_-hcxRd*1GxEGYq(ko+fjYQBt*4swcFjMs~TDi5db%`tSD# zOGlv}T$kl!JcH?@YK}jtkHyj-o`zRiXN|y}eL3B1ynhtP9mw!mClZlAO=Atleb)(F ziB*k&SZ`$`qj~qDumE2bTcC-<)a^h}@R!R*tSl{^ zqM)=K7>6{^mzK^?-3#L(-HY9V;M7)N0P)@#-) zK9#=CE`_H-JJ7vZOa1%5eK=j1b_?{sb@uq&i9g?W{GW67kQ;uXE^L<5-aSJ5w`UK# z?8LrJz+F_F4-gRgKWC4BIe2{@xjw^A(-gNS8h~vtpnUi3lee4H544^Yqpc9I@(}6U z<@DH-`x|N~svvUKBf8rGz6v|)0BnM8r-*&3$ME2jkpZ7Xir@ZxwtPLaF>+_Ka;jY( zH1@b_Q|Y;Qa_&r*SswKMGH_(Ujg2jRocMe@^JeJI_2TG`?d5zuz|;EN%=2RBv0^0+ zTzO&Fip!lLRiTWAHZZn*=jzG1-eIM^p^bYNw0{fv=Jw!V>%nC)e}9>?Ul4Y8W#@L; zy4D608&Kju(Eqln+pxHH%9@$kKv!U}Q|YOe+4;V`eReA{m%)l_KXKecm#IDR{dr%R z{?hiomg5yO0uFp4wFHm5?F9ZfN*dw5!Kif&rX6R)o92a;Fo_&ZWTItE*L#I0ZM^GB z@JcnXqfteplr^0MqhmyZsr`pV$4NKriDX^JM4r*~qM5t?pLJ7*D)72fwH%MRQc9{9JKb)I+68aURHCXmibUY@i24v;=Ppa&!i+y?1o$puP( zmY0X>wpDH}P54Bnh3)r9@(W?0#sh>a9^@rTt3y0^|ES~bJE!-X>$A5T^q)cg&!;_4 z*E5F&uk#%i&Y8H<_~~H&sjtWyukX+z+Q;4!mg(Z+pt-zE59D2l>NHpleVJ*dqc1ImFcou$d=jh z4R0&r;R3l#0v~@LN#auPAq0&z_PWR#hi;lCg!ReFQ*FJK&_1M!z4PkT9VHj6UT z0%I!v3%5v5M}Rv9$ayS~M*x;1NF5z(;yG=5r_*9qf7#z8=Dgu_1zk+>qN#-MN^<(G znpiVN!hm(q^^WquQv*UBR z6ApljevxrRp?;Ogft@B?A|}sCuXd+V6sQ#?iE{e8{;RPd!9Z|PlBzF+tz}HkaIOT! z*B?!6gI5hC1H^R$R{d4Ii14d4CE#ZZuXr`m*L`=LJQoJNXz_TpolYjP9bPp7fZ`5K zltyvzV5}If>j)7UmDvtb&gQ4e&lrG;8y5)GD$_#vNS|k>!c`r*^uk>tr5;U;*kxr+ zkcp^L?I|6i&}ay}TwXm2!K!#D{Ini2F)!{9_bscuz+jG|9b2aS@V?+aFxXKU?BqCRSWSq>2@uw$rXXT~2x zW3ti#hq=-I@Lx($G5A1&1VqH>(z;r`ZGMMTO3hbV`ceT^q4zZ4M+Gqxa% zfA&QmeLaZRA`;_@L%E?t?UX&qPS?W<2F2&l{W9*7UEso~$Bu`RegyT)PL$$C{+ppu zuaJ@&taM1|_^;I&j=vOQL>VY7)OYCR%s5)uPVB7^R(zMarToQ3SFE_IhIM*mA~+b1 z(-gymRmi#NLIPz6!G)s20%d4^5rrVKa&dlJT2ysejq_p*St?onlnhL&?;5H$kneYFvU$ZzyR)M_3(IvFf%o(;W_8 z-{4Mfrn)W_H1cFU7SSrQS38X2YlBJnDfFkps!8KnzoQKyiL6mfAO6{nA<>)7k(Uv0 zNFHNkZ@V*-!_XHd6UT8q7b%E}6i*0N43o+UMk^ct>YcCF)*HHYHA(zU6Erqh9(npu zkC$VS`-Ipm;pA<0A*gBW>Oq(;OidOwJC{7{fob;erb-5uKgO`&&p^&!PR{LpazpC) z8fw?1yfh<*yLQVOqFfgxdotn?shokFtY8&0aK*CWWpRY{R`t)as#uBdgY-;@WJ8;u#X~jY`r42iAjfV6`2H zZnL%g8sP>g(-dpFHr&#$WE4Hm68_Bj=m$(f#XagtJquU=Iv#nLQgp$+AZL;BtTL?W z+hLg{pS^xmN>5EnJq8)suy9F8!oE~>C8J~F|oLh%=I`PMon^xr?nT0Ts^39`M ze6sKCjVFSE_Gu)Cgf8vg_ND_|l6z}{3>J~297u+1w}d?$QpFC@BP|(<(C3v3!)u}a z8BV&k%kSmJ7!q zcB#Pc#JMJUqk!DEn@%FTr%A`yx?L1VYv)=}kOH|EA8soW=N_cC*ABRN(%3p9FKMz3 ziC4C}mi>v{d_W#D*~ztFKL*k$BphBe?o#)|LDMhVtBXy62@+WkuF=QetZ*yYkwZc0 zk(=Do-(4bt;K|&|L-d^X8LD=i+mSKGFE#k{HJ!C4Sdcl7$L~o#(8{j1AbMXC%+Q|S zXfSs5M!S>QLz=2iFu$8v03vIhu^$rHLqgg$-yb9)$`Bun9O2+flrW$rkUdK$N(^_Q zCE&n4&v&B@*}5vi|BUJmXMzM!%@4I*bLbF8?vFZhCQb_Ca;F_N5r;0i0{sc(m}ZCq zb|WDI%CI`f+4_-Xm&GtUBZ-pui+gMTOQAlJTY-M##5JOpe5;FMx9F4XozQQnOogvL4|Od91*r|E>sYYmlR$lg8TNp%LW_Y>3@C_My;?U&?%r_bAuN#Mptli!cqO7t(kDj5vyre}y7T_uGJG&x7=S2IkI z{KqB6#NPm|Xz>S_{?HGc_CpdMxnE+i{ZZ(klNY8Cr5yj08Vrd|ejji(7&a?#KIf&{V^scxOGV15{2zuR8oVFa%9Aei zX+P3B@y&kptLm$8PU+jR;H@X??tq3vbirHdaT8&v>MLNylPxHGcS*JRsP^*jiaSjq56EfP#YN&yN3;x9R5HX5ay+!>=B%>!W5|u3V`K+#j*|A7)8XuSB9iD* zN(_-F7PGD4>cNjwQ?HnR&2d^&Lvuk3+BT7i#Mvs+$tiIib=km8@HxmVZpyq^ea&}DC$e=Kt?*!508oCYC zAbjSU5Bjm6FUMnD)tcJH*q9Ugv!JMIgRH248Urrw;7Bumrq&QONv;}3DkqIXR{WHQ z`267zZSm6JA|S;u0lz%9HyqDIkf=R!U{B5y(if4pjw^w0X9z#}lCO9X2)}GUfc3a5 zSkG<1XZ0nu&2lVH>@QGJ{g7N-nnx^#bsXjM*W4va@!xuH|bCjFZ6FN6JOlk1$$jE4@)?No2nVarJy2WqTxM8b6JNmDtCbgdKzx>Eiwo zdXnS!qmGKwFbS-F!FW8ZH|uPT+g3u!zjncxb^*M=GK`!mPaAn(8hMBKcn021Ul;Uw z1Kk`hxs5wf-+0l$9MZIELZecec^h!5e~$Z&`aB9ym@Kk>zB!TSQ#+|aIPten;2zBI z6cY*aMD_EuF_;EltdagOAK8w?SJYbkNsFAds$<}-lZe>6o(kK z{{D6+`X|K00HWk8`S>FpgM1)Li6Tij(UGp&4e)GJXWXnbPE9w@lZYN#0Y1JVWmTjq z0lp_~RSybGZaAq?P_yCqs1b4)O)fl{Q<9%w?PIT+VKOXvLJ}${Z@~C@0b}luviJns zZkbJdPl>89`QN|47pY+2SZpO_2bxAB#N7~%vsTJ{uTUv3>*JG|fgW|(*(F^5VN=*= zI)$Kc_*LE&{5XE0z3c)3hG@76px#DZ|Lef^I)Gf_Rn-;> zx0`|&&nO^BCuyP^h4WXBH|?m!Lxqa^Z}lXwZYYxl6q(P;hiZ*YIXjb7zG)IE{N;K^wV6%#SVR3c zTt5aTA}NOWxeb*R_!>F*uA8I)iX(!w@7KCYE)YiD)Dm6%Klt~0N&(p1R6pit91Td8 z4E#1hHc0a!JKz138Ggz_M}ky036kon=|SN)EtGs0$rc%n2Sh1$A3>S|D7=XhcCt(3 zgLIYFhBvlVpydI8MR#qD@MIZAhs`l0m>5QH9&MPCHM*?(A*Io=*ScXhI#lw$m%?X8vf-%|Hl9a*oczKsO3XKo9SyFOSF%<$YI= zqidIKv&oZusy-s@4TrDk=BJ<6(+Oor0^8RC zAi(uA{RS=nw#B#WUvqT*kqq8X)zMJ8aVYpMgOC6U7YH(0jig0lu`Yi6h7UI$A)jt` zbaerx&qnwxy;IL;&2Ryz;JX9@KdpXz`e%dwNZh#L13eWd$P6-S{suu>{UAe$aE9$2 zF9koZl};#PD3~$%r?M#chq9CqN>bet@i>KvZ3-uGKMrP^Gx?eEsR^qTo(X^sAq0V7 z1?Zta%so;i8BjPu?944c%E#xc%CQs?`&BIMADF$qpD@vMK47wa{eYRZy#4`m<_oBi zC48Tjr=_JNE)vZ8WlJZj98Ea&Wt~ ztnf%pOf^9!Z7p>|!A`+AYN6Z9c25@Q%53mHIlbU~8V0EAB#z}rq*i7hk={6&vAZL` z{vE@@EZ#K#KKqQZqm-5w6oaEpYpzdK+nUL1rE7;P=G2eK#+sWf*f4aR6MBk}7miZg6u3 zfNjNvdU|^X(Dfkk`wy)fmll%&9IZu~+&7X3v|( zQmb5E;3(@WN)Xdb^UGPA^j}qS1IR+<6T}#fY-&}D!thPtT}_gpKgw+Jn)`I-kjdA4Bdm*5#clUJIZ-1-fvS&sM)rVYdp)&nXy zD|@-uph02Y+ET*X(cr#{i+fk0 zZTgu_`iKpe<@Vf3?@P>E(_PWmP#e?n5#dYempHZ=S>#*$2p1E#S zULn0)usX8m;OMg4_O#B48%dX1^L~7Je0zA>xXcMskhp)msYBo9wRocaED6gx5W@}^ z74>{t&Ti4scA_;QNiwi{y?2uNepBnsp=(LE9CM`geL%aT&2s@)Yt7@E_T9wu^?CNR z*SVql_00TykL~sD;`ZBE1ncseweWjK_Pg~jT|Z3$w?*rypqb4}k6rV2s|?j{Z4J6| z*5!KAkd8u3)^_f*wR=bK{^CHMI}xktIhOGF2(QX&Q+3rx(=4X@H?dx@K!w-x8y zfrvK^uV>F8FHO#C9*^g%*H-RpkL2a+9C&MQweFmB&Jz=B?#zexM+DEiHV<`9uR~~< z599?Ka>9!i6VLZJD0t6MQt$I1ciwlr70ZP;6AvKwx=HW53(wVTrwKv(9p`xC(r*ke z4sHuvR_$Dw?`{uonJusL1vL#)$50JH#^*28>g+UlD$uqu`dFE#!CYy^Fa^X0yK|7pF$PlVmX!PQLfTp=*q}j=+M8 zR=C!~X1z%F48i*w0kLSFKC}FI%-mp3c~eQ913cLXn3>|d`z?>#>Kb@#gc8&wYdN0U z5;f3spJ80>_SR~7~{%8b^e|ePmk8;WAE2j z`1i{$o@4#hpD@qG6zruKaLYDGnPefm`=!&6b+`3A*ntcR&LhT^4|tcC#-&5?j7)P1 zit7D;AQZVQBU^&J_%~(`@>8A`9hboOBzddH)p;eoAcTIm>c^3(Rl;fUV@x1ga@9x- zJgA82&nm5}!0HF}e;p~cY|pDyC<|Z_@L!!+z31RY>FSey;nYJkflcTH7oDGvqukfF zl$`Pj$U;mguG^Wagsl3Ch8zJ=3l=6I504d+U%z%I4C^1*{zY7+5_p?BAkU1(mDwV< ztg~;T)nh&Qr+H<#pIa8nhB64Kq~)zizpa{I0NmQ6pQL!+sKsznB~7gGsE7+FEiRwH z=6^UxOVTfw8ksb8_mK`V!aw^G1&UR%!I`o#Z zYzauJ*%ZloF-ysP29-fh)DM)1Omo`4(CGv6-{;Q-vshGiILmJXNTJQ_L&@T9NWY4t z6q^k5hdSV)>jrR>l46)gkb)`-oiG>sT*U$-6Ofx0=TJn2UUouxk_(4q#8l0h#8B@l zYT zEYc(Rqxx$y2wV(=1gq}8cJICg(%ACF5z>-F(;JkDh`p$@Qemf^G6iN*<5zaN>LRdG|x8YexC4NbRk}0faI3Gu9o2ZJ;e22AeP>p5W6>hYL^j zf1$<}P>S`kId8HTto+Etl%&3=oSTlFJL|up26xb^vYDqX(FdkuS0f^e<=1@r{AvF! zKt}F*X?F1@Wo+v6E(wRUce^LNTpd`>M9+-4*5rP5i2p2G4QB<0xFuv#bSW#t# zlzYg87EY@SqyN$<$ck;d3ehpYiKWW)wz(|qW%IpUQaQYY)5u|M4!p+l=MqtpnVE+KD zvF}xc0R;9Bz(T3Z7L$h%d*T476mr^ZoMIKqbxoqnbeN+mThVO4E))%gLKzLYq6h15 zx~o}@xpEjeDvKw=iFow7=04+4s*;fa}z6iJgNGjSaB}(E-97c#_bRM8@3^um(K+{KerNPwy zh^oF7s$@4}n*Qu~kLZj$(Yv0w62qv9#ijy;&I<@#sO2fR6mec9*ovHP0pbY~>hTqJ zcd}>VvcZ;r9Tt7$Jtr|VEg3g5>nhX<#G+Y-;43MmfRM+vTP{irUoMTo4amHXihVUt ze@B1+#qgmY%iDJhu^i}>Agm}pv~c0DM;*@eANyc05pTwY6>AZpcq$9_?>VTUJ=BL0 z42l7{tbXY@oj|H02N>eftV1S@YANE}4veM}AK0f=euxC)*-+5_U=)B)@Cn&M%BNI7 zM(1sv#f^P z+-Dh%KgwW;11JMywbhCV`O{q#>D3*bq#`p$V`C{lnf%+JjybdFBh&a`vyL?U6M%}% zX&0jOjryLke;2~N7y6$C)b)x@@2rq@4`Z1a=fiVyP%?hvr z#o#?oN_VFmq#Adn6%#Wfs!S^g#(oJaA$DNY9Rk3jsJtnw2tg4w$*Ig03C)91(IC!_ zg%uAazLD2CRM$o>ik=kE6^%d<-_@0Tm_z&MRiTeQehaZ8BtZg9)^z>tqs0Y2T0Bk! zu-fGyQS4Dme0^q2Y$_zftOih|MaCKAPd zfnt~s>ihI5f_-2d{`s+^fB@1(btcU%5GH>Tg$X2aS(P#b1|8cF|J#MiloVtY9l+LxWK7B`_hAWD zvU)bylk$)Br*yO+!b>f0p?F&Iib!-m34k`o>c}$v;Uj4OM{~-xkp3KHctWhfr>r3zN zO6-sDi0`G@C}G<#VQba;R%gFcLTq*Iq`STA!4lLqlhYVo5z`3j(MLz1Hb%Em;`$-} zqCM6Ji;Vw-+?ot+zW0v;%f83AqpfW=sVf5w8ba-<#;%nvW&3gE4TWAT==2J|CMw!} zDjUkMlIz(VpNa=h@_!jb5dF*GRs3HDt8o7^pqTsiBff9;(M+~e8M?fplR`7f?pk@j zMDU9?%@1u~c?_-e3RF;!I)wY_PFlX9=8Xx+5@;L!bDhY5R&KD!%!GhBwvop$>g@n) zjLUWe=T;wOS@UOP9*n=Btt633&+7KHGHO;?^2++>CbsL}UlQ77aFn@{InG~ncVW)H zzU2($Uex0+DAFBUrFXAn`Sf^fL#(76g(Ce>jbHs)P}RS-xVIG(A)}ey?FgJcjOlJ{ zVT&wOST3{M>?>s)(Z*EY7)Gd|%sJ;EX7B%1>N3XU=0gcp*Z4*gSc5B-*`bdV!>sv?A8;IX6^EO1RutOdrjJF;kep zrpHTDHPzS!ww#1IqCm zS2_ny6=;R8`r;FgRo~Q}im#OYRU}TUK>>_&;QYp2GTe&ad}kR9YtsPW_-!L7A#4G# zt%2#|8nP9C{WYu<0ex3q*9)ly+`zYj(FT@Su+Z37M+0}RL2+blcPO^BN7DKor8RIq zE3R++0#k#1+E@Job4^hWmE+I+hSBfH1;6O=SUaKOhz{}y#~ z+9do!Q=hl9wBUDnq2*`b7_rhTq#Jm-f#ehU9W6Y_85|HYJudN)b1!N*xYgn4#1>#E z>58TuxeSnlTLn}xiP7#EQLX=72DqS)YAqZSm2zh6AW(1qGX}b?8{?>Y5+36pzW0$N zdcogW+$O0;3=n=FGcXCFyI4js`mj>9%Mcj`@0zN54*+(FkLrXh$` z0%%m8erni{*Z`7Rt;6w|vg$|4E7KV^BTvE3M=sRXz@lQqMy6IU)nuGT&Y6hQDB)v~*OOi=`nj0L3?=ZH%1TRPZptwVljtVM( zXurqj5dpO}`a)V|pF*)SXWA%!vm|hVnSVs`n(l560coRlg48DTriuTM;``_Td6s4c zscNQXaXdn92hC&CZkKeE&^zwg2U%nQP}CwKvqiWE-DlGnyr0%n=dh*$kT{83>4Vb0 zOJ^Cz0mveikvLfAM3$7h&40_zeoRiPN3zXn{~85-C@Gf8za;+&nMU#N9s#&$nC2BO zC1W;rE_3|pQ#5r!?O0hlE4H~jz-<_yQ~u23FArGRzrnAUzH}%qXhh4Sa@1UdQLy1u z1!(n1WB@4J1~&BlV+7pL{Wjhj#HS_t!BP6MJQ!!83SMrJ&)LiYR0lw;o%+P{3#E^= z33mwFpE>lis^)*F>*?}5Wqq(iKF4)A)J}U`C`d>r3xuy-x^Mj5`)sEO)ldMsTljx! zh-QCwriu5*T%BbWUP1n^m}f|B{q`G5XEB^#gpoj}ZMAadU1&?AJi8Xv(W<{PuaLM! zykqfj-;ub{U|-GaB_6PNspdzOrFV@T{bi9&bvcb`1vmhYdHc=;4&e1X z?GTR5W@m@r@+hu}KD1T~v3F+x|NBSXNaY|>j>M$@pLVXptBGchQbf9dH0d1)N)-rF z1q2d$N2C*JDjn%fl-@%X5Ghg&MF9n*inND@Ceo`^ktRi2guIR4=R@=P-e2&Nb9T?% zoqKm?&&=%3ocUcTTR0Ij_nFa2QToQBMXJQfA3U-eC&LV}t#{HF80r$4b7RG?4C0_n zpE8OKrRLlsBgVVA2H)37a-J3J20O?J->FpJ8@c{YLEl_t1L^M|v5M0iE5r*vvHTaJ zqX{j#A*5l4&VB`fxTfFYu1i$OeHGc^^NEBOZEMEOBQ``^3t1u`LaIB!V!#FhS2*N% zuDF!gIV&=mHs)EtAI~bXh7K>K!S4X0#DkaNoHZYS#@DEWn!|e3&eFj>wBHxmP1Zoaue0wcTIWwzsZS0Ad`OMtja!&| zm)l5B)*WkoM-T5jJZqdYry<)mZA#%(&lcly}YL*|L!L|d(~rEy@n>Ya5KmpzKw z<9Tfg4&x&!x_x@90ARJ1Ji%vQ`;S{`Yce#pQh^=D5|ZDWQ_u!`9rZ<{W7;X14&RlyYgBIp5&mE%RILvuX~FZHn26 z?XOObl${DFE{t*7g5K(K++KQ-2G@ua=;!Pf1f?bjxZa*uI6_pNb!qawGf-)^c$nJG zRdA`Ykw`!H0`&+B+Qnf-vrknBr4M;?bLwIL4gBn8J^7o|vWL;ts=~vS#ZnE@jCWJA zCk*B$^L%5{w55#QrxB0up9QZFnJXxjEG%D>W#3($2#tGc*tL3&9F>uD{Ftup{Fo5? zS}Vzb!pm7n+`XDghA+I7s>g#}#t5oMDH`E!k|`dWjWy|h;urMXoY(MG61lUvHUz*B z?IAi&bc~PH1z*){^S;{b9nGf?#O9C#5l-BZ^6^s#5+Tw&)`*}R`)YmGn=bdaV1vs_ zuSz*=9tqmlM>*!Qet^RUBktaICA=&z6HIzc>dO#}-_&?>VP@NNvHB7G357)q&{+Q& zVmq98@dyGmWqZILi|W^=40Ca}{eN2q8u8!1Sh%is8#_(djOKR=@=XET>P~o#y60H( z72aNl0HwMKMpB-T)xFKab)yC(A=~TauWr5MV|Rs0tq42QUcIA=vY`o?d&M`ztNOfD z*(U;THRF64f_C9E4qZ?5YH949cX#mniiWMsh$X&q+k!@}j!PATI@4SfM45aew&&_4 z;8%min93N?HcW4lC7V0WGgBi)Ch?SHDF>)P2O%G4ioW24!b+}%y3-{`&RRal=URV4 zFJ-%sQYh^(vvR>3N!LhExIdltpwcn3TGv>4sr)N~x86YTu z1v8TV2#ADP--RhTSUWmnTHoDAn$Ar2l-Kuh-3e{>M2edaDX#k_NnV7UyQcG!Cqy0( zdS-83DMMTh%$Dvv(ywj%jLmO%_Yf6Sd*JOa)xttis`li|?Mm6Z@j@;UE~Q_dw4jfi z%IKEgAAPNwW}%oc{08%{kdsFry&tq|n)tp|A0&Ob;)$!|bHvE|#pC_O?MC0Jjge*T zuKo2-M_|i@;^QOt_V+Jv`hK7ia z4K+Q1Ww+I>uG|K;-Teojf?SXJgMxOu>^1iB&0DsalZ0PaP1)KlB~Z}05?J8gV5dtY zSi<|m|16R`gGm@{<@{zc)kf>2hkeLvLJx{1RwRA~p)iFN>l>L6U!0vc%7ja}0Hi9MV8z-h z6Y6_rhiHik$yIv=fV8c0-pJhd#oIZvM2w`)xG1b`@D9INhhMy0Pydp5lb-%%@g6;W z0r4q4eL?XRHc-+oXA=Z{Erz1;;94vN^59yWX91t;Kzu%{vV3$X4LOKk&+{oCbO4^u ztE?TJPooJ!=y?|MsSl*(3o2Vizom%-@#}jQ@o5fZ=1VBMM9+6=}>nayUYta@W?lUFd zq;2AlHWVu@F&Ze(H&bqi_M<&UB%yM`X=yJ>8KsmtnCMpL+ba)57ttD)uCxlY!y+r1 zyocz8KBN13gr@u4+)-U`+b6DSIorf0Pqffp1PgR__pG?No1OzMtwbkJ)Y@lHo&?XI zK~8sb%%?J6wAxdQXAt&h=_1Q$iiMp;T6A#CYcgN_JmxQH*I!-hip;g&oXt?^n|>qm zAg3u9CvBpl>x%NWi znEcfk{1yi92#*Ed1@O%gO#TWCZi>OHJIVZv0!_;}xP^wr6o{1T^7kx=ck?Md8vMc^pV$ZVG@M z8~ES1=l7rW{W%Pczz$!04S3&vBlwT4g{QR*;IAa~9g0p=oA2T})G&ezW24%R+48_s|CFsBks1#I|u6#Ny%awIMI}4>9k(bbX8_Xar z2y>5^ha@~U&)TwOK<_-&VO33b>AE*Dp(`|BkTa)UIuqQmzwYsz%f~-EZEF}c#R)BP zE{*W2ua=g53uamkA8sq~hZa2^T=yHly&fS473qcNiNgXEZ;(y(g^-n_yjzqWvv`$* z`-;FPlCX|}egResmDNy$ZGh`Q>j2v<;r_V*;m6gT7l|sbeiJ>!?9X%^N+m z(I=cnUaffMcH|9bHEKsA642JV)_OZ6P>YX5`e_AlNSG_HLzu1kr>gI)sxax0*Tu6` z(-v8dBeh*E7UYkoFV9C`K7kBMZV%TU13Lir>R!#TTM&7Zf*c47j$Zf@@r&Zz4n)l- zb(NyLHp@kuMg;u`yi;Qc)P2i!Oon;%$P4(4P3}X!zNr$kk2_+$Sc>YFLVq@W-gj+9 zk-*&J4qe1_`Jm-w5hQ!1M!|<96hH3e{J2l#m+L&;ig>gR5J66(;ty&Qn-Ol&QVnd! zqP;j)f;)~uJ>fZRNoUjz`QjZ?Nw15B>*g3TyAgM0sgNK?d9o8bSL3SK=LB#mK3Njo zF0A7uhpX8^NIG?r;EY3YvscRrxWFqTvsbsfrkLoCsMK$K3oE2Ei6Yg)k*1E!QM{yn zotT=&fg8&4(xdA{MozjqJoEZ;dE>sg(0=)IR}Xp>j%}6m(Yi(-3En=0rs&_~>VS6Z z>s3~j3C3EE2cbKu5C28oU|Yf`FetMKaTU}NWH5kV<8f4BG)c`^SYYg-zDzFRKH>G9 z3g4`K2%m>@k))VU{i;f8D1x2S_p+Pm3JBmK>qrT5HtZ>i4IThk^>Gpl+zOct@Q8gDIY zGcLLU?Rfg(Uf%k+s}!t5cjod28zEQ= zVYKBI8xK2T`7YUvw>e?wIqlTO62jx$;KYPdiH_mPy^S) zjJfCuT8E>g*EQZ%g_tuGnzG8Tnn{=A_?c>5ljCvom1239=z^&V z8z^0{j>a5cos|^2HSoC3!;-@i;!P+rN~JdB=1(!1xY>DTC*a-Ow-3yrgHH5o7pC%i z+}$$uc|{bS@k=6TU=R@=9feCbsmw3&RJ*uUHIqSC>XqaVO57qi%I2cxWMtBh#z;kc zljO2mdFa&i;$LcAwSiM{TU$`35)5aiaT?#2Xafu11q(#7MfRPU?I6W1tfPD=%*|a& zm0qSu03v?t$fF)7PRqC;-yrK7^q_C%t$f5`6E4)vNW>vG?Ujm5*4OvU_3UM{g;r|z z0i6`ZY`fL9UyDt0$Zf*%l?BB3iCZK2RTNtCA^d4EdQidl0i6+JdlHkLiHdk}E1636 zp;Kly{Vz&gErJhLH)n!WJs*8vdtmEMJH5(1_DUxyD%0jHt4;+ah@;z##_Hk6%Y7va zsXiiepJ-;CUbCtkrBQ#+%tcEHrf{ArbsEIXQ3VsLau1wJh$9gEW($eGGkhL!h*V>^|*OSz8v?*hMjBmX2~&P~8%@fW9LY~t^JvA+`M0N=p>?jDP+gY6c2 zs&tw7ht99wq1a?>o5EA_SHLd{D8#90AvP7;Sn8DO3)r$?sMt1B*b3M-Hm3@jK=}3F zuBZRY)COA++ZyInPz{LI1_ZHu=cX-xoQ4Wlw7T!v4ABflbGrq@D_x z>i($0Z&OxmHul%vDO<