ViktorC / PP4J

A multiprocessing library for Java that features process pool implementations and a flexible API.
Apache License 2.0
32 stars 6 forks source link

Pool fails to process submissions > 16 #8

Open rob42 opened 5 years ago

rob42 commented 5 years ago

Hi,

Ive built a MatlabExecutor class that starts a static pool as follows:

static {
        JavaProcessOptions jvmConfig = new SimpleJavaProcessOptions(JVMArch.BIT_64, JVMType.CLIENT, 128, 256, 256, 5*60*1000);

        try {
            jvmPool = new JavaProcessPoolExecutor(jvmConfig,4, 8, 1, null, true);
            System.out.println("Started jvmPool");
        } catch (InterruptedException e) {
            logger.error(e,e);
        }
    }

It will eventually be a servlet, so it has a doPost(request,response) method, but at present it just runs via a test that calls the MatlabExecutor wrapped in a runnable. eg

    @Test
    public void shouldProcessCalc() throws ServletException, IOException {

        for(int x=0;x<16;x++) {
            Runnable run = new Runnable() {

                @Override
                public void run() {
                    MockHttpServletRequest request = new MockHttpServletRequest();
                    request.setContent(requestJson.getBytes());
                    MockHttpServletResponse response = new MockHttpServletResponse();
                    try {
                        new ModelScoreExecutor().doPost(request, response);
                        logger.debug("Response Status: {}",response.getStatus());
                        String responseStr = response.getContentAsString();
                        logger.debug("Response Content: {}",responseStr);
                    } catch (ServletException | IOException e) {
                        logger.error(e,e);
                    }
                }
            };
            new Thread(run).start();
        }
}

the important part of the doPost method is:

            String input = IOUtils.toString(request.getReader());
            Json json = Json.read(input);

            java.util.concurrent.Future<String> future =  jvmPool.submit(new Calc(json),true);

            String out = future.get(1, TimeUnit.MINUTES);       
            response.setStatus(HttpServletResponse.SC_OK);

Calc.java is:

    public String call() throws Exception {
        String p1 = json.at("rhs").at(0).asString();
        String p2 = json.at("rhs").at(1).asString();

        List<Object> p = MatlabUtil.getModelScoreInputFromRhs(json);
//makes a JNI call to native matlab calculation
        double[][] s = MatlabUtil.executeModelScore(new CPFunctions_MCR.ModelScore(), p1, p2, p);
        return MatlabUtil.convert2Lhs(s);

    }

So now the problems. 1) If I run the above with "jvmPool.submit(new Calc(json), false);" the I get about 8 successful calcs, and then concurrent exceptions and stream corruptions. It seems like the submissions are not truly atomic and the JVM or streams are left in a bad state. Ideally I want to reuse JVMs for efficiency to avoid startup delays.

ERROR com.cp.matlab.servlet.MatlabExecutor.doPost(MatlabExecutor.java:141) - java.util.concurrent.ExecutionException: java.io.StreamCorruptedException: invalid type code: E0
java.util.concurrent.ExecutionException: java.io.StreamCorruptedException: invalid type code: E0
    at net.viktorc.pp4j.impl.JavaProcessPoolExecutor$JavaSubmission.getResult(JavaProcessPoolExecutor.java:452) ~[pp4j-2.2.jar:?]
    at net.viktorc.pp4j.impl.JavaProcessPoolExecutor$JavaSubmission.getResult(JavaProcessPoolExecutor.java:409) ~[pp4j-2.2.jar:?]
    at net.viktorc.pp4j.impl.ProcessPoolExecutor$InternalSubmission.getResult(ProcessPoolExecutor.java:471) ~[pp4j-2.2.jar:?]
    at net.viktorc.pp4j.impl.ProcessPoolExecutor$InternalSubmissionFuture.get(ProcessPoolExecutor.java:569) ~[pp4j-2.2.jar:?]
    at net.viktorc.pp4j.impl.JavaProcessPoolExecutor$CastFuture.get(JavaProcessPoolExecutor.java:502) ~[pp4j-2.2.jar:?]
    at com.cp.matlab.servlet.MatlabExecutor.doPost(MatlabExecutor.java:130) [classes/:?]
    at com.cp.matlab.servlet.CalcExecutorTest$1.run(CalcExecutorTest.java:65) [test-classes/:?]

2) If I use "jvmPool.submit(new Calc(json),true);" then it works, but not all submissions are completed. I typically get 15 of 16 completed, but if i send 24 submissions i also get 15 completed. The rest dont show errors, but are never processed. Something in the submission queue maybe?

Its possible there is a better way to do this, I'm open to suggestions.

ViktorC commented 5 years ago

Hi Rob,

Could you try and run this using the master branch of PP4J? I have made quite a few changes, including some bug fixes, since version 2.2 and I am about to release a new version soon. I have compiled the jar for you and attached it to this message (I had to zip it to be able to do that).

pp4j-3.0.0.jar.zip

The only thing you'd have to change to make it work with this version is the initialization of the pool. It would have to look something like this:

JavaProcessConfig jvmConfig = new SimpleJavaProcessConfig(JVMArch.BIT_64, JVMType.CLIENT, 128, 256, 256);
JavaProcessManagerFactory<?> jvmProcManagerFactory = new JavaProcessManagerFactory<>(jvmConfig, null, null, 5L*60L*1000L);
try {
    jvmPool = new JavaProcessPoolExecutor(jvmProcManagerFactory, 4, 8, 1);
    System.out.println("Started jvmPool");
} catch (InterruptedException e) {
    logger.error(e,e);
}

If you encounter the same problem using the new version as well, what would help me identify the cause is trace logs. PP4J uses SLF4J so if you have a compatible logging framework to bind to it, you can set the logging level to trace and you'll see a whole bunch of events logged from the pool.

I use Logback for the tests which makes logging configuration really simple. This is a good description of how to configure logging settings using SL4J and Logback: https://www.baeldung.com/logback.

rob42 commented 5 years ago

Hi Victor, Ive used the v3.0.0 jar you provided but still get the same problem when reusing processes( jvmPool.submit(new Calc(json),false);) pp4j-false.txt . The outcome is summarized in the log at the bottom:

Response Content: {"maxTime":22927,"failTotalTime":89731,"minTime":12774,"totalTime":206841,"failMinTime":12830,"initCount":17,"started":16,"failed":5,"succeeded":11,"failMaxTime":22928}

So 16 requests with a pool of 8. In the logs a successful response is denoted:

Response Status: 200

and fail:

Response Status: 500
rob42 commented 5 years ago

FYI the correct output is:

