You can subscribe to this list here.
| 2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(158) |
Dec
(8) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2010 |
Jan
(18) |
Feb
|
Mar
|
Apr
|
May
(122) |
Jun
(464) |
Jul
(514) |
Aug
(103) |
Sep
(121) |
Oct
(96) |
Nov
(9) |
Dec
(6) |
| 2011 |
Jan
(8) |
Feb
(14) |
Mar
(93) |
Apr
(14) |
May
(46) |
Jun
(89) |
Jul
(133) |
Aug
(48) |
Sep
(39) |
Oct
(4) |
Nov
(2) |
Dec
(34) |
| 2012 |
Jan
(102) |
Feb
(237) |
Mar
(130) |
Apr
(98) |
May
(197) |
Jun
(98) |
Jul
(99) |
Aug
(105) |
Sep
(106) |
Oct
(31) |
Nov
(33) |
Dec
(35) |
| 2013 |
Jan
(91) |
Feb
(70) |
Mar
(85) |
Apr
(82) |
May
(27) |
Jun
(7) |
Jul
(35) |
Aug
(15) |
Sep
(11) |
Oct
(38) |
Nov
(33) |
Dec
(24) |
| 2014 |
Jan
(24) |
Feb
(4) |
Mar
(17) |
Apr
(26) |
May
(30) |
Jun
(56) |
Jul
(62) |
Aug
(1) |
Sep
(1) |
Oct
(5) |
Nov
(6) |
Dec
(9) |
| 2015 |
Jan
(1) |
Feb
(239) |
Mar
(1) |
Apr
(1) |
May
(7) |
Jun
(6) |
Jul
(12) |
Aug
(17) |
Sep
(11) |
Oct
(5) |
Nov
(1) |
Dec
(17) |
| 2016 |
Jan
(73) |
Feb
(117) |
Mar
(3) |
Apr
|
May
|
Jun
|
Jul
(67) |
Aug
|
Sep
|
Oct
(8) |
Nov
|
Dec
|
|
From: <br...@us...> - 2016-10-23 21:25:55
|
Revision: 4221
http://sourceforge.net/p/openlcb/svn/4221
Author: bracz
Date: 2016-10-23 21:25:52 +0000 (Sun, 23 Oct 2016)
Log Message:
-----------
Bumps implementation version number.
Modified Paths:
--------------
trunk/prototypes/java/manifest
trunk/prototypes/java/openlcb-demo.jar
trunk/prototypes/java/openlcb.jar
trunk/prototypes/java/src/org/openlcb/Version.java
Modified: trunk/prototypes/java/manifest
===================================================================
--- trunk/prototypes/java/manifest 2016-10-23 21:25:35 UTC (rev 4220)
+++ trunk/prototypes/java/manifest 2016-10-23 21:25:52 UTC (rev 4221)
@@ -7,6 +7,6 @@
Specification-Version: 0.7.4
Specification-Vendor: OpenLCB group
Package-Title: openlcb
-Package-Version: 0.7.5
+Package-Version: 0.7.6
Package-Vendor: OpenLCB group
Modified: trunk/prototypes/java/openlcb-demo.jar
===================================================================
(Binary files differ)
Modified: trunk/prototypes/java/openlcb.jar
===================================================================
(Binary files differ)
Modified: trunk/prototypes/java/src/org/openlcb/Version.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/Version.java 2016-10-23 21:25:35 UTC (rev 4220)
+++ trunk/prototypes/java/src/org/openlcb/Version.java 2016-10-23 21:25:52 UTC (rev 4221)
@@ -34,7 +34,7 @@
/* Library modifier - updated periodically
*/
- static final public int libMod = 5;
+ static final public int libMod = 6;
/**
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-10-23 21:25:37
|
Revision: 4220
http://sourceforge.net/p/openlcb/svn/4220
Author: bracz
Date: 2016-10-23 21:25:35 +0000 (Sun, 23 Oct 2016)
Log Message:
-----------
Fixes unittest breakage due to reordered packets.
Modified Paths:
--------------
trunk/prototypes/java/test/org/openlcb/implementations/BitProducerConsumerTest.java
Modified: trunk/prototypes/java/test/org/openlcb/implementations/BitProducerConsumerTest.java
===================================================================
--- trunk/prototypes/java/test/org/openlcb/implementations/BitProducerConsumerTest.java 2016-10-23 18:38:02 UTC (rev 4219)
+++ trunk/prototypes/java/test/org/openlcb/implementations/BitProducerConsumerTest.java 2016-10-23 21:25:35 UTC (rev 4220)
@@ -206,10 +206,10 @@
expectFrame(":X194C7333N0504030201000708;");
expectFrame(":X194C7333N0504030201000709;");
+ expectFrame(":X19914333N0504030201000708;");
+ expectFrame(":X198F4333N0504030201000708;");
expectFrame(":X19547333N0504030201000708;");
- expectFrame(":X19914333N0504030201000708;");
expectFrame(":X194C7333N0504030201000708;");
- expectFrame(":X198F4333N0504030201000708;");
expectNoFrames();
}
}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-10-23 18:38:04
|
Revision: 4219
http://sourceforge.net/p/openlcb/svn/4219
Author: bracz
Date: 2016-10-23 18:38:02 +0000 (Sun, 23 Oct 2016)
Log Message:
-----------
recompile jars.
Modified Paths:
--------------
trunk/prototypes/java/openlcb-demo.jar
trunk/prototypes/java/openlcb.jar
Modified: trunk/prototypes/java/openlcb-demo.jar
===================================================================
(Binary files differ)
Modified: trunk/prototypes/java/openlcb.jar
===================================================================
(Binary files differ)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-10-23 18:37:47
|
Revision: 4218
http://sourceforge.net/p/openlcb/svn/4218
Author: bracz
Date: 2016-10-23 18:37:45 +0000 (Sun, 23 Oct 2016)
Log Message:
-----------
Treats target rebooted error as OK in the unfreeze message in the loader.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/LoaderClient.java
Modified: trunk/prototypes/java/src/org/openlcb/LoaderClient.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/LoaderClient.java 2016-10-23 18:37:27 UTC (rev 4217)
+++ trunk/prototypes/java/src/org/openlcb/LoaderClient.java 2016-10-23 18:37:45 UTC (rev 4218)
@@ -325,22 +325,26 @@
}
void sendUnfreeze() {
- // System.out.println("lsendUnfreeze");
dcs.sendData(new DatagramService.DatagramServiceTransmitMemo(dest, new int[]{0x20, 0xA0, space}) {
@Override
public void handleSuccess(int flags) {
if (state == State.SUCCESS) {
feedback.onProgress((float) 100.0);
- feedback.onDone(0, "Download Completed");
+ feedback.onDone(0, "");
} else {
- feedback.onDone(0,"Download Failed - "+errorString);
+ feedback.onDone(1,"Download Failed - "+errorString);
}
}
@Override
public void handleFailure(int errorCode) {
- feedback.onDone(0,"Download Failed in UnFreeze - 0x"+Integer.toHexString(errorCode));
+ if (errorCode == DatagramRejectedMessage.DATAGRAM_REJECTED_DST_REBOOT) {
+ // that's ok
+ handleSuccess(0);
+ } else {
+ feedback.onDone(errorCode, "Download Failed in UnFreeze");
+ }
}
});
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-10-23 18:37:30
|
Revision: 4217
http://sourceforge.net/p/openlcb/svn/4217
Author: bracz
Date: 2016-10-23 18:37:27 +0000 (Sun, 23 Oct 2016)
Log Message:
-----------
Terminates the datagram reply timeout when the destination node reboots (sends a Node Initialized Complete message).
This avoids long delays in the firmware upgrade sequences.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/DatagramRejectedMessage.java
trunk/prototypes/java/src/org/openlcb/implementations/DatagramMeteringBuffer.java
Modified: trunk/prototypes/java/src/org/openlcb/DatagramRejectedMessage.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/DatagramRejectedMessage.java 2016-10-23 14:19:00 UTC (rev 4216)
+++ trunk/prototypes/java/src/org/openlcb/DatagramRejectedMessage.java 2016-10-23 18:37:27 UTC (rev 4217)
@@ -65,8 +65,9 @@
static final int DATAGRAM_REJECTED_NO_RESEND_MASK = 0x100;
static final int DATAGRAM_REJECTED_RESEND_MASK = 0x200;
static final int DATAGRAM_REJECTED_TRANSPORT_ERROR_MASK = 0x400;
+
+ public static final int DATAGRAM_REJECTED_DST_REBOOT = 0x10100;
-
public boolean canResend() {
return (code & DATAGRAM_REJECTED_RESEND_MASK) == DATAGRAM_REJECTED_RESEND_MASK;
}
Modified: trunk/prototypes/java/src/org/openlcb/implementations/DatagramMeteringBuffer.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/implementations/DatagramMeteringBuffer.java 2016-10-23 14:19:00 UTC (rev 4216)
+++ trunk/prototypes/java/src/org/openlcb/implementations/DatagramMeteringBuffer.java 2016-10-23 18:37:27 UTC (rev 4217)
@@ -148,6 +148,26 @@
}
/**
+ * Handle "Node Init Complete" message and kill timeout if our destination node has reset.
+ */
+ @Override
+ public void handleInitializationComplete(InitializationCompleteMessage msg, Connection
+ sender) {
+ if (msg.getSourceNodeID() != null && msg.getSourceNodeID().equals(message
+ .getDestNodeID())) {
+ // destination node has reset. Let's stop waiting for replies.
+ DatagramRejectedMessage rejectedMessage = new DatagramRejectedMessage(message
+ .getDestNodeID(), message.getSourceNodeID(),
+ DatagramRejectedMessage.DATAGRAM_REJECTED_DST_REBOOT);
+ System.out.println("Destination node has rebooted while waiting for datagram " +
+ "reply "+ (message != null ? message.toString() : " == null"));
+ handleDatagramRejected(rejectedMessage, null);
+ // Inject message to upstream listener
+ toUpstream.put(rejectedMessage, toUpstream);
+ }
+ }
+
+ /**
* Handle "Datagram Acknowledged" message
*/
@Override
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-10-23 14:19:02
|
Revision: 4216
http://sourceforge.net/p/openlcb/svn/4216
Author: bracz
Date: 2016-10-23 14:19:00 +0000 (Sun, 23 Oct 2016)
Log Message:
-----------
Fixes bug that caused the wrong outputconnection to be returned. The effect of this bug was that network traffic was done on the caller thread which can blow up an androd app.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/OlcbInterface.java
Modified: trunk/prototypes/java/src/org/openlcb/OlcbInterface.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/OlcbInterface.java 2016-10-23 14:18:40 UTC (rev 4215)
+++ trunk/prototypes/java/src/org/openlcb/OlcbInterface.java 2016-10-23 14:19:00 UTC (rev 4216)
@@ -96,7 +96,7 @@
* Accessor for client libraries to send messages out.
*/
public Connection getOutputConnection() {
- return wrappedOutputConnection;
+ return outputConnection;
}
public NodeID getNodeId() {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-10-23 14:18:44
|
Revision: 4215
http://sourceforge.net/p/openlcb/svn/4215
Author: bracz
Date: 2016-10-23 14:18:40 +0000 (Sun, 23 Oct 2016)
Log Message:
-----------
Merge branch 'master' of github.com:openlcb/OpenLCB_Java
Modified Paths:
--------------
trunk/prototypes/java/README
trunk/prototypes/java/build.xml
trunk/prototypes/java/src/org/openlcb/cdi/swing/CdiPanel.java
Added Paths:
-----------
trunk/prototypes/java/lib/jacocoant.jar
Modified: trunk/prototypes/java/README
===================================================================
--- trunk/prototypes/java/README 2016-10-23 13:03:48 UTC (rev 4214)
+++ trunk/prototypes/java/README 2016-10-23 14:18:40 UTC (rev 4215)
@@ -14,4 +14,4 @@
Authors include:
Bob Jacobsen jac...@ma...
-
+ Paul Bender pau...@ac...
Modified: trunk/prototypes/java/build.xml
===================================================================
--- trunk/prototypes/java/build.xml 2016-10-23 13:03:48 UTC (rev 4214)
+++ trunk/prototypes/java/build.xml 2016-10-23 14:18:40 UTC (rev 4215)
@@ -2,7 +2,7 @@
<!-- Bob Jacobsen, Copyright 2009 -->
<!-- Revision $Revision: 370 $ -->
-<project name="OpenLCB" default="run" basedir=".">
+<project name="OpenLCB" default="run" basedir="." xmlns:jacoco="antlib:org.jacoco.ant">
<!-- basedir="." means all paths are relative to the "java" subdir. -->
<description>
@@ -27,6 +27,7 @@
<!-- set global properties for this build -->
<property name="source" value="src"/>
<property name="test" value="test"/>
+ <property name="coveragetarget" value="./coveragereport"/>
<property name="target" value="classes"/>
<property name="jartarget" value="."/>
<property name="doctarget" value="doc"/>
@@ -46,6 +47,52 @@
<pathelement location="${target}/" /> <!-- last to check for name collisions -->
</path>
+ <!-- Java Code Coverage -->
+ <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
+ <classpath path="lib/jacocoant.jar" />
+ </taskdef>
+
+ <!-- fileset for the jacoco targets. -->
+ <fileset id="jacocofileset" dir="${target}">
+ <include name="**/*.class" />
+ <!-- Exclude classes necessary for testing only from the code coverage report-->
+ <exclude name="**/*Test*.class" />
+ <!-- Exclude testing infrastructure classes -->
+ <exclude name="**/*Scaffold.class" />
+ <exclude name="**/*JUnit*.class" />
+ <exclude name="**/*Demo.class" />
+ <exclude name="**/*Mock*.class" />
+ <exclude name="**/package-info.class" />
+ <exclude name="org/openlcb/FakeConnection.class" />
+ <exclude name="org/openlcb/cdi/jdom/SampleFactory.class" />
+ <exclude name="org/openlcb/cdi/swing/CdiPanelDemo.class" />
+ <exclude name="org/openlcb/implementations/MockVersionedValueListener.class" />
+ <exclude name="org/openlcb/FakeOlcbInterface.class" />
+ <exclude name="tools/jmri/DecoderDefnToCdi.class" />
+ <exclude name="tools/cansim/CanFrame.class" />
+ <exclude name="tools/cansim/CanSegment.class" />
+ <exclude name="tools/cansim/CanInterface.class" />
+ <exclude name="tools/Timed.class" />
+ <exclude name="tools/Timer.class" />
+ <exclude name="tools/QueueSim*.class" />
+ <exclude name="simulations/NodeIDCollisions.class" />
+ <exclude name="scenarios/ScenarioRunner*.class" />
+<exclude name="scenarios/TwoBusesFiltered.class" />
+<exclude name="scenarios/ThreeBuses.class" />
+<exclude name="scenarios/NineOnALink.class" />
+<exclude name="scenarios/ConfigDemoApplet*.class" />
+<exclude name="scenarios/BlueGoldCheck*.class" />
+<exclude name="scenarios/TwoBuses.class" />
+<exclude name="scenarios/can/TwoOnASegment.class" />
+<exclude name="scenarios/can/CanScenarios.class" />
+<exclude name="scenarios/can/NineOnASegment.class" />
+<exclude name="scenarios/BlueGoldApplet*.class" />
+ </fileset>
+
+ <!-- end of definitions -->
+
+ <!-- target definitions start here -->
+
<target name="init" description="create needed directories">
<!-- Create the time stamp -->
<tstamp/>
@@ -56,8 +103,11 @@
<target name="clean" description="remove compilation results to force rebuild">
<mkdir dir="${target}"/>
- <delete includeEmptyDirs="true">
+ <delete includeEmptyDirs="true" quiet="true">
<fileset dir="${target}"/>
+ <fileset dir="${coveragetarget}"/>
+ <file file="jacoco.exec"/>
+ <file file="junit-results.xml"/>
</delete>
</target>
@@ -103,7 +153,7 @@
<classpath refid="project.class.path" />
</javac>
</target>
-
+
<target name="run" depends="compile, tests" description="build and run test suite">
<java classname="AllTest"
fork="yes" >
@@ -113,6 +163,33 @@
</java>
</target>
+ <target name="run-coverage" depends="compile, tests" description="build and run test suite, generating coverage report.">
+ <jacoco:coverage destfile="jacoco.exec" excludes="org.slf4j.*">
+ <junit haltonerror="false" haltonfailure="false" showoutput="yes" printsummary="withOutAndErr" fork="yes" dir="." timeout="3600000">
+ <classpath refid="project.class.path" />
+ <sysproperty key="java.security.policy" value="lib/security.policy"/>
+ <sysproperty key="java.library.path" path=".:lib/"/>
+ <test name="AllTest" outfile="junit-results">
+ <formatter type="xml"/>
+ </test>
+ </junit>
+ </jacoco:coverage>
+ <jacoco:report>
+ <executiondata>
+ <file file="jacoco.exec" />
+ </executiondata>
+
+ <structure name="AntTestReporting">
+ <classfiles>
+ <fileset refid="jacocofileset"/>
+ </classfiles>
+ </structure>
+
+ <html destdir="${coveragetarget}" />
+ </jacoco:report>
+
+ </target>
+
<target name="bg" depends="compile, tests" description="build and run Blue/Gold test">
<java classname="scenarios.BlueGoldCheck"
dir=".."
Added: trunk/prototypes/java/lib/jacocoant.jar
===================================================================
--- trunk/prototypes/java/lib/jacocoant.jar (rev 0)
+++ trunk/prototypes/java/lib/jacocoant.jar 2016-10-23 14:18:40 UTC (rev 4215)
@@ -0,0 +1,5096 @@
+PK+\xD3$L\xBD\xF2\x938\xEC\x97\xFF\xF3\x85̾~\x98?\xFF\xA0\xDD8\xCCK\xFFo=\xAB\xD7\xDF\xF8G\xBF\xF0S\xD7/\xFF\xF9R\xBA\xC9?AX=\xFE+\xBD\xE8\xFC\xAB\xD4\xEA]\xE2dq辘\xA8\xD5\xF0\xCF?\xF0\xC2=\x85\xFD(\xDF@\x8D\xFD\xB6.\xBF|\xFB\x87?\xFF\xF8\xF3\x8F\xB7G\xBF)\xF8\xFD\x81W+\xF4\xCFN\x884\xD5\xBFWV\xB7\x99\xBD] \xB5.\xD3d\xFF\x9F1L+\xBF\xE8\xB58\xC6\xD9\x90\xFC\xEA\x94yz\xAF\x94Ux\xF3\x87\xE7\xA1Q2\xBA\x82\xF4Nٝ\xDEt6-G\xCEg\xD2\xCA\xC6x|x\x9E~S\x81\xAA\xF0}@\xCC\;6\xEC"\xB4\x9D\xD8\xC7\xD34{1\x9Dr\xE6\xF9\x833{\x9B?e\xEBj{\xB9\x9D\x89`\xB3>\xD7\xF2\xACvUr+\xFA\xB6\x87do
+{\x83%\x86\xA9\xAF\xD7\xF9\x8B+\x94\xAA:\x8B\xBB3\xF1\xDB\xE1\x83\xD9]et\xE3\xF1i\xEB1\xCB<[zF\xE1T\xB2l\xA2*\xFD\x8C<3\xF9\xAF2\x8D\xDF\xFFڋ\xF4_|\x9D\xE4\x83\xF3\xDDL`fZ\x99\xA7\xB6\xBFC՚X\x9E\xFEP~b\xA7ح$\xD2/\xB8`p\xC1\xC6\xE8\xD8ۣ\xF0\xA5m\x98\xDDV\x88N\xC5rpk\xCB^\x9F\x9Bwz\xDFb\xBBSdun\x84e8f\x82\xE4l\x9Cau\xC8@0Ҵ>!~u\xD8ҝ\xD9N\xC8}\xA0\x8Do{#\xCA\xCF\x97N\xD4\xE6\x99\xC1\x97]\xAA\x95\xA4z\x99/S{\xE6P\x8E\xE0\xD4"s|.-{\x89\x99e\x96\xA3%\xE5x\xF6P\xEA<I-\x80\xCEw\xA1fZl{\x8B\xEC%q\x9D\x89]\xF5\x83\xFFm\xB2\xAC\x9Aڦ\x83\xEBȉt\xDA\xD8$\x93\xCC|\xAE\x927\xBB\xC0F\xC4\xEC\xDDL\xAFnƫ\xBC\x9F\xC5V\xB0HQ\xA8O\xCA\xCC\xD5Xw{LvN\xE5\x88,=\xB6\xE9\xE1ā\xBB\xE9_\x87\xB1/f\xA3\xA7\xB0\xC2\xD6ەҡҊ\xE3q*\xB9"\x81\x97mtd\x9F\xE0\xC8Ѧ\xC0\xDD\xF7\xBE\xBE\xE6H\x8E\x9Bc5l\xD3\xCAr\xA9*\xF9R\xC7THg]ZN\xBCv\x92l\x80\xD3{\xD5s.=fSJ"ci\xB8\xAB \x85\xBB\xA4\xF2\xCD\xDF]`\xDC_1\xED\x88+*p\xD0a\x96\xEE\xBCu\xEB[\xC5&\xF4\xCDV(#\xE8\xF2]\x87Ű6u\x9B\xD4{\x80\xD3$|\xD0s\xD4o\xF1K\x9D\xA8\x8A\x8E;]\xB9к\xF1\xD3\xDE\xE9\x8C,㪗}\x94T\xA6\xA3-\xA5\xB3\xB4\xF0P)\xB9\xF2\xC3\xAFv_\xED\x8D+\x88\xD1\xD2y[\xF1\xEA\xC8#\x86\xFA\x9B\xF1\x98\xE3k\x9A\xC7\xE9fuӽ09\xFB\xBC\xAE/\xFC͌Fd\xA1\xF6#P\xE2G \xE2\xEE\xC40\xE25c\xF0d\x9E\x815\xED\x8A%z\x9D\xA9RC\x9BUM\x8F\xF8\x84\xB7S\xBDc\xD0I\xEB\xBC\xCD\xC2&3\x9B\x95
+\xE1Z!\xD7\xA3\xBD\xB4%M\x9Fޛ>\xC2(\xFF\xEEX*\xCAV'|\x95\xA8"kS\xDE\xE9\xA6;[\x84\xB4\xEB\xA1Wf?eD\xBF\xE3\xAA_+9\xDE\xE4\xD0PR\x91\xD5\xF8uv\xC56\xF3\xA7\\xF3#\xEE}E\xA4\xDEt\x84m\x98vP.']&\xC9r\xE5\xCB%\xB0\xC0\xE77M\xC7\xEC\xF6O\xD0\xE2/\xDEnl1\x8C\xA1ӓ\x9D\xBA#\xB4\xD7-Ûy\x97\x84y\x99\xCFY\x91\xAF\xC9<܌\xA0\xD2\xF7&)a\xCE\xBC\xC9\xCF\xF0\xABa\xBCEl#\xA7ڰj\x83\x87/\xBD\xFA\xAF\xA1v\xDE`\xBB'Bj\xFCn\xA8\x95\xFC\xB4\x97)u\x95ו4&\xC2..6G1m\xCC\xF5ڌ\xADhd1\x87.\x83'#\xC1\xFB\x9BvL\xBC\xBEn\xF39p+W\xFFx\xD6/a\xEC\xFD\xBC\xCB)\x9BM\xD8\xF4:C+\xDF\xED\xD7н\xD0\xFB/A\x9C;jN\xE4\xE4@\xDF
+KW\x8D\xA8"\xAAˠ-\x92!\xB2\xBD\x9C͇0\x97\xEA\xB8
+_\xA2\xA25\xFC\x8BN\xAB\xA2{\xF9yp2#öTmнN\xB6\xF0
+$\xD7z=\xA3\x99 gEt\x95o<\x9648\xA6\x93\xC8\x9F"Ⲯ\xEC+\xE4\xD6\xC4䬅A\xEA\xBDg\xB5\x9D\xAC\xAE\x86\x94y\xA3\xCEЭ*-\xF7\x81e.\xDAnE^\xF2\x83}\xC5ی\x9A\x80\xC1\xDFi\xC3 \xF7f\xB1\xEBּ\xF8i\xD1\xC6t\xE3:\xB4\\xF3\xB6ATaD\\xDEl\xCF#2u\xCB^\xA7G\xB1\x96\x89oG5\x8F ja\xDB݈M\xA5\x88>do\xB4\x82\x9FӦ\xA2$\xC9\xEAT
+1\x9C|o\xDE\xEA]\xA7\x8D\xC4\xC9\xAF\xF7\xFF\xC0\xF5\xB8\xAE}\x91\x92\xC1\xF9D\x99(\xB5,;36y\xD6V\xADBD\xEDi\xF6kP\x87\xD5j\xAD\xBA\xB8)\xE8\x80J\xE0ҷE\xF0z\xD2\xC1\xBC\xD3\xE7\x8D\xF7Cy\xEF\xB6bp\x86\xB2\xF5<Z\x93\xB431\xACk\xBD^v\xEC\xF2\xD7E\xBC\xCBtܶ\xC8\xF0\x96\xDF2\xB0\xAD\x8B'{\xA90.vܚ\xD2Vf\x8B\xE7\xF9&Vo{·I\x80\xCE8d\x8BI\xB2*\xE1-\xA0\xC4\xA9k\xDAicyo\x95%\xBF\x98`-t\x91\x98\xE5Љa\xE1KӬ\xBD\xC3J\xD7X\xB2̦\xF4w\xC1\xD3+\x9D\x9D\xE4\xF68*JP\x896*y{\x8B\xF9\xB8;\x91\x81#\xDD\xC2\xEB`\x84g\xFC\xC0Q\xBE|p\x96ʎ\x8F7>)\x98hO\x9B
+\x82&\xE21\x8EGb\xF2wQT\x93E>եv\xBA\x93\xC0{\x86fݍշ&~\xF19Z\x93lv0\x81\x84,\xC3 ֥}0\xE4\xA3\xEB\x92s\x90A;H \xA7/\xEE\x8DQ7\xD5\xF5j^\xA6\xE5\xFEA\x95\xBE\x91v#2Y5Ah\xA9g-\xBA>\xDD6\xD1\xDEf\xAC\xF0v\x88/#\xD1\xCD]j8nTj\xF6i\xAB\x84\xEBf~\xE0\xC0\xEBJ7!\x9C;/\xE1\xE3NI\xCDO\\x97\xA9]Յ\xBF\xF1\x93;fY֔\x97\xC7n\xAF˸\xC1w\xCEA\xA9\xA9\xDFF=z*\xB8\xBF\x9F\xE2w\xE1\xB1:\x9B\xE5\xE6\xC8hF\xBA
+\xB7Y\xDBJ\xB4Z\x80\xA7
+69v\x87\xFEڷ\xFD82\xF3!d\xAF\xCEɲ\xD1|\x86\\xA5\x86\x84rpFC\x86\x80\x94\xF4),\xF7\xD7\xEBwÎ\xEBa͐M#\x9F\xE3-\xB0\x88\xD53\x98\xEDהZ\xA3Y\xFF3a\xFFw\x85s\x8A~Q\xA7\xA3;\xA0rN/\xDB\xED\xA9\xCE;`\xBB\xDBl]\xF8+\xAA\xA5gS9\x98\xEFk\xFA\x84\xBE\xED\xE8\xE0\x8AJ0\xD8\x89\x83)vjD') K\xCCbYH\xFAq3\x95\xBA\xFC\x85\xE4y#\x8C\x9C\xB3YU*\xA5*\x83괄\x8B\xF6R\xEEgu\xA2p\xE2\xEF\xFC-2\xE5\xA5mO bFi\x9C\xE3\xF0\xF3ۂ?6\xD3\xDBl\x8C\xF7\xFC\x9E
+S_\xAE\xC7/Fm\xBE7\xC8\xFAl鳵v\xBA\x85\x92\x9E\xACOrS\xCF\xC1\xF9gR\xE1\xDD\xF1\xAF\x8C\xF93֞\xCDÕ\xCDg\xC5L\\xD5~D\xD2iSg\xB3τ;\x8F<\xE1+\xA2\xA4
+G\x94r\x95-\xB8\xC8ۛ.\xB7h\xE7\xBC\xAA\xE4\xDE^,\xAA\xA7\xD2H#q\xDC\xC8d \xB1\x8Bzs\xBB\xE6X\xE9j\xA6\xF5\xEE\xB0\xEF\xEC\xADC\xE74\xF3\x8EX\x99apm٭\x90\xA4T)\x93\xBB \xC0Ao\x88Ay\xC1\xC1\xB8~@\x99a\xECW\xF3\xB3\xCC`aQ_[\xF8xHs\xE0^\xD44\x85?"\x96^\xB8\xDBI\xC7\xD9{\xEDCC7\xD9\xF7\xC8\xEEV\xD4Y7\x8F\xB9\xA3;\xDF\xF3\xB0\x85\xC3;\xBCD\xBF\xAD\xFC\xCB%\xCBCCF,e\xA3\xF7j\x82\xF8Lx\xF6\xDD"\xFDZR\xC7.,\x92\xA5q$\xCÈB`\xF6\xB3\x8Do-\xCBdv\xD8\xC0\x9A\xE6|\x82sw\xB0\xF7Y\xA7R\xD0\xD9~\xAD\x82+R\xA7!_\x9B\xEC\xAA+u\xC7\xE7\xBE\xF0|I\xC5#\xA2\xD0S;/O\xD9\xF0,0\xB6[\xEE\x80s\xE2\xA0nwJ\xC5]p\x9E \xBF\xFF|p\xCBm\xEF߸\xCAO\x86\xD5Oױ\xCC
+\xAC݊ew\x89E]\xD7\xD21)\xA62\xF7\xB2WF-6\x92W&\xAD\\xD4\xF5\xB2\xF1\xE0_972\xF2\x98\xF7\xFE\xE2e\xEC\xEB\xFF\xF5l?\x8Da\xE6~|:t2\xB8 B\x94\xAEAщ\xD2\xF5\xDE2\xE8|\xDEcׇe5\x8Fxr\xB3;\x99\x8F\x98I\xE7Hg1 T\xB98F\xF1R\:\x9DRˎ@^\xCD
+\xA8JO\xB4U$\w\xA1b\xB3(
+tL4\xDFF~\x9A~
++\xF749\x83QfM&\xB0ą\xC4:\xD6\xE7\x8A\xC8%\xD1\xF1\xF3\x92\xA2\xFA\xBD\xAA\xA5U
+/\\xC8p
+\x81\x99'T\x8B[S\xA1\xAE\xC6f\xCE\xD6 \xC6\xD0e\xBF\xA4\xF2\xF4\x9B\xC5\xDD%d5߇7\\xACW2\x91\xCA\x8A\xDDi\xC3=ǭ\xB0;2 !t0\xF7\xBDT\x9D\xED\x8EN\x9Dj\xE4T\xF8]\x9A\x99ԍ\xB7Xp*\xDB\xDC\xD0Q\xE0\x9DD\xAA
+J`LJ\xD9~\xB1\xB6B\x83\xBD\xDF \xA6\xDET\xF7o\xA3<P\xA6\xB6\xCF<\xF6\xBAoc\xE4@\xCC6\xA0\xBDʏ܃\x98eQ\x9D?!hKI\x8Fuel!^\xCF\xCE\xD5#\xB6\xD5 ނ\x8C\xFA\x94\xCB|=\xA4\xD1\xE1\xE7\xE4`\xAB\xA5>\xD3\xB5i7\x80\x88TmE\xA5<JF\xFDp:\xC3 \xED\x95\xDA[\xE3n\xA8\xC53i\x9B\xE1>*9\x82b)}\xA2\xDC\xE5\x87\xDB_\xDF~\xE8\xCF`|\xF7\xBDj\xEE\xC9\xFBD\x97]@\xCF\xF0\xB8
+V\x9A-͛\xEE\xE2\x8D\xEE\xFA=\xAA\xFCG
+mO0X\xDB\xD0j@h8ou\xC02\xF6\xC6|\xA6{\x9B6\xD4CrE\xD8ń\x8Ac bj\xB5\xB7.95=\xC7\xEC\x95\xDB3/\x85\x8E\xEF\xA1\xD8\xE7r5\xBF\xA6q\xF5r\xC5I{\xB6\xD9\xE1\xF9-\x87\xAFZ\xD5\x9A`\x85&L\xED\xDA`\xDD^v\xA7W\xFD \xF9\xC10\x97ARG\xDA`[)\xAEYg\xEDf2ؖ\xDCK\xE1v\x9A\xBFe$^+]\xE2ͮ\xF5u)V\xFC\xA7_\xFE\xB5+`\xF4\xDD\x9B<\xD1ӊwx\xEClb\x92bv\x88\xA5QUZ\xFC\xE8\xF8\xBFËr\xCA\xEF#\xCDJr\xE6K\xEFJ6\x941xZ\xAD\8u\x92Y\xFDI\xF1ס{Oڴ\xC09!\xB7K\x9AVt\x82c\xFB\xFD9\xC0\xF2Ӌ\xB8\x9FfY\xF5"e\xCF!'e\xBE3;\x88d@\xEE\xA1\xC6bP\x89!\xD2
+|\xDE<B\xDBu\xFFӷ\xE2\x98\xE1|@&\xD1\xF3ȻbgcYCN\x80\xA0Ln\xD2h\x8E,\xE9]\xB5\xE1\xF5\xF1Sf&T\x85\x9A\xAF3\xD8<xj\xCD\xD2\xEC|\xCD|"uO4\xF9\xE3\xF0\xE6{\xF7\x9D\xBB|XƑ\x96^BV\x81\xCB@B\xA3\xDA\xCD[\xDE,$\xDF\xFB\xB9;\x91sb\xED{?\xC1\xAEuWR\xC2\xD3پ\xBBlp\xA1]l|\xCBZ9\xF7Y\xC7l\x8F\x96Wkf\xDD@Ke_\x8A$\x88\x8E\x9AP\xEADp\xF9{Y\xEE\xBC\xF0\xAB*<\xF62\xFC+\xE8k\xE3\xD5\xC9ٱ\x9Ab/\x96)\xD7m\xCB "\x84w\xF6
+xӤ=sg\xEB\x95\xF0\xAA5\xC73\xA2\xDD\xEC\xD3^\x9E\x97\xC04'\xF0\xE8d6u\xAF\xEB\xE4\xFD\xC7Q逶\xF9Jm\xF3X\xE7\xCC\xDD@U\xC9ZuR\xAC\xA9\xA2[?8\xAFJ\x98a\xC4\xCB\xF8(\xB4[ӦCq\x85N\xDB\x90O\xF6[5ݨ\xEFR\x91\xB9u\xE1oT7\xF9\xBA+\x8D(\xA0֮\xCBa\x82\xDFTw:-\xE6\xFDq\xD43tN58\xF43\xEC\xD90G\xDB\xF5\xCD3q(\xAB\x905n\xB3\x9F\xA3\xE6i\x82$\xB8\xD7ݪvu\xF1\xBCKȔ<hhuM\xE1k1\xF1=!W\x98M[\xB8\xA1\xCC\xEDH\xB9\xEA9h\xB5\xB3C\xB7\xA66\x9C\xC49\xCḀDɟMě\xA3%\xCFXku\xAE\x82\xB0\xB5\xE2\x80ӗ\xC9mV\xF3Y\xF7Q-\xE4\xC3]N\x82\x8B\x8E\xBA\xE0Q\xDCQ\xE6f{}\xD3\xF38$\\xB3\xBF\xFE=k\xF6ַ\xF6K\x81\xC1"a\xC0&_\x9D\xAFl(
+\xB0\xD2\x9B\xEE\x88A\xF3\xA3\xF7\xEF\xFF\xC2\xD0\xDEW0bk,\xDC \xC9[S+\xE6ܘ|\xD4,\xCE\xE6\xDC\xD3v4\xA2\x9BC\xC8B\xCER\xFFI`a\xDCn\xE8\x92ܽ"9\xB3\xE2\xF4\xB9e,Q\x82\xCB\xE9\xCF\xAA\xEF\xB1\xD9\xCEEh\xC81b\xEC\xB6eu\x9C\xDA\xD1i\xAEь\xDEl\x9D\x89j\xDB\x9A\xACW\x83\xC9\xF3Wm;f˙#gm\xB3\x90P41\xC2nqA\xCE\xD7\xE9^\x8EG \xDE\xCB&\x87\xCF\xC4'+\x90\xC2\xFD\x88S\\xDFf\xE4\xA8ڧ\xBE\x92\x8B맛\xA8\xBE\x83\xB0Q
+9oS!8\xB1]\xAC\xB7\xA2[\xCCBܭ֙Q\\xF4\x99\xBC\xCFc\xB6\xD7|\xC0\xD8L1&n\x92e\xB2\xB91\xAD\xC9;\xE1\xB8\x92{\x8A.\x87\xFDD7ϯr\xB6\xB6UP\xC3)_\xE1+$\xAF:\xE4\xC7n2\x91\xC9\xF8վg\x85\xAA\x89\x94\xBB\x93+,\x8B4砧\xA0\xF7XU\xCA\xF0=+\xF2eK\x991b\x9Av(N&\xE9\xFD\xD8E#Nk*\xC8*.\xDEU[\x9D`\x9E\xAF\xD2^\x8B7\xBF\xB9\xA0\x8E"\x8A\xDEﵸ\xBET\xEA\xE6C\x95\xBA\x80\x98\xA0םx\xA1\x97\xDA-W#\x89?\x9Bg\xD4\xD3Э5\x99ޅ\xF790\xB3(\xD8*|\xE2\xB4ۚ\x84\xA8+Y\xF9BD\xAC۵\xFC\xABR\xEE\xE4\x9B\xFB(\xFC\x99\xEE8\xDED\xD0\xF8\xF3h\xAF,\xF7
+FI\xB6 +\x87\xEB\xD8y5ϭ/a\xF9!+:q\x8B\xCF!ܝ;\x96\xDA\xC2J\x84\xAF\x91.\xC1>\xB10-WST\xC9P\xF00\xB4\xBD\xCC\xC0TPV\xEAF;\xEF+G\xFF\xE4\x8F\xDEw\x8C\xFA\xA5\xCB\xFE\xA4\xC5NEZ"\x96\xA2%\xBA\xDC-.\xBEy\x9E\xBBV\xE6\xFD\x9DS(\xD6\xCEJ\xB7b\xE6\xD85o\x8B;\xD4\xF3\xEA\xCD@=!P\xDF\xFA\xB2y}åw\xAC8yY\xD7.d2\xD8 D+\xEAR\xD6\xFB\xEBA\xE1\xA2l>\xEA2{\xA4\xDD\xC7v\x8A<\xEF\x8F;g;i\xB9\xC2+a\x8B\xAF \xB0Ju\xEC\xF6\x86G"\xF1qڼ=\xC2W\xAA"v\xAD\xBA\xEB\xF5\xB0\xCE+WgUé|S\xDF\xC8\xFFKfiX\xAE\xD0~\xBAfv\xCA\\xE1Յ_*\xB4\xEF\xE5m\xB9"O\xDC\xD3\xF1\xCB\xE6\xDF\xCB\xFD\xAA^\xC2^\xEE\xF6^\xA5\xD1K"d \xC1\xEC[\x91\xA9\xEA|G"\xEA\xE7\xF951\xF2\xA13B\xD3dA\xA5\xEA\xC2V˯\xDEiK\xCC")g94\x8D\xB0_\xF2\x9Cf\xF1c1\xE5\x84y9\xCAs\xB3\xEEm\xE05J7K\x9AM\x96\xAE\xE0Ԭ\xBD\xCD\xC4߬X\x9Ce\x9E6\xACw\xA07V\xB1\xB2Vzì\x8B\xA6\xAEW(:vU\xC8`C\xF8pBx\xEF\xBA\x890I\xDA\xA2\xF4p\xF6
+\xD5NǤ\xE0.\xC5i\xF5\xA8\xE9\x99\xC2\xE9v\x90\x9B8\x99w\x87.\x95"P\x967b\xB7,Q\xAB }\xD71\59\xF1s;aD\xB8*9\xE5\xA6\xEA\xA1\xEE\xDF\xEC\xCF\xF3\xAB)\x8E\xF4\xB6\xA5/\xE4\xE0\xCDPq\xB1\x8A1>\xC2h\xBD\x89\xE7\xA49Q\xF0\xFA\xBD\xA70\xA4pV\xBBSYC\xAC+\xB8^ \xAC\xB5\xED\xE0\xAA>-<\xD7,\xC7\xFDd\x8C\x86\xAB\xA6fx!fVv\xF4*X.h\xB8\xB8Z>t3vb\xFD'\x98\xE3B\x969ܵ\xDB\xCA\xE8\xA2\xD5\xA3\x9F\xE6\xCADOŐ\xDF\xE1AU\x84i\xA0fٰ1\xB5\xC9.\xF7rMb\xD0\xCC\xE7\xF5y\xBB6Q!\x97\xF2&\x99\xB2\xAFw\xA7}x!\xDCQZ1\xA5>/6!5_^\x8E\x90\x99K\xFD\x92\xD1\xCA\xD3?s?\xF8\xC2\xC9X\xE2<'\xE1kb\xB0ڲ\xBB\xE5=\xDF\x8F\xDA\xC51\xAFh2q\xEB\xCC;h3\xFD\xC0)ZiC\x96N\xB2C\xAD\x8Fpup(%\xFA\xBD\xFC_\xF20,C\x81)F\xDB\xDE\xE2\xB9U\xE0Y\xC0\xD6\xE5\xAD\xB1\xFE\x9E=yK4\xB3ĩ\x84l6%\xC66\xD9\xD6_7nޮ+\xAA\xDE緱\x86\x95\x8F"\xEEDž\xBFˊwW\xA9\xA6\x92-\xDD$᥊r\x99]a\xE1\x911U\xBC\xF8sA\xFB\xFD\xEB\xD4\xE5\xB40\xCE\xF0-7 D"C\xB0\xAD\x86i\x9E\x9B\xDAG\xB5\xDF\xEBL.O\x97O\xE3gw\xA1\xDBYB\xB3\xC2m\x8E\x88\xE9\xE4\xDEs
+\xEF\xEFU\x9C+A\x9F(h\xFAZ\xC9\xF6\xF9\xCE\xDE\xF7\xA9\x86)\xA8\xC2̙\x9D#\xD3W\xB6\xA8\xCC\xC6;\xB2\xF4E@\xB7\xF4\x96X\x8D]\xDD\xFAA\xAAa\xC4T\xB6֙@S*\xA4\xAE6\xCF\xE9&\x91ٝAZD\xD1\xFD\x9EM)|o\xB8\xB75\x97W_\x9F(\xB6\xA3\xAD0}k\x93\xFEay\x86\x98 Dw\xA7!\xFB\xEF\xF7\xDF.\xA2\xB5<\xE4z\xC9H[\xA1X\xB3=V\xB8\xF1X\xA6\xF9\x87\x88\xE2\xE5\xBA\xF3\xD7\xDA\xD8a\xEAY+\xB3\xFD\xC1
+D|\x8B\xE6<\xB9u\x86m\xDBO\xA9J\xD2Gpz\xE8M\xEAr\x92\x95o\xF7\xEBR\x98\xF2\x9C\xD0`{9v\xEF\xE1On\xE9\xC7i\x86)\x8B\x831\xDB\xEF1Z\xC0\xC5]|t\xE2]r/{\xF1\xC7:\xEB~\\xD1#$x4h\xBA\xD5= \xEF\xD8\xC9\x84-\x82)\xEDam5d\xB9\xC5V⋨|&\xD0\xFE\xA9hpT
+\xF6\x8Ds\xED\xA4\xCAQ\xEC\xD5i\xB3Y3Bt܊ \xEF)<\xF2\xAB-4F(\x9F[cD\xB4'd\xEB<\x87\x8E\\C\xBB\x98\xEA\xAE\xF1\xC5I\xB86\xA0\xB9\xEAi\xB4ȠV
+k\xD9g\x80\xE8c\x9Bt\xC4\xE8ɭ=\xBB\xED\x8ED\xE6\x9CK\xE1\xB4+\xF1\xADBbF!˧~0\xE1>\xB6I;{\xD7\xF8\xACJA\xCFؙb>\x8Ay\xC9\xE7ǚhF\x92K\xDF$y\xAA\xA0܅f\xA2\xE5ڈ{>\xBA!ǘ\x88k\xD1\xD0ũʘ\x97.\x9AԽr\xF6\xDB\xF6\xB8\xD5\xF3\xDEK\xF3\xF2VЭ\xEB磼X6[\xB1}\xE5Wz\xA9w\x84J״?瘝\xCFO\xE5g\x87\xD1\xE3_\xAFt\xEB\xE8\xDDҋ\xCD\xF3
+\x9CQ$\xB6_q\xC1\/.\xA6\x86\xFA\xF6\x83η6\xE2\xE0mvV{a\xB3\xF13\x8E\xD4M\xA4 1'\x8E\xB5\xCF8\xF8\x97\x8BV\xB8G\xE2.\xEF7x\xE498\xA6(\xDB0\xA3S\xE7\xBA9]\xC4T\x9A\xD3\xFC\xFC91|SԱ\xA2\x8F\xAAt\xE6-3y\xA5\x93\xE2Ɖ\xADM\xB78\x94\x9A4\xC6\xF7\x8E\xF8\x85\xBF\xA0)w\xEAc0\xB2\xBC];4%,\x92U\xC0\xE5\xBC]R\x86\xC6⫉;\x81_J`\x87\xC1\xD6\xBF
+ŕ\xA3\xF0|\xB79\xC8.\xA1\x8B{\xCAy\xE9}\x8E2\xBFKrƨꞨcH\x9F\xD5bh\xE7\xFE3\xCEe\xE3^\x9E:\x80\xC7}!/\xE2J\xF9\xD5\xF8刚Ȧ\x86p1V\xDA\xD9eR\xC0\xC8\xE7\xEE\x9C\x8A\x9E\xBA\xDB\xEAMG&˞5d\x9E\xE6\xAC!\xEC\xD7x\xAD\xA8\x8E\xE4ee2\xA6}\x8EI\xF9\x81\x84Qr\x89\x9C]s\xA6\xE6n\xB5\xB9\xDC.m,]\xE9\xC1\xB4\xAD\xB16\x93G*m\xF4\x8E\x83\xA1\xE2\x97d\x91邬gIZ\x89\xBFMr\xA6\xC2\xD4\xDFki~I\x8D\xA7C\xA9qf.
+'\x9F\xBBUD\xCF\x81\xF6\xEEM7\xAC2\x9D\xAF\xFB\xDE6\xEC1\x86\xD2\xF4\xEA\+\xCArmeM\x8BD\x82\xBB\xA2z*c\xFArO\xC9#tG
+\xEDZ\xA6\xBD\x90*\xEB`+\xADj\xFC\xB6:\xA0$\x97OVֽՐL\xD6\xD6Ͳ=(nQ\xE7FN9)\x9BM\xB4e \xE9\x8A\xEA\xFAo\xD8\xF3W\xFFH\xF7qc5\x9C\xFA\xB5\xF7\xE9\\x82\xB1\x8D&1\xF1(bfP)VB\xFD\xBF\xF9/p~\xAD\xEBj\xCC\xBAs\xA4\x9A\xBA\xACk'\\xA5bK\x8C\xDD\xC8\xF6s\xF6C\xED\xCDd1\xFD\xA2\xA3\x9C\xB3/;\xAE\x85U\x8D\b՜\x84#16\x9F\xEE\xD8x\xF1W\xA3 0\xA5\xDB\xD2\xC8\xE1\xC2IΉ\xDAb\x8A0[P\xF4\xC9g:\:\xF3\xBEM\xED\xF1ĭ\x98-ҝv^f`h]I\xDD&\x8Ecp\xF8v\xA5\xDE7E\xA3\xA9\xA1e\\xAE\xD2n1\x80\xD7š\xF3\xA0- \xD6f-=\x95T\xFB\x80O\xA4\xBA
+\xB8\x91-\xA45\x91K%\xB0A\xC5+z\xAC+\xF85\xF9\xC6`O%#\xAF7\xB8U\xC5T\\x99\xBB\xAAlXI8\xE0boA\xFF\x88?\xEDc\x92\xC9\xD3\xF0uy\xE4\x88v\xDCC\xF3*,\xCA\xF3\xADa\x92\xE9\xBD\xFB\xFFPK\xD2wWo\xC9%+\x87\x96\x91\xAC\xB4\xDEؖf\xE6T\xFE\xF3}\xAC*\xEB\xD2uA!s\xACX\xB7\xCAвc\x97LӬ\xB6\xEEG\xB3\x8B\xFBt\xA7b}\xE4\xD4U\xDF\x94a}U\x9B\xE5\xC9P\xD7X\x9B/\xDC!\x9D%\x89\x95^\x840u\xB5&ϳ\xB2~\xBA\xC9PF\x9B\xB1c\x82}錾\xD2$-
+C\xF9\xFEz]U\xCF7)\xDD\xFBZ?/.\xA8\x93\xAC\xEFG\xBAm\xD9\xDC\x97\xCE\xE2&I\xBF!O\xF7\x95\x83
+CW\x82t\x81\x81$G#\x8E\xF7\xF6\xDB3\xF2o^܀\x89պ)x\xDB\xFE\x9F\xF7\xED~\xFC\xE7\xFD\x9B\xE4Y\xF2O^f\xB9[֡\xFB\xFBv\x80\xB72\xF9m\x8F\xEA\xF9\xBA\x8D\xA3\xF5\xC2\xD0\xFC\x80y\x89\x9A\xB8ç\xC7\xCB-\xFFv\xBA\xFBi\xE4ۧ\xA7\xE7\xDA/\x81\xEB\x86+\xAE͎\x97D\x87\x8CNg\xD8p\x80NJ\xFD\xB4X\xD0\xD9m\x9B\xFE\xF9\xC3.Pf \xDE\xDAg\x9D\xCAY\xB5y\xD4\xE4\x91\xBD"\xCF\xD6\xEDCV\xEF2M\xDE\xFF\xF5&\xD2߶M\x92?\xDDo\xED\x87\xF9\xFAr6wAN\x86\x84\xD5i[\xEB\xDC\xA1\xEC\x87\xE7/\xDCw\xD8L\xEC&n\xFA\xFCT\x84\x8A+\xA7X\x94C\xBCc3\xB1\xE1C.,t(\x8C\xED\xC4ymҮ\xEA\xD2rj\xB6̚\\xABp\xCA\xAC\xBA\xB3ֺ\xA8\xC1A\xB2\xC1OrʔF\xDC/9g\x84f侐\xEAZ\x97 \xE5/tꊭ\xE4\xD4(\x94\xF8`\xC7\xDB+\xEE\xC2\xDD\xD6\xF6*\x8B%#+\xA5՜媳,\xAE\xC0\xBB\xE9߄\xB1+d\x93\xAFp\[T\xBF\xB4\xAEޮ.z{\x9Dx\xDF`.\xA2\xE3\xC4Ӧ5\xC8\xDFᄍ\xE6\xC1\xAA\xA2\xA7\xEB\xEA "9\x9D4\xAC+\xFC,ȋ\x95O=͐\x8A\xF1 t\x93\xF1r\xBD\xE4YV\xB2n\xC9\xEB\xBC\xCDe{\xE8\xF2]\x87\x85\xB0zn"\x80\xB0I:Za\xC8\xC0\xE0\xD8v,_\xB1|\xC1F\xE6z\xBA\xF2o\xA0Uuӛә8\xC6\xCET,\xC8[\x8B&_\xE3\xACqޝ\xC4\xE88v\xEB\xE39즏\xC1\&+\xA1\xB4@\xE7N3\x88\xF7\xF1\xAAw:k\x9D\xAEwR:\xCBs)Yl/b睠\xE8u\xB5&\xA2\xC7\xF7\xBBq\xAA\\xBBwx\x8B\x81\xE7l \x9EKĵK懺\xC4κ1\\xD0 $\xF4>Y\xDF@\xC7\xE1\x94\xEF\xEAۣFd\x87Ѳ\xF7ױ\x86\xB6\xA4\xD1u\xD6N;\xCC\xF9\xAAmxl<\xE1@\xB8\x87\xF3\xF9"\x94\xE1v\xD8\xD8P\x8CZ
+\xEE\xC67^\x8F{\xDF\xE9e>\xC2\xCES\x83蠍\xA9mJ\xE7eA\xD0<\xCB\xD3\xC7\xDB^\xAF!\x89o[\xAB\xB5\x840z\xFC\x93V\xEAL<\xD0\xBA\xA6G=\xF0b\xC6"\xFB\xA4u\x88\x96u\x81J\xDB\xE8\x87\xFAh\x92rˉ\xEEa\xDA]A~\x87_\xE3.A\x86L\x94\xB67\xC5\xE7<U\xF9\x9Av'\xC0\xD0/!5y7\xD4R~ګoRS\xE7M\xBD\x9Fa\xBF\x96\xA2'\xF9\xBC]\x97kq\xA8\xA7\xD7[\xF7\xE0\xCC \xDA1\xF3\xF5\xC9ux\x91\xA5C\x96\xFA\x85\x87\x8Fe\xB8\xE1y\x8B\xA4\xD0~\xC2R?y\xEB\xB70\xF6\xFE\xDE՜\xCDn\xB3v\x97\x9C#\xA9\x97
+\xD5\xC4\x8B\x96&\xF9\xD4ٝ\xB0ٟ\x98\xA7&b\x9BD,\\xDF\x9Frex963$\x85\xA7c"\x82\xDB1\x8B\xF9\xD5n\xF1\xD7!-q\xF36\xC5܍\x9E\xDE\xE9\xEC$\xB7\xA6Qeؤ\xF5\xBAjI\xA7\xF2\xFB\xF5+焕w\x82b\xA3\xE3u\xC7\xF3\xBDw\x89'\xAE\xFD\xA6ݷS\xC1\xFD\xEF\xA0\xFDp[Gd?\x85\xEC\xFEz\xC8S \xAA\x80\xBF\xEAv\xD6c'\x8A\xAF\xCEa\xD3?\xB0ܷ\xF7\x9F\xBA7\xCF\x97\xA80\xBD\xAA\xB7\xA7\xAB\x8F\xE1j\xFC}YTN{\x81\xBA\x97(\xFE':\xF9~\xCC\xE7\xF81\x94\xA3\xAB\xBA,\x88y\x91Y\x8C\x98\xF4t\xFEw\x9C\x9E]\xDE\xEE.\xF0\x9C'2\x9A\xD81ё\xE7\xF4`\x8BX5h\xA7b\x93\x94\xEBg\\xE7=8\x9B\xC4v\xCBI=GKQ\x83h\xBC\x9EwGh]\x80\x8E ;\xE5I\xE4A\xE6\xFC3\xB0\x82\xAE \x81\xDF'\xAB\xF6\xB0`W\xFB\xE0jaE\xB8~Ѵ\xBE\xDD<Մ\xF1˿P\x8A5M\xB4:Tw\x93\xEA\xC8\xBA\xA1@\\xF8+Hx\xF7\xCA\xE0;\xD3\xFCp\xD1O7\x93#\xD0ִ
+\x92\xEE\x92G\xBC\x93Cnzaar6\x97\xAF\xFE,\xB2\x9A\xD0\xC9\WK\\x90,\xD2\xF5|\xE9\x9D^+\xBD/'%\xDFÇG^rb\xB70\xEA\xFD\xAC/͜\x95\xB74\x89S,\xC04K\x830\xF3\x92b\xFEje\x9E\xBA`\xD7 \xE5\\xE4\xD16\xA3A\xF0{\xEB\x84O\\xDE]\xC4P\xE6\xE9ru\xCA\xBD\xDDr5$.:\xA6{l}!ۂ\xF5;\xF3C\xDBY\xB7g\xA2\xFD\xEC*\xE4\xFA\xECt\xFBt\xE4L\xF2\xF69rS\xBAv\xB3\x87w\xBE\xE7a\x9F\xDFp\xAA&\x84(\xA1\xAE\xE7\xE4K\xEB\xF5\x85"\xBDa\xEF\xA8\xC5WL\xC7Ho\xB8u./\xEC&\xA1\x97\x82V\xDB.9\x9D\xC3ǽ\xFAfB\x83z\xD0%\xFCi\x97\xFC\xDBť\xB6U>\xB1K\x9Dd\xB9T#,\xA1Z*i\x88Z`v\xEB<\xE1C)\x85v\x83U\x90=?\xD0i\xE8\x8FMӟc\xDF\xEAD\xD68.*T\xAC\xDB {\xFE~ \xFE\xED\xAE>
+%.I\xC3\xE7\xD0Q\xCCXB\x98W\xE8fY6|\xBD?\xDC\xF0\xB5\x9B<\x8Fo\xA8o]/$7Y\xB9k&vPC\x91\xA9Eŏ\xC2\xF5\xB6̓\xF5\xFF\xE7j\x95\xBF\x83xrl\xC02\xF0ahG\x8D9x\x89x\xB2.W\xA5x\xF8\xC4?\xBE\x9Bօ\xB5̪\x80-=\xAA+\xD7=\xAD\xC0]n\xA2->\xE4\x9B\x99\xAB,yZ7D\x96\xA55h\xF5\xED\x85\\xFF9\xD1TX~\x83\x89\xF4\xA6[u[.pӺh\xB2\xB5z\xFD+\x97\xF7!\xB2ØO+c\xA2y0\x83hܰ͆=\x8C\xFBwT\xC5{\x85ԟ\xE7i\xAA\xE01\xB0\xB9\xA5\xB5Z\x83\xC3M\xEA\x986\x83\xF6\x8C\xF9\xD23\xFD̡\x921\xDFx\x84\xC0\x96\x85\xE1dOs\xDA¨H\xC0쯤c\x9F\xC3iJ\xA0\xF2((\xC1\x96h5\x91` \xC3\x93\xD5\xDC#\xBD\xCB\xF4dʃ0\x9CڲT\xCF\xDET7\xDB%`d\xEDp\xA9u\x8B\xCEҗ\xD8L\xF9\xE6\xBAɱk%\xD571\xA3㬺I\xC1vj\x97\xFB$A\xD0u;\x85\x81,\xD0U\xBE\xE4\xBFr]\x84L\xCFS_ v\x80\x88\xF5%\x93OH\xB1c\xB7Rq\xCA\xFC\xE3zt\xCE3Fʝ\x9B\xB9^\xB33HGɔn\xBD\xC7R\xA8\xC5\xBB\xC0\xB7\xC4\xF8\xA6\xF9\xF1\xE5\xE57H1\xF9\xDD\x8AL\xD6\xA30>\xF5ڦ\xC48; \xE5\xB5\xEFofr\xB4\xFFOxQ\xCD\xF9}\x84\xE87\xAB\xF2HfX\x95\x9C\x82ť\xD8\xECܚN\x80\x9D\xD8\xE6\x99\xE2oB7\xBE\xBCh\xD3\xD0D
+\xD8.\xCB\xD6jQv\xF1\xFAz&w\xAA\xDE\xEC;^\xBAKԛ\x94\xBD\x86\x9C\x90^\xAB\x9D\xEE\xB4K{sl\xACC+w\xA6L\xC2E8\x97\x92|\xC2\xD2on\x9F\xBE\xC7<\x87\xE1AALiBnG\xA3\xC4s\x90\xE3zN\xF7sq\xF9[\xB5\xE1/\xF5\xF1sf\x86Cw\xFE`\xE7\xAA;\xF0\x87|\xDDPۤ\xA94zi\xE0͋$\x8Ax\x87\x81q8\xBA\x97\xFB\xCD\xDD\xFF\xF8s?\x83\xCA49\x8B\xD0Q\xD8I2d\xA3\xB3\xE7<S\xC3Y\xE9%\x9E\xBA\x9ES\xCD\xF7p\xBDy3\xDC-/\xCC\xCC\xFB\xDC^\x98\x94\xFF\xE5"
+k\xB2\xBC\xAAs9\xF9Ҋ\x98tR\xD0\xA3\xAF\xAA\x8CV-(+\xA7\xF4\x9B\xBD\xE1\x8CI\x84\xD6,\xB3\xC6\xDA&ՠڶ\x95aKȣ_\xB5Q?#No\xFC\xDEM
+f\xDF_\xEE\xA5
+\xF4\xD0".\xF0U\xE6\6[\xD9h\x85x\xA9D\x98\xFCG \xDC\xCB&\x9F\xE7+\x92\xB5|bךcva*\xA1\x8DZ\xB0ˣ-Ϋ\xD83\xF0\xFD\x84MjH\xEFS\xF6\xACt\xA3Un04\xAE\xB0r\xEEW\x935_\x86\xFA\xEF\xF9\x80\xA9\x9DZ.\xF5\xFB\xDC\xF0\xF3§bo\xECaC\x8E\xAD\x9B\xF4\x85\xC6\xC4N\x93\xE1\xEB/r\xB6\xB1UP\xCF]io\xAB|!ɜ(\\xFAa\xC9\xF1\xA9 -\xA5̰\xBB͟sK^\xC4\xF1\x92\xF4z\x90\xB85h\xAF\x803\xE5$\xA6cf_)\xCC\xF9\x98Ȟ\xD6\xEB\xF5m\xEF\xC2c\xB6a^\xD4բw\xBD\xE2Q\x9E\xB0\x9F \x8D\xAAiM\xF8\xCB9\xCC\xD7]\xE9\xF5!+[a\x8B"%\xE2\xAF|}\xECs\xD9\xC7\xC8\xC9\xC8\xEB7\xDA\xF2.\xC8/\x97g\xE0z\xA5L=\xAE\xE1r\x91\xB0\x8B5\xDA@pk\xEC\xDFeQ\xD4\xEF\x9F&\xCC\xA4\xC1\xA9-s\xC6¡O.\xB5\x95\xBD\xD0<\xE6B\xC3\\xE1\xE9\x87\xEC\xF8}\xCD\xD9|\xB5\xBB\x837
+\x9B\x99X\xC4\xB59\xEFy\xAA!L\xA7\x92\x8A\xFD\xEF\xF9\xF7\x99\xE6\x90\xCBA\xD2\xCAU\xB1\x8A2\x90j1\x9Ed\x93H\x85 3龟\x85ks\x82̲U[\x9F\xC1@$\xC5DW\xD4\xE8pIe\x82(\xB9\x9Dq,\xB7@h\xB6\x9A\xE6\xB8Lk\xDA\\x99蔗\x82@X`\x96
+\x80Si\xAC\x97[\\xD1焋r\xBAME_\x8C\xC1\xBEb\xDCx\xDETa/P\x9A\xCD\xEF\xF7\x80#\x9F\xF75\x92ǥ\xBBm2V\xE8\xD0\xE9bYK\xA1h\xFF,{#[\xF7\xCCJ=S+\xB0Ii{\xCD\xBEů\xBCK<\x84\xF2̇\x98\xAF8ßZqɺg\xB4\xA1\xA5㪬\x8A,\x85\xDD\xB7m\xBE\x88\x8Eu\xD0s\xC9\xF6\x9F\xCA\xF0k\x8B\xCEs\xBE \x92\x8E\x95\xBAغu\x96\xD2|\x91[m\xBA\xA8ʑ\xCF\xCA\xDD˾МM.\xB7\xD8\xC5V\x8C)\xD8uH8jg\xB9\x8C\xC0\xE6K\xD4\xE7Ou\xFB\xA8ؓ-:9\xE0Vj\x9Dmk\xE9\x80Kڸ\xBA\xA3\xD5/\xE6"\xB0\xED\xF4\xDFi\xF7GG\xF8\x9CpeP\xC7\xD1Q\xEDP\xAFQ\xE1\xAC\xCFwv\xC6-\x84\xBAg_2"<\xE2\i6-\xE2\xB2o\xF9_0W\xB9\xC02Bm\xDF\xED^\xCA+?3U\xCFKx\xE0BZ\x8F\xB5\xC6\xE9e\xAC_\xCF\xC3\xC9\xE7N{t\x89j\xFF\xAE\x86\xBDz\xCEk\xDA\xF5
+ʇ\x8D\xB7t\x8AL\x97YR:\x8CI\xCA\xCDT\xE7\xD9D8\xB9Μf\xD2a-\xA2\x85Ɩ\x91\xF3\xE0\xACTRDt\xB3\xC9>W\xA6`\xE3u\\x9FUp1\xA9\xA2u\x86\xB1K\xBA\xAE\xD6ʱ^X1YSU\xE6\xAF\xD5\xC0<\x9F\x80P\x88ⷪc\xE4\x94r.A\xDF\xD8)E\xD3m\x90,\x89j\xEA\xAE6\xE1DqON#;l!A~\xADJ\xF1p\x95J?V/5\xDD~
+\xF1y\xDFD4d\xA3\xE6\x87^O\x8C\xEE2\xA1\x8B\xF8Z\xB7\xC8\xD7d\xFB^\xD95)\xD8W\xF7\xE4\x8A\xDDm\x923\xB8_x\xC01\xDDK\xF0B\xE8\xEATM\xD7Mn\xBF\xE2\xD0~B\x825\x9D\xC7\xE6\xB5\xF2\xB3#\xE5
+F\x9FW\xF6\xC5ڂ\xFB~\x98`\xA6~1.\x92\xE7\xC5\xF7\xEF\xFA\xA3R\xF3a7\xDFfv|\xEC'\xFA\xCF\xFF\xFC\xF5\xE4eP/\x92\x8E\xFBq\x8BBG|\xD4OБe\xA9\xA6\x9A\x93\x82\xADEg\xF4\xF3hڮּBy\xB1\xE0\x9D\xB2\xF6B\xB7\xEA\xE5\\xE8\xF3\xC1/X\xA9\xDF\xDC;%'N\xA6N\xB6\xBD~l֠\xC2\xFB\xB1\xEC\xAAL\xDD&\x8C/\xB3\xF8o\x90u2D\xAC\xB5(\xCD,\xD9(\xA2\xCA(\xAB\xD5\xEFR\xD3\xED
+\xF95\xFAu\xF4\xC3sr\xA3Xcà\x9EM\x9E)_<\xEA8\xC9\xF6\x81\xF3\x88\xFE\x81U^c\xD4!/\xA89\xDC)υ\x91pa\xA8<\xE0d\xCA\xD2_\xAD\x9F\xC0\xA3J՟\xEB\xCE\xDCjĜv[\s`\xA7\xED\xFBL\\xBF\x94\x8C\xF8q]?\xB3\xF6\x93\x8Aw\x8A\xAD>\xF8\xC7|e@\x8D\x86M: \xF8\xE0 \xF0\x92\x89|\xF3\x8F?\xAA\xD4\xE6K\x9B\xB7\xE6+\x88\xAF\xA5\x81\x98%\xF4\xEA\xACvɞ?E:35\xCE\xE2c\x9D\xCB䲡\xBF\x8F\x82\xCBC@++$:L\xEE\xFB~\xBE0\x97\xE31\xE0\xE9Eޱ\x81\xC6\xDD:YʁχC\x92\xAAbm\xF3\xF8!\xDAS\xD7\xFF\xD5\xF1\xCB\xF6xb\xEA9\xE6\x9D7\x87\x85\xB49:\xF4\xAEA#\xF9L\xCE\xE9\xC16\xCDP\xF8\xC5
+֔\xEC\x95\xE5\xE2z\xD8\xDC\\xEF^\x9C\x95XS\x8A\xDF]\xECkz\xC6]w{\xAD\xDC`G)Y6\xBA&
+\xAB\xBA[|\xE1j\x9F\xA6EɊ\xCEL\xF1\x819L#\xFC1?\x8E\xC7հ\x81
+z]薳\xD4\xCE\xEE\xEF\xF7\xAC\xF8y'Sc/\xC4\xFE\xB2\x96\xAC\x8E9\x90\x90\xB4\xDE6\xD0\xE24H\xE6T\xFD\xF2\xAC?\xFAب0\xE9\x976\xB8.\x98kd\xAE\xD5l7\x8D+ٞ'6\xB6\x9E5V\xB6\xA2}\xBA\x9Ejt\xFD\x99ļ\xE7\xC4'\xD5O'\xAC.ӸK\xCE,\xC0\xB6\xD8\xAC#\xC4D\xDD|f\xDD\xEF\xFD\xDE[M\xE5\xD3;\x9DBq\\x9A\xA6\xB2b\xF7*\xCE`\xC0 :\x9Cd\xC3'rgJ\xE1\x89\xC4\xC7ko\xAD\xE7k\xEA\xE6\xE6ij\xFAa\x91(\xF9δ\xF5\xAAm\xC9UP\xE2\xF9T\xD1ݫ6\xFByȄ\x9F֨\x98ޢ\xBFT\x84\xBE\xEA\xBB$A8\xF0TL\x95
+\xCE]ҽܯ\xBE\x89A\xF8\xC0\xEB\xCFUQ+PN\x95\xF68\x9D\x9C\xE4\xBD.vJ\xF6C\x82\x97\xE5+\x89e^\xB3\xF8\xB1x5\xA3\xEE\xBE'b\x80^9\xBB+\xD3\xD5\xE1\xE1(\x9F\xCDWR\xFC#\xFF\xF7ܸ\x9E*A8\xC6\xC3\xC5@ؒ鯃0\xA0\x81\xB31,\xF9\xDF\xED\x96<\xCC\xF9\x9B9qTY\xB0\x85\x9Ev(l\xEE\x8B\xCBX\xB5\xD2^\x95%e.\xCD\xF8{\x9D\xF9\xFD\x9Fs3cݵ\xE5#\x91\xC6\xE9:\xB5w0\xC4\xC5O\xCER\xFCRB\xEDC\\xDF\xDCS\xC2O\x8E\xA3"\xFDy0\x93\x83\x91\xA40\xB8_\xA4:\xBDR\xBAs \xF5\xEEk\x9D\x80\x93:8$%+\xCC0.wv\xF0\xF6\xF3\xEF\xDB\xCF'\x93h\x86 \xBC\xCB\xDE<X\x93\xEDzHE\xBB*n\xFD\xBB\xEA\x8Bҽ<\xEF`\xCD\xD7@\x8F\x86\x94%r\x92\x9E\x81\xB7\xA86\x99J\xF0KC=\xEC\xD2{m\xEC\xF3\xE8\xC5
+\xB3E\xCC\xEEyC\xA7\x8E\x9Fd\xD7D'\xD5\xD7s3|\xBE\xCFVbGV\x8A\xA8\xD5\xC9ҭ\xBD0U\x9C\xA4F\xC68\x84\xE6\xBF\xF2veVh:\xEFt\x91\xE2M\xEDԣ\x84U\xA3ě\x98\x8D[\xCB#\xFEZ!\xCA\xFB\x9D̡'\x8B\xD4/\xC4\xC1JN\xEApD<\xDC\xE9S*\xCFk}\xDD~\x8D\x8F\xFFu\xABɈ\x8E\xE5\xBB4\xE9-J>u\xA0P\x95\xC3FEb\xFC\x93\xBC\xCC{Q\xD2\xFCT\x9A\x98\xC9<\xD8^պ\xDD\xD3Dž\x8D\x93\x81\x99ѤB\xFB\xF2W\x9A\x87f\xEAn\xCB'S>\x89F_\xAF\x8E*\xA9|M\xEDx`\x9D\xDAC\xC1\x9Dl\xA1\x9EJN\xEF\xF3\xA8 \x99\xDCH߸b\x83\xA0-\x83\x99\xA8Z1\x82\xF5,\x88\x84\xFC:z)\xC3\xFF?
+\x9AN}>\xA6;v\xEA\xD8\xF3+\xB8% ;ZB\xDB\xD2p,+\xFF\xC283C-f\xAAxv\x85\x8C\x85z\x8CK_nC%\xF2\xD9\xCCtEV/Y\xD6?\xAD\x9D>A\xEA\xD4\x87\xF5Xv\\xF8a\xA9\xC1X\x806N\xB3\x87
+\xF6%\xE3\xF4[\xB5\xE3\xE4{\x982\x99_\xF1 2Mb\xA1
+\xC6o\xF1\x81[\x87Iʿ\x94Qz\x9A\x9F:FK\xA8\xB6/\xCAQ\xF7\x87t\xCF\xFB\xE5X\xB3kL8~%\xF38ك\xFA\x98<Tj\x83\xB0\x8C\xE5\xF9J,\\xB5\xD2\xF8\xE6L\xA9\xB0\x90\x9C\xA5\xF9=\xB9\xF4]\xF7gB\xDC+b\x8F 'l
+,̋j5\xD9 \xF2\xC13\xA1\xAF#\xADo\xEF\xD4\xE7\xE4\x9C\xE7\xE0`\xF1\xE6\xDA\xDA#\xB9\xC2\xE2'Y\x8E\xE0\x81M\x8E\x92s\xCA\xF3ֲ\x93:w\xAD\xA9\xC3۽=F\x88\xDEw\xDE\xFE\xEA\xA6w\xDC|\x92\x84;荴t\xB5+\xCB@\x8EE\xD5P\\xB78\xF3\x95\xA2\xDE_\\x83_QۄC\xF7\xC7hLc\xCA2Wj\xE16іݜ\xE2\xAFܾ
+Z\xE1}\x88\xC7\xFCv\xE6 d|\xEAA5^\x98\xC1ߑ\xBB\x83@\xF8\x9BlvYi\xBF4h\xE5O5\x9E*\xFA\xA8\xD1rY\xB5\xEB\xDAR+\xF5\x80\x86\xC4\xE3\x98G՚\x89ފS\x9F{\xB5S\x98^{\x88\x90Jw\xD9A0Y}kv\xC885\x92t\xC2\xCD|\x83\xE7\xDC\xF3\x99\xECi\xD6ܥ\xC6\xE0U%\xF1ذ+#n\xB9kӹZ\x8C?I\xA1\xE9Y\x92\$"[\x95`\xA0v\x94\5\xD2\x89գE\x92\xED\xA7x\x9A \x85\x99\x9D\xDE\xE7\x8E\xEC\xC1F\xE8\xFD\xE4z+\xACp%cF\xC5\xC7<\xFF\xA5G~\x8C?ySõ[O`l\xCDcB\x80_Vy]\x8C\xDF\xD0Z%\xD55_\xFE\xD0J\xB2(\xF2\xF5\xDED\x81&r\xC4\xE1`0\xB5@H\xA6"3\xD3:=ʢ\x80D\xC8N\x8E\xC7\xEB8q]Fk\x9E\xE9z\xCDZ\x9B\xFE\xFC\x96O\x9F\xA5Ɨ"}.\x94}ᔁ\x8Bzp\x8D\xA1\xFBE3\xC7\xFEh{^\x9E@\J\xEAhm\xC6]I\xA6Â\xAD\x90\xF6t\xAFW\x8B\xBDE\x89Τ\xEDS\xAC.r\xACp9G]\xDEK;\xBB\x8A˄M\xBF\xDCkHfk\xEB\x88(*λ
+\xBE㔎ٰc\x99\xEA{6\xFB\xF2,\xF7'͓nC\x9DX\xB4\xCF䇣R\xF2\xF2̖\xC6\xF6d?;&v\xC2W\xBD;|\xE6\x9F\xD6\xCFS\xCC\xED\x8B7a\xB6\xB2\x90\x97\x9EKP1\x91\xBD/\x92\xAFqt\xBF\xD4\xDE\xCCe\x9D~%\xECs\xCD\xD9\xE26\x91\xB1~l\xD3\xD5\xEC\xEA\xFCe\xF0\xFA\xE6\xAF&\x81\xC5Л\xB5\xAC\xEF*B9\xFA\xDDj\xB9 ^2\x93QIh\xBE\xD1\xE1\xCFV\xC7\xE7\xE5=F\xB8ˣ\x9C
+<=\x90\xA1\x9C\x9E\\xAD6\xFEq|\xC9n\xFD\x8Eg\xD2^\x86\xDEJ\x87\xF7@\x94w\xDE\xDE\xF4\xD3:JmM_\xBE\x92\x86\xBAg\x8F&\x93P\xBE\xACSx\x9CW\x97\xAD\x9ED\xA9
+
+\xA2\xA7(\xD2\xF6jL\xFD\xCD\xAF\x94\xBF^\xFF0\xC2\xF2er\x94^_kRQ\xC7B\xEB\xBDܫ\xB6~F\xA5="VRt\xBBG\xB5\xC4ly\xC6Bw\xDA\xC45tI\xC01\xCE\xC0\xDCx]v\xFAK\xBC\xE6\xDBè\xF4{\xEE\xAE^\x84E\x98\xB7\xB0\xA1\xD4U}\x84vM\xAF2D\xFE\xC4B\xDE]\xFB}=5\xEBf 꺡H\xA4\xB4\xA2T\xFC\x93ߠ\xC7\x80\xE3B\xB4\xB8\xF0\xEB\xA3\xB8\xFB\xDBL\x85Š\xCEn\xB5^\x81\xF5u\xC9b\x8D\xCBep\xAC\xFE]\xCDՏ\x8E\xE6?\xBEe\x94Xk\xF7Ǧ\x99\xC2dh[\xEFrr\xAA
+\xE4-\xF7\x83*\x9FK\xC3\xE5\xC1\xF1\xA4Ҏ .4\x9E\xD7T\xA5\xAE\xCD^hF\xCB\xFC\xAC[\xFA\xFC\xCC\x80k\x9D>\xDF,b\xD1\xE0\x8A
+]Г6"\xCD\xD5)\x84\xB7\xFAPK\xB7\x84_5($+ vp\xCCQ\xCD\xF0\xD0\xCC<l{pd
+\x8ED@\xE9c\xFCp\xE8u+7\xA3\xE7\xF2R\xE4l\xC6Y1\x87\"\xBFn\xBDc?X\x9C\xF4\xFF!r+ \xE3PD\x82OZ[<7?e\xF9\xDCx_)eM$R\xC0ST\xA8\xC4\xCFQA\x85rB\xC0y
+\x85\xD3&g9td5\xE4?>\x93\xEB@Fr\xB2\xB1o"x\xBE\xF7ٷ\xCB\xD3\xD8Ac\x8Eu\xB3PM\xD0\xC1G\\x8A\xA9\xAA\xA2\xA3\xE6\xC8\xF3\xA2m7O\xA9\xC3\xCA\xE3;6\xBA"\xEE=2HII\x84\xB9G{\xB8e3\x9C\x9F\xE4
+e\xAF\xA2P\xF6Ҥ\xBDybk0*Ɣ\xC3TA|7\xFC͂Unz\xDBa\xF4}\xD6\xC5Ϣ\x91\xF1\xF9C\xB9]\xFE8\xF6\xB3\xBB\xC3\xDEU\xB6I\xECg\xBF\xB5\xEFLo\xC5\xDC\xEE}\xAC%\xA7\xAF
++
+Ç\xDC\xE2^*<质6s_\xDF\xF38no\x85\x89\xE5CO&1\xD13&\xF5O\x94\x93\x85\xFB\x93D\xEB\xEEy\x8C\xAA|kLvJys/\xF3\xAEM\x84r\xEAؙ$\xF1S^\xD6M/\x91\xEA\xF9A]aqVO\xB6\xE4\xF0\xB3Z\xC6\xD2\xEB\x91\xE7\x85mW\x92\x89i\x9C\xC7|\x8B?%\xF6\xE4\xCCb`F\xD5\xCD\xD8\xEFU}x\xC9w\xD1\x81\xFF\xC4$\xE1\x82+c\xCC04\xF7\xEC\x96\xE9P\xD5Ɂ\xD4:6\xA5\x9F#\xBC\xBER7\xA7g\xAEgBlzЩ\x99\xD8/\xF4R\xF0\xA38.\xDAא\xCD\xE6K\x86\xD29\xE7\xBBD\x95(\xC1d!/;\xC8%\xAC\xA85"\xD2\xE7e\x93p\xC1\x8C\x90#ޒ\x92]2\x9A\xF2rq\x81g\xCA\xDC$\xC5\xC7C\xED\xCDz\xB2T\xF6M\xEB\xB0\xEDL\xDD*/\xE9\xED\xAE\xF7\xE2\xCB)\xB4\x91ϓTU\xE7\xEFA(6\xEB>9\xBA\xFB\x9C\xB0S\xEB/\x88\x916Iy\xCC\xB3\x8D\xD3\xE2\xC8R^qO\x94'\xA0OBK\xB6\xC7W\xB9\xF3\x8Ce\xC5\xD0\xF6\xA8\xA4\xFA\xFC\x96\x92\xF4\xB1<\x81\xCF#5\xFErDyy\xF3\x9D\x802om)\x80ʸħ\xAFK\xF8\x84\xCF
+\xE0\x98\xCF-V5\xBA\xEEw\xAA\xF9\xD3\xCF\xF8\xF4\xAF\x8Ci:~\xA8j`V\xB1\x8Chu@]Ee%\xC7\xC8\\xB3\x99\x81!\x9Ak\xC1\xC1\xA4\x8Ai&C\xC2cМ\xA0y\xF9\xC2<\x80\x80\xC7z.o\xCC\xC2+bN P0x\x82/\x9E\xE0NF\xF9\xBA\xEDBI\x83f(\xA1L\x8D\x96S.V^^\xE2J\x86\x84C\xE0q>D?_\x81\xB2b\xFDo\x95\xFC-"\xE5\x87=\x98\xDBHu.|\xBD?\xD81<3Ss\xF8\x8B\xBCY\xE7}X\xDC\x98g\xF6\xAD\xF6$\x97
+Y=\xAEۢ\x8FK-3wW$\x9Ddu\xCA{lR\xEC4a\xA6Sv\xEC\x90\xF1t\xCC+\xB3;\x91\xFE\xB0\xBB>s:\xCDԕ\xA5\xB7\xF0\xDB\xE1Ĝʳ\x81\x83&\xA9E7/D\xBD\xBE\xB5\xE5\xF3\xB3H^*2\xFD\x92\xF5\xE9Ie\x9B>\xE8\xA0d\xAB0\x89\xFF\x94g\x90\xABT\xDE4T\xDFyS\xFA\xE1[яcs\xE5T\xA7\xEE'\xC7-\xF4\xB3Lnu\xCA]Nh.\xFEPuC\xB3\xAC\xF81f\xB865U^\x82\xF4\xDD=&\xA71'#@\xCEO\x9B\xC9\xF7-[\xF4\x9F\x9F\xC6\xFB{4\xCE?\xCEk\xA5\xC9\xE8\x9DidƔ\x99\xA7\\x99\xCA\xC3#ڧ\xC6%\xA6\xED\x8CS\xEA\x9F\xF5\xE0\xBFZ$\xA6\xDB\xC9x\x9D?\xE2\x8F{b\xF9\xD3{)#<Pg}\xB0\x8C@B\x87k%ѿ\xE3N\xAAie?7K¥*\x8Eٙ\x90B\xC9+\x85Ӣ\xAE£.Q\xC1\xCBE\xC0\xE4`\x808\xC0\xB4$\xE7\x8DJ\x94d\xDC\xD5TR\x90>2\xB13 c\xFCщ\x83o\xA9.\xF9"\xC8 V\xC0\xEA\x80
+\x98Qk\xAA\x81Y\xAE#+\xAB\xB2<\xE6gQp\x9A\xAC\x88\xC5(z\xA8(aq$і\xCB:\xDFk/\xF2\xB5\xB0@Ӕi\x8Aku\xD1k\x8F\xDF\xE8 \x9C\x81\xB0\xE9\xBA\xD8F7\xCC\xEE\xC6\xC0l
+\x8A\xA6\x8D71\x9ES\x8EoL\x9C?\xF6f\x8F\xAEN}\xF2\x93\xCFa\x9B\xFBCXf'\x8E\xE8e}\xAFc؝^\xD4\xE9\x93\xF3>'S\xB3\x9F\xF7\xFE\x83ƭ\xBC\xCF\xEFEM\x8A\xB3S^&K\|83K \x97\x9819x\xBE6[\xF1\xF2ё\x82\x81"\xFE\xCC\xCCi\xEE\xCA7V\xB9\xA6o\x9D\xBF\xBE\xE58\xBF)\xA7\x87j\xEFJz~\xCEb\x97\xC1w\xA17Lɬ\x9D\x9E\x879{\xBB6\xEF\xDFi[\xCD^\xF2\xBE\xB1\xDA\xA93\xFE\x88\x9AYC0\xBF\xE4\x8F\xFFIc\xECWm:\xDDE\xB6\xD4\xD4U\x9A
+
+\x88U\xFA]\x9Bn\xADC-u\xECx+\xDC߰%\xC8.\xF6\xDC6+q\x82\xC3!\xDBݤ\xD2
+
+^\xD1\x98\x8F\xEB\x8D\xF4<ۣ+d'Ϗp)\xD0\xF4\x92Xwv\xB7Ptd\x9A
+\x93ii#\xBD6#\xFD\xBBC\xE4y\xF6jeA\x8B:\xAF\xFEC\x8D\xCD\xFEC\xA1\x88\xAE\xAE1\xA29\xDA[k\xCA\xC9\xD5U8t+\x8Eh3\xC2\xF7ZO\x9F\xAE\xAEּ\xEB\x9D~\xBD\x80\xC2ڪ\x87
+-
+`\xE7m\xE3\xD4L\xBA\xC5&^\xD2
+\xE97\xD8ی\xAD\xB4\xD8b\xF6\x8Bڑ\xA7\xA3ȵUU\xBBͅ \x851\x81
+H\xF6\xEA\xF0U=\xBC\x99\xDC<i\xC4\xC1\xB0\xD5\xE5\xFE\xE4+m\xEDܺ\xDBy\xF6\xD5UU\xC1l\xF5\xF2\xFD\x9E\xC9[\xD0ByjrĂIvg\xFFPK'z\xDB\xD70+\x9Fc1\xE7mk\xE7\xDA%\xA5\x9B\xCD&\x85%զ\xA2*&)\xB42\xE9YZ\xBBF\xCEb\xFD\x9E˰\xF4\xFC{\xD3W\xA0\xB6\xE4\xF1\xA8{\x92\xA1\x84\xC3,\xC9\xF5\xEA}\x8C۴\xC0
+{.\xB3$\xC1\x8E`\x9D>w\xFB\xA7\xEC\xD5|\xE0ѰT\xCAZ\xC6\xEBHd\xF5\xD3}\x99f\xBE\xAF\xB9|\xB2b\x8F\xF6\xAC7_\xF6rA\xBB\xBB\xFD
+\x96eS\xD0ʊ\xA5
+\xC2[\xCDC\xFC\x8C\x9CCAҿ\xFC\x98}\xCC\xD2'[\xCE\xACB\xDE\xE8\xE4\xAFq\x8B\xE0 \xA7\x99/^\xDEbÕ+B\xD9\xF2\xCA\xE8\xAE}_\xE84\xFDĸ\xE6:\xA7;YD0\xE3\xC4\xE3nJם\x90eNGʈV\xA0\xC8\xD2o\xD2W\xA9\x9F\xE9\xECbq\x99]..r\xBA\xD3E\xA4\x89e\xE8a\xC5\]\xA4)=v>Ax\xE6tG}v\x96Sn\xCA\xCACk\xA0\xF8\xC0n\xF4\x8D&\xCB%\xB9\xF6\x98 \xF3\xCA,7\xA2\xF5\xD9a@\xEE\x99}\xB49kg\xDEn\x87\xE28\xDFC&{Ѷfq_\xD6\xCF\xFF\xE6+$\x94\xF7l"\8Q_z쿉n\xA0\xD5\xC6\xFD\xF1\xEE\xF2\xBF\xEF\xFD
+;\xC6\xE2oB\x8D\xCD֊\xBA\xF1\xE4
+Kfy\xFE\xE1+\xCA/\xECܜ2\x9F\xE3\xFARC\xB4ǭh\xC3L\xF6\xA4\x81\xF14\x90\xCC\xF0ih\x8E˽\xBB\xC6\xB4-w\x8B8\xF2Ԭg\x949\xF5\xCCԱ|\x8C\xA7\xAC\xBA:eR\xFE\xC3\xD3l\xDC\xE3\xC99\xCAPtlGw\xA6\xB3>
+\x8Bkm\xEC\xB6t\x96\xD9s0\xD6\xD9e\xA1\xAF\xC3#(\x93?PK\xC3
+Z\xA3k+g\xC1'\xA0C\xDD.\xC2\xF14@ \xDD&\xF6^\xB4\xF4\x84{\x8C\xF8+
+>Q\xF2\xC1ͦ\xEB\xEB:\xF5j3>9kV\xC7V\x97;\xE7\xFA\xB7\x98\xD5\xC4}PK23\xDAo+Y\xE6\xE9\xBD͞=<\x81"\xA3\xAF\xE8>
+w:d\x93\xDD<]\xEF\xF5Lc\xE8`\xCE|]P\x9A\xFE\xDE|\x8B\x9C\xA7k\xEB\xA3G}Yh\x8C\xF5\xDB\xC6[3\xC5{vbN\x99Nɧ\x81\xE1\xB0_\x82\xE3V4a.kZ\xCF\xC1璧\xF7wG=\xBD|#\x9A\xE3-γ\x81V\xC5p#7\xE1>\xFD1\xDC2: ?\x84\xFC\xE8q\xB8\xB1\xF0\x87\x94ӇbS\xED\xCCr\x972\xA7\xFE*\x8B\xFBI \x8B\xB6J\x98\x94\xFF\xBD\xB7\x8E!(n\xA0;\xD3Zo\x84\xC5s\xBB*\x9C\xE5y\xFA\x8C}\x86*o\x9FR1\xFAPK
+\xC6\xF2/\x86+\xEC\xDDd\xBA-\xF7\xB1U\x9B\xF0\x93&u\xD1\xCA\xFC\x8C\xA9\xFC-\x9A,j\xC5}PK\xE4\xAF\xF7p+$%\xC7\xF2\xDFw"\xA5J\x96\xEC,\x92\x81y\xF7\xDC\xF1\xE1\xDDsg'\xAF\xEFKAІ+y\xB6\\x85\xF1\x92\x80d*\xE32?[\xFE\xF1\xF1mp\xBA|\x9D.\x92\xAF\x82`A\xB9P\xD5N\xF3\xBC\xB0\xE4[\xF69\x89\xE3_\xE0\xFF\xD5+r\xADji)\x97%\x97\x99!\xEF\xCA۟\xC97\x88ɯ\xEF\x95~\x94V\xF3\xDB\xDA*m\xDAD\xE7B\x97\xC8
+tYH>ܐJ\xAB\\xD3\xD2E\xD9eL\x95\x95;dDJjAs*\\xAA
+B\xCA\xBD@j\x99\x81va\x88+
+Qwx\xC3\xAF\x90\x9B\xFAVpF\xAE8\x89\xC7\x9F\xDB&\xDA\x9C_.\xE2`0\x99d\xDCx\xCEX\x9A\x8E\x87\xBB\xA8mck\xABum\xB7\xDB\xFC-\xA1\xD2y$ \xA7"\x82J\xCD*[\x8A\x85\xAF\xDFP\x86uk\xC0\xBF7MrG\xAE\xF1\xCD?\xAB\x86\x84Kn\xF1\x95\xE4\xFC\xE6\xD2\xDF[VJ\xC0
+\xB7\A\x80\xC1:\xDD\xB3\xFB'\xCDٲ\xE3Q\xD2dH+\xCA
+O\xE4\xE6\xB7\xEB\xE8e\xB7}u\xC8\xF5\xBD\xE1_\xD0-\xEB\xED\xF7\x87\xBD\E__}\xC0\xC0\x92\K%\x8C2|m\x9C\xF1J1w\xFF.#\xC7\xCE4/?ş\xE2\xF0\xDEd\xCB\xAB\x90\x94*\xF1\xA7a\xEA$ў\xAD-^RaåM]ْ\\xAB\xBA\xBA\xCCRL\xDEQ\xA6\x98J\xA2\xDE\xE6T[\xBE\xA1\xCC\xEE\x81\xC2ۚ\x8B,\x89FN\x8F\xEEF \x8D\xC3\xC2Wa\xAB\xE9\xF8du\x9F\xAEN\x92\xA8\xF7y\xA4\x81eh\xE0\x86\xDA"
+\xC3h\x9E|\xD12\x8Fzꋣ\xBC(\x8A\xC0\xEE\xF3j\xC1\x92\x96\x90\xFEB/ԅ"\xEB59\xF7(gm\xDD\xA6y\xD5v\xA5Gu\x90\xB1\xC7erܺ'Uk?q\x8DRz\x97͒hj\xl%\xEAՐvj\xED\xCE\xFDq҉\xAEӾ\xED]\xE4\xA4/\xD3\xDExEdPήd\xBB\xC0\x87\xCD[\xE4\xE1\x98H3\xC7汵%[Pi\xA5\xA1m@\x80\xE4>c\x9D\xB1μ\xCD\xAE\x95}[gMn=|E\xFBq?&:\x940%7<\xAF5\x9D\xF3\xBF\xDCB9\xBBn⟻G\xE5\xFE\xFA\x9Fn\x84\x9D\xE5\xE1@\xA1%\x9E\xCB.\xD4\xF6p\xB9ǯ\xD4\xBE\xE1\xA0S*D\x8D·\xE0\xFD\xC8,;\xCB\xC3d\x9C&q([\xFB\x96x\xDF*\xDCs\xF4\xEF\xA8v\xA2\xBC\xF3\xDAE\x8Fo\xDF;ﴪmU\xDBA\xFEs79a\xD6{\xFC\xDB\x85=\x8D\x99\xE5ħ\xFE\xA5\xB9\x85\xDFA+p\xEE8\xFAA\xD2\xCA\xCA\xCEc\xCF\xD1\xE0\xCB\xCD{\xD8b\x8B\xAC\xAEǑ\xBDy\xA2\xE6\xA3\xCAM\xA262\xDB!\xEA\xD7Ó\xD6\xFE\x82\xD6&,\xD5\xDDt;\xF0H\x94\xAEA\xA2\xF8\xA5g)\xB5\xB7W\xD0g\xC3\xFE\xF2\xEC\xF0>\xF9\x9F{dr\xC1s\xAF\x94\xC7\xD6\xC9\xC1a\xDB\xE0(=A\xE7\xD1l]ࡌvW\xB5c\x8B\xF7\xE9?\x89\xC6ߌ\xBC\x84Ǘ\xC9\xD0\xDE\xE3=\xAD׳*y|2\xFE\xEB\xBC\xFB.E\xAB/]\xBA\xF8PK\x94\x89R\xC5+\xC20+W\x99p\xFC\xE0\x83w\xC9\xD0\xAF
+{\xD1\xA4s{8\xB6\xE4\xF1rБ\xF5\xB0KYg\xCD\x99\x93\xF1\xE6W\xE4l\xA0`\xA4\xA2\xDB\xFB>uZ\x92Y8jT\xE0R\xE7'\xC7\xFA\xB7\x86\x93\xE4
+_PKM\xCBw=o+\xD9\xFFs?\xF3aݴ\x8AՐ>\xF7\xAC\xE2(|\xC9X腦\xC3x\xE7\xBB\x8B\xB18\xD0\xBA\xA2\xE7[\xD9h\xBD-\x82\x96_O^-Ϲzܹ\xA3\xC4jh;\xD9U)5\xD7\xE6\x89T\xB9\xDA\xD9A,s\\x92s\xE6f\xD1ZG\x9AD\x8B\x9F\xC2x\xFAQ\xE8=R\xD1\xF7\x98\xED.U ;\xD0\xCC^S\xA1o\x99\x89{\xD50Rl*LF\x92\xA6\x86\xB2\x9A\xBB\xD3-g\x9B̹\xA6ɹ\xA0S\x91\xC1\xB3\xD1d\xFB\xDAJ|Bv8\x8Aw)d\xFD\xF4x\x8Ex\xEF4\xF0\xB2\xBE\x80
+\xFB;<S\xB5\x9DR\x93\x96°\x94\xBD͊\xE6,\xC5\xF2gEy\xFE\xADT\xA5\x84\xA9Y+T\x97\x96\xDB*\xF8"\xBE$̾\xAC\xB0\xEF\xADc\xAE\xF0\xDE\xF5J~\xD5
+튕\x9D\x9C\x9Bsxx[ڑ\xE9\x93Ez\x9C\xB3\xDCz\xE2\xC5\xD2W|\xC7
+|
+_\xD7\xF1
+\xDF\xC4+\xBE\x85o?̳\xB5 5\xF0џ\xC4y\x85\xDDm\xD4J\xA9\x83A\xAA\xE8\x98A`\xA9\xD0\xE3\x8C\xD5\xDBJ\xD8\xE4\xEC#\xA0\xE3\xBB\xBE\x87;\xBE\x8FWu\xFC\xC0\xC0\xF1#?\xC6Ox@\xDA{\x83\x81\x9F\xE2U!\xFB3?\xC7/\xFCR\x8C\xFE
+wv\xB5뵗\x89\xA8\x8F\xF85~\xA3\xE3\xB7~\x87\xD7d\xF8=\x8B\xA1C\xDD\xF8^Qx\xEC\x8C\xEF{~\xEA\xC6<\xB1R\xAD`\xBBe: \x80\xA4\x97o\xDA\xE4\x92\xA3V_\xEBfS\xD8T\xB6B9\x9E\xF5\xCA؛>\xD4\xF9䬪\xB0\xA6\x8F\xA6ۊ\x9D\xEE\x91\xD0C\x8E[s\x93\x{13AC4D}\xE7v\xB5<\xF2g\xA2FF\xCD\xD3fh\xD6\xCB\xC2\xAEO\xB55\xE3\xBB\xD9{I\xBDc\xF7\xE9\xDF(e\xEF\x9C7\x83 \xEBf\xDD1\xBCr47\x9A\xECXi+Bl\xB2\x83ӫDŽwEK#\xCF\xEA*K\xE9\xEB\xD7M\xA7jM\xCE \x8F|;FC\x83 [铳\x81\xE7\xB0e\x9F7\xC3\xF9\xF5\xD6\xA1\S\x9Au\xBBМ\xE7WL|\xBAC\xF0\xAFn\xA4\xDC\xB7\xDB\xF15\xD0A\xAC\x93ބYa\x83ڿ\xEE.\xEC\xAC\xDFG\xFD\xF3\xA6\xCFR\xAB\xB7\xB5\xAD\xABδ\xBE
+\xE2\x95Ev\xA6i3u\xDB\xDA*\x9B\xF2\xDA~\xDBת\xF4\x93\xEF\xA7鎊\x9D\x9Bq\xA6\x{11F53A8} \x84\xE8E\xBE\x90c\xAC\xE8x\xFD\xD8\xD5٠\xB8\x9CLw6+k\xF1\x92\xE5Xr\xE7;\x8F\x96dz\xDE\xF7n\xC8\xED\xF7\xD6g{\xF97\xCAO\xC8n~\xF9\xB1\xC7\xF3\xAD_\xBA>\x9F]\xD2\xF8\xF9\x8CC\xC9\xCD\xC1\xF1)\xCE\xCEQS\xF19\x90Y\x86ʬ\xA0\xAB\xB0\x8C\xEE{\xD02\xDA=\xC4^\x8F\xB6\xBD\x87\xA3QW\xC2\xD3\xC8\xF1\xF9n\xFE6s#\xB0\x86\xB1i\xAE\xC3X\xF48wu\x89\xA9\xCC\xE1{\x88\xB7P\xEB\xD2\x8A\xBC E\xE1%\xA2\xB5#\x88\x91&\xAFb\xAC\xC7Z\xC3h#\x96\xB8u\x8CX\xC2\xE8}8\xD1\xC0:\xD9\xC0\xEA\xCD\xFC\xDA\xE1\xF4\xF5p\xBDM\xB8^*?\xB3\xEE\xBFk\xCFRr\x8A\xB1\xEB8\x95\xA4\xD1W^&\\xFC\x9Fض\x82\x9EBo\xA6\x86\xC426=\xE8[\x81QXA#\xBAy[\x9E\xA1Z\xAC\x86\xADb\xBC\x86m\xA3A\xBF\xC2\xF3e\xBB\xC2?\xB0#\xA7%\xB92p\xF1\xBBo\xFCg(3\x92Ԗ1xm\xEC\xEE\xFF\xCE\xF4\xEF\x8C\xFD
+\xBB
+\xDDC\xF7\x91\x9C*hb\xB1\x86\xB7M\xDD\xC7P
+\x8F\xBD%\\xDC8JB\xEFg\x9EN\x93\xAE&\xD4\xED\xC4ɟ#\xFDa\ų\xC8G.<G\xDD\xE7\xB8s\xBC\x91\xE1\xBA\xE4yJ\xC4\xEDs\xCEuJ0A\x8CI\xEE~\x819\xBB@\xCD)\xC6u\x9A\xAB9\xBB\xC4\xF1
+^B\xB3\x98\xE1߁\xA9
+\xDAg\xB3\xA5ޭ\xF5\xF8\xAB\xA3\xC4\xEA\xE1\xCA\xED\xEC.\x88#5\xECY\xC6\xE3\xA35\xA4j\xD8{Y\xE54\x95\x8BQ\xBA/\xA7\xAD`atr\xB1\xC3I-)\xC2=5|*\x9E\xD4\xEEc8\xBB\x8F\xB7\xC4_\xCB\xE9\xADiR\x90ӈt\xE8r\x94\x88\x8ClDb\x94\xD4\xEAY9\xFC\x80\xAC\xF6\xB0*\xF2d\x91\xA7_\xF2\xDC\xC5\xC8\a\xE79ʳ^ϒ\xEB\xEB\xF0\xFA'{r\xF4x\x9AѝA\x8A\xDE^\x8A\xA2{\xBBY.\xB7\xA3\x98\xAA\xE8Mb߅\xAD\x8C\xF8eVw{,\xAFQj\xD2^\x91\xC8%b\xCE\xE1+\xC4&I\xD6
+\x96\xE1
+2Ԥ:\xAF2\xC4G\xEC"\x81h\xCA\x96\x9E\xAB\xCCtg\x92L\xE2$\xB3\xB6\xC6ͫ\xDC12\xE3^\xD9 \xBFZwG6$^\xB1N\xED+\xA4*c\xC9z\xB6\xD8K\xC7W$}I\xD7*\xAD\xE4\xD1%M_\xF9\xA5(\xCAy\xBB\xE2h\xFAyCDvO\xB5\x9D^\xA1Q\xA1\xDE\xE9#\xE8\x9Bڇ\x87/g
+\xD7SЅn\x86\x93;A\x8D.\xDB\xF8\xBA\xE6 \xEF*p@8jg+T\xBD;zQ\xEEu1\xAD\x92\x82N2\x8BL\xF4p\x85\xEAr\xC3k\x863\x96\xB9\xACږ\xAE\xFA\xAB\x8A(\xA9\xB7Ԃ\xAE\xBA\x95\x85\xD3Љi\xAB^\x99$\x80\x92\xEE\xCB(\xF0P\xC0%\xDCR\xB0\x84e\xAF\xE0Cw\x87\xAB\xAEjٞ\xCA\xD5En\xC5P\xB3=\xB3\xA9\x84\x87Zvof|\xA20K\xBD&\xE1=\xEF\xE3\xE26Cs\xE0\x95\x82J\x8Ao^yC\x83\x82\x8F\x84Տ\xF1\x89\x82;8\xAB\xE0S\xF4)\xF8\x9FK\xF8B\xC1\x97\xB8\xAD\xE0+|͐z\xDA
+Rp\xDF0\x9C\xAA\x8E\xC5|\xC5\xF5\xB6c\xC6vwD\xC1\xAB\xA28\xED`*\xCCH\xD5\xEEP\xC1\xF5\xAEy[\xA5\x8E>\xB1AGl\xCB\xE34(\xD5}\xA9[>\xA2\x8F\xA8\xB7\xF7E
+6<4\xF6W7_\x90\x8A\xFE\xCEi\x86\x86\x92\xEE\x89\xD1ȶ\xA5:\xA3Ⱥu\xDA\xE9\x886\xFE\x8FC\xDD\xC1'\xFA\x80XG\xE4\x81\x88F\xBB\xB7\xF3\xA8#(Y\xF3\x9Cz\xE9l\xA6G\xE9\xAD7\xDCQK\xCCۢ?\xA4\xA77\xE1\xE3\xA4ƴK\xDB\xE2W\xF4\x86pD\x8E4\xCE\xF3\xE5\x82N\x89\x9C1J\xFE\xD7&a\x84#\x8A\xBEN\xEBnm]\xC9ǹ4\xC4\xCA\xDC\xCD\xE9K\xE4[\xDC\xF2_[\xA3:D\x9FOQ\xB8\xB6\xE3\xB9\x80H\x98\xD3h\xA3\x8Fu\x8Eӝ )\xA6\xAD{\xE8\xBAC/\xFDi\x9E\xD0:N<\x81\xF4<E\xD4]\xBA-0zgӫ`釈M\xAD\xA2\xE6\xE2\xE9\x88کt\xB2n\xD21\\xDB\xE4\xD5o\xE3\xC9\xC4kX\x85\xF0\xBE\xF7->OO%Ѝp\x86ާ\xE9ߌ:z\xF6\x8A\xE3h"T\xC7\xD5\xC2u\x9901\xBC\x88\xB3!\xAE?!\x91`\x92\x81]\xBFc\xCFC4N%\x9B\xD2+ؽ\x8A=\xBF\xA6\xBB`W\xD7
+\x92\xE3\xE9\xEEU\xEC\xCD\xF5<B\x8B/\xB1/\xFE3\xF6O\xD5t\xE7ā
+\xE1<sm\xE9\xE4\xB3\xC1\xA6и\x82\x83Bd\xCD=]k8)k\xD9ĝl\x87\xB8\xC5\xEA%\xC2\xC8p\xE3\xE8\xC7+\xA3t#\xA0~+َu\xE2\xEA\xDAN\x8BA\xDC:ӈ\xFDPKE-J{D++6\xE7f\xCDy3m\xBB\xE9\xBE\xF7+P\xCDB\x81f]\xF5\xA5\x92\xE9\xD3\xBEg;E.GˮG%\xAB@\xF3,?\xE4V*bf\xB9l9Nl\xC7\xF6\xCF)\x88\xA4\xFA\xAE\xD2~\xC8-\xD0M{\xCEv\xACKչi˛4\xA7\xC5qW\xCE͛\xA5\xAB\xA6g\xCB{C\xF5glzޑs\xBDbz\xD6̻y7m:~:C
+\x93f\xE5\xD8H\x99\xE5\xF0;S\xFF\x8D_\j\xB4l\x92\xE8I\xADg!F*\x8D\xC6*\xD1TV\x9B\xA8_E(!(
+N\xD1Ե\xE6\x9EL\x90\xCCx`\xE4R\xB5\xAC|\xD5g,\xB1\x92k,O\xC1\xA1\xD5\xE1\xE7]\xCFJ\xFB\xAE[\xAA\xA4\x87i)Q\xE6;rQ\xB8\xABg\x99@vtx!o\x95}\xDBu\xB8˗lKi\x85&\xD1vܡ-o'omzyk$\xC8Ҧf\xFE\x8E\x8B/GpTG\xBD:\xF6\x89؏*\xE6t88\xA4㠈\xC3H\xE9\xE8a\xA0W\xC1~\x89\xC0,\x9B\xF9\x99\xA6s9\x94\xF3U\xBBTX\xF6\xC9\xCD:\xF3f\xC9.$\xA5D\x92\x9CV-.\xCA\xE2ﮂ\xD3rj\xB6c\x8AqRN/iW\x92\x9Eu\xB7j{V!yo\xC6r\x92R\xA9<\xA0d=\xA5bW0}\x93\xF5\xF0\x9Cr8pB\xE8YDZ\xBC\xA1\x92Y\xA9X\xF1\xE6\xA9\xE0؏\xB3:D\x9C\xC6)\xE1\xCBd\xEE΄\xBAH\xFAn\xF2 \xB3ֱR+\xA3ӳV\xDEWQ\xD51\x8F{*t\xDCLJ:>\xC2It|\x8COt\x87\x9C\x9D\q\xA4\x9CT%\xF3\xEE\xBC\xE5\x99E+p%\xF1}\xAA`\xDBs(5ȮKv}\xED\xC0\xDAR\xF0X\xAB\xF6\x9C\x95,\xB2F\x9B\x87ߞ\xBC\x92\x9B\xBC5\x98ɌOL\xF0\xD6-_.\=\xC0\xDET_.\xD4Kӄ\xD5\xF4Z\xC8\xC5y\xC1&\xB9#\xBBSϽ\xBB\xB2\xBC\x8E@X-+\xE8q\x9E\xED\xFB\xBF\xD7J_\xDD\x98
+r\x9C\xAE\xB8%\xDE\xD21ӟQ\xB0\x85\xFCCz[\xC7Zo\xE1mכ3љ\x90\x88\xAE\xE7֖K(n\xA4\xE4[R_\x89\x9E\xBD\xA6b\xCEK{\\xD3\x94
+;\x93\xCD\xE4\x8C\xE7ޓ\xCA{\xF1A\xA1\x97\x9F\x8C\xBD\xFCR\xA9h\x93N\xC0Y\x9B4\x83`d?F\xB6\x82`d7ƾ\xC6hv \xDE<6\xCAc|\xABP\xCFˈc\xC6(Ft mFd CYB\xD4\xF8\x963:\xB7?Z\x82jthK\x88\x8BI\xE2q+m\xAAk\xA3Q\x83\xFE\x9B\x9EQ\xD9\xF6\xDB9D\xFFj\xACmn\xAE=E\xFB+\xB9#wD\xACj\xE8\x941RC\x97\x8C\xF1\xBAe\x8C l
+[.֑]=\xD1?\xB0u*"\x905l\x9B\xF8
+\xDBk\xD8qT^\xF9$j\xD8\xF93\xBA/\x9Ev\xAD\xBBz\xE9\xD9c\x86<\x8E/\xF0%v5\xA8,\xFA[\x94\xE7\xF0&5_\xF1/\xF0-\xF4\xCF\xF2\xAF\xEF<\x86\xF4ϣ\x83r\x81w\xF9>z\xF8\x81ڏ\xB4\xFA\x9CV_s\xED\\xC0\xB7\xF4\xF01\xBF\xE7?\xE2\xFCt\xFDH\x8F\xE8\xF1!\xD1\xE2l"D\x89'\xA9\x92>\x82\xF7\x82Բ\x81 ǿPKL\xA4\x80\xE2 ++fbH\xE0z7\xBCC\x9B^\x8Aa/^\xE6\xE6n^\xE5F\xE7fVANA^@\xC9\xAE̛\x8E@kvQ\xBF\xA5gL;3j\x8Cs^\x9A\xA3\xB1@xζ\xA5A\xA0\x84*\xE8\xD6|fR:\xA65\xCF@\xC3\xCA\xD9y\xB0`\xE7t\xF6\x80ei2Y\xCFF\xC0\xB0\0\xDD\xEE~\x81\x83Yۙ\xCF,\xEA9;ggtKf\xAE%ۑS\xBA{\x93a\xE7M˔\x83\x87\x93
+p}\xD3\xA1!;O\x9B\xB5eM˸R.\xCEΔ>\xEBo\xCF{N\xEB\x8E\xC9\xF3\xC0\xE2\xEDv_\x9Aώ\xDANQ\x97t\xA6\x91\x82Q4,)\xA0\x8EY\x96\xE1t\xD75տ\xFD\xD6\xDD\xF5(\xEE\x98k\xC8\xE1u9ۓ\xD5zr\xB8-\xC05J\xB3\xD1@d\xAD\xB0\xDE\xA5q[\xFA\x8E#\x91\xD91\xE8\xBC3\xE7\xBA4\xA6Mה6u'\xFB6\xEExAg\xC6\xFC\xE0K\xECJ\xF2+
+\xA8\x8Ar\xA2,Ke9\xE9\xAD1\xCA\xF6\xE6=\xF58\xC7\xCBi\xFAľyD\xE7\xD6e\xA9\xEF\xB4 \x8B\x85L\x95|\xAC\xDB\xC8\xED\x9CQ\x92\xA6m\xB9
+\xE6h>i\x97\x9D\x9C1\xEA\xA9Զ\xA1\xFBqUE/\x92*\xFA\xB0 @\xEF\xFFat \xEC\xB865z촊nt)0U,⦊GУ\xE24\x9D\xD0Ta tqPzI\xCF-i\xDB܋e\xB3\x90\xAF\x84!paĔ\x86\xA3q
+\x98\x96\xCEF\x8D\xAE\xD5ȑ|w4\xDB\xD1\xF8
+\xB5bٕڬ\xA1\xB9\xE5R\xA9`\xF9\xA3\x9Ae\x93\xC1\x96*l\x948\xCA\xD7\xF6m\xA70\xAF\x90N\xB52]7K5\xEA2\x9AT~\xA0\x904\xBA\x8DU\xD7|j\x81\xDE\xDA\xED8\xB0\x9A\xFD\xE8-\xDD\xCF\xFDqX\xAE
+\x89S*\xCAܜ\xC1-g\xF1\xBA\xC0\xF1\xCB \x81\xD4\xF6\xB5\xE0x\xADi\xD2c\x95\xBBTp[\xE0\\xA3B\xD2 \xD1OxI\xDFZ\xCA\xE8\x89\xCEs&\xCF\xE9$ʹ:\xD5n\xFF\xB6\xBC\x94\xD0%\xDDq\x8Du\xB6\x9Ez\xD9_\x8F\xB2e\xDE\xCF|\xFF\x91v\xB9^\xF3\x9A\xD7!\xE4q\xB2\xF5\xFF8\xF1\x91\xF7oT\xAF\xAA\x9A\xC0k\xCDInwV\xAAהW\xA2\xDAi\xEEC7
+\xD5zU\xDB|\x{1BD73C}\xBFzr_\xA5\xEC`\x83\xEB\xA3\xD4?D_W \x8C&\xAE4j\xE2r\xE0\xF5T:\xBC\xBE;\xE8\xA9`+]\x94\xEE[D\xF0Y\xCE\xE2͉N(t=ʹr7\xF5b\xF70@]\xF4v\xAFA\x9DI줉XF\xEB
+\xDA>YC|\x86!+hϮ!1\x93^\xC1\xAE\xF1\xB7\xD0\xCB\xF8\xCF\xFC\xEE*|\xE3\xA3+\xD83\xBE\x86\xBD3+ؗM\x93!\xB4\x8C\xFD܇\x97q\x80\xFB\xC82\xA6\x8F.\xE3\xA1\xF7*\xC78IgNS\xF0\xE7\xF1\x84w\xBBͤ\xDF/\xFC\xBB\xC1\xD1nГ\xF5m9z\xE6O\x92&\xFE!Ϣ\x95\xDA\xEF\xE9\xFF@\xA3\xE9\xC5\xFCDL?\xC7/tK\xBF\x92\xCFo\x98\xC0\xEF\xE4\xFFy\xFE\x89\x9B\xF8.\xFE\xC6\xF8\xC93D<C\xC4:\xEC\xC52\x82~\xEA\xD0\xFE\x87\xE8og\x86\xD6So\x84\x9A0O=\xE2\x91\xFF++\xA3\x96i\xEAYW\xB2\x90 \xCDuj\xA9\xFF\xA9/\xA0\xE8\xEBz\xB6\xEC\xD2\xC1\xB0ii9\xDD8\xB1\x95TֲkHiJJ\xD73\x9Eu\xA3\xE9\xF5\xAC^\x92@4\x94\xEA}\x89\xBDiK\xCF\xADvԣ21]\x87#v\xA4\xC6J\xA0w/\xA4\xA8\xD2ZS\x99qm][݆],\x95]\x9B\x82m5\xC1 W\xB75\xD7"烾h\xD95\xCCTm\x97\x92\x9D\xDBsO\x8B\xD5\xFCj 69B\x95\xA0\xA3ݢ@tƳp\xC1/\xD9zY\x9C\x94j*\xE8H\xEE\xBD\U\x9C\xC0*zЫb\xA7\xBA\xEA\x9E/f\xAEE\x81\xE3\xB2\xFC\x8C\xA2&WqY\x86\xF1ղ\xE3Ɨ\xF4\xB8S.\x95LCϩ(\xFE\x94z\xF6\x928g0\xA4"-\x87a+pT\xB8(\xAB\xB8\x85\xB5\xA7\xB9\xB5=S*\xD6Q8&\xF1\x8Cb>\xEE\xA0\xF40\xA7\xB9\x9A\xEFf/\xAA͋\xB0\xA9\xF3\xA9\xE9\xA5\xAC\x82\xDB*>\xC2\xC7*>\xC1\xA7*>\xC3\xE7ҙ;
+\xBEP\xF1%\xEEhPJ\xBCxsE\x99\xB3\xB8kř\xFF\xB1%߯\xE8\xEC\xDBp\xA5\xAB2;\xB9\x9D\x8EP\xBE\xD7Q\xF0\xB5\x8Ao\xF0\xADd\xFC\x9D~\x82\xB5Fe\xBD\xA6Zw\xFA\xF0\xD3\xFA\x81@W\xC3\xD8\xF8g66\x8C\xBC\xEEʂ\xAB&/\xD1\xF0k",\xB6\xD3զ\xE2E\x89\xF5M6\xC3\xFF\xA1$/^Ĩ~'\xAD4,\xFD\xD8\xEE]v\x8B\x82\xE6L\xE9\xEB\xAE\xD74Y\xECEoq\xB0\xB2%[\xB2Θasnٷ\xB7\xE5\xD3\xF7\x94-gٲW5\x9Ci\xC0\xE3\xEAnȾ\xDDR\xF4Ĵ\xD5\xD1\xE00>\xEBD\x93"pV\xC09\xC8\xF1\x9D)>\x9C\xE7\xC3>\xE4\щ\\xDEĴ\x80K"$\xE4\xF8p\x99o\x89xW\xF8pU\xC45(!\xCC(\x88(B\xE5\xEBY\xA5\xE6\xF8\xB9&b'\xE6,\xD0\xAB\xA2\xAB6C8;\xAF,)r\xC5\xD1t9\xAB\xD9N\x9A\xA1sJ+\x8AS\xB1T\x86CuǣY\xD3*\xC9\xF3J\xC1,\x98\xB2\xA5\x96MˑsjaA\xCE^\xFA8\xA9\x8BK\x9A\xA9+\x8Ef\xCF.1\xF4\xCC*\x9A>i\xE4\xB6\xD7D\xCEZfY\xB5\x96z\xAB\x96t\xC5(\xC9S\x8E\xA5%\xC2
+:s\x9A=t\x88!\xB6ٮb8rε}^\xB1\xB8بfh\xCEq\x86\xC1D\xB9\x91<\x83\xCC,RX=Y\xCDP\xCFTgT\xEB\xBC2\xA3\xABܼYP\xF4\xBCbi|\xEDm\xFA\xB9y\x86\xFE1\xE1\x84i-*\x8E\xA3Z㺺\xA8\x83\x941\xD5\xD3\xDB\xE6Tnm{\xA8)'\xAB`\xA9\x8A\xA3r\xF2≑\xF6\xF4\x92G\x96+9\xF8(\xB9^[u&\xEAi\xF7'.\xB9\xCC\xEAJ\x89\xA2"\x91|]JD\xA21\-T\xDE\xD9V\xF5:\xAFٚcZCM\xCFT\xE3\xF7\xA4xaͮ\xC00\xDC6\xDB\xE5K\xE5J\xE2\xF8\x8D\x82Zv}`2t\x99\x9BC\xBA\xB9%\xE1\xD3R\x89yE_\xB65[Ό\x99K\xAA\xA5\x94\xD43\x94\xF3t{\xC6Z\x9Ef\xB5E\xCDI7g\xA4\xC3ԋt\x93\x96\xBD\xC5pK\xEB\xB1"M\x9D\x833\xEC~\x84uaQ\xB5mR\xA4R\x9F\xA5R\xB7\xE7\xC8x\x82\xBB N\x99\xAB\xA0Nh\xBC*zjw\x90;,a?F@|\xF7\xD5\xEE\xF1I\xCBR\x96\xF9e\xE6GY \x83\xD8-\xE1)\xEC\x950ć}fhǖ+%\xFEq\x92(a \xD7%\x8Cↀe 7\xF1\x8E\x84w\xF1\x9E\x80\xF7%|\x80[\xC4\xC3>[\xDC\xC7{Q\x8D\xE5əy\xB5\xE0\xB8-\xE1C|$\xE1c\xDCa\xD8˭)e\x85LȎi\xEA\xB6{\xCBNU4\xBD\xB8Q$\xD6Y\x8E\xBB\xAE\xC4y\xF7Q\x8B\xF1bE\x8D;f\xBC\xDAyh\xED\xF6\xBF\x83\xEE\xE2\xE7\xE1\xF9^_\x86dk\x8DF\xE1p\xE3\xD6H+\xFA2\xB5\x8B9Yq\xCAg=\x81\x9A)g&7\x82\xF0)\xD2\xED\xDA^\x9B\xAEt\xD8-\xE3\xEE\xAD-\x9EJK)\xEB\xFA@5\xE9j\xE7!\xEA\xB9\xEAǣ/Q\xFF\xF5\xE0x\x93\x89\x96\xF5\xDCW\xFA\xB1G\xB4e\xE4\xACnR3\x8B4iZ\xF7\x82\x94T\x87z\xF7\xBE\xD6`jȓH{\x85\xDFꜺO\xCE\xEB\x83\xC3\xCDZe\xB3\xEFX\xB8~\x8F_d\xB7\x8E6\xB9܄\xFAf\xB8]\xF6fw\xF67Ajx\xFC\x83W\xBD1{ZѲ.B\x96\x8E4\xC3n\xAF\xC4
+\xC5\xDA\xF6\xD0\xCE+\x82Iz\x92l\xA1.\xDE\xD34J\xA4OZ8Hd\xC0z"\xE4\xD8et\xB1+\x88\xB0\xAB\x88\xB1k\x883\x85\xE4\x9E\xC1\xB3\x9E\xB5s\xA4ͭ\x{16F853},\x88\xD9\xE4O\xA4~A\x97S?n\x80G\xAABx\xDBp\xCF7\xD3M\x83i\xB1y\xF4\xB1\xDA}/x\xF0\xC7=\xF8`2F?\xA8\xC3zx\xFC\xEDE\xA2\xA6\x8A'\xF23\xB6\x84+\x8F\xFE\xFD>\x9B($\x9A\xE8\x9B\xFE(㙥\x83EfΙs\xFD\xCEe~\xFE\xFA\xF2
+\xC026t\x8Cb6\x854\xF2:\xE6pC\xC3|7uz\xDF\xD2\xC3m\xC5-\xA8\xAB\x90DQђ\x8E2\xEEhXĐ\xEC\xF8^G\xF8\xF2\x90!Sm\xF27[ܵ\xCD]\xE9;\xAE\xBDʐXs\Gn0D\xC5}\x86ؖWcU\xC7;\xDDvM\xF8{\xBC\xD6\xCAٳxk\x9F\xFB\x8Ez\xF7\x851\xD9p\x86\xE9\xAA\xE7\xDBf\x93[\x9E\xE5\x99ܕ\xE6\xA6-\\xB9ǃה`$\xF2\xC5+\x96\xE6"\xDE\xE1VC\x98\xD2\xF3ZA\x88\xEBi\xD7i\xD5a \xCD)\xB0\xBC\xE4\xDBܭs\xE9\xF9\x87\xEE\xE2\x9E
+\xBAb\xE0>x\x88G0\xF0O4\xACX\xC3:\xC3\xD4E5\xF7\x93\xFF\xA9\xAA\xD2\xE7\x96\xDC\xF2z\xC2\xE7\xB68\xB1?\xDF\xAA\xBD%\[6\xC2a<\xA7\xD6\xD9B\xAA\xB6\x9F\x80\x9D+\xABC\xAB:5\xA1f\xAFi\xEF\x9CT\xF7SN\xB0\x{DA91}\xD6\xC3ԯ\xB2*5\xEF\xBAV\x83B\xD08\xBAm\xAA\x8EĄa\xC8\xE9v8㦰\xC8&ξ\xD9\xCF\xFCKO\xF3\xA5\x95\xD9oζfaXYC\xF6\x88\xFEG\x9A~\xC0Q\xFB@\\x94xZ\xBA/\xD1\xCB$J\xA3D\xBCt\xF6\x91\x98&\xA1F
+\x91\xC3e\xA2Y:\x89P\x92\xA5{
+W\xFA\xCEdQ\xBAR\xF93"gi\xDF[q*5\xE3\xE8\xA1n\x96b\xE7I2M@"a\xAC\xB7\xF4u\x95f\xBD\xF4 \x91H+r\x84\xE8{L|E\xECe&^:B\xE2\xDAw\xA2\xC9wЉ\xA4> \x9Eѫč(\xE3\xF2\x8C\xF3\xD6\xFB*ԅ\xAB9J\x94\xA8e\xB2HZ\x936\xB8\x82\x92\xC6\xC8F\x9Dka\xA4\xEB\xBFPK\x9D\xFA|t+.(\x88\x92\xFA\xC9'\xBE\xF9\xA9\x8F\xFA\xEA\x83~\xBE觟>\xA8\xAF~\xFE\xCFd\x9A\xA6C\xEAC\xCE\xDC{ι\xBF{\xEE\xB9\xF7\x9E\x99|\xFB\xEF\xE7+\xCAךQ\xAA }c\xBA\xAF[\xB7:\xC5YAU،h\xF1.\xCD2\xA4\xEF*\xCB\xED\x83a\xCD\xCFKKء\xA6\xEE\x94mi{\xAD\xB9W\xB7\xB8\x84N-\xB5\x9B3\x8C\xD4\xFA\xC1\xB99g\xA6t;\xA7*\xAF\xD9*!\x8C\xA1n].\xFC 5\xC3\xE3w\x82̚tlJ&\xF5\xC7VhnCF\xB7$"\xF143\xA0`\xB2;:\xAE%b\xA1\xDB21\x87\xE07r.U{d)\xEB\xFB]\xFCz\xAEY\xE5\xD6ƵT*ljQ\xDDb\xB6t\xAFf\xAA\xC5Ӵ%I\xC7*+\xD3mHr\x9B\xA2Q\x8B Ϋ\xE5ZT\xB7\x9B\x96- oqҙtzJWB\x9B\x85\xC0\xA3W2ʑ\xD4o\xE8\xEBg\xB7W䤘n\x87\xB5t"\xD2\xC3t5Y\xB1tO\xD55\xB5\x85\x9291i\xE9I\xCDқ\x86\x9D\xE5:\x8F\xF04\xAB\x9C\xCEQ5;\xFB>~p\x9A\xA13І\xCCr\xED\xC1\xBCrm\xD4O\xCE
+ji\xE3\xEA\x9Ec\x83fڊ\xE8\xD9\xC1\xD3\xDD\xC52P\xC5UX\xA6`\xDEHbV\xB1W2\xEE\xFC(y\xA8\xB2\xC3\xEB\xFDzDhkU,FH\xC5,U\xB1+U\xAC]\xB3\x88\xE7El]XD\xABtۤ\xB5IZ"6\xA3K\xC5ء\xE2E\xE9n\xEBNܡBC\xB7\x8Acxɇ\x97U4\xE2U\xAF\xE1uo\xE0M\xAB\xC4\xF5-\xBC\xCD4\xEDt\xC3ɥˇwT\x9C\xC0I\xDEU\xF1\x9E@\xDE\xFA8\xC5=,\x90;s%ZR\x8B\xF4\xE8!\xDB4\xE3)\xE7\xF6\xAFI\xF1h\x9E\xCD\xCE
+\xAF\xB6\xCDj\xBD\xDFIn\xB53gu\xAFf\xA9\xF8I2N\xBB\xB4KT\xEEP\xC19\xB3\xB6a\xB73>x;\xE5\xF4t\xA7\xCCx\xDA\xD6\xDB5\xBB'\xEF\x94\xCB}Z'\xE7{,}\xBAZ\x87N\xF2o\xD5)t\xAEC#9
+\xF3\xB2ײ\xD5)\xAB\xC1\xFC\x8EڒH\xE8V\xEE\xCE/\xD1m\xC8\xC3ɱ\x8F
+]\xFBe#\xBCO\xC3 \xFA\x9E\xB4\xF7Vʶ\xEE^=b78\x9AS\xB4[\xA6\xF4T\xBBs\\x94~׃\xC0\x99\xA5\xEC\xBCY\R\xB7\xEC\xFD|\x9F*υR==\xFFh\xC8b\xB2Kڠq\xEF&\xBB\x87\xAA\xD3\xEC\xD4\xFB\x92Cw\xDEo\x9B\xD9\xF1\xD9r>4\xEB\xC2\xB3~MH\xB4C\xC0\xD9\xC5V?\xE8\xC2@[J\xB3;{,s\x9F\\x86\x86K\x90j\xBB0\x9B_\xF5\xFC\x9A\x85*)'l\x95I\xBDp\x9E,|NB\xB9%(\xB8\x9A\xBD\xED\xEC)|Ω\x80Rwe[0\xEA\xCA\xD9\xBD\xA5\xAAb+G\xB3\x84\xB2+\xDD\xC17лLlu3\x86\x852%\xABuGKK\xA98\x9C\xA0c[Av5\xAB\xC8\xF0\xB2깶R\xACF'\xE8!\xD6z\xB2\x9A\xA9Y\x9D\x8B\xAB\xC9e\xB8\xA8\xF2\xBD\xB8@\xA0\xF3\xF0\xD0\xDA\xE1geV\xA4\x80\xC2\xD5g0\xA6n\xE3\xC9\xC7m#n;5\xCDEqj)܍\xDC.\xE2b\xD4\xDCT7\xB6\xAEŃ\xB3\x88KQ\xB3\xA1h\xEEƕ\xC2\xDD\xEC\xC9\xDD\xE2R.\x8A\xAB\xFC?\xB8C\xC4\xA6\xA6\xB5\xE8bǗ\xC2m\xF4,\xF6qG\xA9i+݄R\xB8vOtlj{\x85\x9AME\xA3\xAB*\x85\xBB\xC5\xDD \xE2NR\xD3Q7\xB1\xAEӃ;K\xDC'\xD4\xF0Ӣ\xC8b'\x95\xC2݊ۆ\xE1\xBE \xEE5[rv\x9D\x8BS\xDD\xE8&g0\xC5KTsD[=\xD7\xF6k\x8C\xC17\xD4l+\xBASK\xB8ݳ\xDF1\xC0\xEFY\xEAn\xC7\xB7\x9Cz\xC5 pBBi
+\xADeZ'?\xCDw\xBD\x8B\xD6{h\xE5g\xA3\x876Q\x8B\x9BZi\xB3\x87n\xA0%.\xDA"4[\xF9AT\xDF\xE6\xA2\xED\x84\x85v\x87\xD0\xEE\xA06\xED\x941\xA8R\xBB\x8Bntc\x90v\xC9\xCFn\xF9 \xB9\x90T\xE9&7ڣR\x87J\x9D*u@\xD0B\x86\xA1'\xDAb\xE1dRO\xB4
+\xEA\x917\xC6C\xE1TJO\xB4\xC7\xF4!\xDDH\xE6\xEE\xEC(\xB1\xDA\xD6}\xB0xu\xFE\xEE\x9ER\xC4\xD5\xC5KڮD<=l?\xAA\xB4\x97\xE0펧\xFD\xC6hLO\xE6
@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-10-23 13:03:50
|
Revision: 4214
http://sourceforge.net/p/openlcb/svn/4214
Author: bracz
Date: 2016-10-23 13:03:48 +0000 (Sun, 23 Oct 2016)
Log Message:
-----------
Add rule to convert files to txt.
Modified Paths:
--------------
trunk/specs/Makefile
Modified: trunk/specs/Makefile
===================================================================
--- trunk/specs/Makefile 2016-07-15 05:09:56 UTC (rev 4213)
+++ trunk/specs/Makefile 2016-10-23 13:03:48 UTC (rev 4214)
@@ -43,7 +43,7 @@
pdf: $(OUTPUT)
.SUFFIXES:
-.SUFFIXES: .odt .ods .pdf
+.SUFFIXES: .odt .ods .pdf .txt
# Spreadsheets
.ods.pdf:
@@ -53,6 +53,9 @@
.odt.pdf:
$(OFFICE) --headless --convert-to pdf $<
+.odt.txt:
+ odt2txt $< > $@
+
.PHONY: veryclean
veryclean: clean
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-15 05:09:59
|
Revision: 4213
http://sourceforge.net/p/openlcb/svn/4213
Author: bracz
Date: 2016-07-15 05:09:56 +0000 (Fri, 15 Jul 2016)
Log Message:
-----------
Updates to 0.7 version of the library, regenerates JAR files.
Modified Paths:
--------------
trunk/prototypes/java/manifest
trunk/prototypes/java/openlcb-demo.jar
trunk/prototypes/java/openlcb.jar
trunk/prototypes/java/src/org/openlcb/Version.java
Modified: trunk/prototypes/java/manifest
===================================================================
--- trunk/prototypes/java/manifest 2016-07-14 17:31:36 UTC (rev 4212)
+++ trunk/prototypes/java/manifest 2016-07-15 05:09:56 UTC (rev 4213)
@@ -4,9 +4,9 @@
Name: org.openlcb
Specification-Title: OpenLCB
-Specification-Version: 0.6.4
+Specification-Version: 0.7.4
Specification-Vendor: OpenLCB group
Package-Title: openlcb
-Package-Version: 0.6.5
+Package-Version: 0.7.5
Package-Vendor: OpenLCB group
Modified: trunk/prototypes/java/openlcb-demo.jar
===================================================================
(Binary files differ)
Modified: trunk/prototypes/java/openlcb.jar
===================================================================
(Binary files differ)
Modified: trunk/prototypes/java/src/org/openlcb/Version.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/Version.java 2016-07-14 17:31:36 UTC (rev 4212)
+++ trunk/prototypes/java/src/org/openlcb/Version.java 2016-07-15 05:09:56 UTC (rev 4213)
@@ -26,7 +26,7 @@
* Minor number changes with change that
* effects interoperability
*/
- static final public int minor = 6;
+ static final public int minor = 7;
/* Specification modifier - updated periodically
*/
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:31:39
|
Revision: 4212
http://sourceforge.net/p/openlcb/svn/4212
Author: bracz
Date: 2016-07-14 17:31:36 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Merge branch 'debug' of bracz.zrh:train/openlcb/gitsvn/svn into debug
# Conflicts:
# src/org/openlcb/LoaderClient.java
# src/org/openlcb/StreamDataCompleteMessage.java
# src/org/openlcb/implementations/MemoryConfigurationService.java
# test/org/openlcb/ProtocolIdentificationTest.java
# test/org/openlcb/cdi/jdom/CdiMemConfigReaderTest.java
# test/org/openlcb/implementations/DatagramMeteringBufferTest.java
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/DatagramAcknowledgedMessage.java
trunk/prototypes/java/src/org/openlcb/LoaderClient.java
trunk/prototypes/java/src/org/openlcb/OlcbInterface.java
trunk/prototypes/java/src/org/openlcb/can/GridConnect.java
trunk/prototypes/java/src/org/openlcb/can/MessageBuilder.java
trunk/prototypes/java/src/org/openlcb/can/OpenLcbCanFrame.java
trunk/prototypes/java/src/org/openlcb/can/impl/GridConnectInput.java
trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java
trunk/prototypes/java/src/org/openlcb/cdi/jdom/CdiMemConfigReader.java
trunk/prototypes/java/src/org/openlcb/implementations/DatagramMeteringBuffer.java
trunk/prototypes/java/src/org/openlcb/implementations/DatagramService.java
trunk/prototypes/java/src/org/openlcb/implementations/DatagramUtils.java
trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigSpaceRetriever.java
trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigurationService.java
trunk/prototypes/java/src/org/openlcb/swing/memconfig/MemConfigDescriptionPane.java
trunk/prototypes/java/src/org/openlcb/swing/memconfig/MemConfigReadWritePane.java
trunk/prototypes/java/test/org/openlcb/FakeConnection.java
trunk/prototypes/java/test/org/openlcb/InterfaceTestBase.java
trunk/prototypes/java/test/org/openlcb/LoaderClientTest.java
trunk/prototypes/java/test/org/openlcb/can/GridConnectTest.java
trunk/prototypes/java/test/org/openlcb/can/MessageBuilderTest.java
trunk/prototypes/java/test/org/openlcb/cdi/jdom/CdiMemConfigReaderTest.java
trunk/prototypes/java/test/org/openlcb/implementations/DatagramMeteringBufferTest.java
trunk/prototypes/java/test/org/openlcb/implementations/DatagramServiceTest.java
trunk/prototypes/java/test/org/openlcb/implementations/MemoryConfigurationServiceTest.java
trunk/prototypes/java/test/org/openlcb/implementations/StreamTransmitterTest.java
trunk/prototypes/java/test/org/openlcb/swing/memconfig/MemConfigDescriptionPaneTest.java
trunk/prototypes/java/test/org/openlcb/swing/memconfig/MemConfigReadWritePaneTest.java
trunk/prototypes/java/test/tools/cansim/CanFrame.java
Added Paths:
-----------
trunk/prototypes/java/src/org/openlcb/FailureCallback.java
trunk/prototypes/java/src/org/openlcb/NoReturnCallback.java
trunk/prototypes/java/test/org/openlcb/implementations/DatagramUtilsTest.java
trunk/prototypes/java/test/org/openlcb/implementations/MemoryConfigurationServiceInterfaceTest.java
Modified: trunk/prototypes/java/src/org/openlcb/DatagramAcknowledgedMessage.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/DatagramAcknowledgedMessage.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/DatagramAcknowledgedMessage.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -16,8 +16,18 @@
public DatagramAcknowledgedMessage(NodeID source, NodeID dest) {
super(source, dest);
+ flags = 0;
}
-
+
+ public DatagramAcknowledgedMessage(NodeID source, NodeID dest, int flags) {
+ super(source, dest);
+ this.flags = flags;
+ }
+
+ int flags;
+
+ public int getFlags() { return flags; }
+
/**
* Implement message-type-specific
* processing when this message
@@ -35,7 +45,8 @@
if (o == null) return false;
if (! (o instanceof DatagramAcknowledgedMessage))
return false;
- return super.equals(o);
+ if (!super.equals(o)) return false;
+ return (flags == ((DatagramAcknowledgedMessage)o).flags);
}
@Override
Added: trunk/prototypes/java/src/org/openlcb/FailureCallback.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/FailureCallback.java (rev 0)
+++ trunk/prototypes/java/src/org/openlcb/FailureCallback.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -0,0 +1,13 @@
+package org.openlcb;
+
+/**
+ * Created by bracz on 5/2/16.
+ */
+public interface FailureCallback {
+ /**
+ * Called when the requested operation encounters an error. Temporary errors are usually
+ * internally re-tried.
+ * @param errorCode OpenLCB error code (16-bit)
+ */
+ void handleFailure(int errorCode);
+}
Modified: trunk/prototypes/java/src/org/openlcb/LoaderClient.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/LoaderClient.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/LoaderClient.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -10,6 +10,7 @@
import org.openlcb.StreamInitiateReplyMessage;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.logging.Logger;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
@@ -25,6 +26,7 @@
//#include "LoaderClient.hpp"
public class LoaderClient extends MessageDecoder {
+ static Logger logger = Logger.getLogger("LoaderClient");
enum State { IDLE, ABORT, FREEZE, INITCOMPL, PIP, PIPREPLY, SETUPSTREAM, STREAM, STREAMDATA, DG, UNFREEEZE, SUCCESS, FAIL };
Connection connection;
Connection fromDownstream;
@@ -104,18 +106,22 @@
dcs.sendData(
new DatagramService.DatagramServiceTransmitMemo(dest, new int[]{0x20, 0xA1, space}) {
@Override
- public void handleReply(int code) {
- // System.out.println("lFreeze handleReply: "+code);
- //if((state==State.FREEZE)) {
- // if(code==DG_OK) { state = State.INITCOMPL; } // DG ok
- // else if(code==DG_FAIL) { state = State.INITCOMPL; } // DG timed out, but ok timeouts
- // else state = State.FAIL; // Apparently this node doesn't handle DGs
- //}
- state = State.PIP;
- sendPipRequest();
- startTimeout(3000);
- //System.out.println("lhandleFreeze Reply Exit: "+state);
+ public void handleSuccess(int flags) {
+ if(state==State.FREEZE) {
+ state = State.PIP;
+ sendPipRequest();
+ startTimeout(3000);
+ } else {
+ // ignore; maybe a late timeout callback.
+ }
}
+
+ @Override
+ public void handleFailure(int errorCode) {
+ // It is actually OK to have this fail because the remote node may have
+ // rebooted.
+ handleSuccess(0);
+ }
});
}
Timer timer;
@@ -199,12 +205,18 @@
bufferSize = 64;
state = State.STREAM;
- mcs.request(new McsWriteStreamMemo(dest, space, address) {
+ mcs.request(new McsWriteStreamMemo(dest, space, address, 4) {
@Override
- public void handleWriteReply(int code) {
- // System.out.println("Reply mcs.request McsWriteStreamMemo handleWriteReply: ");
+ public void handleSuccess() {
sendStream();
}
+
+ @Override
+ public void handleFailure(String where, int errorCode) {
+ state = State.FAIL;
+ logger.warning("Failed to setup stream at " + where + ": error 0x" + Integer
+ .toHexString(errorCode));
+ }
});
}
@@ -281,14 +293,18 @@
for (int i=0; i<size; i++) data[i] = content[nextIndex+i];
//System.out.println("lsendDGNext mcs.request(new McsWriteMemo: "+state);
- mcs.request(new McsWriteMemo(dest, space, nextIndex, data) {
+ mcs.requestWrite(dest, space, nextIndex, data, new McsWriteHandler() {
@Override
- public void handleWriteReply(int code) {
- //System.out.println("Reply mcs.request McsWriteMemo handleWriteReply: "+code);
+ public void handleFailure(int errorCode) {
+ sendDGNext();
+ }
+
+ @Override
+ public void handleSuccess() {
if(nextIndex<content.length) sendDGNext();
else {
+ state = State.SUCCESS;
sendUnfreeze();
- state = State.SUCCESS;
}
}
});
@@ -311,19 +327,22 @@
void sendUnfreeze() {
// System.out.println("lsendUnfreeze");
dcs.sendData(new DatagramService.DatagramServiceTransmitMemo(dest, new int[]{0x20, 0xA0, space}) {
+
@Override
- public void handleReply(int code) {
- System.out.println("lc-sendUnfreeze reply: "+state);
- if(state == State.SUCCESS) {
- // if(state == State.SUCCESS && msg.getSourceNodeID().equals(dest)) {
- feedback.onProgress((float)100.0);
- feedback.onDone(0,"Download Completed");
- }
- else {
- //feedback.onProgress((float)0.0);
+ public void handleSuccess(int flags) {
+ if (state == State.SUCCESS) {
+ feedback.onProgress((float) 100.0);
+ feedback.onDone(0, "Download Completed");
+ } else {
feedback.onDone(0,"Download Failed - "+errorString);
}
}
+
+ @Override
+ public void handleFailure(int errorCode) {
+ feedback.onDone(0,"Download Failed in UnFreeze - 0x"+Integer.toHexString(errorCode));
+ }
+
});
}
}
\ No newline at end of file
Added: trunk/prototypes/java/src/org/openlcb/NoReturnCallback.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/NoReturnCallback.java (rev 0)
+++ trunk/prototypes/java/src/org/openlcb/NoReturnCallback.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -0,0 +1,14 @@
+package org.openlcb;
+
+/**
+ * Represents the callback for an operation that returns nothing. THis will be shared by a number
+ * of different services.
+ *
+ * Created by bracz on 5/2/16.
+ */
+public interface NoReturnCallback extends FailureCallback {
+ /**
+ * Called when the requested operation completes successfully.
+ */
+ void handleSuccess();
+}
Modified: trunk/prototypes/java/src/org/openlcb/OlcbInterface.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/OlcbInterface.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/OlcbInterface.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -115,6 +115,14 @@
return mcs;
}
+ /**
+ * Blocks the current thread until the outgoing messages are all sent out. Useful for testing.
+ */
+ public void flushSendQueue() {
+ dmb.waitForSendQueue();
+ queuedOutputConnection.waitForSendQueue();
+ }
+
public void registerMessageListener(Connection c) {
inputConnection.registerMessageListener(c);
}
@@ -198,6 +206,7 @@
private class QueuedOutputConnection implements Connection {
private final Connection realOutput;
private final BlockingQueue<Message> outputQueue = new LinkedBlockingQueue<>();
+ private int pendingCount = 0;
QueuedOutputConnection(Connection realOutput) {
this.realOutput = realOutput;
@@ -205,6 +214,9 @@
@Override
public void put(Message msg, Connection sender) {
+ synchronized(this) {
+ pendingCount++;
+ }
outputQueue.add(msg);
}
@@ -213,6 +225,17 @@
internalOutputConnection.registerStartNotification(c);
}
+ public void waitForSendQueue() {
+ while(true) {
+ synchronized (this) {
+ if (pendingCount == 0) return;
+ }
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {}
+ }
+ }
+
/**
* Never returns.
*/
@@ -221,6 +244,9 @@
try {
Message m = outputQueue.take();
realOutput.put(m, null);
+ synchronized(this) {
+ pendingCount--;
+ }
} catch (InterruptedException e) {
continue;
}
Modified: trunk/prototypes/java/src/org/openlcb/can/GridConnect.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/can/GridConnect.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/can/GridConnect.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -1,5 +1,7 @@
package org.openlcb.can;
+import org.openlcb.implementations.DatagramUtils;
+
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
@@ -198,7 +200,7 @@
@Override
public int getElement(int n) {
- return data[n];
+ return DatagramUtils.byteToInt(data[n]);
}
@Override
Modified: trunk/prototypes/java/src/org/openlcb/can/MessageBuilder.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/can/MessageBuilder.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/can/MessageBuilder.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -4,6 +4,7 @@
import java.util.HashMap;
import java.util.List;
import org.openlcb.*;
+import org.openlcb.implementations.DatagramUtils;
import org.openlcb.messages.TractionControlReplyMessage;
import org.openlcb.messages.TractionControlRequestMessage;
import org.openlcb.messages.TractionProxyReplyMessage;
@@ -250,9 +251,13 @@
case SimpleNodeIdentInfoReply:
retlist.add(new SimpleNodeIdentInfoReplyMessage(source, dest, content));
return retlist;
-
- case DatagramReceivedOK:
- retlist.add(new DatagramAcknowledgedMessage(source,dest));
+ case DatagramReceivedOK:
+ if (content != null && content.length > 0) {
+ retlist.add(new DatagramAcknowledgedMessage(source, dest, DatagramUtils
+ .byteToInt(content[0])));
+ } else {
+ retlist.add(new DatagramAcknowledgedMessage(source, dest));
+ }
return retlist;
case DatagramRejected:
retlist.add(new DatagramRejectedMessage(source,dest,(int)f.dataAsLong()));
@@ -649,8 +654,11 @@
public void handleDatagramAcknowledged(DatagramAcknowledgedMessage msg, Connection sender){
OpenLcbCanFrame f = new OpenLcbCanFrame(0x00);
f.setOpenLcbMTI(MessageTypeIdentifier.DatagramReceivedOK.mti());
+ f.setSourceAlias(map.getAlias(msg.getSourceNodeID()));
+ if (msg.getFlags() != 0) {
+ f.setData(new byte[]{0, 0, (byte)msg.getFlags()});
+ }
f.setDestAlias(map.getAlias(msg.getDestNodeID()));
- f.setSourceAlias(map.getAlias(msg.getSourceNodeID()));
retlist.add(f);
}
/**
@@ -679,7 +687,7 @@
OpenLcbCanFrame f = new OpenLcbCanFrame(0x00);
f.setOpenLcbMTI(MessageTypeIdentifier.StreamInitiateReply.mti());
// dest(2), maxBufferSize(2), flags(2),sourceStream, destinationStream
- f.setData(new byte[]{ (byte)0, (byte)0, 0, 64, msg.getSourceStreamID(), msg.getDestinationStreamID() } );
+ f.setData(new byte[]{(byte) 0, (byte) 0, 0, 64, msg.getSourceStreamID(), msg.getDestinationStreamID() } );
f.setDestAlias(map.getAlias(msg.getDestNodeID()));
f.setSourceAlias(map.getAlias(msg.getSourceNodeID()));
retlist.add(f);
Modified: trunk/prototypes/java/src/org/openlcb/can/OpenLcbCanFrame.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/can/OpenLcbCanFrame.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/can/OpenLcbCanFrame.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -1,6 +1,7 @@
package org.openlcb.can;
import org.openlcb.*;
+import org.openlcb.implementations.DatagramUtils;
import javax.annotation.Nullable;
@@ -68,7 +69,7 @@
public boolean isRtr() { return false; }
public int getNumDataElements() { return length; }
- public int getElement(int n) { return data[n]; }
+ public int getElement(int n) { return DatagramUtils.byteToInt(data[n]); }
// bit 1
static final int MASK_FRAME_TYPE = 0x08000000;
Modified: trunk/prototypes/java/src/org/openlcb/can/impl/GridConnectInput.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/can/impl/GridConnectInput.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/can/impl/GridConnectInput.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -2,6 +2,7 @@
import org.openlcb.can.CanFrame;
import org.openlcb.can.CanFrameListener;
+import org.openlcb.implementations.DatagramUtils;
import java.io.BufferedReader;
import java.io.IOException;
@@ -162,7 +163,7 @@
@Override
public int getElement(int n) {
- return data[n];
+ return DatagramUtils.byteToInt(data[n]);
}
@Override
Modified: trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -195,13 +195,17 @@
count = 64;
}
final int fcount = count;
- connection.getMemoryConfigurationService().request(
- new MemoryConfigurationService.McsReadMemo(remoteNodeID, space,
- currentRangeNextOffset, count) {
+ connection.getMemoryConfigurationService().requestRead(remoteNodeID, space,
+ currentRangeNextOffset, count,
+ new MemoryConfigurationService.McsReadHandler() {
@Override
- public void
- handleWriteReply(int code) {
- super.handleWriteReply(code);
+ public void handleFailure(int code) {
+ logger.warning("Error reading memory space cache: dest " + remoteNodeID +
+ "space" + space + " offset " + currentRangeNextOffset + " error " +
+ "0x" + Integer.toHexString(code));
+ // ignore and continue reading other stuff.
+ currentRangeNextOffset += fcount;
+ loadRange();
}
@Override
@@ -217,7 +221,7 @@
" address= " + address + " length=" + data.length + " " +
"expected" +
" address=" + currentRangeNextOffset + " expectedspace=" +
- MemorySpaceCache.this.space + " expectedcount=" + this.count);
+ MemorySpaceCache.this.space + " expectedcount=" + fcount);
}
if (data.length == 0) {
logger.warning(String.format("Datagram read returned 0 bytes. " +
@@ -235,8 +239,7 @@
}
loadRange();
}
- }
- );
+ });
}
private Map.Entry<Range, byte[]> getCacheForRange(long offset, int len) {
@@ -267,19 +270,21 @@
}
logger.finer("Writing to space " + space + " offset 0x" + Long.toHexString(offset) +
" payload length " + data.length);
- connection.getMemoryConfigurationService().request(
- new MemoryConfigurationService.McsWriteMemo(remoteNodeID, space, offset, data) {
+ connection.getMemoryConfigurationService().requestWrite(remoteNodeID, space, offset,
+ data, new MemoryConfigurationService.McsWriteHandler() {
@Override
- public void handleWriteReply(int code) {
- if (code != 0) {
- logger.warning(String.format("Write failed (space %d address %d): " +
- "%04x", space, offset, code));
- } else {
- logger.finer(String.format("Write complete (space %d address %d): " +
- "%04x", space, offset, code));
- }
+ public void handleFailure(int errorCode) {
+ logger.warning(String.format("Write failed (space %d address %d): 0x" +
+ "%04x", space, offset, errorCode));
cdiEntry.fireWriteComplete();
}
+
+ @Override
+ public void handleSuccess() {
+ logger.finer(String.format("Write complete (space %d address %d).",
+ space, offset));
+ cdiEntry.fireWriteComplete();
+ }
}
);
// @TODO: 4/2/16 Handle write errors and report to user somehow.
Modified: trunk/prototypes/java/src/org/openlcb/cdi/jdom/CdiMemConfigReader.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/cdi/jdom/CdiMemConfigReader.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/cdi/jdom/CdiMemConfigReader.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -58,9 +58,16 @@
if (retval != null) {
retval.progressNotify(buf.length(), -1);
}
- MemoryConfigurationService.McsReadMemo memo =
- new MemoryConfigurationService.McsReadMemo(node, space, nextAddress, LENGTH) {
- public void handleReadData(NodeID dest, int space, long address, byte[] data) {
+ MemoryConfigurationService.McsReadHandler memo =
+ new MemoryConfigurationService.McsReadHandler() {
+ @Override
+ public void handleFailure(int code) {
+ done();
+ // TODO: 5/2/16 proxy error messages to the caller.
+ // don't do next request
+ }
+
+ public void handleReadData(NodeID dest, int space, long address, byte[] data) {
// handle return data, checking for null in string or zero-length reply
if (data.length == 0) {
done();
@@ -78,7 +85,7 @@
nextRequest();
}
};
- service.request(memo);
+ service.requestRead(node, space, nextAddress, LENGTH, memo);
}
private void done() {
Modified: trunk/prototypes/java/src/org/openlcb/implementations/DatagramMeteringBuffer.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/implementations/DatagramMeteringBuffer.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/implementations/DatagramMeteringBuffer.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -1,6 +1,5 @@
package org.openlcb.implementations;
-import edu.umd.cs.findbugs.annotations.SuppressWarnings;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.Timer;
@@ -34,7 +33,7 @@
public DatagramMeteringBuffer(Connection toDownstream) {
this.toDownstream = toDownstream;
- new Thread(new Consumer(queue)).start();
+ datagramComplete();
fromDownstream = new ReplyHandler();
}
@@ -42,7 +41,8 @@
Connection toDownstream;
Connection fromDownstream;
MessageMemo currentMemo;
-
+ int timeoutMillis = TIMEOUT;
+
/**
* This is where e.g. replies from the OpenLCB
* network should be returned to.
@@ -52,18 +52,43 @@
}
BlockingQueue<MessageMemo> queue = new LinkedBlockingQueue<MessageMemo>();
-
+ int pendingEntries = 0;
+
+ public void setTimeout(int timeoutMillis) {
+ this.timeoutMillis = timeoutMillis;
+ }
+
+ public void waitForSendQueue() {
+ while(true) {
+ synchronized (this) {
+ if (pendingEntries == 0) return;
+ }
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {}
+ }
+ }
+
/**
* Accept a datagram message to be sent
*/
@Override
public void put(Message msg, Connection toUpstream) {
- if (msg instanceof DatagramMessage)
- queue.add(new MessageMemo((DatagramMessage)msg, toUpstream, toDownstream));
- else
+ if (msg instanceof DatagramMessage) {
+ synchronized (this) {
+ ++pendingEntries;
+ }
+ queue.add(new MessageMemo((DatagramMessage) msg, toUpstream, toDownstream));
+ } else {
toDownstream.put(msg, fromDownstream);
+ }
}
-
+
+ private void datagramComplete() {
+ currentMemo = null;
+ new Thread(new Consumer(queue)).start();
+ }
+
class ReplyHandler extends AbstractConnection {
/*
* Find the current handler and have it handle it
@@ -106,8 +131,7 @@
timerExpired();
}
};
- timer.schedule(task, TIMEOUT);
-
+ timer.schedule(task, timeoutMillis);
}
void endTimeout() {
if (timer != null) timer.cancel();
@@ -130,16 +154,12 @@
public void handleDatagramAcknowledged(DatagramAcknowledgedMessage msg, Connection sender){
// check if this is from right source & to us
if ( ! (msg.getDestNodeID()!=null && msg.getSourceNodeID()!=null && msg.getDestNodeID().equals(message.getSourceNodeID()) && message.getDestNodeID().equals(msg.getSourceNodeID()) ) ) {
- // not for us, just forward
- //toUpstream.put(msg, toUpstream);
+ // not for us
return;
}
endTimeout();
- // forward message upstream
- //toUpstream.put(msg, toUpstream);
-
- // and allow sending another
- new Thread(new Consumer(queue)).start();
+ // allow sending another
+ datagramComplete();
}
/**
@@ -149,8 +169,7 @@
public void handleDatagramRejected(DatagramRejectedMessage msg, Connection sender) {
// check if this is from right source & to us
if ( ! (msg.getDestNodeID()!=null && msg.getSourceNodeID()!=null && msg.getDestNodeID().equals(message.getSourceNodeID()) && message.getDestNodeID().equals(msg.getSourceNodeID()) ) ) {
- // not for us, just forward
- //toUpstream.put(msg, toUpstream);
+ // not for us
return;
}
endTimeout();
@@ -158,21 +177,22 @@
if (msg.canResend()) {
forwardDownstream();
} else {
- // forward upstream to originator and let them sort it out
- //toUpstream.put(msg, toUpstream);
- // and allow sending another
- new Thread(new Consumer(queue)).start();
+ // allow sending another
+ datagramComplete();
}
}
}
- static class Consumer implements Runnable {
+ class Consumer implements Runnable {
private final BlockingQueue<MessageMemo> queue;
Consumer(BlockingQueue<MessageMemo> q) { queue = q; }
@Override
public void run() {
try {
consume(queue.take());
+ synchronized (DatagramMeteringBuffer.this) {
+ pendingEntries--;
+ }
} catch (InterruptedException ex) {}
// and exits. Another has to be started with this item is done.
}
Modified: trunk/prototypes/java/src/org/openlcb/implementations/DatagramService.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/implementations/DatagramService.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/implementations/DatagramService.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -38,7 +38,8 @@
this.downstream = downstream;
}
-
+
+ public static final int FLAG_REPLY_PENDING = 0x80;
static final int DEFAULT_ERROR_CODE = 0x1000;
NodeID here;
Connection downstream;
@@ -56,7 +57,13 @@
* Send data to layout
*/
public void sendData(NodeID dest, int[] data){
- DatagramServiceTransmitMemo memo = new DatagramServiceTransmitMemo(dest, data);
+ DatagramServiceTransmitMemo memo = new DatagramServiceTransmitMemo(dest, data) {
+ @Override
+ public void handleSuccess(int flags) {}
+
+ @Override
+ public void handleFailure(int errorCode) {}
+ };
xmtMemo = memo;
Message m = new DatagramMessage(here, memo.dest, memo.data);
downstream.put(m, this);
@@ -97,9 +104,11 @@
@Override
public void handleDatagramRejected(DatagramRejectedMessage msg, Connection sender){
if (xmtMemo != null && msg.getDestNodeID().equals(here) && xmtMemo.dest.equals(msg.getSourceNodeID()) ) {
- xmtMemo.handleReply(msg.getCode());
+ if (msg.canResend()) return;
+ DatagramServiceTransmitMemo temp = xmtMemo;
+ xmtMemo = null;
+ temp.handleFailure(msg.getCode());
}
- xmtMemo = null;
}
/**
@@ -110,7 +119,7 @@
if (xmtMemo != null && msg.getDestNodeID().equals(here) && xmtMemo.dest.equals(msg.getSourceNodeID()) ) {
DatagramServiceTransmitMemo temp = xmtMemo;
xmtMemo = null;
- temp.handleReply(0);
+ temp.handleSuccess(msg.getFlags());
}
}
@@ -219,7 +228,7 @@
// TODO are these really immutable, given that subclass will inherit and change them?
@Immutable
@ThreadSafe
- static public class DatagramServiceTransmitMemo {
+ static public abstract class DatagramServiceTransmitMemo {
public DatagramServiceTransmitMemo(NodeID dest, int[] data) {
this.data = data;
this.dest = dest;
@@ -254,12 +263,19 @@
public int hashCode() { return this.data.length+this.data[0]+dest.hashCode(); }
/**
- * Overload this to for notification of response
- * @param code 0 for OK, non-zero for error reply
+ * Notifies that the datagram was accepted by the destination.
+ * @param flags are the 8-bit flags returned by the destination; bit 0x80 for reply
+ * pending.
*/
- public void handleReply(int code) {
- }
+ public abstract void handleSuccess(int flags);
+ /**
+ * Notifies that the datagram send has failed. Retryable errors are internally retried
+ * and not reported here.
+ * @param errorCode the 16-bit OpenLCB error code.
+ */
+ public abstract void handleFailure(int errorCode);
+
}
}
Modified: trunk/prototypes/java/src/org/openlcb/implementations/DatagramUtils.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/implementations/DatagramUtils.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/implementations/DatagramUtils.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -23,4 +23,36 @@
payload[offset++] = (int) ((value >> 8) & 0xff);
payload[offset++] = (int) (value & 0xff);
}
+
+ static int parseErrorCode(int[] payload, int offset) {
+ int retval = payload[offset++];
+ retval <<= 8;
+ retval |= payload[offset] & 0xff;
+ return retval;
+ }
+
+ static void renderErrorCode(int[] payload, int offset, int errorCode) {
+ payload[offset++] = (errorCode >> 8) & 0xff;
+ payload[offset++] = errorCode & 0xff;
+ }
+
+ public static int byteToInt(byte b) {
+ return b < 0 ? ((int)b) + 256 : b;
+ }
+
+ static void byteToIntArray(int[] dst, int iDst, byte[] src, int iSrc, int len) {
+ for (int i = 0; i < len; ++i) {
+ dst[i+iDst] = byteToInt(src[i+iSrc]);
+ }
+ }
+
+ static byte intToByte(int b) {
+ return (byte) b;
+ }
+
+ static void intToByteArray(byte[] dst, int iDst, int[] src, int iSrc, int len) {
+ for (int i = 0; i < len; ++i) {
+ dst[i+iDst] = intToByte(src[i + iSrc]);
+ }
+ }
}
Modified: trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigSpaceRetriever.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigSpaceRetriever.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigSpaceRetriever.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -29,8 +29,13 @@
}
void nextRequest() {
- MemoryConfigurationService.McsReadMemo memo =
- new MemoryConfigurationService.McsReadMemo(node, space, nextAddress, LENGTH) {
+ MemoryConfigurationService.McsReadHandler memo =
+ new MemoryConfigurationService.McsReadHandler() {
+ @Override
+ public void handleFailure(int code) {
+ cb.onFailure(code);
+ }
+
public void handleReadData(NodeID dest, int space, long address, byte[] data) {
// handle return data, checking for null in string or zero-length reply
if (data.length == 0) {
@@ -49,7 +54,7 @@
nextRequest();
}
};
- service.request(memo);
+ service.requestRead(node, space, nextAddress, LENGTH, memo);
}
private void done() {
Modified: trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigurationService.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigurationService.java 2016-07-14 17:31:15 UTC (rev 4211)
+++ trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigurationService.java 2016-07-14 17:31:36 UTC (rev 4212)
@@ -2,13 +2,21 @@
import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;
+
+import org.openlcb.FailureCallback;
+import org.openlcb.NoReturnCallback;
import org.openlcb.NodeID;
+import org.openlcb.Utilities;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Stack;
import java.util.logging.Logger;
+import javax.xml.crypto.Data;
+
/**
* Service for reading and writing via the Memory Configuration protocol
* <p>
@@ -33,7 +41,14 @@
public static final int SPACE_TRACTION_FDI = 0xFA;
public static final int SPACE_TRACTION_FUNCTION = 0xF9;
+ private static final int SUBCMD_REPLY = 0x10;
+ private static final int SUBCMD_ERROR = 0x08;
+ private static final int SUBCMD_WRITE = 0x00;
+ private static final int SUBCMD_WRITE_STREAM = 0x20;
+ private static final int SUBCMD_READ = 0x40;
+ private static final int SUBCMD_READ_STREAM = 0x60;
+
/**
* @param downstream Connection in the direction of the layout
*/
@@ -56,34 +71,6 @@
service) {
//log System.out.println("OLCB: handleData");
service.acceptData(0);
- if (readMemo != null) {
- // figure out address space uses byte?
- boolean spaceByte = ((data[1] & 0x03) == 0);
- byte[] content;
- if ((data[1] & 0x08) == 0) {
- // normal read reply
- content = new byte[data.length - 6 + (spaceByte ? -1 : 0)];
- for (int i = 0; i < content.length; i++)
- content[i] = (byte) data[i + 6 + (spaceByte ? 1 : 0)];
- } else {
- // error read reply, return zero length
- content = new byte[0];
- }
- long retAddress = DatagramUtils.parseLong(data, 2);
- int retSpace = spaceByte ? data[6] : (0xFC + (data[1] & 0x03));
- McsReadMemo memo;
- synchronized (this) {
- memo = readMemo;
- readMemo = null;
- }
- memo.handleReadData(dest, retSpace, retAddress, content);
- synchronized (this) {
- if (readMemo == null && !pendingReads.isEmpty()) {
- readMemo = pendingReads.pop();
- sendRead();
- }
- }
- }
if (addrSpaceMemo != null) {
// doesn't handle decode of desc string, but should
int space = data[2] & 0xFF;
@@ -98,6 +85,7 @@
McsAddrSpaceMemo memo = addrSpaceMemo;
addrSpaceMemo = null;
memo.handleAddrSpaceData(dest, space, highAddress, lowAddress, flags, "");
+ return;
}
// config memo may trigger address space read, so do second
if (configMemo != null) {
@@ -109,7 +97,9 @@
McsConfigMemo memo = configMemo;
configMemo = null;
memo.handleConfigData(dest, commands, options, highSpace, lowSpace, "");
+ return;
}
+ /*
if (writeMemo != null && ((data[1] & 0xF0) == 0x10)) {
McsWriteMemo memo = writeMemo;
long retAddress = DatagramUtils.parseLong(data, 2);
@@ -128,28 +118,60 @@
code = (data[codeOffset] << 8) + data[codeOffset + 1];
}
memo.handleWriteReply(code);
- }
- // dph
-
+ }*/
if (writeStreamMemo != null) {
- // receive destinationStreamID
// figure out address space uses byte?
boolean spaceByte = ((data[1] & 0x03) == 0);
- byte[] content;
+ int spaceOfs = spaceByte ? 1 : 0;
+ McsWriteStreamMemo memo = writeStreamMemo;
+ writeStreamMemo = null;
+ // TODO: compare the incoming parameters to the information in the memo.
if ((data[1] & 0x08) == 0) {
- // normal read reply
- content = new byte[data.length - 6 + (spaceByte ? -1 : 0)];
- for (int i = 0; i < content.length; i++)
- content[i] = (byte) data[i + 6 + (spaceByte ? 1 : 0)];
+ // OK
+ memo.handleSuccess();
} else {
- // error read reply, return zero length
- content = new byte[0];
+ // error
+ memo.handleFailure("WriteStreamReply", DatagramUtils.parseErrorCode(data,
+ 6 + spaceOfs));
}
- McsWriteStreamMemo memo = writeStreamMemo;
- writeStreamMemo = null;
- //memo.handleWriteStreamData(dest, memo.space, memo.address, content);
+ return;
}
-
+ int requestCode = getRequestTypeFromResponseType(data[1]);
+ RequestWithReplyDatagram memo = null;
+ McsRequestMemo rqMemo = null;
+ synchronized (this) {
+ if (pendingRequests.containsKey(requestCode)) {
+ rqMemo = pendingRequests.get(requestCode);
+ if (!rqMemo.getDest().equals(dest)) {
+ logger.warning("Spurious MemCfg response datagram " + Utilities
+ .toHexSpaceString(data)+": expected source " + rqMemo.getDest()
+ + " actual source " + dest);
+ return;
+ }
+ if (!(rqMemo instanceof RequestWithReplyDatagram)) {
+ logger.warning("Spurious MemCfg response datagram " + Utilities.toHexSpaceString(data)+
+ ": the request memo does not support response datagrams. " +
+ "Memo: " + rqMemo);
+ return;
+ }
+ memo = (RequestWithReplyDatagram) rqMemo;
+ if (!memo.compareResponse(data)) {
+ logger.warning("Unexpected MemCfg response datagram from " + dest
+ .toString() + ": " + memo + " payload " + Utilities
+ .toHexSpaceString(data));
+ return;
+ } else {
+ checkAndPopMemo(rqMemo);
+ }
+ } else {
+ logger.warning("Could not find a matching memo for MemCfg response " +
+ "datagram from " + dest.toString() + " payload " + Utilities
+ .toHexSpaceString(data));
+ }
+ }
+ if (memo != null) {
+ memo.handleResponseDatagram(data);
+ }
}
});
}
@@ -162,15 +184,401 @@
this(mcs.here, mcs.downstream);
}
- McsWriteMemo writeMemo; // can receive a delayed reply
- public void request(McsWriteMemo memo) {
- // forward as write Datagram
- writeMemo = memo;
- WriteDatagramMemo dg = new WriteDatagramMemo(memo.dest, memo.space, memo.address, memo.data, memo);
- downstream.sendData(dg);
+
+ private abstract static class McsRequestMemo {
+ protected final NodeID dest;
+ // contains the subcommand (second byte) of the datagram for the request, having zeroed
+ // out any bits on the space shortcut.
+ protected final int requestCode;
+ protected final FailureCallback failureCallback;
+
+ McsRequestMemo(NodeID dest, int requestCode, FailureCallback cb) {
+ this.dest = dest;
+ this.requestCode = requestCode;
+ this.failureCallback = cb;
+ }
+
+ public int getRequestCode() {
+ return requestCode;
+ }
+
+ protected NodeID getDest() { return dest; }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof McsRequestMemo)) return false;
+ McsRequestMemo m = (McsRequestMemo) o;
+ if (!this.dest.equals(m.dest)) return false;
+ if (getRequestCode() != m.getRequestCode()) return false;
+ return true;
+ }
+
+ /**
+ * Creates the payload of the datagram to transmit.
+ * @return the transmit datagram bytes.
+ */
+ protected abstract int[] renderTransmitDatagram();
+
}
- McsReadMemo readMemo;
+ /**
+ * Request memos that can receive a reply must implement this method to handle the response
+ * datagram.
+ */
+ private interface RequestWithReplyDatagram {
+ /**
+ * If a response datagram came back that matches this request (i.e. compareResponse
+ * returns true), then this function will be called with the response datagram payload.
+ * @param data response datagram payload.
+ */
+ void handleResponseDatagram(int[] data);
+
+ /**
+ * Returns true if the received response belongs to this request.
+ * @param data datagram pyaload
+ */
+ boolean compareResponse(int[] data);
+ }
+
+ /**
+ * Request memos that do not have to receive a reply datagram must implement this method in
+ * order to allow the datagram transmit OK to be forwarded back to the client.
+ */
+ private interface RequestWithNoReply {
+ NoReturnCallback getNoReturnCallback();
+ }
+
+ /**
+ * Common base class for all request/response memos that take a space byte and an address
+ * offset, such as read, write, read stream, write stream.
+ */
+ private abstract static class McsAddressedRequestMemo extends McsRequestMemo implements
+ RequestWithReplyDatagram {
+ protected final int space;
+ protected final long address;
+ McsAddressedRequestMemo(NodeID dest, int requestCode, int space, long address,
+ FailureCallback cb) {
+ super(dest, requestCode, cb);
+ this.space = space;
+ this.address = address;
+ }
+
+ /**
+ * Checks whether there is a desired
+ * @return 1 if there should be a separate space byte, 0 otherwise.
+ */
+ protected int getSpaceOffset() {
+ return space >= 0xFD ? 0 : 1;
+ }
+
+ /**
+ * Computes the offset where the payload is in the datagram.
+ * @return 7 if there is a separate space byte, 6 if the space is encoded in the low bits.
+ */
+ protected int getPayloadOffset() {
+ return 6 + getSpaceOffset();
+ }
+
+ /**
+ * Computes the offset where the payload is in the datagram.
+ * @return 7 if there is a separate space byte, 6 if the space is encoded in the low bits.
+ */
+ protected int getPayloadOffset(int[] data) {
+ return 6 + ((data[1] & 0x3) != 0 ? 0 : 1);
+ }
+
+ protected void fillRequest(int[] data) {
+ data[0] = DATAGRAM_TYPE;
+ data[1] = getRequestCode();
+ if (space >= 0xFD) {
+ data[1] |= space & 3;
+ } else {
+ data[6] = space & 0xff;
+ }
+ DatagramUtils.renderLong(data, 2, address);
+ }
+
+ /**
+ * @return how many bytes to allocate after the (optional) space byte.
+ */
+ protected abstract int getPayloadLength();
+
+ /**
+ * Fills in the payload bytes of the transmit datagram.
+ * @param data already allocated array with everything until the payload (space,
+ * address, request code, datagram code) being filled in.
+ */
+ protected abstract void fillPayload(int[] data);
+
+ @Override
+ protected int[] renderTransmitDatagram() {
+ int[] data = new int[getPayloadOffset() + getPayloadLength()];
+ fillRequest(data);
+ fillPayload(data);
+ return data;
+ }
+
+ @Override
+ public boolean compareResponse(int[] data) {
+ if (data.length < (6 + getSpaceOffset())) return false;
+ if (address != DatagramUtils.parseLong(data, 2)) return false;
+ if (space != getSpaceFromPayload(data)) return false;
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!super.equals(o)) return false;
+ if (!(o instanceof McsAddressedRequestMemo)) return false;
+ McsAddressedRequestMemo m = (McsAddressedRequestMemo) o;
+ if (this.space != m.space) return false;
+ if (this.address != m.address) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() { return getRequestCode()+dest.hashCode()+((int)address)+space; }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ": dest " + dest.toString() + " space 0x" +
+ Integer.toHexString(space) + " address 0x" + Long.toHexString(address);
+ }
+
+ @Override
+ public void handleResponseDatagram(int[] data) {
+ if ((data[1] & SUBCMD_ERROR) != 0) {
+ failureCallback.handleFailure(DatagramUtils.parseErrorCode(data, getPayloadOffset(data)));
+ return;
+ }
+ handleSuccessResponse(data);
+ }
+
+ /**
+ * Called only if the response does not have the failure bit and all parameters are
+ * matching.
+ * @param data payload of response datagram.
+ */
+ protected abstract void handleSuccessResponse(int[] data);
+ }
+
+ public static int getSpaceFromPayload(int[] data) {
+ if ((data[1] & 0x3) != 0) { return 0xFC + (data[1] & 0x3); }
+ return data[6];
+ }
+
+ /**
+ * Computes what the request type would be that caused this response command to arrive.
+ * @param subCmd data[1] of an incoming response.
+ * @return data[1] (minus the space)
+ */
+ public static int getRequestTypeFromResponseType(int subCmd) {
+ if (subCmd < 0x80) {
+ return subCmd & 0xE0;
+ } else {
+ return subCmd & 0xFC;
+ }
+ }
+
+ // Holds the memo pointers to all pending operations: datagrams that were sent out and are
+ // waiting a response. Must be synchronized(this) for all accesses.
+ final Map<Integer, McsRequestMemo> pendingRequests = new HashMap<>(5);
+ final Map<Integer, List<McsRequestMemo>> queuedRequests = new HashMap<>(5);
+
+
+ /**
+ * Tests if the given memo is in the top memo in pendingRequests for its request type. If so,
+ * pops it.
+ * @param memo the memo to test.
+ */
+ private void checkAndPopMemo(McsRequestMemo memo) {
+ int rqCode = memo.getRequestCode();
+ synchronized(this) {
+ if (pendingRequests.get(rqCode) == memo) {
+ pendingRequests.remove(memo.getRequestCode());
+ memo = null;
+ if (queuedRequests.containsKey(rqCode)) {
+ List<McsRequestMemo> l = queuedRequests.get(rqCode);
+ if (!l.isEmpty()) {
+ memo = l.remove(l.size() - 1);
+ pendingRequests.put(rqCode, memo);
+ }
+ }
+ } else {
+ logger.warning("Error checking the pending request memo for code " + rqCode + " " +
+ "expected " + memo.toString() + " actual " +
+ pendingRequests.get(memo.getRequestCode()));
+ memo = null;
+ }
+ }
+ if (memo != null) {
+ sendRequest(memo);
+ }
+ }
+
+ private void sendRequest(final McsRequestMemo memo) {
+ downstream.sendData(new DatagramService.DatagramServiceTransmitMemo(memo.getDest(), memo.renderTransmitDatagram()) {
+ @Override
+ public void handleSuccess(int flags) {
+ if (memo instanceof RequestWithNoReply &&
+ ((flags & DatagramService.FLAG_REPLY_PENDING) == 0)) {
+ checkAndPopMemo(memo);
+ ((RequestWithNoReply) memo).getNoReturnCallback().handleSuccess();
+ return;
+ }
+ if (memo instanceof RequestWithReplyDatagram &&
+ ((flags & DatagramService.FLAG_REPLY_PENDING) != 0)) {
+ // Leave the memo in the pending, wait for reply datagram.
+ return;
+ }
+ // Now: something is fishy.
+ if (memo instanceof RequestWithReplyDatagram) {
+ logger.info("Expected reply pending, got zero.");
+ // We will still wait for a reply datagram.
+ return;
+ }
+ logger.warning("The remote node wants to send a reply but we don't know how to " +
+ "handle it. memo: " + memo.toString());
+ checkAndPopMemo(memo);
+ ((RequestWithNoReply) memo).getNoReturnCallback().handleSuccess();
+ }
+
+ @Override
+ public void handleFailure(int errorCode) {
+ checkAndPopMemo(memo);
+ memo.failureCallback.handleFailure(errorCode);
+ }
+ });
+ }
+
+ public void request(McsRequestMemo memo) {
+ synchronized(this) {
+ int rqCode = memo.getRequestCode();
+ if (pendingRequests.containsKey(rqCode)) {
+ if (!queuedRequests.containsValue(rqCode)) {
+ queuedRequests.put(rqCode, new ArrayList<McsRequestMemo>());
+ }
+ queuedRequests.get(rqCode).add(memo);
+ return;
+ } else {
+ pendingRequests.put(memo.getRequestCode(), memo);
+ }
+ }
+ sendRequest(memo);
+ }
+
+ static class McsWriteMemo extends McsAddressedRequestMemo implements
+ RequestWithNoReply {
+ public McsWriteMemo(NodeID dest, int space, long address, byte[] data, NoReturnCallback
+ cb) {
+ super(dest, SUBCMD_WRITE, space, address, cb);
+ this.data = data;
+ this.callback = cb;
+ }
+
+ final byte[] data;
+ final NoReturnCallback callback;
+
+ @Override
+ public boolean equals(Object o) {
+ if (!super.equals(o)) return false;
+ if (! (o instanceof McsWriteMemo)) return false;
+ McsWriteMemo m = (McsWriteMemo) o;
+ if (this.data.length != m.data.length) return false;
+ for (int i = 0; i < this.data.length; i++)
+ if (this.data[i] != m.data[i]) return false;
+ return true;
+ }
+
+ @Override
+ protected int getPayloadLength() {
+ return data.length;
+ }
+
+ @Override
+ protected void fillPayload(int[] data) {
+ for (int i = 0; i < this.data.length; ++i) {
+ data[getPayloadOffset() + i] = DatagramUtils.byteToInt(this.data[i]);
+ }
+ }
+
+ @Override
+ protected void handleSuccessResponse(int[] data) {
+ callback.handleSuccess();
+ }
+
+ @Override
+ public NoReturnCallback getNoReturnCallback() {
+ return callback;
+ }
+ }
+
+ public interface McsWriteHandler extends NoReturnCallback {}
+
+ public void requestWrite(NodeID dest, int space, long address, byte[] data, McsWriteHandler
+ cb) {
+ request(new McsWriteMemo(dest, space, address, data, cb));
+ }
+
+ public interface McsReadHandler extends FailureCallback {
+ /**
+ * This function will be called upon successful read.
+ * @param dest the node ID from which the read happened
+ * @param space the space number from which the read happened
+ * @param address address within the space at where the read happened
+ * @param data the returned payload. not null, should be at least one byte long (or else
+ * a handleFailure call will be invoked).
+ */
+ void handleReadData(NodeID dest, int space, long address, byte[] data);
+ }
+
+ static class McsReadMemo extends McsAddressedRequestMemo implements
+ RequestWithReplyDatagram {
+ public McsReadMemo(NodeID dest, int space, long address, int len, McsReadHandler
+ cb) {
+ super(dest, SUBCMD_READ, space, address, cb);
+ this.len = len;
+ this.callback = cb;
+ }
+
+ final int len;
+ final McsReadHandler callback;
+
+ @Override
+ public boolean equals(Object o) {
+ if (!super.equals(o)) return false;
+ if (! (o instanceof McsReadMemo)) return false;
+ McsReadMemo m = (McsReadMemo) o;
+ if (this.len != m.len) return false;
+ return true;
+ }
+
+ @Override
+ protected int getPayloadLength() {
+ return 1;
+ }
+
+ @Override
+ protected void fillPayload(int[] data) {
+ data[getPayloadOffset()] = len;
+ }
+
+ @Override
+ protected void handleSuccessResponse(int[] data) {
+ int payofs = getPayloadOffset(data);
+ byte[] response = new byte[data.length - payofs];
+ DatagramUtils.intToByteArray(response, 0, data, payofs, response.length);
+ callback.handleReadData(dest, space, address, response);
+ }
+ }
+
+ public void requestRead(NodeID dest, int space, long address, int len, McsReadHandler
+ cb) {
+ request(new McsReadMemo(dest, space, address, len, cb));
+ }
+
+
+/* McsReadMemo readMemo;
Stack<McsReadMemo> pendingReads = new Stack<>();
public synchronized void request(McsReadMemo memo) {
// forward as read Datagram
@@ -185,7 +593,7 @@
private void sendRead() {
ReadDatagramMemo dg = new ReadDatagramMemo(readMemo.dest, readMemo.space, readMemo.address, readMemo.count, readMemo);
downstream.sendData(dg);
- }
+ }*/
// dph
McsWriteStreamMemo writeStreamMemo;
@@ -194,7 +602,8 @@
//System.out.println("writeStreamMemo: "+memo.dest+","+memo.space+","+memo.address);
// System.out.println("writeStreamMemo: "+memo.dest);
writeStreamMemo = memo;
- WriteStreamMemo dg = new WriteStreamMemo(memo.dest, memo.space, memo.address, memo);
+ WriteStreamMemo dg = new WriteStreamMemo(memo.dest, memo.space, memo.address, memo.srcStreamId,
+ memo);
downstream.sendData(dg);
}
@@ -215,80 +624,30 @@
}
@Immutable
- @ThreadSafe
- static public class McsReadMemo {
- public McsReadMemo(NodeID dest, int space, long address, int count) {
- this.count = count;
- this.address = address;
- this.space = space;
- this.dest = dest;
- }
-
- protected final int count;
- final long address;
- final int space;
- final NodeID dest;
-
- @Override
- public boolean equals(Object o) {
- if (o == null) return false;
- if (! (o instanceof McsReadMemo)) retur...
[truncated message content] |
|
From: <br...@us...> - 2016-07-14 17:31:18
|
Revision: 4211
http://sourceforge.net/p/openlcb/svn/4211
Author: bracz
Date: 2016-07-14 17:31:15 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Fixes termination condition of datagram based loader client.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/LoaderClient.java
Modified: trunk/prototypes/java/src/org/openlcb/LoaderClient.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/LoaderClient.java 2016-07-14 17:30:56 UTC (rev 4210)
+++ trunk/prototypes/java/src/org/openlcb/LoaderClient.java 2016-07-14 17:31:15 UTC (rev 4211)
@@ -287,8 +287,8 @@
//System.out.println("Reply mcs.request McsWriteMemo handleWriteReply: "+code);
if(nextIndex<content.length) sendDGNext();
else {
- //sendUnfreeze();
- //state = State.SUCCESS;
+ sendUnfreeze();
+ state = State.SUCCESS;
}
}
});
@@ -305,12 +305,7 @@
replyCount++;
float p = 100.0F * replyCount / expectedTransactions;
feedback.onProgress(p);
- if( p > 100.0F*(expectedTransactions-1)/expectedTransactions ) state=state.UNFREEEZE;
}
- if(state == State.UNFREEEZE && msg.getSourceNodeID().equals(dest)) {
- sendUnfreeze();
- state = State.SUCCESS;
- }
}
void sendUnfreeze() {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:30:59
|
Revision: 4210
http://sourceforge.net/p/openlcb/svn/4210
Author: bracz
Date: 2016-07-14 17:30:56 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Adds better printout for the stream data complete message.
Fixes stream transmitter test because it was setting incorrect expectations that did not correctly set the src/dst IDs.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/StreamDataCompleteMessage.java
trunk/prototypes/java/test/org/openlcb/implementations/StreamTransmitterTest.java
Modified: trunk/prototypes/java/src/org/openlcb/StreamDataCompleteMessage.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/StreamDataCompleteMessage.java 2016-07-14 17:30:35 UTC (rev 4209)
+++ trunk/prototypes/java/src/org/openlcb/StreamDataCompleteMessage.java 2016-07-14 17:30:56 UTC (rev 4210)
@@ -50,7 +50,7 @@
public String toString() {
return super.toString()
- +" StreamDataComplete";
+ +" StreamDataComplete srcId=" + sourceStreamID + " dstId=" + destStreamID;
}
public int getMTI() { return MTI_STREAM_DATA_COMPLETE; }
Modified: trunk/prototypes/java/test/org/openlcb/implementations/StreamTransmitterTest.java
===================================================================
--- trunk/prototypes/java/test/org/openlcb/implementations/StreamTransmitterTest.java 2016-07-14 17:30:35 UTC (rev 4209)
+++ trunk/prototypes/java/test/org/openlcb/implementations/StreamTransmitterTest.java 2016-07-14 17:30:56 UTC (rev 4210)
@@ -62,10 +62,9 @@
xmt.put(m, null);
Assert.assertEquals("1st messages", 2, messagesReceived.size());
- Assert.assertTrue(messagesReceived.get(0)
- .equals(new StreamDataSendMessage(hereID, farID, data)));
- Assert.assertTrue(messagesReceived.get(1)
- .equals(new StreamDataCompleteMessage(hereID, farID, (byte)0, (byte)0)));
+ Assert.assertEquals(messagesReceived.get(0), new StreamDataSendMessage(hereID, farID, data));
+ Assert.assertEquals(messagesReceived.get(1), new StreamDataCompleteMessage(hereID, farID,
+ (byte)4, (byte)0));
}
public void testTwoMsgStream() {
@@ -109,7 +108,7 @@
Assert.assertTrue(messagesReceived.get(0)
.equals(new StreamDataSendMessage(hereID, farID, new int[256])));
Assert.assertTrue(messagesReceived.get(1)
- .equals(new StreamDataCompleteMessage(hereID, farID, (byte)0, (byte)0)));
+ .equals(new StreamDataCompleteMessage(hereID, farID, (byte)4, (byte)0)));
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:30:38
|
Revision: 4209
http://sourceforge.net/p/openlcb/svn/4209
Author: bracz
Date: 2016-07-14 17:30:35 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Fixes bug in decoding space byte for read replies.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigurationService.java
Modified: trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigurationService.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigurationService.java 2016-07-14 17:30:18 UTC (rev 4208)
+++ trunk/prototypes/java/src/org/openlcb/implementations/MemoryConfigurationService.java 2016-07-14 17:30:35 UTC (rev 4209)
@@ -70,7 +70,7 @@
content = new byte[0];
}
long retAddress = DatagramUtils.parseLong(data, 2);
- int retSpace = spaceByte ? data[6] : (0xFD + (data[1] & 0x03));
+ int retSpace = spaceByte ? data[6] : (0xFC + (data[1] & 0x03));
McsReadMemo memo;
synchronized (this) {
memo = readMemo;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:30:20
|
Revision: 4208
http://sourceforge.net/p/openlcb/svn/4208
Author: bracz
Date: 2016-07-14 17:30:18 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Fixes broken test after extending the read API with feedback and adds expectation on CDI mem config reader.
Modified Paths:
--------------
trunk/prototypes/java/test/org/openlcb/cdi/jdom/CdiMemConfigReaderTest.java
Modified: trunk/prototypes/java/test/org/openlcb/cdi/jdom/CdiMemConfigReaderTest.java
===================================================================
--- trunk/prototypes/java/test/org/openlcb/cdi/jdom/CdiMemConfigReaderTest.java 2016-07-14 17:29:58 UTC (rev 4207)
+++ trunk/prototypes/java/test/org/openlcb/cdi/jdom/CdiMemConfigReaderTest.java 2016-07-14 17:30:18 UTC (rev 4208)
@@ -79,8 +79,21 @@
}
java.io.Reader rdr;
public void testCycle() throws java.io.IOException {
- CdiMemConfigReader cmcr = new CdiMemConfigReader(nidHere, store, service);
+ CdiMemConfigReader cmcr = new CdiMemConfigReader(nidHere, store, service);
+
+ class ReaderFb {
+ long bytesRead;
+ long totalBytes;
+ }
+ final ReaderFb fb = new ReaderFb();
+
CdiMemConfigReader.ReaderAccess a = new CdiMemConfigReader.ReaderAccess() {
+ @Override
+ public void progressNotify(long bytesRead, long totalBytes) {
+ fb.bytesRead = bytesRead;
+ fb.totalBytes = totalBytes;
+ }
+
public void provideReader(java.io.Reader r) {
rdr = r;
}
@@ -94,6 +107,7 @@
int count = 2;
while (rdr.read() > 0) count++;
Assert.assertEquals("length", testString.length()-1, count); // -1 for trailing zero on input
+ assertEquals("feedback", count, fb.totalBytes);
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:30:01
|
Revision: 4207
http://sourceforge.net/p/openlcb/svn/4207
Author: bracz
Date: 2016-07-14 17:29:58 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Adds another way to fill in the alias map upon startup, in addition to a global AME frame sending a global verify node ID message out as well. This is somewhat problematic, but at this point we do not have a mechanism to fetch node aliad upon need.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/can/CanInterface.java
Modified: trunk/prototypes/java/src/org/openlcb/can/CanInterface.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/can/CanInterface.java 2016-07-14 17:29:39 UTC (rev 4206)
+++ trunk/prototypes/java/src/org/openlcb/can/CanInterface.java 2016-07-14 17:29:58 UTC (rev 4207)
@@ -88,6 +88,9 @@
OpenLcbCanFrame ameFrame = new OpenLcbCanFrame(0);
ameFrame.setAME(aliasWatcher.getNIDa(), null);
frameOutput.send(ameFrame);
+ OpenLcbCanFrame gReqFrame = new OpenLcbCanFrame(aliasWatcher.getNIDa());
+ gReqFrame.setVerifyNID(null);
+ frameOutput.send(gReqFrame);
try {
Thread.sleep(200);
} catch(InterruptedException e) {}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:29:42
|
Revision: 4206
http://sourceforge.net/p/openlcb/svn/4206
Author: bracz
Date: 2016-07-14 17:29:39 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Moves the thread creation for OlcbConnection to a separate call instead of the constructor. This avoids crashes upon construction when the new thread tries to call into the connection functions earlier than the variables were to be setup.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/can/impl/OlcbConnection.java
trunk/prototypes/java/src/org/openlcb/cdi/cmd/Util.java
Modified: trunk/prototypes/java/src/org/openlcb/can/impl/OlcbConnection.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/can/impl/OlcbConnection.java 2016-07-14 17:29:20 UTC (rev 4205)
+++ trunk/prototypes/java/src/org/openlcb/can/impl/OlcbConnection.java 2016-07-14 17:29:39 UTC (rev 4206)
@@ -47,13 +47,11 @@
this.listenerProxy = new ListenerProxy();
this.listenerProxy.add(connectionListener);
this.nodeId = nodeId;
+ }
+
+ public void startConnect() {
new Thread() {
public void run() {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // ignore
- }
connect();
}
}.start();
Modified: trunk/prototypes/java/src/org/openlcb/cdi/cmd/Util.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/cdi/cmd/Util.java 2016-07-14 17:29:20 UTC (rev 4205)
+++ trunk/prototypes/java/src/org/openlcb/cdi/cmd/Util.java 2016-07-14 17:29:39 UTC (rev 4206)
@@ -82,6 +82,7 @@
};
OlcbConnection connection = new OlcbConnection(localNode, host, port, l);
+ connection.startConnect();
if (s.get()) {
return connection;
} else {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:29:23
|
Revision: 4205
http://sourceforge.net/p/openlcb/svn/4205
Author: bracz
Date: 2016-07-14 17:29:20 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Removes accidental copy-paste.
Modified Paths:
--------------
trunk/prototypes/java/openlcb.jar
trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java
Modified: trunk/prototypes/java/openlcb.jar
===================================================================
(Binary files differ)
Modified: trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java 2016-07-14 17:28:59 UTC (rev 4204)
+++ trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java 2016-07-14 17:29:20 UTC (rev 4205)
@@ -13,7 +13,7 @@
import java.util.Map;
import java.util.NavigableMap;
import java.util.Queue;
-import java.util.TreeMap;Upgrade gradle to 2.10
+import java.util.TreeMap;
import java.util.logging.Logger;
/**
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:29:01
|
Revision: 4204
http://sourceforge.net/p/openlcb/svn/4204
Author: bracz
Date: 2016-07-14 17:28:59 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Fixes DMB test because the metering buffer is not trying to forward messages to the source connection anymore.
Modified Paths:
--------------
trunk/prototypes/java/test/org/openlcb/implementations/DatagramMeteringBufferTest.java
Modified: trunk/prototypes/java/test/org/openlcb/implementations/DatagramMeteringBufferTest.java
===================================================================
--- trunk/prototypes/java/test/org/openlcb/implementations/DatagramMeteringBufferTest.java 2016-07-14 17:28:40 UTC (rev 4203)
+++ trunk/prototypes/java/test/org/openlcb/implementations/DatagramMeteringBufferTest.java 2016-07-14 17:28:59 UTC (rev 4204)
@@ -89,17 +89,6 @@
Assert.assertTrue(messagesForwarded.get(0).equals(datagram1));
}
- public void testSendReplyOK() throws InterruptedException {
- buffer.put(datagram1, replyConnection1);
-
- Thread.currentThread().sleep(10);
-
- returnConnection.put(replyOK, null);
-
- Assert.assertEquals("reply messages", 1, repliesReturned1.size());
- Assert.assertTrue(repliesReturned1.get(0).equals(replyOK));
- }
-
public void testSendReplyNakRetransmit() throws InterruptedException {
buffer.put(datagram1, replyConnection1);
@@ -123,10 +112,28 @@
returnConnection.put(replyOK, null);
- Assert.assertEquals("reply messages", 1, repliesReturned1.size());
- Assert.assertTrue(repliesReturned1.get(0).equals(replyOK));
+ assertSendReady();
}
+ private void assertSendReady() throws InterruptedException {
+ int pastSendMsg = messagesForwarded.size();
+ buffer.put(datagram2, replyConnection1);
+
+ Thread.currentThread().sleep(10);
+
+ assertEquals("forwarded new datagram",pastSendMsg + 1, messagesForwarded.size());
+ assertEquals("new forward", datagram2, messagesForwarded.get(messagesForwarded.size() - 1));
+ }
+
+ private void assertSendBusy() throws InterruptedException {
+ int pastSendMsg = messagesForwarded.size();
+ buffer.put(datagram2, replyConnection1);
+
+ Thread.currentThread().sleep(10);
+
+ assertEquals("not forwarded new datagram",pastSendMsg, messagesForwarded.size());
+ }
+
public void testSendReplyOtherNakNoInterfere() throws InterruptedException {
buffer.put(datagram1, replyConnection1);
@@ -136,15 +143,11 @@
returnConnection.put(otherReply, null);
Assert.assertEquals("forwarded messages", 1, messagesForwarded.size());
- Assert.assertEquals("reply messages", 1, repliesReturned1.size());
- Assert.assertTrue(repliesReturned1.get(0).equals(otherReply));
otherReply = new DatagramAcknowledgedMessage(farID, farID);
returnConnection.put(otherReply, null);
Assert.assertEquals("forwarded messages", 1, messagesForwarded.size());
- Assert.assertEquals("reply messages", 2, repliesReturned1.size());
- Assert.assertTrue(repliesReturned1.get(1).equals(otherReply));
returnConnection.put(replyNAKresend, null);
@@ -153,8 +156,7 @@
returnConnection.put(replyOK, null);
- Assert.assertEquals("reply messages", 3, repliesReturned1.size());
- Assert.assertTrue(repliesReturned1.get(2).equals(replyOK));
+ assertSendReady();
}
public void testSendTwoNonDatagramGoesThrough() throws InterruptedException {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:28:42
|
Revision: 4203
http://sourceforge.net/p/openlcb/svn/4203
Author: bracz
Date: 2016-07-14 17:28:40 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Fixes deadlock when the hub in run from JMRI and a large number of incoming packets crowd the internal queue of the hub. This causes deadlock because if the internal queue is full, the AWT thread will not be able to send a new message to the hub's queue, while also blocking any message being popped from the queue and forwarded to JMRI.
This bug is specific to JMRI because it's CAN message listener tries to forward everything to the AWT event thread.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/hub/Hub.java
Modified: trunk/prototypes/java/src/org/openlcb/hub/Hub.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/hub/Hub.java 2016-07-14 17:28:17 UTC (rev 4202)
+++ trunk/prototypes/java/src/org/openlcb/hub/Hub.java 2016-07-14 17:28:40 UTC (rev 4203)
@@ -54,7 +54,7 @@
t.start();
}
- ArrayBlockingQueue<Memo> queue = new ArrayBlockingQueue<Memo>(CAPACITY, true); //fairness
+ BlockingQueue<Memo> queue = new LinkedBlockingQueue<Memo>();
ArrayList<Forwarding> threads = new ArrayList<Forwarding>();
int port;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:28:21
|
Revision: 4202
http://sourceforge.net/p/openlcb/svn/4202
Author: bracz
Date: 2016-07-14 17:28:17 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Fixes broken test.
Modified Paths:
--------------
trunk/prototypes/java/test/org/openlcb/ProtocolIdentificationTest.java
Modified: trunk/prototypes/java/test/org/openlcb/ProtocolIdentificationTest.java
===================================================================
--- trunk/prototypes/java/test/org/openlcb/ProtocolIdentificationTest.java 2016-07-14 17:27:58 UTC (rev 4201)
+++ trunk/prototypes/java/test/org/openlcb/ProtocolIdentificationTest.java 2016-07-14 17:28:17 UTC (rev 4202)
@@ -71,9 +71,10 @@
public void testCreationFromMessage() {
ProtocolIdentification pi = new ProtocolIdentification(
- new ProtocolIdentificationReplyMessage(
- new NodeID(new byte[]{1,3,3,4,5,6}),new NodeID(new byte[]{2,3,3,4,5,6}),
- 0x03));
+ new NodeID(new byte[]{2,3,3,4,5,6}),
+ new ProtocolIdentificationReplyMessage(
+ new NodeID(new byte[]{1,3,3,4,5,6}),new NodeID(new byte[]{2,3,3,4,5,6}),
+ 0x03));
Assert.assertTrue((long)0x03 == pi.getValue());
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:28:01
|
Revision: 4201
http://sourceforge.net/p/openlcb/svn/4201
Author: bracz
Date: 2016-07-14 17:27:58 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Fixes a 2's complement bug with rendering the big-endian binary value to an integer for display.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/cdi/impl/ConfigRepresentation.java
Modified: trunk/prototypes/java/src/org/openlcb/cdi/impl/ConfigRepresentation.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/cdi/impl/ConfigRepresentation.java 2016-07-14 17:27:41 UTC (rev 4200)
+++ trunk/prototypes/java/src/org/openlcb/cdi/impl/ConfigRepresentation.java 2016-07-14 17:27:58 UTC (rev 4201)
@@ -545,8 +545,8 @@
long ret = 0;
for (int i = 0; i < b.length; ++i) {
ret <<= 8;
- int p = b[i];
- if (p < 0) p += 128;
+ int p = b[i] & 0xff;
+ //if (p < 0) p += 128;
ret |= p;
}
return ret;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:27:43
|
Revision: 4200
http://sourceforge.net/p/openlcb/svn/4200
Author: bracz
Date: 2016-07-14 17:27:41 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Makes refresh write into the original data payload instead of adding a new data payload to the cache.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java
Modified: trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java 2016-07-14 17:27:23 UTC (rev 4199)
+++ trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java 2016-07-14 17:27:41 UTC (rev 4200)
@@ -13,7 +13,7 @@
import java.util.Map;
import java.util.NavigableMap;
import java.util.Queue;
-import java.util.TreeMap;
+import java.util.TreeMap;Upgrade gradle to 2.10
import java.util.logging.Logger;
/**
@@ -171,9 +171,20 @@
*/
private void loadRange() {
if (currentRangeNextOffset < 0) {
- currentRangeNextOffset = nextRangeToLoad.start;
- currentRangeData = new byte[(int) (nextRangeToLoad.end - nextRangeToLoad.start)];
- dataCache.put(nextRangeToLoad, currentRangeData);
+ int len = (int)(nextRangeToLoad.end - nextRangeToLoad.start);
+ // Try to check if there is an existing range covering the stuff to load.
+ Map.Entry<Range, byte[]> cachedRange = getCacheForRange(nextRangeToLoad.start, len);
+ if (cachedRange == null) {
+ currentRangeData = new byte[len];
+ dataCache.put(nextRangeToLoad, currentRangeData);
+ currentRangeNextOffset = nextRangeToLoad.start;
+ } else {
+ currentRangeData = cachedRange.getValue();
+ currentRangeNextOffset = nextRangeToLoad.start;
+ // We must make sure that the start offset is the same as the cached range,
+ // otherwise the bytes will be copied to the wrong place inside the data array.
+ nextRangeToLoad = new Range(cachedRange.getKey().start, nextRangeToLoad.end);
+ }
}
int count = (int)(nextRangeToLoad.end - currentRangeNextOffset);
if (count <= 0) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:27:25
|
Revision: 4199
http://sourceforge.net/p/openlcb/svn/4199
Author: bracz
Date: 2016-07-14 17:27:23 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Adds some debugging assertions.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/MimicNodeStore.java
trunk/prototypes/java/src/org/openlcb/ProtocolIdentification.java
Modified: trunk/prototypes/java/src/org/openlcb/MimicNodeStore.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/MimicNodeStore.java 2016-07-14 17:27:05 UTC (rev 4198)
+++ trunk/prototypes/java/src/org/openlcb/MimicNodeStore.java 2016-07-14 17:27:23 UTC (rev 4199)
@@ -102,6 +102,9 @@
}
public ProtocolIdentification getProtocolIdentification() {
if (pIdent == null) {
+ if (id == null) {
+ throw new AssertionError("MimicNodeStore id == null");
+ }
pIdent = new ProtocolIdentification(node, id);
pIdent.start(connection);
}
Modified: trunk/prototypes/java/src/org/openlcb/ProtocolIdentification.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/ProtocolIdentification.java 2016-07-14 17:27:05 UTC (rev 4198)
+++ trunk/prototypes/java/src/org/openlcb/ProtocolIdentification.java 2016-07-14 17:27:23 UTC (rev 4199)
@@ -80,6 +80,12 @@
}
void start(Connection connection) {
+ if (dest == null) {
+ throw new AssertionError("PIP dest==null");
+ }
+ if (source == null) {
+ throw new AssertionError("PIP src = null");
+ }
connection.put(new ProtocolIdentificationRequestMessage(source, dest), null);
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:27:08
|
Revision: 4198
http://sourceforge.net/p/openlcb/svn/4198
Author: bracz
Date: 2016-07-14 17:27:05 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
adds refresh (reload) support to the memory space cache.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/cdi/impl/ConfigRepresentation.java
trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java
Modified: trunk/prototypes/java/src/org/openlcb/cdi/impl/ConfigRepresentation.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/cdi/impl/ConfigRepresentation.java 2016-07-14 17:26:45 UTC (rev 4197)
+++ trunk/prototypes/java/src/org/openlcb/cdi/impl/ConfigRepresentation.java 2016-07-14 17:27:05 UTC (rev 4198)
@@ -339,6 +339,12 @@
public void fireWriteComplete() {
firePropertyChange(UPDATE_WRITE_COMPLETE, null, null);
}
+
+ /// Reads the values again from the original source.
+ public void reload() {
+ MemorySpaceCache cache = getCacheForSpace(space);
+ cache.reload(origin, size);
+ }
}
public class Root implements CdiContainer {
@@ -395,6 +401,10 @@
}
@Override
+ public void reload() {
+ }
+
+ @Override
public String getName() {
return segment.getName();
}
Modified: trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java 2016-07-14 17:26:45 UTC (rev 4197)
+++ trunk/prototypes/java/src/org/openlcb/cdi/impl/MemorySpaceCache.java 2016-07-14 17:27:05 UTC (rev 4198)
@@ -8,9 +8,11 @@
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
+import java.util.Queue;
import java.util.TreeMap;
import java.util.logging.Logger;
@@ -38,6 +40,7 @@
private Range nextRangeToLoad = null;
private long currentRangeNextOffset;
private byte[] currentRangeData;
+ private Queue<Range> rangesToLoad = new LinkedList<>();
public MemorySpaceCache(OlcbInterface connection, NodeID remoteNode, int space) {
this.connection = connection;
@@ -143,6 +146,7 @@
if (rlist.isEmpty()) return;
for (Range r : rlist) {
dataCache.put(r, null);
+ rangesToLoad.add(r);
}
continueLoading();
}
@@ -151,14 +155,9 @@
* Finds the next unloaded cached range and invokes load on it.
*/
private void continueLoading() {
- if (dataCache.isEmpty()) return;
+ if (dataCache.isEmpty() && rangesToLoad.isEmpty()) return;
+ nextRangeToLoad = rangesToLoad.poll();
if (nextRangeToLoad == null) {
- nextRangeToLoad = dataCache.firstKey();
- }
- while (nextRangeToLoad != null && dataCache.get(nextRangeToLoad) != null) {
- nextRangeToLoad = dataCache.higherKey(nextRangeToLoad);
- }
- if (nextRangeToLoad == null) {
// loading complete.
firePropertyChange(UPDATE_LOADING_COMPLETE, null, null);
return;
@@ -211,13 +210,14 @@
}
if (data.length == 0) {
logger.warning(String.format("Datagram read returned 0 bytes. " +
- "Remote node %s, space %d, address 0x%x", dest.toString(),
+ "Remote node %s, space %d, address 0x%x", dest
+ .toString(),
space, address));
currentRangeNextOffset += fcount;
} else {
System.arraycopy(data, 0, currentRangeData, (int)
(currentRangeNextOffset -
- nextRangeToLoad.start), data.length);
+ nextRangeToLoad.start), data.length);
notifyPartialRead(currentRangeNextOffset, currentRangeNextOffset + data
.length);
currentRangeNextOffset += data.length;
@@ -276,6 +276,16 @@
}
/**
+ * Performs a refresh of some data. Calls the data update listeners when done.
+ * @param origin
+ * @param size
+ */
+ public void reload(long origin, int size) {
+ rangesToLoad.add(new Range(origin, origin + size));
+ continueLoading();
+ }
+
+ /**
* Represents the registered listeners of a given range.
*/
private class ChangeEntry {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2016-07-14 17:26:49
|
Revision: 4197
http://sourceforge.net/p/openlcb/svn/4197
Author: bracz
Date: 2016-07-14 17:26:45 +0000 (Thu, 14 Jul 2016)
Log Message:
-----------
Refreshes SNIP and PIP data for nodes that send a NodeInitComplete message to the bus.
Modified Paths:
--------------
trunk/prototypes/java/src/org/openlcb/MimicNodeStore.java
trunk/prototypes/java/src/org/openlcb/ProtocolIdentification.java
Modified: trunk/prototypes/java/src/org/openlcb/MimicNodeStore.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/MimicNodeStore.java 2016-07-14 17:26:24 UTC (rev 4196)
+++ trunk/prototypes/java/src/org/openlcb/MimicNodeStore.java 2016-07-14 17:26:45 UTC (rev 4197)
@@ -97,7 +97,7 @@
ProtocolIdentification pIdent = null;
public void handleProtocolIdentificationReply(ProtocolIdentificationReplyMessage msg, Connection sender){
// accept assumes from mimic'd node
- pIdent = new ProtocolIdentification(msg);
+ pIdent = new ProtocolIdentification(node, msg);
pcs.firePropertyChange(UPDATE_PROP_PROTOCOL, null, pIdent);
}
public ProtocolIdentification getProtocolIdentification() {
@@ -144,10 +144,24 @@
return;
}
// have to resend the PIP request
- connection.put(new ProtocolIdentificationRequestMessage(node, msg.getSourceNodeID()), null);
+ connection.put(new ProtocolIdentificationRequestMessage(node, msg.getSourceNodeID
+ ()), null);
}
}
-
+
+ @Override
+ public void handleInitializationComplete(InitializationCompleteMessage msg, Connection sender) {
+ if (!msg.getSourceNodeID().equals(id)) {
+ return;
+ }
+ if (pSimpleNode != null) {
+ pSimpleNode.start(connection);
+ }
+ if (pIdent != null) {
+ //pIdent.start(connection);
+ }
+ }
+
java.beans.PropertyChangeSupport pcs = new java.beans.PropertyChangeSupport(this);
public synchronized void addPropertyChangeListener(java.beans.PropertyChangeListener l) {pcs.addPropertyChangeListener(l);}
public synchronized void removePropertyChangeListener(java.beans.PropertyChangeListener l) {pcs.removePropertyChangeListener(l);}
Modified: trunk/prototypes/java/src/org/openlcb/ProtocolIdentification.java
===================================================================
--- trunk/prototypes/java/src/org/openlcb/ProtocolIdentification.java 2016-07-14 17:26:24 UTC (rev 4196)
+++ trunk/prototypes/java/src/org/openlcb/ProtocolIdentification.java 2016-07-14 17:26:45 UTC (rev 4197)
@@ -65,7 +65,9 @@
NodeID source;
NodeID dest;
- public ProtocolIdentification( ProtocolIdentificationReplyMessage msg) {
+ public ProtocolIdentification(NodeID me, ProtocolIdentificationReplyMessage msg) {
+ this.source = me;
+ this.dest = msg.getSourceNodeID();
value = msg.getValue();
}
public ProtocolIdentification() {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|