DEBUG com.cp.matlab.servlet.CalcExecutorTest.run(CalcExecutorTest$1.java:68) - Response Content: {"lhs":[{"mwtype":"double"....

The calculation takes up to 20 seconds.

rob42 commented 5 years ago

for the other scenario jvmPool.submit(new Calc(json),true); i get :

Response Content: {"maxTime":40246,"failTotalTime":1208483,"minTime":13468,"totalTime":241641,"failMinTime":302008,"initCount":17,"started":16,"failed":4,"succeeded":12,"failMaxTime":302456}

So after 12 or so iterations it fails with a timeout:

java.util.concurrent.TimeoutException: Submission {commands:["rO0ABXNyADpuZXQudmlrdG9yYy5wcDRqLmltcGwuSmF2YVByb2Nlc3NQb29sRXhlY3V0b3IkQ2FzdENhbGxhYmxl4/3/jk8uJJMCAAFMAAhjYWxsYWJsZXQAH0xqYXZhL3V0aWwvY29uY3VycmVudC9DYWxsYWJsZTt4cHNyABpjb20uY3AubWF0bGFiLnNlcnZsZXQuQ2FsYwAAAAAAAAABAgABTAAEanNvbnQADExtanNvbi9Kc29uO3hwc3IAFW1qc29uLkpzb24kT2JqZWN0SnNvbgAAAAAAAAABAgABTAAGb2JqZWN0dAAPTGphdmEvdXRpbC9NYXA7eHIACm1qc29uLkpzb24AAAAAAAAAAQIAA0wACWVuY2xvc2luZ3EAfgAETAAIZnVsbFBhdGh0ABJMamF2YS9sYW5nL1N0cmluZztMAAlwYXJlbnRLZXlxAH4ACXhwcHBwc3IAJmphdmEudXRpbC5jb25jdXJyZW50LkNvbmN1cnJlbnRIYXNoTWFwZJneEp2HKT0DAANJAAtzZWdtZW50TWFza0kADHNlZ21lbnRTaGlmdFsACHNlZ21lbnRzdAAxW0xqYXZhL3V0aWwvY29uY3VycmVudC9Db25jdXJyZW50SGFzaE1hcCRTZWdtZW50O3hwAAAADwAAABx1cgAxW0xqYXZhLnV0aWwuY29uY3VycmVudC5Db25jdXJyZW50SGFzaE1hcCRTZWdtZW50O1J3P0Eymzl0AgAAeHAAAAAQc3IALmphdmEudXRpbC5jb25jdXJyZW50LkNvbmN1cnJlbnRIYXNoTWFwJFNlZ21lbnQfNkyQWJMpPQIAAUYACmxvYWRGYWN0b3J4cgAoamF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MuUmVlbnRyYW50TG9ja2ZVqCwsyGrrAgABTAAEc3luY3QAL0xqYXZhL3V0aWwvY29uY3VycmVudC9sb2Nrcy9SZWVudHJhbnRMb2NrJFN5bmM7eHBzcgA0amF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MuUmVlbnRyYW50TG9jayROb25mYWlyU3luY2WIMudTe78LAgAAeHIALWphdmEudXRpbC5jb25jdXJyZW50LmxvY2tzLlJlZW50cmFudExvY2skU3luY7geopSqRFp8AgAAeHIANWphdmEudXRp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cQB+ARBwcHNxAH4AgUA0AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA1AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA2AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA3AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA4AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA5AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA6AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA7AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA8AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA9AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA+AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUA/AAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBAAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBAgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBBAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBBgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBCAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBCgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBDAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBDgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBEAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBEgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBFAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBFgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBGAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBGgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBHAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBHgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBIAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBIgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBJAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBJgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBKAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBKgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBLAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBLgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBMAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBMgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBNAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBNgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBOAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBOgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBPAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBPgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBQAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBQQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBQgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBQwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBRAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBRQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBRgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBRwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBSAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBSQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBSgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBSwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBTAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBTQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBTgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBTwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBUAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBUQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBUgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBUwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBVAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBVQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBVgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBVwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBWAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBWQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBWgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBWwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBXAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBXQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBXgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBXwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBYAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBYQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBYgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBYwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBZAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBZQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBZgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBZwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBaAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBaQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBagAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBawAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBbAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBbQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBbgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBbwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBcAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBcQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBcgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBcwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBdAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBdQAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBdgAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBdwAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBeAAAAAAAAc3EAfgA4cQB+ARBwcHNxAH4AgUBeQAAAAAAAeHBweHNxAH4ABnEAfgBLcHBzcQB+AAsAAAAPAAAAHHVxAH4ADgAAABBzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHQABm13dHlwZXNxAH4AP3EAfgIEcHB0AAZkb3VibGV0AAZtd3NpemVzcQB+AElxAH4CBHBwc3EAfgBMAAAAAncEAAAAAnNxAH4AOHEAfgIrcHBxAH4BDXNxAH4AOHEAfgIrcHBxAH4APXh0AAZtd2RhdGFzcQB+AElxAH4CBHBwc3EAfgBMAAAAeXcEAAAAeXNxAH4AOHEAfgIwcHBzcQB+AIE/Gjbi6xxDLXNxAH4AOHEAfgIwcHBzcQB+AIE/Ojbi6xxDLXNxAH4AOHEAfgIwcHBzcQB+AIE/M6kqMFUyYXNxAH4AOHEAfgIwcHBzcQB+AIE/ngDRtxdY4nNxAH4AOHEAfgIwcHBzcQB+AIE/hHrhR64Ue3NxAH4AOHEAfgIwcHBzcQB+AIE/l8G9pRGc4HNxAH4AOHEAfgIwcHBzcQB+AIE/09cKPXCj13NxAH4AOHEAfgIwcHBzcQB+AIE/iJN0vGp++nNxAH4AOHEAfgIwcHBzcQB+AIE/iwiaAnUlRnNxAH4AOHEAfgIwcHBzcQB+AIE/iJN0vGp++nNxAH4AOHEAfgIwcHBzcQB+AIE/sCDEm6XjVHNxAH4AOHEAfgIwcHBzcgAUamF2YS5tYXRoLkJpZ0RlY2ltYWxUxxVX+YEoTwMAAkkABXNjYWxlTAAGaW50VmFsdAAWTGphdmEvbWF0aC9CaWdJbnRlZ2VyO3hxAH4APAAAABJzcgAUamF2YS5tYXRoLkJpZ0ludGVnZXKM/J8fqTv7HQMABkkACGJpdENvdW50SQAJYml0TGVuZ3RoSQATZmlyc3ROb256ZXJvQnl0ZU51bUkADGxvd2VzdFNldEJpdEkABnNpZ251bVsACW1hZ25pdHVkZXQAAltCeHEAfgA8///////////////+/////gAAAAF1cgACW0Ks8xf4BghU4AIAAHhwAAAABy5jngoukNp4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHN0IRz6aJ7nh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAc//WxlGnFSeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB0iVrcqKRwJ4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAGz3fmZkzpeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwjvsICJX7x4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHYYva2sFd73h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdpl7eAIOzfeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwtZpeVZPdB4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHeUYlOtPVpnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcM5BI7Nx5aeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABw2kBJ7yPyt4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHj8SM6sGuJHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcPGWHYAOHkeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB54T/sVL5fx4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHEIC0/dqwvnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcRLxrJk8i1eHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxHZ/hB/q7d4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHEoFe0p5Zv3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAe/dGKfXjwReHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxPFmMh0FuZ4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFGJx/CsmB3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcU+8irFQAueHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB9ewIFPwdbJ4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAH3WdQyQrX1nh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcWsr2bA1DWeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxc+Cja4Vxx4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHF8XUTaAobHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcYShvfusTDeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxjK4O0ILCN4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGUgjdYheinh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcZweN5O1v5eHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxo4IPghJHB4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGqrb8jm37Xh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcbGhRnhRZzeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxuFylgDQAJ4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHG+39w7Q0mnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcC1RF3dZhseHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxyz3Qyuft54eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHRGI6ffUjXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcda7JCc/VCeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx3CWRYi4QB4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHAwImI7Oox3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAceZR8vGRmTeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx6xPnRgZml4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHvnbNNp+R3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcfPvVwh2EreHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx+AjSdnDxh4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHH76iWXmIDnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcDMoVNeXrOeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByAwRS822xF4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIGPS0uG1G3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcgk93xv1ozeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwNGcKeUx254eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIOlsoRMFcnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchDvAxiQufeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByEw8T0x3NR4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIU9vxA15EXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchamvGG+BUeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByGB5UNdEqB4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIZXcO9EP83h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchplCvd9hReHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByGzQp5Ra7N4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIbyyCF3KIHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchwp7tnPOReHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwNggO40sM54eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIcPxKbOnk3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchv1aAizIbeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwNfH1UO8/h4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIauZn9KoSXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchnHdoQpPteHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByGJ0qvlSpl4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIXOrarrMTHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchWgGkwxkGeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwNS4iKZa0d4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIRwmimwTkHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcg9/U2DMFieHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByDQQVzgOj54eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIKUK/uZ+Inh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcgdlIcH40KeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwM6AkVBI+Z4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIA5YyCoL9Xh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcf1RhW+3v4eHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx+YVWD/twB4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHH1gP5ja9E3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcDG6DKQ0FreHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx7M/WI9Kkt4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHoIwWQyRdnh4c3EAfgA4cQB+AjBwcHNxAH4AgT+1w2fD0Nudc3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcd4g64Q8DfeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx2MuiCriSF4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHTPjBEYca3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcc14ljE3q3eHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxx3rT0TpBN4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHAs7UqDpCcnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcbrW1irFfdeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxtDCa5E4kt4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGtUjdRA3wXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcaY7q3DlhEeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwKX4Yuf7S54eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGXZhrKL6WXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcCf3G80oxleHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxh6/o8CyJR4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHF/gJOP7gO3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcXcZFeLcLleHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxbnlv6PcJx4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFloaGiPpYXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAfZ2wrpL8OMeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxU0mMLlO/l4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFJyUUBIVzXh4eHBweHNxAH4ABnEAfgBLcHBzcQB+AAsAAAAPAAAAHHVxAH4ADgAAABBzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHQABm13dHlwZXNxAH4AP3EAfgQDcHB0AAZkb3VibGV0AAZtd3NpemVzcQB+AElxAH4EA3Bwc3EAfgBMAAAAAncEAAAAAnNxAH4AOHEAfgQqcHBxAH4BDXNxAH4AOHEAfgQqcHBxAH4APXh0AAZtd2RhdGFzcQB+AElxAH4EA3Bwc3EAfgBMAAAAeXcEAAAAeXNxAH4AOHEAfgQvcHBzcQB+AIE/Gjbi6xxDLXNxAH4AOHEAfgQvcHBzcQB+AIE/Gjbi6xxDLXNxAH4AOHEAfgQvcHBzcQB+AIE/M6kqMFUyYXNxAH4AOHEAfgQvcHBzcQB+AIE/YtdzGPxQSHNxAH4AOHEAfgQvcHBzcQB+AIE/hHrhR64Ue3NxAH4AOHEAfgQvcHBzcQB+AIE/hvAGjbi6x3NxAH4AOHEAfgQvcHBzcQB+AIE/lHrhR64Ue3NxAH4AOHEAfgQvcHBzcQB+AIE/l41P3ztkWnNxAH4AOHEAfgQvcHBzcQB+AIE/nrhR64UeuHNxAH4AOHEAfgQvcHBzcQB+AIE/nrhR64UeuHNxAH4AOHEAfgQvcHBzcQB+AIE/uNT987ZFonNxAH4AOHEAfgQvcHBzcQB+AIE/Gjbi6xxDLXNxAH4AOHEAfgQvcHBzcQB+AIE/UDQg0CbmlnNxAH4AOHEAfgQvcHBzcQB+AkkAAAATc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHQrgkxD/wu3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABNzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdiTXfT/KkUeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwz9FEn48CV4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHECWcmFicL3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcB7jbj3zpseHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAE3NxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB+CixBLvio94eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGZ81g3egS3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAccx73R10xTeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx/wRiA2+F14eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIxjObpakZnh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcmQVa89lBveHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABylp3wtV/Hl4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHLJJnWbWognh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAZ6MHoANpt4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHMuN39nUAlXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAc2DABE1KyeeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwW4dA64b0R4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHPF0Q4ZQEsnh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAc/hZkv87C7eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwarA1luvHp4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHRdapzLMIzXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdI/zIbErTVeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB0wnumlyYN54eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHT1BCt9IM6nh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdSeMsGMbjzeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwiQIe7bVuZ4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHWMnbovERBHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdb8mPxUL0NeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABvN4H1tdNnh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdiQ3SOEBUieHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB2Vr/NxvwSp4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHCnVAhEfxUnh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdrvQ15Lxk8eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB27llceOxUh4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHC2fPzv4+iHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcLuKo9OwLveHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwwJhKt3x1d4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHe4e3AQ11cnh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcMqzmH8VAmeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwz8E/YuFI14eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHhQFP7Cx5jHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAeIKdg6jCWUeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABw3uo0DkYcN4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHAWy/xLaD0Xh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAeRo3ElqymveHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABw7hMouarvl4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHDzIM+ddzYHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcBjRckAgWUeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABw/TwdZQ/C94eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHoW4arYmF4Xh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcQdXayyoT+eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxDGUSEHSWV4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHERcrj0QNzHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcRaAX9gNI0eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB7E4xDVn4hN4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHEgm62fpbA3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcSWpVINx9qeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB7qyXSCG5i14eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHvdrlbuaSNnh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAfBA229Rj5GeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxOd/wEqMQh4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHE+7Zb2b1b3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAfKfQaoZUJgeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxSQjkvgfj54eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFOFouh1CpXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcVMkMoWgcMeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB9cfJ+Hj8oN4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFdP4BNOP23h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcWJNJzEFRCeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxZ1rOFNGKl4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFsaHT4ndEXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcXF2G9xqF4eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxdoPCwDZeB4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHF7kWmkAqSHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcYCfEIfO6ueHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxhay3a5sxV4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGKul5PZ3fXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcY/IBTMzvleHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxlNWsFwAEt4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGZ41L6zEs3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcZ7w+d6YkaeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwKf/c4D1I14eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGpDEemMR6Hh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAca4Z7on9ZQeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxsyeVbcmrd4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHG4NTxRlfH3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcb1C4zViOHeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxwlCKGS5+54eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHAtiWtMf3onh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAccxr1+DHC8eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx0Xl+xJNSR4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHWhyWoX5i3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcC+O4UE3lleHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx4KJzb/gll4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHlsBpTxGwXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAceq9wTeQspeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwMZRXNe+yh4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHH02Q7/KT9nh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcfnmteL1heeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx/vRcxsHMZ4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAA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"]}@704f0d50 timed out
    at net.viktorc.pp4j.impl.ProcessPoolExecutor$InternalSubmissionFuture.get(ProcessPoolExecutor.java:609) ~[pp4j-3.0.0.jar:?]
    at net.viktorc.pp4j.impl.JavaProcessPoolExecutor$CastFuture.get(JavaProcessPoolExecutor.java:283) ~[pp4j-3.0.0.jar:?]
    at com.cp.matlab.servlet.MatlabExecutor.doPost(MatlabExecutor.java:123) 

pp4j-true.txt

I have some timeouts on the threads etc, but Ive extended those and see no difference, so I assume they are coming from your code?

rob42 commented 5 years ago

The reason for this whole app is that only a single matlab calculation is possible at a time in a process, but matlab only uses one CPU core per calc. So to scale you need to have one calc per CPU core, and run them in separate processes.

The calculations come via an activemq JMS server, so lots arrive there, and activemq distributes them to a pool of these matlab-calc servers. Since activemq already queues them, in an optimal design the matlab-calc server will signal that its pool is all busy when a new calc arrives, and activemq will try another server.

Is it possible to find the current depth of submissions from pp4j?

Also I discovered that enabling debug in my code resulted in the calc outputting debug in the JavaProcess, which caused the process to assume it was complete and return. Turing it off solved that but its worth considering that a process may output several lines while running, then a final answer. Is there a way to access or control that?

ViktorC commented 5 years ago

Hi Rob,

Thanks for giving it a go with the new version and for uploading the log file. I'm looking through it right now. It seems to be an issue with decoding the tasks sent to the Java processes. I am not sure what triggers this yet as some processes can apparently execute two tasks without any problems.

Out of curiosity, does it work now when you don't reuse the processes?

EDIT: Ah, nevermind. I forgot to refresh and just saw your comments.

rob42 commented 5 years ago

Maybe ? https://stackoverflow.com/questions/35292836/input-byte-array-has-incorrect-ending-byte-at-40#35293091

ViktorC commented 5 years ago

I am not sure I know what you mean by the current depth of submissions. Can you elaborate on that, please?

As for outputting stuff to the standard streams from tasks submitted to the Java process pool, it should not be a problem. The process output handler is invoked every time a line is output to the stream, but it will only consider the task complete if this line is a Base64 encoded, serialized instance of a special class used for encapsulating the results of tasks. If it is not, it should be just ignored. If that's not case, there is probably a bug somewhere. I would be keen to take a look at the logs of that run, if you happen to have them.

ViktorC commented 5 years ago

Maybe ? https://stackoverflow.com/questions/35292836/input-byte-array-has-incorrect-ending-byte-at-40#35293091

I did consider it being a charset mismatch, but I don't see how that could happen. Both the pool and the processes are coded explicitly to use ISO_8859_1.

rob42 commented 5 years ago

When I send a new submission I get a trace line:

Processes: 8; submissions: 10

is there a

int x = jvmPool.getCurrentProcesses();
int y = jvmPool.getCurrentSubmissions();
ViktorC commented 5 years ago

When I send a new submission I get a trace line:

Processes: 8; submissions: 10

is there a

int x = jvmPool.getCurrentProcesses();
int y = jvmPool.getCurrentSubmissions();

Ah, yes. You can invoke getNumOfProcesses() and getNumOfSubmissions() on the pool.

rob42 commented 5 years ago

Re ISO_8859_1. My JVM (on linux) is probably using UTF-8 or UTF-16. But since its sending the same job each time that should cause the same failure each time.

What about the 'space at the end', eg using trim() on the decode string? Maybe there is a spurious CR/LF or space happpening?

ViktorC commented 5 years ago

Re ISO_8859_1. My JVM (on linux) is probably using UTF-8 or UTF-16. But since its sending the same job each time that should cause the same failure each time.

What about the 'space at the end', eg using trim() on the decode string? Maybe there is a spurious CR/LF or space happpening?

All lines are trimmed before decoding, so unfortunately that's probably not it either.

By the way, the timeouts when terminating the processes after each submission are caused by decoding/serialization issues as well. I can see in the logs that a clearly Base64 encoded string is printed to the process' standard out, yet the process output handler does not recognize it as a legit response, and therefore the task is considered to be executing indefinitely.

ViktorC commented 5 years ago

Is this the same behaviour you observed when using v2.2? Because the serialization and encoding mechanism did change a bit, perhaps for the worse.

rob42 commented 5 years ago

Yes same with v2.2. That fits with something else I noticed before add timeouts to cleanup at my end. There were often 2-4 processes waiting indefinitely.

ViktorC commented 5 years ago

Cool, thanks. Then it has probably been the same problem all along. I'll keep digging tomorrow to identify what goes wrong.

rob42 commented 5 years ago

Looking at https://github.com/ViktorC/PP4J/blob/master/src/main/java/net/viktorc/pp4j/impl/JavaObjectCodec.java

JavaObjectCodec is a singleton and has encoder and decoder as attributes. So all instances are using the same instances of them. Wondering if its thread-safe. Std way of using it may be worth testing with

 public String encode(Object object) throws IOException {
    try (ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
        ObjectOutputStream objectOutput = new ObjectOutputStream(byteArrayOut)) {
      objectOutput.writeObject(object);
      return new **String(Base64.getEncoder()**.encode(byteArrayOut.toByteArray()), CHARSET);
    }
  }
ViktorC commented 5 years ago

Looking at https://github.com/ViktorC/PP4J/blob/master/src/main/java/net/viktorc/pp4j/impl/JavaObjectCodec.java

JavaObjectCodec is a singleton and has encoder and decoder as attributes. So all instances are using the same instances of them. Wondering if its thread-safe. Std way of using it may be worth testing with

 public String encode(Object object) throws IOException {
    try (ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
        ObjectOutputStream objectOutput = new ObjectOutputStream(byteArrayOut)) {
      objectOutput.writeObject(object);
      return new **String(Base64.getEncoder()**.encode(byteArrayOut.toByteArray()), CHARSET);
    }
  }

That's what it was like in v2.2 which suffers from the same problem. I changed to having them as members of the JavaObjectCodec class as both the encoder and the decoder are singletons so all calls to getEncoder() and getDecoder() return the same instances. According to the documentation, they should be thread safe: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Decoder.html

Instances of Base64.Decoder class are safe for use by multiple concurrent threads.

Nevertheless, that's a good lead. I'm pretty sure the problem is somewhere within that class.

rob42 commented 5 years ago

I was trying various things yesterday. Made some progress. Same with both jvmPool.submit(new Calc(json),true); and jvmPool.submit(new Calc(json),true);

1) If I dont create the native object and replace the call to it with a sleep(10000), it works as expected.

2) If I create the native object but dont call it, it still fails (hangs for true, stream errors for false). I tried careful cleanup of the native object, but still failed. Im wondering if there are threads or something that are not completing, hence the JVM never exits properly and the pool becomes exhausted?

Looks like this is due to the matlab native code after all. Basically I think it causes the JVM not to exit, causing the effects we see above. I have the java wrapper src code for the matlab natives, but not the deeper lib, so its difficult to see whats causing it.

One solution might be to add a different way to recognise that a JVM is free. eg execute callable and forceCompletion when it returns, ignoring remnants?

rob42 commented 5 years ago

Or maybe get the callable to output a flag to stdout in a finally clause?

ViktorC commented 5 years ago

I did try to recreate the problem to no avail. I even used JNI (with that simple native code I use for the tests), but everything worked fine.

I suspect JNI is the catalyst, though. The standard streams are redirected in the Java processes maintained by the pool so if you submit a task that prints to System.out, the message will never actually make its way to the standard out stream. However, if you use JNI, the native code will still be able to print to the standard streams. I am thinking this might cause complications in some cases.

JNI also has a peculiar way of crashing the JVM if there is an error in the native code. As you suggested, it might also just corrupt it instead of completely blowing it up.

ViktorC commented 5 years ago

Or maybe get the callable to output a flag to stdout in a finally clause?

The slave Java process sends back a response to the pool if either the Callable's execution completes or an exception is thrown. If the callable completes, the response will contain its result, and if an exception is thrown, it will contain the exception (which then you can access wrapped in an ExecutionException when calling get() on the future instance).

So I guess this response functions as a flag.

As for terminating the process, it is again done by the exchange of specific request and response object.

rob42 commented 5 years ago

While JNI is a dodgy beast, the actual JNI code used here is quite robust. If I run it in a single JVM it rarely causes any problems. I suspect it starts an Executor or some other thread, which holds the JVM open, or maybe its an anomaly of the in and out stream redirection?

How does your lib decide when the task is complete?

ViktorC commented 5 years ago

I built a new version that has somewhat better logging which might help us identify when and where it all goes south.

pp4j-3.0.0.jar.zip

If you have some time to rerun it again with the new version, I would gladly inspect the logs.

ViktorC commented 5 years ago

While JNI is a dodgy beast, the actual JNI code used here is quite robust. If I run it in a single JVM it rarely causes any problems. I suspect it starts an Executor or some other thread, which holds the JVM open, or maybe its an anomaly of the in and out stream redirection?

How does your lib decide when the task is complete?

Basically, it just waits for the callable to finish running or throw an exception. This is what happens in the Java process:

try {
  String line = in.readLine();
  if (line == null) {
    return;
  }
  line = line.trim();
  if (line.isEmpty()) {
    continue;
  }
  Object input = JavaObjectCodec.getInstance().decode(line);
  if (input == Request.TERMINATE) {
    System.out.println(JavaObjectCodec.getInstance().encode(Signal.TERMINATED));
    return;
  } else if (input instanceof Callable<?>) {
    Callable<?> c = (Callable<?>) input;
    redirectStdOut(dummyOut);
    Object output = c.call();
    redirectStdOut(originalOut);
    System.out.println(JavaObjectCodec.getInstance().encode(new Response(false, output)));
  }
} catch (Throwable e) {
  redirectStdOut(originalOut);
  System.out.println(JavaObjectCodec.getInstance().encode(new Response(true, e)));
}
rob42 commented 5 years ago

tried the new version - logging looks the same :-(

ViktorC commented 5 years ago

The difference is subtle but important. Every process executor uses multiple child threads (one for taking submissions off the queue and executing them, one for listening to the process' standard out stream, one for timing periods of idleness, etc.). With the new logging, we should be able to identify which threads belong to which process executor and therefore work out exactly what was sent to which process and what was sent back in return.

ViktorC commented 5 years ago

There should be log entries like Starting {} thread of process executor {}....

rob42 commented 5 years ago

ok, attached. I see that thread 13 seems to execute, terminate, then starts, is sent a callable, but then stalls. Much later it gets 'terminated while executing'

11:44:40.326 [processPoolExecutor@1a052a00-secondaryThreadPool-thread-13] TRACE net.viktorc.pp4j.impl.AbstractProcessExecutor.executeCommand(AbstractProcessExecutor.java:432) - Command succeeded
11:44:40.326 [processPoolExecutor@1a052a00-secondaryThreadPool-thread-13] TRACE net.viktorc.pp4j.impl.AbstractProcessExecutor.executeSubmission(AbstractProcessExecutor.java:457) - Submission {commands:["rO0ABXNyADpuZXQudmlrdG9yYy5wcDRqLmltcGwuSmF2YVByb2Nlc3NQb29sRXhlY3V0b3IkQ2FzdENhbGxhYmxl4/3/jk8uJJMCAAFMAAhjYWxsYWJsZXQAH0xqYXZhL3V0aWwvY29uY3VycmVudC9DYWxsYWJsZTt4cHNyABpjb20uY3AubWF0bGFiLnNlcnZsZXQuQ2FsYwAAAAAAAAABAgAESgAIY2FsY1RpbWVKAAlxdWV1ZVRpbWVKAAlzdGFydFRpbWVMAARqc29udAAMTG1qc29uL0pzb247eHAAAAAAAAAAAAAAAAAAAAAAAAABbLu3bK9zcgAVbWpzb24uSnNvbiRPYmplY3RKc29uAAAAAAAAAAECAAFMAAZvYmplY3R0AA9MamF2YS91dGlsL01hcDt4cgAKbWpzb24uSnNvbgAAAAAAAAABAgADTAAJZW5jbG9zaW5ncQB+AARMAAhmdWxsUGF0aHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACXBhcmVudEtleXEAfgAJeHBwcHBzcgAmamF2YS51dGlsLmNvbmN1cnJlbnQuQ29uY3VycmVudEhhc2hNYXBkmd4SnYcpPQMAA0kAC3NlZ21lbnRNYXNrSQAMc2VnbWVudFNoaWZ0WwAIc2VnbWVudHN0ADFbTGphdmEvdXRpbC9jb25jdXJyZW50L0NvbmN1cnJlbnRIYXNoTWFwJFNlZ21lbnQ7eHAAAAAPAAAAHHVyADFbTGphdmEudXRpbC5jb25jdXJyZW50LkNvbmN1cnJlbnRIYXNoTWFwJFNlZ21lbnQ7Unc/QTKbOXQCAAB4cAAAABBzcgAuamF2YS51dGlsLmNvbmN1cnJlbnQuQ29uY3VycmVudEhhc2hNYXAkU2VnbWVudB82TJBYkyk9AgABRgAKbG9hZEZhY3RvcnhyAChqYXZhLnV0aWwuY29uY3VycmVudC5sb2Nrcy5SZWVudHJhbnRMb2NrZlWoLCzIausCAAFMAARzeW5jdAAvTGphdmEvdXRpbC9jb25jdXJyZW50L2xvY2tzL1JlZW50cmFudExvY2skU3luYzt4cHNyADRqYXZhLnV0aWwuY29uY3VycmVudC5sb2Nrcy5SZWVudHJhbnRMb2NrJE5vbmZhaXJTeW5jZYgy51N7vwsCAAB4cgAtamF2YS51dGls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cQB+ADhxAH4BEHBwc3EAfgCBQDIAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDMAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDQAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDUAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDYAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDcAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDgAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDkAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDoAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDsAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQDwAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQD0AAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQD4AAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQD8AAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEAAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQECAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEEAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEGAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEIAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEKAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEMAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEOAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEQAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQESAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEUAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEWAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEYAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEaAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEcAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEeAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEgAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEiAAAAAAABzcQB+ADhxAH4BEHBwc3EAfgCBQEkAAAAAAABzcQB+ADhxAH4B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gT+wIMSbpeNUc3EAfgA4cQB+AjBwcHNyABRqYXZhLm1hdGguQmlnRGVjaW1hbFTHFVf5gShPAwACSQAFc2NhbGVMAAZpbnRWYWx0ABZMamF2YS9tYXRoL0JpZ0ludGVnZXI7eHEAfgA8AAAAEnNyABRqYXZhLm1hdGguQmlnSW50ZWdlcoz8nx+pO/sdAwAGSQAIYml0Q291bnRJAAliaXRMZW5ndGhJABNmaXJzdE5vbnplcm9CeXRlTnVtSQAMbG93ZXN0U2V0Qml0SQAGc2lnbnVtWwAJbWFnbml0dWRldAACW0J4cQB+ADz///////////////7////+AAAAAXVyAAJbQqzzF/gGCFTgAgAAeHAAAAAHLmOeCi6Q2nh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAc3QhHPponueHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABz/9bGUacVJ4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHSJWtyopHAnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAbPd+ZmTOl4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHCO+wgIlfvHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdhi9rawV3veHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB2mXt4Ag7N94eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHC1ml5Vk90Hh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAd5RiU609WmeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwzkEjs3Hlp4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHDaQEnvI/K3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAePxIzqwa4keHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABw8ZYdgA4eR4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHnhP+xUvl/Hh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcQgLT92rC+eHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxEvGsmTyLV4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHEdn+EH+rt3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcSgV7Snlm/eHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB790Yp9ePBF4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHE8WYyHQW5nh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcUYnH8KyYHeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxT7yKsVAC54eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAH17AgU/B1snh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAfdZ1DJCtfWeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxayvZsDUNZ4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFz4KNrhXHHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcXxdRNoChseHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxhKG9+6xMN4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGMrg7QgsI3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcZSCN1iF6KeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxnB43k7W/l4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGjgg+CEkcHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcaqtvyObfteHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxsaFGeFFnN4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHG4XKWANAAnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcb7f3DtDSaeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwLVEXd1mGx4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHLPdDK5+3nh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcdEYjp99SNeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx1rskJz9UJ4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHcJZFiLhAHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcDAiYjs6jHeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx5lHy8ZGZN4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHrE+dGBmaXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAce+ds02n5HeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx8+9XCHYSt4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHH4CNJ2cPGHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcfvqJZeYgOeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwMyhU15es54eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIDBFLzbbEXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcgY9LS4bUbeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByCT3fG/WjN4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHA0Zwp5THbnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcg6WyhEwVyeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByEO8DGJC594eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHITDxPTHc1Hh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchT2/EDXkReHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByFqa8Yb4FR4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIYHlQ10SoHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchldw70Q/zeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByGmUK932FF4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIbNCnlFrs3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchvLIIXcogeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByHCnu2c85F4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHA2CA7jSwznh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchw/Eps6eTeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByG/VoCLMht4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHA18fVQ7z+Hh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchq5mf0qhJeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByGcd2hCk+14eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHIYnSq+VKmXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchc6tqusxMeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByFaAaTDGQZ4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHA1LiIplrR3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAchHCaKbBOQeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByD39TYMwWJ4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHINBBXOA6Pnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcgpQr+5n4ieHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByB2UhwfjQp4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHAzoCRUEj5nh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcgDljIKgv1eHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx/VGFb7e/h4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHH5hVYP+3AHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcfWA/mNr0TeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwMboMpDQWt4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHsz9Yj0qS3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcegjBZDJF2eHhzcQB+ADhxAH4CMHBwc3EAfgCBP7XDZ8PQ251zcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx3iDrhDwN94eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHYy6IKuJIXh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcdM+MERhxreHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxzXiWMTerd4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHHetPROkE3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcCztSoOkJyeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxutbWKsV914eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHG0MJrkTiS3h4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAca1SN1EDfBeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxpjurcOWER4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHApfhi5/tLnh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcZdmGsovpZeHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwJ/cbzSjGV4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGHr+jwLIlHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcX+Ak4/uA7eHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxdxkV4twuV4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFueW/o9wnHh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcWWhoaI+lheHhzcQB+ADhxAH4CMHBwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB9nbCukvw4x4eHNxAH4AOHEAfgIwcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFTSYwuU7+Xh4c3EAfgA4cQB+AjBwcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcUnJRQEhXNeHh4cHB4c3EAfgAGcQB+AEtwcHNxAH4ACwAAAA8AAAAcdXEAfgAOAAAAEHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAc3EAfgAQc3EAfgAUAAAAAD9AAABzcQB+ABBzcQB+ABQAAAAAP0AAAHNxAH4AEHNxAH4AFAAAAAA/QAAAdAAGbXd0eXBlc3EAfgA/cQB+BANwcHQABmRvdWJsZXQABm13c2l6ZXNxAH4ASXEAfgQDcHBzcQB+AEwAAAACdwQAAAACc3EAfgA4cQB+BCpwcHEAfgENc3EAfgA4cQB+BCpwcHEAfgA9eHQABm13ZGF0YXNxAH4ASXEAfgQDcHBzcQB+AEwAAAB5dwQAAAB5c3EAfgA4cQB+BC9wcHNxAH4AgT8aNuLrHEMtc3EAfgA4cQB+BC9wcHNxAH4AgT8aNuLrHEMtc3EAfgA4cQB+BC9wcHNxAH4AgT8zqSowVTJhc3EAfgA4cQB+BC9wcHNxAH4AgT9i13MY/FBIc3EAfgA4cQB+BC9wcHNxAH4AgT+EeuFHrhR7c3EAfgA4cQB+BC9wcHNxAH4AgT+G8AaNuLrHc3EAfgA4cQB+BC9wcHNxAH4AgT+UeuFHrhR7c3EAfgA4cQB+BC9wcHNxAH4AgT+XjU/fO2Rac3EAfgA4cQB+BC9wcHNxAH4AgT+euFHrhR64c3EAfgA4cQB+BC9wcHNxAH4AgT+euFHrhR64c3EAfgA4cQB+BC9wcHNxAH4AgT+41P3ztkWic3EAfgA4cQB+BC9wcHNxAH4AgT8aNuLrHEMtc3EAfgA4cQB+BC9wcHNxAH4AgT9QNCDQJuaWc3EAfgA4cQB+BC9wcHNxAH4CSQAAABNzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdCuCTEP/C7eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAE3NxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB2JNd9P8qRR4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHDP0USfjwJXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcQJZyYWJwveHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwHuNuPfOmx4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAATc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAH4KLEEu+Kj3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcZnzWDd6BLeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxzHvdHXTFN4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHH/BGIDb4XXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcjGM5ulqRmeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAByZBVrz2UG94eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHKWnfC1X8eXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcskmdZtaiCeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABnowegA2m3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcy43f2dQCVeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABzYMAETUrJ54eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHBbh0DrhvRHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAc8XRDhlASyeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABz+FmS/zsLt4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHBqsDWW68enh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdF1qnMswjNeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB0j/MhsStNV4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHTCe6aXJg3nh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdPUEK30gzqeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB1J4ywYxuPN4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHCJAh7ttW5nh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAdYydui8REEeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB1vyY/FQvQ14eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAG83gfW102eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB2JDdI4QFSJ4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHZWv83G/BKnh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcKdUCER/FSeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB2u9DXkvGTx4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHbuWVx47FSHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcLZ8/O/j6IeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwu4qj07Au94eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHDAmEq3fHV3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAd7h7cBDXVyeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwyrOYfxUCZ4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHDPwT9i4UjXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAeFAU/sLHmMeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB4gp2DqMJZR4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHDe6jQORhw3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcBbL/EtoPReHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB5GjcSWrKa94eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHDuEyi5qu+Xh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcPMgz513NgeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwGNFyQCBZR4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHD9PB1lD8L3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAehbhqtiYXheHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxB1drLKhP54eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHEMZRIQdJZXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcRFyuPRA3MeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxFoBf2A0jR4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHsTjENWfiE3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcSCbrZ+lsDeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxJalUg3H2p4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHurJdIIbmLXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABJzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAe92uVu5pI2eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB8EDbb1GPkZ4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHE53/ASoxCHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcT7tlvZvVveHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEnNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAAB8p9BqhlQmB4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFJCOS+B+Pnh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcU4Wi6HUKleHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxUyQyhaBwx4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAASc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAH1x8n4ePyg3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcV0/gE04/beHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxYk0nMQVEJ4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHFnWs4U0YqXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcWxodPid0ReHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxcXYb3GoXh4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHF2g8LANl4Hh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcXuRaaQCpIeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxgJ8Qh87q54eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGFrLdrmzFXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcYq6Xk9nd9eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxj8gFMzO+V4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGU1awXAAS3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcZnjUvrMSzeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxnvD53piRp4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHAp/9zgPUjXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcakMR6YxHoeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxrhnuif1lB4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHGzJ5Vtyat3h4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcbg1PFGV8feHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxvULjNWI4d4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHCUIoZLn7nh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABBzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcC2Ja0x/eieHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABxzGvX4McLx4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHReX7Ek1JHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcdaHJahfmLeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEHNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABwL47hQTeWV4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHHgonNv+CWXh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAceWwGlPEbBeHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx6r3BN5Cyl4eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAAQc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8AAAAHAxlFc177KHh4c3EAfgA4cQB+BC9wcHNxAH4CSQAAABFzcQB+Akz///////////////7////+AAAAAXVxAH4CTwAAAAcfTZDv8pP2eHhzcQB+ADhxAH4EL3Bwc3EAfgJJAAAAEXNxAH4CTP///////////////v////4AAAABdXEAfgJPAAAABx+ea14vWF54eHNxAH4AOHEAfgQvcHBzcQB+AkkAAAARc3EAfgJM///////////////+/////gAAAAF1cQB+Ak8A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"]}@38d29baf executed
11:44:40.327 [processPoolExecutor@1a052a00-secondaryThreadPool-thread-13] TRACE net.viktorc.pp4j.impl.AbstractProcessExecutor.tryExecute(AbstractProcessExecutor.java:518) - Terminating process after successful submission execution
11:44:40.327 [processPoolExecutor@1a052a00-secondaryThreadPool-thread-13] TRACE net.viktorc.pp4j.impl.AbstractProcessExecutor.tryTerminate(AbstractProcessExecutor.java:552) - Attempting to terminate process using termination submission
11:44:40.327 [Thread-8] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 19676
11:44:40.328 [processPoolExecutor@1a052a00-secondaryThreadPool-thread-13] TRACE net.viktorc.pp4j.impl.AbstractProcessExecutor.tryExecute(AbstractProcessExecutor.java:505) - Attempting to execute submission {commands:["rO0ABX5yACluZXQudmlrdG9yYy5wcDRqLmltcGwuSmF2YVByb2Nlc3MkUmVxdWVzdAAAAAAAAAAAEgAAeHIADmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQACVRFUk1JTkFURQ=="]}
11:44:40.328 [processPoolExecutor@1a052a00-secondaryThreadPool-thread-13] TRACE net.viktorc.pp4j.impl.AbstractProcessExecutor.executeSubmission(AbstractProcessExecutor.java:452) - Starting execution of submission
11:44:40.328 [processPoolExecutor@1a052a00-secondaryThreadPool-thread-13] TRACE net.viktorc.pp4j.impl.AbstractProcessExecutor.executeCommand(AbstractProcessExecutor.java:417) - Writing instruction "rO0ABX5yACluZXQudmlrdG9yYy5wcDRqLmltcGwuSmF2YVByb2Nlc3MkUmVxdWVzdAAAAAAAAAAAEgAAeHIADmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQACVRFUk1JTkFURQ==" to process' standard in
11:44:40.328 [Thread-8] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 4574
11:44:40.329 [Thread-8] DEBUG com.cp.matlab.servlet.CalcExecutorTest.run(CalcExecutorTest$1.java:67) - Response Status: 200
11:44:40.330 [Thread-8] DEBUG com.cp.matlab.servlet.CalcExecutorTest.run(CalcExecutorTest$1.java:69) - Response Content: {"calcTime":4574,"reply":"{\"lhs\":....

pp4j-true-extra-log.txt

ViktorC commented 5 years ago

Thank you for the logs. I found some interesting things.

I looked at a process executor that stalled. It first executed your task successfully and returned your JSON response. Then it proceeded to try and terminate the process (as expected given the terminateProcessAfterwards parameter was true) and sent the usual TERMINATE request to the process. However, when the process tried to decode the request, this exception was thrown:

java.io.StreamCorruptedException: invalid stream header: 057E7200
    at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:808)
    at java.io.ObjectInputStream.<init>(ObjectInputStream.java:301)
    at net.viktorc.pp4j.impl.JavaObjectCodec.decode(JavaObjectCodec.java:90)
    at net.viktorc.pp4j.impl.JavaProcess.main(JavaProcess.java:62)

When an exception is thrown in the process, it is caught and returned within a Response object. The problem is that the process output handler expects the process to output a TERMINATED signal in response and ignores everything else. As it never happens thanks to the exception, the process executor stalls until it is forcibly shut down.

This is definitely a resiliency issue that I can address in the library, but it only solves the problem of stalling executors. I am still not sure why the stream gets corrupted in the first place. 🤔

rob42 commented 5 years ago

Wonder if the matlab JNI is interfering with the redirectStdOut? Or maybe it needs a flush() somewhere?

rob42 commented 5 years ago

convert 057E7200 to UTF-8 and you get 爀 Its the chinese spying! Or maybe its the russians pretending to be chinese?

ViktorC commented 5 years ago

It's gotta go deeper than that. It's the Chinese disguised as Russians pretending to be Chinese. 💥

ViktorC commented 5 years ago

Hi Rob,

I've built yet another version. If the stream corruption issue is deterministic, I reckon I could pinpoint the cause or at least identify the problematic submission from the logs of a run with this version. If the stream corruption is not specific to the tasks you submit to the pool, this version will allow all submissions to succeed at the cost of terminating the Java processes with the corrupted streams and spinning up new ones.

pp4j-3.0.0.jar.zip

rob42 commented 5 years ago

Ive run it with the new jar, using . It now completes the jobs successfully. It still throws the stream errors but recovers ok. Log attached jvmPool.submit(new Calc(json),true); pp4j-true-extra-log.txt

rob42 commented 5 years ago

jvmPool.submit(new Calc(json),true); also succeeds now, due to recreating the jvm on error. Log attached.

BTW Ive done some tests using the matlab calc directly (so single thread/CPU) and initial calcs are ~3500ms, dropping quickly to ~40ms, so hotspot improvement is significant. Re-using the JVM's is going to be important I think. pp4j-false-extra-log.txt

rob42 commented 5 years ago

You can see the effect of hotspot here, line *** drops to 500ms calcTime, but then reverts, presumably a new JVM

jobTiming
/home/robert/temp/pp4j-false-extra-log.txt
09:17:21.728 [Thread-6] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 6561
09:17:21.728 [Thread-6] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3563
09:17:21.742 [Thread-1] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 6631
09:17:21.742 [Thread-1] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3506
09:17:22.094 [Thread-8] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 6602
09:17:22.282 [Thread-8] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3889
09:17:22.283 [Thread-5] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 6924
09:17:22.283 [Thread-5] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3637
09:17:32.461 [Thread-10] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 16085
09:17:32.462 [Thread-10] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3772
09:17:32.564 [Thread-9] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 17118
09:17:32.564 [Thread-9] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3618
09:17:33.012 [Thread-2] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 17752
09:17:33.012 [Thread-2] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3652
09:17:33.211 [Thread-4] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 17805
09:17:33.211 [Thread-4] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3634
09:17:34.012 [Thread-11] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 19131
*** 09:17:34.013 [Thread-11] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 525
09:17:34.444 [Thread-13] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 18175
*** 09:17:34.444 [Thread-13] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 531
09:17:34.868 [Thread-14] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 17985
*** 09:17:34.869 [Thread-14] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 548
09:17:44.649 [Thread-15] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 24154
09:17:44.650 [Thread-15] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3683
09:17:45.169 [Thread-12] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 27018
09:17:45.169 [Thread-12] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3933
09:17:46.063 [Thread-17] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 23554
09:17:46.064 [Thread-17] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3766
09:17:46.215 [Thread-16] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 24605
09:17:46.215 [Thread-16] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3867
09:17:54.835 [Thread-18] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:160) - queue time: 31768
09:17:54.835 [Thread-18] DEBUG com.cp.matlab.servlet.MatlabExecutor.jobTiming(MatlabExecutor.java:165) - calc time: 3884
ViktorC commented 5 years ago

Hi Rob,

Sorry for the late reply.

Thank you for the logs! I looked through them but I couldn't find a pattern that would explain the decoding issues. It seems as if the processes were receiving input to their std in from sources other than the process pool. The error messages vary from java.lang.IllegalArgumentException: Last unit does not have enough valid bits through java.lang.IllegalArgumentException: Input byte array has wrong 4-byte ending unit and java.io.StreamCorruptedException: invalid type code: 00 to java.io.StreamCorruptedException: invalid stream header: {some string in hex} with values such as 6C61622E, 6150726F, 22443617, 3B40015C, and 372003A6. But all these exceptions are thrown by the same line of code, the one decoding the messages printed to the Java process' std in.

The invalid header exceptions are especially interesting. 6C61622E converted to string is lab., which suggests this might have something to do with the Matlab code invoked through JNI?

At any rate, I built another version (to nobody's surprise) that includes the messages read from the std in stream in the error responses of the Java processes. This should allow us to see the messages sent to the processes by third parties and help us figure out where they come from.

pp4j-3.0.0.jar.zip

If you don't mind the hassle, the logs of a new run would be much appreciated once again.

I also made a lot of general improvements to the library so as soon as we solve this issue or decide that the library is not at fault, I'll release a new, stable version.

rob42 commented 5 years ago

Logs attached, same issue :-( pp4j-true.txt pp4j-false.txt

rob42 commented 5 years ago

Some ideas: 1) std.out buffer size - see https://stackoverflow.com/questions/10904067/in-c-whats-the-size-of-stdout-buffer 2) buffers flushing due to buffer-full, then more data which is not read and remains in buffer, especially if there is a pause before its written, eg finalize() etc

rob42 commented 5 years ago

Javadocs mention you must read out and err to avoid blocking and deadlocks. On writing you probably need to flush also?

rob42 commented 5 years ago

Some interesting methods in ObjectOutputStream:

 /**
  483        * Reset will disregard the state of any objects already written to the
  484        * stream.  The state is reset to be the same as a new ObjectOutputStream.
  485        * The current point in the stream is marked as reset so the corresponding
  486        * ObjectInputStream will be reset at the same point.  Objects previously
  487        * written to the stream will not be refered to as already being in the
  488        * stream.  They will be written to the stream again.
  489        *
  490        * @throws  IOException if reset() is invoked while serializing an object.
  491        */
  492       public void reset() throws IOException {

also flush(), drain(), note close() does a flush().

ViktorC commented 5 years ago

Some ideas:

  1. std.out buffer size - see https://stackoverflow.com/questions/10904067/in-c-whats-the-size-of-stdout-buffer
  2. buffers flushing due to buffer-full, then more data which is not read and remains in buffer, especially if there is a pause before its written, eg finalize() etc

This should not be a problem because both the Java process and the process executor use readLine which only returns if a newline character is printed to the stream. So the streams can safely flush chunks of the Base64 encoded objects exchanged between the process executors and the processes.

ViktorC commented 5 years ago

Looking at the logs, the problem is not caused by additional messages printed to the process' std in. It's the opposite. Messages sent to the process miss chunks of characters. Usually it is the first few dozen characters of the encoded message but sometimes it is a similarly sized chunk missing from the middle of the message.

I tried to reproduce the issue by sending those same instructions to a Java process pool but they always came through in full. The only explanation for those missing chunks I can think of is something reading bytes from the std in streams of the Java processes. Do you think the native code you are executing might be doing that?

rob42 commented 5 years ago

I dont think it can be the matlab native code reading the IO. The native code is called explicitly later in the call() method. It is a transient static object so is not used in the deserialization process, although it is instantiated during the first Calc dehydration.

That said it does write error messages to std out (err?). I will investigate further.

If misc bits of the stream are missing then buffer overflows could be the cause. I'm not sure but I expect that the IO is javaObject>bytestream>base64String>System.out>process.out>process.in>etc The process.* are the java process OS out and err buffers, hence they will be C buffers in the VM? If those buffers overflow, then we could see this kind of problem?

I may be able to extend the buffer size (in linux) and see if that helps

ViktorC commented 5 years ago

Yeah, you're right, it should not be able to interfere with the messages to stdin. 🤔

The IO chain looks something like this:

+-------------------------------------------------------------+--------------------------------------------------------------+
|                Process Executor (master JVM)                |                    Java Process (slave JVM)                  |
+--------------------------------------------+----------------+-----------------+--------------------------------------------+
|                   Encode                   | Write to STDIN | Read from STDIN |                   Decode                   |
| javaObject --> bytestream --> base64String | -------------> | ------XXX-----> | base64String --> bytestream --> javaObject |
+--------------------------------------------+----------------+-----------------+--------------------------------------------+

The process executor encodes the Callable and writes it to the stdin of the 'slave' process through a buffered writer instantiated after the startup of the process like new BufferedWriter(new OutputStreamWriter(process.getOutputStream(), charset)). After it writes the message to the stream, it writes a newline character to it as well and finally flushes it (see here). No obvious problems here.

In the mean time, the slave process is blocking waiting for a newline character to be printed to its stdin. It does so using a buffered reader like new BufferedReader(new InputStreamReader(System.in, JavaObjectCodec.CHARSET)) (this is the same charset as the one used by the process executor). Once the slave process detects a newline character, it reads the full contents of the stream (see here). This is where the problem is. The messages read from stdin seem to be occasionally incomplete. The problematic messages are each missing a single continuous block of 2 to ~50 characters. These blocks can be missing from anywhere in the messages (beginning, middle, end) and they don't seem to be related to the sizes of the messages.

Given these incomplete messages, the slave process naturally fails to decode them. The decoding fails at one of two different points; either the messages are not valid Base64 strings anymore so the string can't even be decoded, or by chance the messages are still valid Base64 strings and the deserialization fails because the bytestream is missing information.

rob42 commented 5 years ago

If String line = in.readLine(); gets incomplete bytes, then the easiest fix might be to simply use a different method to read the stream? Maybe https://commons.apache.org/proper/commons-io/javadocs/api-release/index.html?