Open retronym opened 6 years ago
Great initiative! I have a WIP branch for lamdbalift ordering, I thought I filed a ticket already but it seems I missed it. Anyway, maybe this helps: https://github.com/dragos/scala/commit/7c0f351f61e84ab72c97101b1e6481633e1ba30d
Stability, for us, means that bytecode should be identical for the same inputs, where "same" allows some minor differences:
touch
-ing some files and recompiling should give exactly the same results)I would like a bit simpler (I think) definition. To have a resident compiler in bazel, we have a process that bazel manages (called a "worker") that gets passed the arguments to the compiler run. We then allocate a new scala.tools.nsc.MainClass
and just pass it Array[String]
args to the process method:
I would like the contract that if you do this multiple times, if the input args are identical (that Array[String]), then the output to be bit-for-bit identical (and for the names of the files generated to be identical).
Note, this is not currently true for us. We occasionally see reproducibility bugs (as we call them) and have yet to diagnose the cause.
In the most extreme case, bazel took the output from a scalac that did not error, but the jar we got was incorrect, such that downstream compilations failed. But bazel didn't rerun the compilation because its inputs had not changed (and it even got cached on our CI).
We don't know if this bug is in bazel (highly unlikely since google uses it at such scale and does heavily cache), in the bazel scala rules somehow (again, we can't see how we can mess it up, but it of course is possible), or if scalac has some state that is not removed by allocating a new MainClass
. It is very hard for us to be sure about the last one.
I think any effort towards making compilation a pure function would be great. For the big picture/why, this matters for the purpose of both caching and verification. https://reproducible-builds.org/ says:
Reproducible builds are a set of software development practices that create a verifiable path from human readable source code to the binary code used by computers.
Related to this might be various use of timestamps that might sneak into the final product, like in JAR (https://github.com/sbt/io/pull/58). It would be nice to get good performance on incremental compilation while keeping these properties.
we definitely zero out the timestamps in bazel when creating jars, but perhaps there could be some non-determinism in the class files.
We have a test for reproducibility in the bazel rules_scala, and it passes. But like I said, internally at stripe we have seen some non-reproducibility (which is almost certainly not timestamps on jars).
Thanks for all the input.
@dragos Thanks for the patch. I'll also try just using a LinkedHashSet
there.
@johnynek If you run into that problem, could you please hold onto the pair of differing class files? A diff of the output of javap -v -private
might be enough for me to figure out the problem.
@eed3si9n Glad SBT is making moves in this area at the JAR/ZIP level. Here's a related maven plugin that might serve as inspiration: https://zlika.github.io/reproducible-build-maven-plugin/
I've added another test for quasiquotes.
Here's my WIP branch that uses finer grained fresh names counters (one per source-file-defined method/class, rather than one per source file). It fixes all the problems identified in this repo so far.
/cc @smarter
@johnynek The reproducibility test still fails for me locally from time to time. We should take a look at how to make it more fine grain since right now when it fails it's hard to know which jars differ, let alone which class files and we also don't keep a copy of them to give to @retronym
In Dotty, @nicolasstucki implemented idempotency tests for this sort of things: https://github.com/lampepfl/dotty/blob/master/compiler/test/dotty/tools/dotc/IdempotencyTests.scala
Hmmm I'm not sure I can recall this right now. @densh, maybe that was necessary for your work on quasiquotes?
Some progress:
I've ported the test cases from this PR into unit tests in my stable-output WIP branch.
I wrote a script that can run a stability test for any project after exporting a files with the compiler options. I have a local sbt plugin that adds the argsFile
task to perform this export.
Using this script on the compiler sources themselves reveals the next problem: the order of default getter methods within the data of the @ScalaSignature
annotation depends on the order that their methods were type completed. I've added a failing test for this. Perhaps the pickler could sort decls before writing, at least those of synthetic methods. (That seems to work)
I've also published a new version of jardiff
, which I used to inspect and compare class files (or classpaths thereof). The new raw mode -r
is useful to highlights differences that the tool normalizes away by default (such as method ordering).
Parameter alias computation was also unstable to order-of-typechecking, we need to defer some of that to post-typer, I beleive.
Static forwarders of synthetics (e.g. default getters) need to be sorted in the same way that I've started sorting synthetics themselves. Bridges probably have the same problem. Maybe we should enter default getters of a template into scope eagerly in a deterministic order, rather than deferring that job to the type completers.
I've implemented eager entry of default getters, which indeed is central way to fix the various symptoms of instability that they cause. I was able to rollback some previous fixes.
I also found a problem with mixin outer accessors, which would incorrectly take on the position of the super class. This position was only available under joint compilation, so it was incorrect and unstable.
Next cabs off the rank:
diff --git a/scala/tools/nsc/typechecker/Macros.class.asm b/scala/tools/nsc/typechecker/Macros.class.asm
index 2ad1af1..33e8908 100644
--- a/scala/tools/nsc/typechecker/Macros.class.asm
+++ b/scala/tools/nsc/typechecker/Macros.class.asm
@@ -4,7 +4,7 @@
// compiled from: Macros.scala
Individually compiling /Users/jz/code/scala/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala
diff --git a/scala/tools/nsc/transform/patmat/PatternMatching$OptimizingMatchTranslator.class.asm b/scala/tools/nsc/transform/patmat/PatternMatching$OptimizingMatchTranslator.class.asm
index 1183847..a4054cd 100644
--- a/scala/tools/nsc/transform/patmat/PatternMatching$OptimizingMatchTranslator.class.asm
+++ b/scala/tools/nsc/transform/patmat/PatternMatching$OptimizingMatchTranslator.class.asm
@@ -338,6 +338,9 @@
// access flags 0x42
private volatile Lscala/tools/nsc/transform/patmat/MatchTreeMaking$TreeMakers$SubstOnlyTreeMaker$; SubstOnlyTreeMaker$module
+ // access flags 0x42
+ private volatile Lscala/tools/nsc/transform/patmat/MatchTreeMaking$TreeMakers$TypeTestTreeMaker$; TypeTestTreeMaker$module
+
// access flags 0x12
private final Z debugInfoEmitVars
@@ -349,9 +352,6 @@
// access flags 0x42
private volatile Lscala/tools/nsc/transform/patmat/MatchTreeMaking$TreeMakers$IrrefutableExtractorTreeMaker$; IrrefutableExtractorTreeMaker$module
-
- // access flags 0x42
- private volatile Lscala/tools/nsc/transform/patmat/MatchTreeMaking$TreeMakers$TypeTestTreeMaker$; TypeTestTreeMaker$module
// access flags 0x42
private volatile Lscala/tools/nsc/transform/patmat/MatchTreeMaking$TreeMakers$EqualityTestTreeMaker$; EqualityTestTreeMaker$module
@@ -2305,6 +2305,25 @@
MAXLOCALS = 1
Looks like we've got an instability in the OVERRIDE
flag.
cat /tmp/test.scala && git diff && scalac -d /tmp /tmp/test.scala && qscala -cp /tmp Test a > /tmp/a.log; qscala -cp /tmp Test b > /tmp/b.log && diff -u /tmp/{a,b}.log
import scala.reflect.internal.Flags
import scala.reflect.internal.pickling.ByteCodecs
import scala.tools.nsc.symtab.classfile.ClassfileParser
object Test {
def main(args: Array[String]): Unit = {
def test(ssig: String): Unit = {
val bytes = ssig.getBytes(java.nio.charset.StandardCharsets.UTF_8)
val len = ByteCodecs.decode(bytes)
import scala.tools.nsc._
val g = new Global(new Settings)
import g._
new Run
object unpickler extends scala.reflect.internal.pickling.UnPickler {
val symbolTable: g.type = g
}
unpickler.unpickle(bytes take len, 0, NoSymbol.newClassSymbol(TypeName("dummy")), NoSymbol.newModuleSymbol(TermName("dummy$"), newFlags = Flags.MODULE), "test.scala")
}
if (args.head == "a") test(a)
else test(b)
}
val a = "\u0006\u0001\u0019uh!C\u0001\u0003!\u0003\r\u0009a\u0003D~\u0005\u0019i\u0015m\u0019:pg*\u00111\u0001B\u0001\u000cif\u0004Xm\u00195fG.,'O\u0003\u0002\u0006\r\u0005\u0019an]2\u000b\u0005\u001dA\u0011!\u0002;p_2\u001c(\"A\u0005\u0002\u000bM\u001c\u0017\r\\1\u0004\u0001M)\u0001\u0001\u0004\u0009\u001bAA\u0011QBD\u0007\u0002\u0011%\u0011q\u0002\u0003\u0002\u0007\u0003:L(+\u001a4\u0011\u0005EAR\"\u0001\n\u000b\u0005M!\u0012a\u0002:v]RLW.\u001a\u0006\u0003+Y\u0009a!\\1de>\u001c(BA\u000c\u0009\u0003\u001d\u0011XM\u001a7fGRL!!\u0007\n\u0003\u001b5\u000b7M]8Sk:$\u0018.\\3t!\u0009Yb$D\u0001\u001d\u0015\u0009iB#\u0001\u0003vi&d\u0017BA\u0010\u001d\u0005\u0019!&/Y2fgB\u00111$I\u0005\u0003Eq\u0011q\u0001S3ma\u0016\u00148\u000fC\u0003%\u0001\u0011\u0005Q%\u0001\u0004%S:LG\u000f\n\u000b\u0002MA\u0011QbJ\u0005\u0003Q!\u0011A!\u00168ji\"A!\u0006\u0001EC\u0002\u0013\u00051&A\u0005gCN$HK]1dWV\u0009A\u0006E\u0002._Ej\u0011A\u000c\u0006\u0003/\u0019I!\u0001\r\u0018\u0003\u0013\u0019\u000b7\u000f\u001e+sC\u000e\\W\"\u0001\u0001\u0009\u000bM\u0002A\u0011\u0001\u001b\u0002\u001d\u001ddwNY1m'\u0016$H/\u001b8hgV\u0009Q\u0007\u0005\u00027o5\u0009A!\u0003\u00029\u0009\u0009A1+\u001a;uS:<7\u000fC\u0003;\u0001\u0011E1(\u0001\u000bgS:$W*Y2s_\u000ec\u0017m]:M_\u0006$WM\u001d\u000b\u0002yA\u0011QHQ\u0007\u0002})\u0011q\u0008Q\u0001\u0005Y\u0006twMC\u0001B\u0003\u0011Q\u0017M^1\n\u0005\rs$aC\"mCN\u001cHj\\1eKJ4A!\u0012\u0001A\r\n\u0001R*Y2s_&k\u0007\u000f\u001c\"j]\u0012LgnZ\n\u0005\u000929%\n\u0005\u0002\u000e\u0011&\u0011\u0011\n\u0003\u0002\u0008!J|G-^2u!\u0009i1*\u0003\u0002M\u0011\u0009a1+\u001a:jC2L'0\u00192mK\"Aa\n\u0012BK\u0002\u0013\u0005q*\u0001\u0005jg\n+h\u000e\u001a7f+\u0005\u0001\u0006CA\u0007R\u0013\u0009\u0011\u0006BA\u0004C_>dW-\u00198\u0009\u0011Q#%\u0011#Q\u0001\nA\u000b\u0011\"[:Ck:$G.\u001a\u0011\u0009\u0011Y#%Q3A\u0005\u0002=\u000b!\"[:CY\u0006\u001c7NY8y\u0011!AFI!E!\u0002\u0013\u0001\u0016aC5t\u00052\u000c7m\u001b2pq\u0002B\u0001B\u0017#\u0003\u0016\u0004%\u0009aW\u0001\nG2\u000c7o\u001d(b[\u0016,\u0012\u0001\u0018\u0009\u0003;\u0012t!A\u00182\u0011\u0005}CQ\"\u00011\u000b\u0005\u0005T\u0011A\u0002\u001fs_>$h(\u0003\u0002d\u0011\u00051\u0001K]3eK\u001aL!!\u001a4\u0003\rM#(/\u001b8h\u0015\u0009\u0019\u0007\u0002\u0003\u0005i\u0009\nE\u0009\u0015!\u0003]\u0003)\u0019G.Y:t\u001d\u0006lW\r\u0009\u0005\u0009U\u0012\u0013)\u001a!C\u00017\u0006AQ.\u001a;i\u001d\u0006lW\r\u0003\u0005m\u0009\nE\u0009\u0015!\u0003]\u0003%iW\r\u001e5OC6,\u0007\u0005\u0003\u0005o\u0009\nU\r\u0011\"\u0001p\u0003%\u0019\u0018n\u001a8biV\u0014X-F\u0001q!\r\u0009h/\u001f\u0008\u0003eRt!aX:\n\u0003%I!!\u001e\u0005\u0002\u000fA\u000c7m[1hK&\u0011q\u000f\u001f\u0002\u0005\u0019&\u001cHO\u0003\u0002v\u0011A\u0019\u0011O\u001e>\u0011\u0005mdX\"\u0001\u0002\n\u0005u\u0014!a\u0003$j]\u001e,'\u000f\u001d:j]RD\u0001b #\u0003\u0012\u0003\u0006I\u0001]\u0001\u000bg&<g.\u0019;ve\u0016\u0004\u0003BCA\u0002\u0009\nU\r\u0011\"\u0001\u0002\u0006\u0005)A/\u0019:hgV\u0011\u0011q\u0001\u0009\u0005cZ\u000cI\u0001\u0005\u0003\u0002\u000c\u0005UabA\u0019\u0002\u000e%!\u0011qBA\u0009\u0003\u00199Gn\u001c2bY&\u0019\u00111\u0003\u0002\u0003\u0011\u0005s\u0017\r\\={KJLA!a\u0006\u0002\u001a\u0009!AK]3f\u0013\u0011\u0009Y\"!\u0008\u0003\u000bQ\u0013X-Z:\u000b\u0007\u0005}a#\u0001\u0005j]R,'O\\1m\u0011)\u0009\u0019\u0003\u0012B\u0009B\u0003%\u0011qA\u0001\u0007i\u0006\u0014xm\u001d\u0011\u0009\u000f\u0005\u001dB\u0009\"\u0001\u0002*\u00051A(\u001b8jiz\"b\"a\u000b\u0002.\u0005=\u0012\u0011GA\u001a\u0003k\u00099\u0004\u0005\u00022\u0009\"1a*!\nA\u0002ACaAVA\u0013\u0001\u0004\u0001\u0006B\u0002.\u0002&\u0001\u0007A\u000c\u0003\u0004k\u0003K\u0001\r\u0001\u0018\u0005\u0007]\u0006\u0015\u0002\u0019\u00019\u0009\u0011\u0005\r\u0011Q\u0005a\u0001\u0003\u000fAa!a\u000fE\u0009\u0003y\u0015!F5t?\u0012\nX.\u0019:lIEl\u0017M]6%c6\u000c'o\u001b\u0005\u0007\u0003!E\u0011A(\u0002\u0015%\u001cx\u000b[5uK\n|\u0007\u0010C\u0005\u0002D\u0011\u000b\u0009\u0011\"\u0001\u0002F\u0005!1m\u001c9z)9\u0009Y#a\u0012\u0002J\u0005-\u0013QJA(\u0003#B\u0001BTA!!\u0003\u0005\r\u0001\u0015\u0005\u0009-\u0006\u0005\u0003\u0013!a\u0001!\"A!,!\u0011\u0011\u0002\u0003\u0007A\u000c\u0003\u0005k\u0003\u0003\u0002\n\u00111\u0001]\u0011!q\u0017\u0011\u0009I\u0001\u0002\u0004\u0001\u0008BCA\u0002\u0003\u0003\u0002\n\u00111\u0001\u0002\u0008!A\u0011Q\u000b#\u0002\u0002\u0013\u0005q*\u0001\u0008d_BLH\u0005Z3gCVdG\u000fJ\u0019\u0009\u0011\u0005eC)!A\u0005\u0002=\u000babY8qs\u0012\"WMZ1vYR$#\u0007\u0003\u0005\u0002^\u0011\u000b\u0009\u0011\"\u0001\\\u00039\u0019w\u000e]=%I\u00164\u0017-\u001e7uIMB\u0001\"!\u0019E\u0003\u0003%\u0009aW\u0001\u000fG>\u0004\u0018\u0010\n3fM\u0006,H\u000e\u001e\u00135\u0011!\u0009)\u0007RA\u0001\n\u0003y\u0017AD2paf$C-\u001a4bk2$H%\u000e\u0005\n\u0003S\"\u0015\u0011!C\u0001\u0003\u000b\u0009abY8qs\u0012\"WMZ1vYR$c\u0007C\u0005\u0002n\u0011\u000b\u0009\u0011\"\u0011\u0002p\u0005i\u0001O]8ek\u000e$\u0008K]3gSb,\"!!\u001d\u0011\u0007u\n\u0019(\u0003\u0002f}!I\u0011q\u000f#\u0002\u0002\u0013\u0005\u0011\u0011P\u0001\raJ|G-^2u\u0003JLG/_\u000b\u0003\u0003w\u00022!DA?\u0013\r\u0009y\u0008\u0003\u0002\u0004\u0013:$\u0008\"CAB\u0009\u0006\u0005I\u0011AAC\u00039\u0001(o\u001c3vGR,E.Z7f]R$B!a\"\u0002\u000eB\u0019Q\"!#\n\u0007\u0005-\u0005BA\u0002B]fD!\"a$\u0002\u0002\u0006\u0005\u0009\u0019AA>\u0003\rAH%\r\u0005\n\u0003'#\u0015\u0011!C!\u0003+\u000bq\u0002\u001d:pIV\u001cG/\u0013;fe\u0006$xN]\u000b\u0003\u0003/\u0003b!!'\u0002 \u0006\u001dUBAAN\u0015\r\u0009i\nC\u0001\u000bG>dG.Z2uS>t\u0017\u0002BAQ\u00037\u0013\u0001\"\u0013;fe\u0006$xN\u001d\u0005\n\u0003K#\u0015\u0011!C\u0001\u0003O\u000b\u0001bY1o\u000bF,\u0018\r\u001c\u000b\u0004!\u0006%\u0006BCAH\u0003G\u000b\u0009\u00111\u0001\u0002\u0008\"I\u0011Q\u0016#\u0002\u0002\u0013\u0005\u0013qV\u0001\u0009Q\u0006\u001c\u0008nQ8eKR\u0011\u00111\u0010\u0005\n\u0003g#\u0015\u0011!C!\u0003k\u000b\u0001\u0002^8TiJLgn\u001a\u000b\u0003\u0003cB\u0011\"!/E\u0003\u0003%\u0009%a/\u0002\r\u0015\u000cX/\u00197t)\r\u0001\u0016Q\u0018\u0005\u000b\u0003\u001f\u000b9,!AA\u0002\u0005\u001duaBAa\u0001!\u0005\u00111Y\u0001\u0011\u001b\u0006\u001c'o\\%na2\u0014\u0015N\u001c3j]\u001e\u00042!MAc\r\u0019)\u0005\u0001#\u0001\u0002HN!\u0011Q\u0019\u0007K\u0011!\u00099#!2\u0005\u0002\u0005-GCAAb\u0011!\u0009y-!2\u0005\u0002\u0005E\u0017A\u00039jG.dW-\u0011;p[R!\u0011\u0011BAj\u0011!\u0009).!4A\u0002\u0005\u001d\u0015aA8cU\"A\u0011\u0011\\Ac\u0009\u0003\u0009Y.\u0001\u0007v]BL7m\u001b7f\u0003R|W\u000e\u0006\u0003\u0002\u0008\u0006u\u0007\u0002CAp\u0003/\u0004\r!!\u0003\u0002\u0009Q\u0014X-\u001a\u0005\u0009\u0003G\u000c)\r\"\u0001\u0002f\u00061\u0001/[2lY\u0016$B!!\u0003\u0002h\"A\u0011\u0011^Aq\u0001\u0004\u0009I!\u0001\u0007nC\u000e\u0014x.S7qYJ+g\r\u0003\u0005\u0002n\u0006\u0015G\u0011AAx\u0003!)h\u000e]5dW2,G\u0003BA\u0016\u0003cD\u0001\"a9\u0002l\u0002\u0007\u0011\u0011\u0002\u0005\u0009\u0003k\u000c)\r\"\u0003\u0002x\u0006\u0019!m\u001c=\u0016\u0009\u0005e(1\u0004\u000b\u0005\u0003w\u0014\u0019\u0002\r\u0003\u0002~\n\u001d\u0001#B/\u0002\u0000\n\r\u0011b\u0001B\u0001M\n)1\u0009\\1tgB!!Q\u0001B\u0004\u0019\u0001!AB!\u0003\u0002t\u0006\u0005\u0009\u0011!B\u0001\u0005\u0017\u00111a\u0018\u00132#\u0011\u0011i!a\"\u0011\u00075\u0011y!C\u0002\u0003\u0012!\u0011qAT8uQ&tw\r\u0003\u0005\u0003\u0016\u0005M\u0008\u0019\u0001B\u000c\u0003\u0015\u0019G.\u0019>{!\u0015i\u0016q B\r!\u0011\u0011)Aa\u0007\u0005\u0011\u0009u\u00111\u001fb\u0001\u0005\u0017\u0011\u0011\u0001\u0016\u0005\u000b\u0005C\u0009)-!A\u0005\u0002\n\r\u0012!B1qa2LHCDA\u0016\u0005K\u00119C!\u000b\u0003,\u00095\"q\u0006\u0005\u0007\u001d\n}\u0001\u0019\u0001)\u0009\rY\u0013y\u00021\u0001Q\u0011\u0019Q&q\u0004a\u00019\"1!Na\u0008A\u0002qCaA\u001cB\u0010\u0001\u0004\u0001\u0008\u0002CA\u0002\u0005?\u0001\r!a\u0002\u0009\u0015\u0009M\u0012QYA\u0001\n\u0003\u0013)$A\u0004v]\u0006\u0004\u0008\u000f\\=\u0015\u0009\u0009]\"1\u0009\u0009\u0006\u001b\u0009e\"QH\u0005\u0004\u0005wA!AB(qi&|g\u000e\u0005\u0006\u000e\u0005\u0001\u0006\u000b\u0018/q\u0003\u000fI1A!\u0011\u0009\u0005\u0019!V\u000f\u001d7fm!Q!Q\u0009B\u0019\u0003\u0003\u0005\r!a\u000b\u0002\u0007a$\u0003\u0007C\u0004\u0003J\u0001!\u0009!a\u001c\u0002\u00175\u000c7M]8F]\u001eLg.\u001a\u0005\u0008\u0005\u001b\u0002A\u0011\u0001B(\u00035\u0011\u0017N\u001c3NC\u000e\u0014x.S7qYR)aE!\u0015\u0003`!A!1\u000bB&\u0001\u0004\u0011)&\u0001\u0005nC\u000e\u0014x\u000eR3g!\u0011\u0009YAa\u0016\n\u0009\u0009e#1\u000c\u0002\u0007'fl'm\u001c7\n\u0009\u0009u\u0013Q\u0004\u0002\u0008'fl'm\u001c7t\u0011!\u0009IOa\u0013A\u0002\u0005%\u0001b\u0002B2\u0001\u0011\u0005!QM\u0001\u0015Y>\u000cG-T1de>LU\u000e\u001d7CS:$\u0017N\\4\u0015\u0009\u0009\u001d$\u0011\u000e\u0009\u0006\u001b\u0009e\u00121\u0006\u0005\u0009\u0005'\u0012\u0009\u00071\u0001\u0003V!1a\u000b\u0001C\u0001\u0005[\"2\u0001\u0015B8\u0011!\u0011\u0009Ha\u001bA\u0002\u0005%\u0011\u0001C3ya\u0006tG-Z3\u0009\rY\u0003A\u0011\u0001B;)\r\u0001&q\u000f\u0005\u0009\u0005'\u0012\u0019\u00081\u0001\u0003V!9!1\u0010\u0001\u0005\u0002\u0009u\u0014AE:uC:$\u0017M\u001d3Jg\nc\u0017mY6c_b$2\u0001\u0015B@\u0011!\u0011\u0019F!\u001fA\u0002\u0009U\u0003b\u0002BB\u0001\u0011\u0005!QQ\u0001$G>l\u0007/\u001e;f\u001b\u0006\u001c'o\u001c#fMRK\u0008/\u001a$s_6l\u0015m\u0019:p\u00136\u0004HNU3g)\u0019\u00119I!%\u0003\u001cB!\u00111\u0002BE\u0013\u0011\u0011YI!$\u0003\u0009QK\u0008/Z\u0005\u0005\u0005\u001f\u000biBA\u0003UsB,7\u000f\u0003\u0005\u0003\u0014\n\u0005\u0005\u0019\u0001BK\u0003%i\u0017m\u0019:p\u0009\u0012,g\r\u0005\u0003\u0002\u000c\u0009]\u0015\u0002\u0002BM\u00033\u0011a\u0001R3g\u0009\u00164\u0007\u0002CAu\u0005\u0003\u0003\r!!\u0003\u0009\u000f\u0009}\u0005\u0001\"\u0001\u0003\"\u0006qA/\u001f9fI6\u000b7M]8C_\u0012LHCBA\u0005\u0005G\u0013\u0009\u000c\u0003\u0005\u0003&\nu\u0005\u0019\u0001BT\u0003\u0015!\u0018\u0010]3s!\r\u0009$\u0011V\u0005\u0005\u0005W\u0013iKA\u0003UsB,'/C\u0002\u00030\n\u0011a\u0001V=qKJ\u001c\u0008\u0002\u0003BJ\u0005;\u0003\rA!&\u0009\u000f\u0009U\u0006\u0001\"\u0001\u00038\u000612\u000f^1oI\u0006\u0014H\rV=qK\u0012l\u0015m\u0019:p\u0005>$\u0017\u0010\u0006\u0004\u0002\n\u0009e&1\u0018\u0005\u0009\u0005K\u0013\u0019\u000c1\u0001\u0003(\"A!1\u0013BZ\u0001\u0004\u0011)\nC\u0004\u0003@\u0002!\u0009A!1\u0002\u00195\u000c7M]8D_:$X\r\u001f;\u0015\u0011\u0009\r'Q\u001aBh\u0005'\u00042!\rBc\u0013\u0011\u00119M!3\u0003\u00195\u000b7M]8D_:$X\r\u001f;\n\u0007\u0009-'A\u0001\u0008Ti\u0012\u000cE\u000f^1dQ6,g\u000e^:\u0009\u0011\u0009\u0015&Q\u0018a\u0001\u0005OC\u0001B!5\u0003>\u0002\u0007\u0011\u0011B\u0001\u000baJ,g-\u001b=Ue\u0016,\u0007\u0002\u0003Bk\u0005{\u0003\r!!\u0003\u0002\u0019\u0015D\u0008/\u00198eK\u0016$&/Z3\u0007\r\u0009e\u0007\u0001\u0011Bn\u0005%i\u0015m\u0019:p\u0003J<7oE\u0003\u0003X29%\nC\u0006\u0003`\n]'Q3A\u0005\u0002\u0009\u0005\u0018!A2\u0016\u0005\u0009\r\u0007b\u0003Bs\u0005/\u0014\u0009\u0012)A\u0005\u0005\u0007\u000c!a\u0019\u0011\u0009\u0017\u0009%(q\u001bBK\u0002\u0013\u0005!1^\u0001\u0007_RDWM]:\u0016\u0005\u00095\u0008\u0003B9w\u0003\u000fC1B!=\u0003X\nE\u0009\u0015!\u0003\u0003n\u00069q\u000e\u001e5feN\u0004\u0003\u0002CA\u0014\u0005/$\u0009A!>\u0015\r\u0009](\u0011 B~!\r\u0009$q\u001b\u0005\u0009\u0005?\u0014\u0019\u00101\u0001\u0003D\"A!\u0011\u001eBz\u0001\u0004\u0011i\u000f\u0003\u0006\u0002D\u0009]\u0017\u0011!C\u0001\u0005$bAa>\u0004\u0002\r\r\u0001B\u0003Bp\u0005{\u0004\n\u00111\u0001\u0003D\"Q!\u0011\u001eB!\u0003\u0005\rA!<\u0009\u0015\u0005U#q[A\u0001\n\u0003\u0011\u0009\u000f\u0003\u0006\u0002Z\u0009]\u0017\u0011!C\u0001\u0005WD!\"!\u001c\u0003X\u0006\u0005I\u0011IA8\u0011)\u00099Ha6\u0002\u0002\u0013\u0005\u0011\u0011\u0010\u0005\u000b\u0003\u0007\u00139.!A\u0005\u0002\r=A\u0003BAD\u0007#A!\"a$\u0004\u000e\u0005\u0005\u0009\u0019AA>\u0011)\u0009\u0019Ja6\u0002\u0002\u0013\u0005\u0013Q\u0013\u0005\u000b\u0003K\u00139.!A\u0005\u0002\r]Ac\u0001)\u0004\u001a!Q\u0011qRB\u000b\u0003\u0003\u0005\r!a\"\u0009\u0015\u00055&q[A\u0001\n\u0003\ny\u000b\u0003\u0006\u00024\n]\u0017\u0011!C!\u0003kC!\"!/\u0003X\u0006\u0005I\u0011IB\u0011)\r\u000161\u0005\u0005\u000b\u0003\u001f\u001by\"!AA\u0002\u0005\u001du!CB\u0014\u0001\u0005\u0005\u0009\u0012AB\u0015\u0003%i\u0015m\u0019:p\u0003J<7\u000fE\u00022\u0007W1\u0011B!7\u0001\u0003\u0003E\u0009a!\u000c\u0014\u000b\r-2q\u0006&\u0011\u0015\rE2Q\u0007Bb\u0005[\u001490\u0004\u0002\u00044)\u00111\u0003C\u0005\u0005\u0007o\u0019\u0019DA\u0009BEN$(/Y2u\rVt7\r^5p]JB\u0001\"a\n\u0004,\u0011\u000511\u0008\u000b\u0003\u0007SA!\"a-\u0004,\u0005\u0005IQIA[\u0011)\u0011\u0009ca\u000b\u0002\u0002\u0013\u00055\u0011\u0009\u000b\u0007\u0005o\u001c\u0019e!\u0012\u0009\u0011\u0009}7q\u0008a\u0001\u0005\u0007D\u0001B!;\u0004@\u0001\u0007!Q\u001e\u0005\u000b\u0005g\u0019Y#!A\u0005\u0002\u000e%C\u0003BB&\u0007'\u0002R!\u0004B\u001d\u0007\u001b\u0002r!DB(\u0005\u0007\u0014i/C\u0002\u0004R!\u0011a\u0001V;qY\u0016\u0014\u0004B\u0003B#\u0007\u000f\n\u0009\u00111\u0001\u0003x\"91q\u000b\u0001\u0005\u0002\re\u0013!C7bGJ|\u0017I]4t)\u0019\u00119pa\u0017\u0004^!A!QUB+\u0001\u0004\u00119\u000b\u0003\u0005\u0003r\rU\u0003\u0019AA\u0005\u0011\u001d\u0019\u0009\u0007\u0001C\u0001\u0007G\n\u0011c\u001d;b]\u0012\u000c'\u000fZ'bGJ|\u0017I]4t)\u0019\u00119p!\u001a\u0004h!A!QUB0\u0001\u0004\u00119\u000b\u0003\u0005\u0003r\r}\u0003\u0019AA\u0005\u0011%\u0019Y\u0007\u0001a\u0001\n\u0003\u0019i'A\u0006`_B,g.T1de>\u001cXCAB8!\u0019\u0019\u0009ha\u001e\u0004z5\u001111\u000f\u0006\u0005\u0007k\nY*A\u0005j[6,H/\u00192mK&\u0019qoa\u001d\u0013\u0009\rm4q\u0010\u0004\u0007\u0007{\u0002\u0001a!\u001f\u0003\u0019q\u0012XMZ5oK6,g\u000e\u001e \u0011\u0009\r\u00055qQ\u0007\u0003\u0007\u0007S1a!\"\u0015\u0003!\u0019wN\u001c;fqR\u001c\u0018\u0002BBE\u0007\u0007\u0013qaQ8oi\u0016DH\u000f\u0003\u0006\u0004\u000e\u000em$\u0019!D\u0001\u0007\u001f\u000b\u0001\"\u001e8jm\u0016\u00148/Z\u000b\u0003\u0003\u0017A\u0011ba%\u0001\u0001\u0004%\u0009a!&\u0002\u001f}{\u0007/\u001a8NC\u000e\u0014xn]0%KF$2AJBL\u0011)\u0009yi!%\u0002\u0002\u0003\u00071q\u000e\u0005\u0008\u00077\u0003A\u0011AB7\u0003)y\u0007/\u001a8NC\u000e\u0014xn\u001d\u0005\u0008\u0007?\u0003A\u0011ABQ\u0003A\u0001Xo\u001d5NC\u000e\u0014xnQ8oi\u0016DH\u000fF\u0002'\u0007GC\u0001Ba8\u0004\u001e\u0002\u0007!1\u0019\u0005\u0007\u0007O\u0003A\u0011A\u0013\u0002\u001fA|\u0007/T1de>\u001cuN\u001c;fqRDqaa+\u0001\u0009\u0003\u0019i+\u0001\u000cf]\u000edwn]5oO6\u000b7M]8Q_NLG/[8o+\u0009\u0019y\u000b\u0005\u0003\u00042\u000eUVBABZ\u0015\ri\u0012QD\u0005\u0005\u0007o\u001b\u0019L\u0001\u0005Q_NLG/[8o\r\u001d\u0019Y\u000cAA\u0001\u0007{\u0013Q\"T1de>,\u0005\u0010]1oI\u0016\u00148cAB]\u0019!Y!QUB]\u0005\u000b\u0007I\u0011ABa+\u0009\u00119\u000bC\u0006\u0004F\u000ee&\u0011!Q\u0001\n\u0009\u001d\u0016A\u0002;za\u0016\u0014\u0008\u0005C\u0006\u0003r\re&Q1A\u0005\u0002\r%WCAA\u0005\u0011-\u0019im!/\u0003\u0002\u0003\u0006I!!\u0003\u0002\u0013\u0015D\u0008/\u00198eK\u0016\u0004\u0003\u0002CA\u0014\u0007s#\u0009a!5\u0015\r\rM7Q[Bl!\r\u00094\u0011\u0018\u0005\u0009\u0005K\u001by\r1\u0001\u0003(\"A!\u0011OBh\u0001\u0004\u0009I\u0001\u0003\u0005\u0004\\\u000eef\u0011ABo\u0003%ygnU;dG\u0016\u001c8\u000f\u0006\u0003\u0002\n\r}\u0007\u0002CBq\u00073\u0004\r!!\u0003\u0002\u0011\u0015D\u0008/\u00198eK\u0012D\u0001b!:\u0004:\u001a\u00051q]\u0001\u000b_:4\u0015\r\u001c7cC\u000e\\G\u0003BA\u0005\u0007SD\u0001b!9\u0004d\u0002\u0007\u0011\u0011\u0002\u0005\u0009\u0007[\u001cI\u000c\"\u0001\u0004p\u0006aqN\\*vaB\u0014Xm]:fIR!\u0011\u0011BBy\u0011!\u0011\u0009ha;A\u0002\u0005%\u0001\u0002CB{\u0007s#\u0009aa>\u0002\u0013=tG)\u001a7bs\u0016$G\u0003BA\u0005\u0007sD\u0001b!9\u0004t\u0002\u0007\u0011\u0011\u0002\u0005\u0009\u0007{\u001cI\u000c\"\u0001\u0004\u0000\u0006IqN\\*lSB\u0004X\r\u001a\u000b\u0005\u0003\u0013!\u0009\u0001\u0003\u0005\u0004b\u000em\u0008\u0019AA\u0005\u0011!!)a!/\u0005\u0002\u0011\u001d\u0011!C8o\r\u0006LG.\u001e:f)\u0011\u0009I\u0001\"\u0003\u0009\u0011\r\u0005H1\u0001a\u0001\u0003\u0013A\u0001B!\u0009\u0004:\u0012\u0005AQ\u0002\u000b\u0005\u0003\u0013!y\u0001\u0003\u0005\u0005\u0012\u0011-\u0001\u0019AA\u0005\u0003%!Wm];hCJ,G\r\u0003\u0005\u0005\u0016\reF\u0011\u0003C\u000c\u0003\u0019)\u0007\u0010]1oIR!\u0011\u0011\u0002C\r\u0011!!\u0009\u0002b\u0005A\u0002\u0005%aA\u0002C\u000f\u0001\u0001!yB\u0001\u0009EK\u001al\u0015m\u0019:p\u000bb\u0004\u0018M\u001c3feN!A1DBj\u00115\u0011)\u000bb\u0007\u0003\u0002\u0003\u0006IAa*\u0004@\"i!\u0011\u000fC\u000e\u0005\u0003\u0005\u000b\u0011BA\u0005\u0007\u000fD1\u0002b\n\u0005\u001c\u0009\u0005\u0009\u0015!\u0003\u0005*\u0005!Qn\u001c3f!\u0011!Y\u0003b\u000c\u000f\u0007Y\"i#\u0003\u0002v\u0009%!A\u0011\u0007C\u001a\u0005\u0011iu\u000eZ3\u000b\u0005U$\u0001b\u0003C\u001c\u00097\u0011\u0009\u0011)A\u0005\u0005\u000f\u000bqa\\;uKJ\u0004F\u000f\u0003\u0005\u0002(\u0011mA\u0011\u0001C\u001e))!i\u0004b\u0010\u0005B\u0011\rCQ\u0009\u0009\u0004c\u0011m\u0001\u0002\u0003BS\u0009s\u0001\rAa*\u0009\u0011\u0009ED\u0011\u0008a\u0001\u0003\u0013A\u0001\u0002b\n\u0005:\u0001\u0007A\u0011\u0006\u0005\u0009\u0009o!I\u00041\u0001\u0003\u0008\"YA\u0011\nC\u000e\u0011\u000b\u0007I\u0011\u0001C&\u0003\u001dIgN\\3s!R,\"Aa\"\u0009\u0011\rmG1\u0004C!\u0009\u001f\"B!!\u0003\u0005R!AA1\u000bC'\u0001\u0004\u0009I!A\u0005fqB\u000cg\u000eZ3ea!A1Q\u001fC\u000e\u0009\u0003\"9\u0006\u0006\u0003\u0002\n\u0011e\u0003\u0002\u0003C.\u0009+\u0002\r!!\u0003\u0002\u000f\u0011,G.Y=fI\"A1Q\u001dC\u000e\u0009\u0003\"y\u0006\u0006\u0003\u0002\n\u0011\u0005\u0004\u0002\u0003C2\u0009;\u0002\r!!\u0003\u0002\u0011\u0019\u000cG\u000e\u001c2bG.Dq\u0002b\u001a\u0005\u001cA\u0005\u0019\u0011!A\u0005\n\r\u00057qX\u0001\u000cgV\u0004XM\u001d\u0013usB,'\u000fC\u0004\u0005l\u0001!\u0009\u0001\"\u001c\u0002\u00175\u000c7M]8FqB\u000cg\u000e\u001a\u000b\u000b\u0003\u0013!y\u0007\"\u001d\u0005t\u0011U\u0004\u0002\u0003BS\u0009S\u0002\rAa*\u0009\u0011\u0009ED\u0011\u000ea\u0001\u0003\u0013A\u0001\u0002b\n\u0005j\u0001\u0007A\u0011\u0006\u0005\u0009\u0009o\"I\u00071\u0001\u0003\u0008\u0006\u0011\u0001\u000f\u001e\u0005\u0008\u0009w\u0002A\u0011\u0001C?\u0003M\u0019H/\u00198eCJ$W*Y2s_\u0016C\u0008/\u00198e))\u0009I\u0001b \u0005\u0002\u0012\rEQ\u0011\u0005\u0009\u0005K#I\u00081\u0001\u0003(\"A!\u0011\u000fC=\u0001\u0004\u0009I\u0001\u0003\u0005\u0005(\u0011e\u0004\u0019\u0001C\u0015\u0011!!9\u0008\"\u001fA\u0002\u0009\u001dea\u0002CE\u0001\u0005\u0005B1\u0012\u0002\u000c\u001b\u0006\u001c'o\\*uCR,8oE\u0002\u0005\u00082A1\u0002b$\u0005\u0008\n\u0015\r\u0011\"\u0001\u0004J\u00061!/Z:vYRD1\u0002b%\u0005\u0008\n\u0005\u0009\u0015!\u0003\u0002\n\u00059!/Z:vYR\u0004\u0003\u0002CA\u0014\u0009\u000f#\u0009\u0001b&\u0015\u0009\u0011eE1\u0014\u0009\u0004c\u0011\u001d\u0005\u0002\u0003CH\u0009+\u0003\r!!\u0003*\u0019\u0011\u001dEq\u0014Cl\u000b#)I%b!\u0007\r\u0011\u0005\u0006\u0001\u0011CR\u0005\u001d!U\r\\1zK\u0012\u001cb\u0001b(\u0005\u001a\u001eS\u0005b\u0003C.\u0009?\u0013)\u001a!C\u0001\u0007\u0013DQ\u0002\"+\u0005 \nE\u0009\u0015!\u0003\u0002\n\u00115\u0015\u0001\u00033fY\u0006LX\r\u001a\u0011\u0009\u0011\u0005\u001dBq\u0014C\u0001\u0009[#B\u0001b,\u00052B\u0019\u0011\u0007b(\u0009\u0011\u0011mC1\u0016a\u0001\u0003\u0013A!\"a\u0011\u0005 \u0006\u0005I\u0011\u0001C[)\u0011!y\u000bb.\u0009\u0015\u0011mC1\u0017I\u0001\u0002\u0004\u0009I\u0001\u0003\u0006\u0002V\u0011}\u0015\u0011!C\u0001\u0007\u0013D!\"!\u001c\u0005 \u0006\u0005I\u0011IA8\u0011)\u00099\u0008b(\u0002\u0002\u0013\u0005\u0011\u0011\u0010\u0005\u000b\u0003\u0007#y*!A\u0005\u0002\u0011\u0005G\u0003BAD\u0009\u0007D!\"a$\u0005@\u0006\u0005\u0009\u0019AA>\u0011)\u0009\u0019\nb(\u0002\u0002\u0013\u0005\u0013Q\u0013\u0005\u000b\u0003K#y*!A\u0005\u0002\u0011%Gc\u0001)\u0005L\"Q\u0011q\u0012Cd\u0003\u0003\u0005\r!a\"\u0009\u0015\u00055FqTA\u0001\n\u0003\ny\u000b\u0003\u0006\u00024\u0012}\u0015\u0011!C!\u0003kC!\"!/\u0005 \u0006\u0005I\u0011\u0009Cj)\r\u0001FQ\u001b\u0005\u000b\u0003\u001f#\u0009.!AA\u0002\u0005\u001deA\u0002Cm\u0001\u0001#YNA\u0004GC&dWO]3\u0014\r\u0011]G\u0011T$K\u0011-!y\u000eb6\u0003\u0016\u0004%\u0009a!3\u0002\u000f\u0019\u000c\u0017\u000e\\;sK\"iA1\u001dCl\u0005#\u0005\u000b\u0011BA\u0005\u0009\u001b\u000b\u0001BZ1jYV\u0014X\r\u0009\u0005\u0009\u0003O!9\u000e\"\u0001\u0005hR!A\u0011\u001eCv!\r\u0009Dq\u001b\u0005\u0009\u0009?$)\u000f1\u0001\u0002\n!Q\u00111\u0009Cl\u0003\u0003%\u0009\u0001b<\u0015\u0009\u0011%H\u0011\u001f\u0005\u000b\u0009?$i\u000f%AA\u0002\u0005%\u0001BCA+\u0009/\u000c\u0009\u0011\"\u0001\u0004J\"Q\u0011Q\u000eCl\u0003\u0003%\u0009%a\u001c\u0009\u0015\u0005]Dq[A\u0001\n\u0003\u0009I\u0008\u0003\u0006\u0002\u0004\u0012]\u0017\u0011!C\u0001\u0009w$B!a\"\u0005~\"Q\u0011q\u0012C}\u0003\u0003\u0005\r!a\u001f\u0009\u0015\u0005MEq[A\u0001\n\u0003\n)\n\u0003\u0006\u0002&\u0012]\u0017\u0011!C\u0001\u000b\u0007!2\u0001UC\u0003\u0011)\u0009y)\"\u0001\u0002\u0002\u0003\u0007\u0011q\u0011\u0005\u000b\u0003[#9.!A\u0005B\u0005=\u0006BCAZ\u0009/\u000c\u0009\u0011\"\u0011\u00026\"Q\u0011\u0011\u0018Cl\u0003\u0003%\u0009%\"\u0004\u0015\u0007A+y\u0001\u0003\u0006\u0002\u0010\u0016-\u0011\u0011!a\u0001\u0003\u000f3a!b\u0005\u0001\u0001\u0016U!\u0001\u0003$bY2\u0014\u0017mY6\u0014\r\u0015EA\u0011T$K\u0011-!\u0019'\"\u0005\u0003\u0016\u0004%\u0009a!3\u0009\u001b\u0015mQ\u0011\u0003B\u0009B\u0003%\u0011\u0011\u0002CG\u0003%1\u0017\r\u001c7cC\u000e\\\u0007\u0005\u0003\u0005\u0002(\u0015EA\u0011AC\u0010)\u0011)\u0009#b\u0009\u0011\u0007E*\u0009\u0002\u0003\u0005\u0005d\u0015u\u0001\u0019AA\u0005\u0011)\u0009\u0019%\"\u0005\u0002\u0002\u0013\u0005Qq\u0005\u000b\u0005\u000bC)I\u0003\u0003\u0006\u0005d\u0015\u0015\u0002\u0013!a\u0001\u0003\u0013A!\"!\u0016\u0006\u0012\u0005\u0005I\u0011ABe\u0011)\u0009i'\"\u0005\u0002\u0002\u0013\u0005\u0013q\u000e\u0005\u000b\u0003o*\u0009\"!A\u0005\u0002\u0005e\u0004BCAB\u000b#\u0009\u0009\u0011\"\u0001\u00064Q!\u0011qQC\u001b\u0011)\u0009y)\"\r\u0002\u0002\u0003\u0007\u00111\u0010\u0005\u000b\u0003'+\u0009\"!A\u0005B\u0005U\u0005BCAS\u000b#\u0009\u0009\u0011\"\u0001\u0006<Q\u0019\u0001+\"\u0010\u0009\u0015\u0005=U\u0011HA\u0001\u0002\u0004\u00099\u0009\u0003\u0006\u0002.\u0016E\u0011\u0011!C!\u0003_C!\"a-\u0006\u0012\u0005\u0005I\u0011IA[\u0011)\u0009I,\"\u0005\u0002\u0002\u0013\u0005SQ\u0009\u000b\u0004!\u0016\u001d\u0003BCAH\u000b\u0007\n\u0009\u00111\u0001\u0002\u0008\u001a1Q1\n\u0001A\u000b\u001b\u0012qaU6jaB,Gm\u0005\u0004\u0006J\u0011euI\u0013\u0005\u000c\u000b#*IE!f\u0001\n\u0003\u0019I-A\u0004tW&\u0004\u0008/\u001a3\u0009\u001b\u0015US\u0011\nB\u0009B\u0003%\u0011\u0011\u0002CG\u0003!\u00198.\u001b9qK\u0012\u0004\u0003\u0002CA\u0014\u000b\u0013\"\u0009!\"\u0017\u0015\u0009\u0015mSQ\u000c\u0009\u0004c\u0015%\u0003\u0002CC)\u000b/\u0002\r!!\u0003\u0009\u0015\u0005\rS\u0011JA\u0001\n\u0003)\u0009\u0007\u0006\u0003\u0006\\\u0015\r\u0004BCC)\u000b?\u0002\n\u00111\u0001\u0002\n!Q\u0011QKC%\u0003\u0003%\u0009a!3\u0009\u0015\u00055T\u0011JA\u0001\n\u0003\ny\u0007\u0003\u0006\u0002x\u0015%\u0013\u0011!C\u0001\u0003sB!\"a!\u0006J\u0005\u0005I\u0011AC7)\u0011\u00099)b\u001c\u0009\u0015\u0005=U1NA\u0001\u0002\u0004\u0009Y\u0008\u0003\u0006\u0002\u0014\u0016%\u0013\u0011!C!\u0003+C!\"!*\u0006J\u0005\u0005I\u0011AC;)\r\u0001Vq\u000f\u0005\u000b\u0003\u001f+\u0019(!AA\u0002\u0005\u001d\u0005BCAW\u000b\u0013\n\u0009\u0011\"\u0011\u00020\"Q\u00111WC%\u0003\u0003%\u0009%!.\u0009\u0015\u0005eV\u0011JA\u0001\n\u0003*y\u0008F\u0002Q\u000b\u0003C!\"a$\u0006~\u0005\u0005\u0009\u0019AAD\r\u0019))\u0009\u0001!\u0006\u0008\n91+^2dKN\u001c8CBCB\u00093;%\nC\u0006\u0004b\u0016\r%Q3A\u0005\u0002\r%\u0007\"DCG\u000b\u0007\u0013\u0009\u0012)A\u0005\u0003\u0013!i)A\u0005fqB\u000cg\u000eZ3eA!A\u0011qECB\u0009\u0003)\u0009\n\u0006\u0003\u0006\u0014\u0016U\u0005cA\u0019\u0006\u0004\"A1\u0011]CH\u0001\u0004\u0009I\u0001\u0003\u0006\u0002D\u0015\r\u0015\u0011!C\u0001\u000b3#B!b%\u0006\u001c\"Q1\u0011]CL!\u0003\u0005\r!!\u0003\u0009\u0015\u0005US1QA\u0001\n\u0003\u0019I\r\u0003\u0006\u0002n\u0015\r\u0015\u0011!C!\u0003_B!\"a\u001e\u0006\u0004\u0006\u0005I\u0011AA=\u0011)\u0009\u0019)b!\u0002\u0002\u0013\u0005QQ\u0015\u000b\u0005\u0003\u000f+9\u000b\u0003\u0006\u0002\u0010\u0016\r\u0016\u0011!a\u0001\u0003wB!\"a%\u0006\u0004\u0006\u0005I\u0011IAK\u0011)\u0009)+b!\u0002\u0002\u0013\u0005QQ\u0016\u000b\u0004!\u0016=\u0006BCAH\u000bW\u000b\u0009\u00111\u0001\u0002\u0008\"Q\u0011QVCB\u0003\u0003%\u0009%a,\u0009\u0015\u0005MV1QA\u0001\n\u0003\n)\u000c\u0003\u0006\u0002:\u0016\r\u0015\u0011!C!\u000bo#2\u0001UC]\u0011)\u0009y)\".\u0002\u0002\u0003\u0007\u0011qQ\u0004\n\u000b{\u0003\u0011\u0011!E\u0001\u000b\u000bqaU;dG\u0016\u001c8\u000fE\u00022\u000b\u00034\u0011\"\"\"\u0001\u0003\u0003E\u0009!b1\u0014\u000b\u0015\u0005WQ\u0019&\u0011\u0011\rERqYA\u0005\u000b'KA!\"3\u00044\u0009\u0009\u0012IY:ue\u0006\u001cGOR;oGRLwN\\\u0019\u0009\u0011\u0005\u001dR\u0011\u0019C\u0001\u000b\u001b$\"!b0\u0009\u0015\u0005MV\u0011YA\u0001\n\u000b\n)\u000c\u0003\u0006\u0003\"\u0015\u0005\u0017\u0011!CA\u000b'$B!b%\u0006V\"A1\u0011]Ci\u0001\u0004\u0009I\u0001\u0003\u0006\u00034\u0015\u0005\u0017\u0011!CA\u000b3$B!b7\u0006^B)QB!\u000f\u0002\n!Q!QICl\u0003\u0003\u0005\r!b%\u0008\u0013\u0015\u0005\u0008!!A\u0009\u0002\u0015\r\u0018\u0001\u0003$bY2\u0014\u0017mY6\u0011\u0007E*)OB\u0005\u0006\u0014\u0001\u0009\u0009\u0011#\u0001\u0006hN)QQ]Cu\u0015BA1\u0011GCd\u0003\u0013)\u0009\u0003\u0003\u0005\u0002(\u0015\u0015H\u0011ACw)\u0009)\u0019\u000f\u0003\u0006\u00024\u0016\u0015\u0018\u0011!C#\u0003kC!B!\u0009\u0006f\u0006\u0005I\u0011QCz)\u0011)\u0009#\">\u0009\u0011\u0011\rT\u0011\u001fa\u0001\u0003\u0013A!Ba\r\u0006f\u0006\u0005I\u0011QC})\u0011)Y.b?\u0009\u0015\u0009\u0015Sq_A\u0001\u0002\u0004)\u0009cB\u0005\u0006\u0000\u0002\u0009\u0009\u0011#\u0001\u0007\u0002\u00059A)\u001a7bs\u0016$\u0007cA\u0019\u0007\u0004\u0019IA\u0011\u0015\u0001\u0002\u0002#\u0005aQA\n\u0006\r\u000719A\u0013\u0009\u0009\u0007c)9-!\u0003\u00050\"A\u0011q\u0005D\u0002\u0009\u00031Y\u0001\u0006\u0002\u0007\u0002!Q\u00111\u0017D\u0002\u0003\u0003%)%!.\u0009\u0015\u0009\u0005b1AA\u0001\n\u00033\u0009\u0002\u0006\u0003\u00050\u001aM\u0001\u0002\u0003C.\r\u001f\u0001\r!!\u0003\u0009\u0015\u0009Mb1AA\u0001\n\u000339\u0002\u0006\u0003\u0006\\\u001ae\u0001B\u0003B#\r+\u0009\u0009\u00111\u0001\u00050\u001eIaQ\u0004\u0001\u0002\u0002#\u0005aqD\u0001\u0008'.L\u0007\u000f]3e!\r\u0009d\u0011\u0005\u0004\n\u000b\u0017\u0002\u0011\u0011!E\u0001\rG\u0019RA\"\u0009\u0007&)\u0003\u0002b!\r\u0006H\u0006%Q1\u000c\u0005\u0009\u0003O1\u0009\u0003\"\u0001\u0007*Q\u0011aq\u0004\u0005\u000b\u0003g3\u0009#!A\u0005F\u0005U\u0006B\u0003B\u0011\rC\u0009\u0009\u0011\"!\u00070Q!Q1\u000cD\u0019\u0011!)\u0009F\"\u000cA\u0002\u0005%\u0001B\u0003B\u001a\rC\u0009\u0009\u0011\"!\u00076Q!Q1\u001cD\u001c\u0011)\u0011)Eb\r\u0002\u0002\u0003\u0007Q1L\u0004\n\rw\u0001\u0011\u0011!E\u0001\r{\u0009qAR1jYV\u0014X\rE\u00022\r1\u0011\u0002\"7\u0001\u0003\u0003E\u0009A\"\u0011\u0014\u000b\u0019}b1\u0009&\u0011\u0011\rERqYA\u0005\u0009SD\u0001\"a\n\u0007@\u0011\u0005aq\u0009\u000b\u0003\r{A!\"a-\u0007@\u0005\u0005IQIA[\u0011)\u0011\u0009Cb\u0010\u0002\u0002\u0013\u0005eQ\n\u000b\u0005\u0009S4y\u0005\u0003\u0005\u0005`\u001a-\u0003\u0019AA\u0005\u0011)\u0011\u0019Db\u0010\u0002\u0002\u0013\u0005e1\u000b\u000b\u0005\u000b74)\u0006\u0003\u0006\u0003F\u0019E\u0013\u0011!a\u0001\u0009SDqA\"\u0017\u0001\u0009\u00031Y&A\u0003EK2\u000c\u0017\u0010\u0006\u0003\u00050\u001au\u0003\u0002CBq\r/\u0002\r!!\u0003\u0009\u000f\u0019\u0005\u0004\u0001\"\u0001\u0007d\u0005!1k[5q)\u0011)YF\"\u001a\u0009\u0011\r\u0005hq\u000ca\u0001\u0003\u0013AqA\"\u001b\u0001\u0009\u00031Y'\u0001\u000cnC\u000e\u0014x.\u0012=qC:$w+\u001b;i%VtG/[7f)!!IJ\"\u001c\u0007p\u0019E\u0004\u0002\u0003BS\rO\u0002\rAa*\u0009\u0011\u0009Edq\ra\u0001\u0003\u0013Aqa\u0005D4\u0001\u00041\u0019\u0008E\u00022\rkJ1Ab\u001e\u0019\u00051i\u0015m\u0019:p%VtG/[7f\u0011\u001d1Y\u0008\u0001C\u0001\r{\n\u0011$\\1de>,\u0005\u0010]1oI^KG\u000f[8viJ+h\u000e^5nKR1A\u0011\u0014D@\r\u0003C\u0001B!*\u0007z\u0001\u0007!q\u0015\u0005\u0009\u0005c2I\u00081\u0001\u0002\n!AaQ\u0011\u0001A\u0002\u0013\u0005q*A\riCN\u0004VM\u001c3j]\u001el\u0015m\u0019:p\u000bb\u0004\u0018M\\:j_:\u001c\u0008\"\u0003DE\u0001\u0001\u0007I\u0011\u0001DF\u0003uA\u0017m\u001d)f]\u0012LgnZ'bGJ|W\u0009\u001f9b]NLwN\\:`I\u0015\u000cHc\u0001\u0014\u0007\u000e\"I\u0011q\u0012DD\u0003\u0003\u0005\r\u0001\u0015\u0005\u0007\r#\u0003A\u0011A(\u0002?QL\u0008/\u001a:TQ>,H\u000eZ#ya\u0006tG\rR3gKJ\u0014X\rZ'bGJ|7\u000fC\u0005\u0007\u0016\u0002\u0011\r\u0011\"\u0003\u0007\u0018\u00061am\u001c:dK\u0012,\"A\"'\u0011\r\rEf1TA\u0005\u0013\u00111ija-\u0003\u0017]+\u0017m\u001b%bg\"\u001cV\r\u001e\u0005\n\u00097\u0002!\u0019!C\u0005\rC+\"Ab)\u0011\u0011\u0019\u0015f1VA\u0005\r_k!Ab*\u000b\u0009\u0019%\u00161T\u0001\u0008[V$\u0018M\u00197f\u0013\u00111iKb*\u0003\u0017]+\u0017m\u001b%bg\"l\u0015\r\u001d\u0009\u0007\rK3\u0009,a\u001f\n\u0009\u0019Mfq\u0015\u0002\u0004'\u0016$\u0008b\u0002D\\\u0001\u0011%a\u0011X\u0001\nSN$U\r\\1zK\u0012$2\u0001\u0015D^\u0011!\u0011\u0009H\".A\u0002\u0005%\u0001B\u0002D`\u0001\u0011\u0005Q%\u0001\u0007dY\u0016\u000c'\u000fR3mCf,G\rC\u0004\u0007D\u0002!IA\"2\u0002)\r\u000cGnY;mCR,WK\u001c3fiB\u000c'/Y7t)\u00111yKb2\u0009\u0011\u0009Ed\u0011\u0019a\u0001\u0003\u0013A\u0011Bb3\u0001\u0005\u0004%IA\"4\u0002\u0017UtG-\u001a;qCJ\u000cWn]\u000b\u0003\r\u001f\u0004bA\"*\u0007R\u0006m\u0014\u0002\u0002Dj\rO\u0013q\u0001S1tQN+G\u000fC\u0004\u0007X\u0002!\u0009A\"7\u0002-9|G/\u001b4z+:$W\r\u001e9be\u0006l7/\u00113eK\u0012$2A\nDn\u0011!1iN\"6A\u0002\u0019}\u0017!\u00038foVsG-\u001a;t!\u0011\u0009hO!\u0016\u0009\u000f\u0019\r\u0008\u0001\"\u0001\u0007f\u0006Ibn\u001c;jMf,f\u000eZ3ua\u0006\u0014\u0018-\\:J]\u001a,'O]3e)\u00151cq\u001dDv\u0011!1IO\"9A\u0002\u0019}\u0017aC;oI\u0016$hj\\'pe\u0016D\u0001B\"<\u0007b\u0002\u0007aq^\u0001\nS:4WM\u001d:fIN\u0004B!\u001d<\u0003\u0008\"9a1\u001f\u0001\u0005\u0002\u0019U\u0018AD7bGJ|W\u0009\u001f9b]\u0012\u000cE\u000e\u001c\u000b\u0007\u0003\u001319P\"?\u0009\u0011\u0009\u0015f\u0011\u001fa\u0001\u0005OC\u0001B!\u001d\u0007r\u0002\u0007\u0011\u0011\u0002\u0009\u0004w\u0006E\u0001"
val b = "\u0006\u0001\u0019uh!C\u0001\u0003!\u0003\r\u0009a\u0003D~\u0005\u0019i\u0015m\u0019:pg*\u00111\u0001B\u0001\u000cif\u0004Xm\u00195fG.,'O\u0003\u0002\u0006\r\u0005\u0019an]2\u000b\u0005\u001dA\u0011!\u0002;p_2\u001c(\"A\u0005\u0002\u000bM\u001c\u0017\r\\1\u0004\u0001M)\u0001\u0001\u0004\u0009\u001bAA\u0011QBD\u0007\u0002\u0011%\u0011q\u0002\u0003\u0002\u0007\u0003:L(+\u001a4\u0011\u0005EAR\"\u0001\n\u000b\u0005M!\u0012a\u0002:v]RLW.\u001a\u0006\u0003+Y\u0009a!\\1de>\u001c(BA\u000c\u0009\u0003\u001d\u0011XM\u001a7fGRL!!\u0007\n\u0003\u001b5\u000b7M]8Sk:$\u0018.\\3t!\u0009Yb$D\u0001\u001d\u0015\u0009iB#\u0001\u0003vi&d\u0017BA\u0010\u001d\u0005\u0019!&/Y2fgB\u00111$I\u0005\u0003Eq\u0011q\u0001S3ma\u0016\u00148\u000fC\u0003%\u0001\u0011\u0005Q%\u0001\u0004%S:LG\u000f\n\u000b\u0002MA\u0011QbJ\u0005\u0003Q!\u0011A!\u00168ji\"A!\u0006\u0001EC\u0002\u0013\u00051&A\u0005gCN$HK]1dWV\u0009A\u0006E\u0002._Ej\u0011A\u000c\u0006\u0003/\u0019I!\u0001\r\u0018\u0003\u0013\u0019\u000b7\u000f\u001e+sC\u000e\\W\"\u0001\u0001\u0009\u000bM\u0002A\u0011\u0001\u001b\u0002\u001d\u001ddwNY1m'\u0016$H/\u001b8hgV\u0009Q\u0007\u0005\u00027o5\u0009A!\u0003\u00029\u0009\u0009A1+\u001a;uS:<7\u000fC\u0003;\u0001\u0011E1(\u0001\u000bgS:$W*Y2s_\u000ec\u0017m]:M_\u0006$WM\u001d\u000b\u0002yA\u0011QHQ\u0007\u0002})\u0011q\u0008Q\u0001\u0005Y\u0006twMC\u0001B\u0003\u0011Q\u0017M^1\n\u0005\rs$aC\"mCN\u001cHj\\1eKJ4A!\u0012\u0001A\r\n\u0001R*Y2s_&k\u0007\u000f\u001c\"j]\u0012LgnZ\n\u0005\u000929%\n\u0005\u0002\u000e\u0011&\u0011\u0011\n\u0003\u0002\u0008!J|G-^2u!\u0009i1*\u0003\u0002M\u0011\u0009a1+\u001a:jC2L'0\u00192mK\"Aa\n\u0012BK\u0002\u0013\u0005q*\u0001\u0005jg\n+h\u000e\u001a7f+\u0005\u0001\u0006CA\u0007R\u0013\u0009\u0011\u0006BA\u0004C_>dW-\u00198\u0009\u0011Q#%\u0011#Q\u0001\nA\u000b\u0011\"[:Ck:$G.\u001a\u0011\u0009\u0011Y#%Q3A\u0005\u0002=\u000b!\"[:CY\u0006\u001c7NY8y\u0011!AFI!E!\u0002\u0013\u0001\u0016aC5t\u00052\u000c7m\u001b2pq\u0002B\u0001B\u0017#\u0003\u0016\u0004%\u0009aW\u0001\nG2\u000c7o\u001d(b[\u0016,\u0012\u0001\u0018\u0009\u0003;\u0012t!A\u00182\u0011\u0005}CQ\"\u00011\u000b\u0005\u0005T\u0011A\u0002\u001fs_>$h(\u0003\u0002d\u0011\u00051\u0001K]3eK\u001aL!!\u001a4\u0003\rM#(/\u001b8h\u0015\u0009\u0019\u0007\u0002\u0003\u0005i\u0009\nE\u0009\u0015!\u0003]\u0003)\u0019G.Y:t\u001d\u0006lW\r\u0009\u0005\u0009U\u0012\u0013)\u001a!C\u00017\u0006AQ.\u001a;i\u001d\u0006lW\r\u0003\u0005m\u0009\nE\u0009\u0015!\u0003]\u0003%iW\r\u001e5OC6,\u0007\u0005\u0003\u0005o\u0009\nU\r\u0011\"\u0001p\u0003%\u0019\u0018n\u001a8biV\u0014X-F\u0001q!\r\u0009h/\u001f\u0008\u0003eRt!aX:\n\u0003%I!!\u001e\u0005\u0002\u000fA\u000c7m[1hK&\u0011q\u000f\u001f\u0002\u0005\u0019&\u001cHO\u0003\u0002v\u0011A\u0019\u0011O\u001e>\u0011\u0005mdX\"\u0001\u0002\n\u0005u\u0014!a\u0003$j]\u001e,'\u000f\u001d:j]RD\u0001b #\u0003\u0012\u0003\u0006I\u0001]\u0001\u000bg&<g.\u0019;ve\u0016\u0004\u0003BCA\u0002\u0009\nU\r\u0011\"\u0001\u0002\u0006\u0005)A/\u0019:hgV\u0011\u0011q\u0001\u0009\u0005cZ\u000cI\u0001\u0005\u0003\u0002\u000c\u0005UabA\u0019\u0002\u000e%!\u0011qBA\u0009\u0003\u00199Gn\u001c2bY&\u0019\u00111\u0003\u0002\u0003\u0011\u0005s\u0017\r\\={KJLA!a\u0006\u0002\u001a\u0009!AK]3f\u0013\u0011\u0009Y\"!\u0008\u0003\u000bQ\u0013X-Z:\u000b\u0007\u0005}a#\u0001\u0005j]R,'O\\1m\u0011)\u0009\u0019\u0003\u0012B\u0009B\u0003%\u0011qA\u0001\u0007i\u0006\u0014xm\u001d\u0011\u0009\u000f\u0005\u001dB\u0009\"\u0001\u0002*\u00051A(\u001b8jiz\"b\"a\u000b\u0002.\u0005=\u0012\u0011GA\u001a\u0003k\u00099\u0004\u0005\u00022\u0009\"1a*!\nA\u0002ACaAVA\u0013\u0001\u0004\u0001\u0006B\u0002.\u0002&\u0001\u0007A\u000c\u0003\u0004k\u0003K\u0001\r\u0001\u0018\u0005\u0007]\u0006\u0015\u0002\u0019\u00019\u0009\u0011\u0005\r\u0011Q\u0005a\u0001\u0003\u000fAa!a\u000fE\u0009\u0003y\u0015!F5t?\u0012\nX.\u0019:lIEl\u0017M]6%c6\u000c'o\u001b\u0005\u0007\u0003!E\u0011A(\u0002\u0015%\u001cx\u000b[5uK\n|\u0007\u0010C\u0005\u0002D\u0011\u000b\u0009\u0011\"\u0001\u0002F\u0005!1m\u001c9z)9\u0009Y#a\u0012\u0002J\u0005-\u0013QJA(\u0003#B\u0001BTA!!\u0003\u0005\r\u0001\u0015\u0005\u0009-\u0006\u0005\u0003\u0013!a\u0001!\"A!,!\u0011\u0011\u0002\u0003\u0007A\u000c\u0003\u0005k\u0003\u0003\u0002\n\u00111\u0001]\u0011!q\u0017\u0011\u0009I\u0001\u0002\u0004\u0001\u0008BCA\u0002\u0003\u0003\u0002\n\u00111\u0001\u0002\u0008!A\u0011Q\u000b#\u0002\u0002\u0013\u0005q*\u0001\u0008d_BLH\u0005Z3gCVdG\u000fJ\u0019\u0009\u0011\u0005eC)!A\u0005\u0002=\u000babY8qs\u0012\"WMZ1vYR$#\u0007\u0003\u0005\u0002^\u0011\u000b\u0009\u0011\"\u0001\\\u00039\u0019w\u000e]=%I\u00164\u0017-\u001e7uIMB\u0001\"!\u0019E\u0003\u0003%\u0009aW\u0001\u000fG>\u0004\u0018\u0010\n3fM\u0006,H\u000e\u001e\u00135\u0011!\u0009)\u0007RA\u0001\n\u0003y\u0017AD2paf$C-\u001a4bk2$H%\u000e\u0005\n\u0003S\"\u0015\u0011!C\u0001\u0003\u000b\u0009abY8qs\u0012\"WMZ1vYR$c\u0007C\u0005\u0002n\u0011\u000b\u0009\u0011\"\u0011\u0002p\u0005i\u0001O]8ek\u000e$\u0008K]3gSb,\"!!\u001d\u0011\u0007u\n\u0019(\u0003\u0002f}!I\u0011q\u000f#\u0002\u0002\u0013\u0005\u0011\u0011P\u0001\raJ|G-^2u\u0003JLG/_\u000b\u0003\u0003w\u00022!DA?\u0013\r\u0009y\u0008\u0003\u0002\u0004\u0013:$\u0008\"CAB\u0009\u0006\u0005I\u0011AAC\u00039\u0001(o\u001c3vGR,E.Z7f]R$B!a\"\u0002\u000eB\u0019Q\"!#\n\u0007\u0005-\u0005BA\u0002B]fD!\"a$\u0002\u0002\u0006\u0005\u0009\u0019AA>\u0003\rAH%\r\u0005\n\u0003'#\u0015\u0011!C!\u0003+\u000bq\u0002\u001d:pIV\u001cG/\u0013;fe\u0006$xN]\u000b\u0003\u0003/\u0003b!!'\u0002 \u0006\u001dUBAAN\u0015\r\u0009i\nC\u0001\u000bG>dG.Z2uS>t\u0017\u0002BAQ\u00037\u0013\u0001\"\u0013;fe\u0006$xN\u001d\u0005\n\u0003K#\u0015\u0011!C\u0001\u0003O\u000b\u0001bY1o\u000bF,\u0018\r\u001c\u000b\u0004!\u0006%\u0006BCAH\u0003G\u000b\u0009\u00111\u0001\u0002\u0008\"I\u0011Q\u0016#\u0002\u0002\u0013\u0005\u0013qV\u0001\u0009Q\u0006\u001c\u0008nQ8eKR\u0011\u00111\u0010\u0005\n\u0003g#\u0015\u0011!C!\u0003k\u000b\u0001\u0002^8TiJLgn\u001a\u000b\u0003\u0003cB\u0011\"!/E\u0003\u0003%\u0009%a/\u0002\r\u0015\u000cX/\u00197t)\r\u0001\u0016Q\u0018\u0005\u000b\u0003\u001f\u000b9,!AA\u0002\u0005\u001duaBAa\u0001!\u0005\u00111Y\u0001\u0011\u001b\u0006\u001c'o\\%na2\u0014\u0015N\u001c3j]\u001e\u00042!MAc\r\u0019)\u0005\u0001#\u0001\u0002HN!\u0011Q\u0019\u0007K\u0011!\u00099#!2\u0005\u0002\u0005-GCAAb\u0011!\u0009y-!2\u0005\u0002\u0005E\u0017A\u00039jG.dW-\u0011;p[R!\u0011\u0011BAj\u0011!\u0009).!4A\u0002\u0005\u001d\u0015aA8cU\"A\u0011\u0011\\Ac\u0009\u0003\u0009Y.\u0001\u0007v]BL7m\u001b7f\u0003R|W\u000e\u0006\u0003\u0002\u0008\u0006u\u0007\u0002CAp\u0003/\u0004\r!!\u0003\u0002\u0009Q\u0014X-\u001a\u0005\u0009\u0003G\u000c)\r\"\u0001\u0002f\u00061\u0001/[2lY\u0016$B!!\u0003\u0002h\"A\u0011\u0011^Aq\u0001\u0004\u0009I!\u0001\u0007nC\u000e\u0014x.S7qYJ+g\r\u0003\u0005\u0002n\u0006\u0015G\u0011AAx\u0003!)h\u000e]5dW2,G\u0003BA\u0016\u0003cD\u0001\"a9\u0002l\u0002\u0007\u0011\u0011\u0002\u0005\u0009\u0003k\u000c)\r\"\u0003\u0002x\u0006\u0019!m\u001c=\u0016\u0009\u0005e(1\u0004\u000b\u0005\u0003w\u0014\u0019\u0002\r\u0003\u0002~\n\u001d\u0001#B/\u0002\u0000\n\r\u0011b\u0001B\u0001M\n)1\u0009\\1tgB!!Q\u0001B\u0004\u0019\u0001!AB!\u0003\u0002t\u0006\u0005\u0009\u0011!B\u0001\u0005\u0017\u00111a\u0018\u00132#\u0011\u0011i!a\"\u0011\u00075\u0011y!C\u0002\u0003\u0012!\u0011qAT8uQ&tw\r\u0003\u0005\u0003\u0016\u0005M\u0008\u0019\u0001B\u000c\u0003\u0015\u0019G.\u0019>{!\u0015i\u0016q B\r!\u0011\u0011)Aa\u0007\u0005\u0011\u0009u\u00111\u001fb\u0001\u0005\u0017\u0011\u0011\u0001\u0016\u0005\u000b\u0005C\u0009)-!A\u0005\u0002\n\r\u0012!B1qa2LHCDA\u0016\u0005K\u00119C!\u000b\u0003,\u00095\"q\u0006\u0005\u0007\u001d\n}\u0001\u0019\u0001)\u0009\rY\u0013y\u00021\u0001Q\u0011\u0019Q&q\u0004a\u00019\"1!Na\u0008A\u0002qCaA\u001cB\u0010\u0001\u0004\u0001\u0008\u0002CA\u0002\u0005?\u0001\r!a\u0002\u0009\u0015\u0009M\u0012QYA\u0001\n\u0003\u0013)$A\u0004v]\u0006\u0004\u0008\u000f\\=\u0015\u0009\u0009]\"1\u0009\u0009\u0006\u001b\u0009e\"QH\u0005\u0004\u0005wA!AB(qi&|g\u000e\u0005\u0006\u000e\u0005\u0001\u0006\u000b\u0018/q\u0003\u000fI1A!\u0011\u0009\u0005\u0019!V\u000f\u001d7fm!Q!Q\u0009B\u0019\u0003\u0003\u0005\r!a\u000b\u0002\u0007a$\u0003\u0007C\u0004\u0003J\u0001!\u0009!a\u001c\u0002\u00175\u000c7M]8F]\u001eLg.\u001a\u0005\u0008\u0005\u001b\u0002A\u0011\u0001B(\u00035\u0011\u0017N\u001c3NC\u000e\u0014x.S7qYR)aE!\u0015\u0003`!A!1\u000bB&\u0001\u0004\u0011)&\u0001\u0005nC\u000e\u0014x\u000eR3g!\u0011\u0009YAa\u0016\n\u0009\u0009e#1\u000c\u0002\u0007'fl'm\u001c7\n\u0009\u0009u\u0013Q\u0004\u0002\u0008'fl'm\u001c7t\u0011!\u0009IOa\u0013A\u0002\u0005%\u0001b\u0002B2\u0001\u0011\u0005!QM\u0001\u0015Y>\u000cG-T1de>LU\u000e\u001d7CS:$\u0017N\\4\u0015\u0009\u0009\u001d$\u0011\u000e\u0009\u0006\u001b\u0009e\u00121\u0006\u0005\u0009\u0005'\u0012\u0009\u00071\u0001\u0003V!1a\u000b\u0001C\u0001\u0005[\"2\u0001\u0015B8\u0011!\u0011\u0009Ha\u001bA\u0002\u0005%\u0011\u0001C3ya\u0006tG-Z3\u0009\rY\u0003A\u0011\u0001B;)\r\u0001&q\u000f\u0005\u0009\u0005'\u0012\u0019\u00081\u0001\u0003V!9!1\u0010\u0001\u0005\u0002\u0009u\u0014AE:uC:$\u0017M\u001d3Jg\nc\u0017mY6c_b$2\u0001\u0015B@\u0011!\u0011\u0019F!\u001fA\u0002\u0009U\u0003b\u0002BB\u0001\u0011\u0005!QQ\u0001$G>l\u0007/\u001e;f\u001b\u0006\u001c'o\u001c#fMRK\u0008/\u001a$s_6l\u0015m\u0019:p\u00136\u0004HNU3g)\u0019\u00119I!%\u0003\u001cB!\u00111\u0002BE\u0013\u0011\u0011YI!$\u0003\u0009QK\u0008/Z\u0005\u0005\u0005\u001f\u000biBA\u0003UsB,7\u000f\u0003\u0005\u0003\u0014\n\u0005\u0005\u0019\u0001BK\u0003%i\u0017m\u0019:p\u0009\u0012,g\r\u0005\u0003\u0002\u000c\u0009]\u0015\u0002\u0002BM\u00033\u0011a\u0001R3g\u0009\u00164\u0007\u0002CAu\u0005\u0003\u0003\r!!\u0003\u0009\u000f\u0009}\u0005\u0001\"\u0001\u0003\"\u0006qA/\u001f9fI6\u000b7M]8C_\u0012LHCBA\u0005\u0005G\u0013\u0009\u000c\u0003\u0005\u0003&\nu\u0005\u0019\u0001BT\u0003\u0015!\u0018\u0010]3s!\r\u0009$\u0011V\u0005\u0005\u0005W\u0013iKA\u0003UsB,'/C\u0002\u00030\n\u0011a\u0001V=qKJ\u001c\u0008\u0002\u0003BJ\u0005;\u0003\rA!&\u0009\u000f\u0009U\u0006\u0001\"\u0001\u00038\u000612\u000f^1oI\u0006\u0014H\rV=qK\u0012l\u0015m\u0019:p\u0005>$\u0017\u0010\u0006\u0004\u0002\n\u0009e&1\u0018\u0005\u0009\u0005K\u0013\u0019\u000c1\u0001\u0003(\"A!1\u0013BZ\u0001\u0004\u0011)\nC\u0004\u0003@\u0002!\u0009A!1\u0002\u00195\u000c7M]8D_:$X\r\u001f;\u0015\u0011\u0009\r'Q\u001aBh\u0005'\u00042!\rBc\u0013\u0011\u00119M!3\u0003\u00195\u000b7M]8D_:$X\r\u001f;\n\u0007\u0009-'A\u0001\u0008Ti\u0012\u000cE\u000f^1dQ6,g\u000e^:\u0009\u0011\u0009\u0015&Q\u0018a\u0001\u0005OC\u0001B!5\u0003>\u0002\u0007\u0011\u0011B\u0001\u000baJ,g-\u001b=Ue\u0016,\u0007\u0002\u0003Bk\u0005{\u0003\r!!\u0003\u0002\u0019\u0015D\u0008/\u00198eK\u0016$&/Z3\u0007\r\u0009e\u0007\u0001\u0011Bn\u0005%i\u0015m\u0019:p\u0003J<7oE\u0003\u0003X29%\nC\u0006\u0003`\n]'Q3A\u0005\u0002\u0009\u0005\u0018!A2\u0016\u0005\u0009\r\u0007b\u0003Bs\u0005/\u0014\u0009\u0012)A\u0005\u0005\u0007\u000c!a\u0019\u0011\u0009\u0017\u0009%(q\u001bBK\u0002\u0013\u0005!1^\u0001\u0007_RDWM]:\u0016\u0005\u00095\u0008\u0003B9w\u0003\u000fC1B!=\u0003X\nE\u0009\u0015!\u0003\u0003n\u00069q\u000e\u001e5feN\u0004\u0003\u0002CA\u0014\u0005/$\u0009A!>\u0015\r\u0009](\u0011 B~!\r\u0009$q\u001b\u0005\u0009\u0005?\u0014\u0019\u00101\u0001\u0003D\"A!\u0011\u001eBz\u0001\u0004\u0011i\u000f\u0003\u0006\u0002D\u0009]\u0017\u0011!C\u0001\u0005$bAa>\u0004\u0002\r\r\u0001B\u0003Bp\u0005{\u0004\n\u00111\u0001\u0003D\"Q!\u0011\u001eB!\u0003\u0005\rA!<\u0009\u0015\u0005U#q[A\u0001\n\u0003\u0011\u0009\u000f\u0003\u0006\u0002Z\u0009]\u0017\u0011!C\u0001\u0005WD!\"!\u001c\u0003X\u0006\u0005I\u0011IA8\u0011)\u00099Ha6\u0002\u0002\u0013\u0005\u0011\u0011\u0010\u0005\u000b\u0003\u0007\u00139.!A\u0005\u0002\r=A\u0003BAD\u0007#A!\"a$\u0004\u000e\u0005\u0005\u0009\u0019AA>\u0011)\u0009\u0019Ja6\u0002\u0002\u0013\u0005\u0013Q\u0013\u0005\u000b\u0003K\u00139.!A\u0005\u0002\r]Ac\u0001)\u0004\u001a!Q\u0011qRB\u000b\u0003\u0003\u0005\r!a\"\u0009\u0015\u00055&q[A\u0001\n\u0003\ny\u000b\u0003\u0006\u00024\n]\u0017\u0011!C!\u0003kC!\"!/\u0003X\u0006\u0005I\u0011IB\u0011)\r\u000161\u0005\u0005\u000b\u0003\u001f\u001by\"!AA\u0002\u0005\u001du!CB\u0014\u0001\u0005\u0005\u0009\u0012AB\u0015\u0003%i\u0015m\u0019:p\u0003J<7\u000fE\u00022\u0007W1\u0011B!7\u0001\u0003\u0003E\u0009a!\u000c\u0014\u000b\r-2q\u0006&\u0011\u0015\rE2Q\u0007Bb\u0005[\u001490\u0004\u0002\u00044)\u00111\u0003C\u0005\u0005\u0007o\u0019\u0019DA\u0009BEN$(/Y2u\rVt7\r^5p]JB\u0001\"a\n\u0004,\u0011\u000511\u0008\u000b\u0003\u0007SA!\"a-\u0004,\u0005\u0005IQIA[\u0011)\u0011\u0009ca\u000b\u0002\u0002\u0013\u00055\u0011\u0009\u000b\u0007\u0005o\u001c\u0019e!\u0012\u0009\u0011\u0009}7q\u0008a\u0001\u0005\u0007D\u0001B!;\u0004@\u0001\u0007!Q\u001e\u0005\u000b\u0005g\u0019Y#!A\u0005\u0002\u000e%C\u0003BB&\u0007'\u0002R!\u0004B\u001d\u0007\u001b\u0002r!DB(\u0005\u0007\u0014i/C\u0002\u0004R!\u0011a\u0001V;qY\u0016\u0014\u0004B\u0003B#\u0007\u000f\n\u0009\u00111\u0001\u0003x\"91q\u000b\u0001\u0005\u0002\re\u0013!C7bGJ|\u0017I]4t)\u0019\u00119pa\u0017\u0004^!A!QUB+\u0001\u0004\u00119\u000b\u0003\u0005\u0003r\rU\u0003\u0019AA\u0005\u0011\u001d\u0019\u0009\u0007\u0001C\u0001\u0007G\n\u0011c\u001d;b]\u0012\u000c'\u000fZ'bGJ|\u0017I]4t)\u0019\u00119p!\u001a\u0004h!A!QUB0\u0001\u0004\u00119\u000b\u0003\u0005\u0003r\r}\u0003\u0019AA\u0005\u0011%\u0019Y\u0007\u0001a\u0001\n\u0003\u0019i'A\u0006`_B,g.T1de>\u001cXCAB8!\u0019\u0019\u0009ha\u001e\u0004z5\u001111\u000f\u0006\u0005\u0007k\nY*A\u0005j[6,H/\u00192mK&\u0019qoa\u001d\u0013\u0009\rm4q\u0010\u0004\u0007\u0007{\u0002\u0001a!\u001f\u0003\u0019q\u0012XMZ5oK6,g\u000e\u001e \u0011\u0009\r\u00055qQ\u0007\u0003\u0007\u0007S1a!\"\u0015\u0003!\u0019wN\u001c;fqR\u001c\u0018\u0002BBE\u0007\u0007\u0013qaQ8oi\u0016DH\u000f\u0003\u0006\u0004\u000e\u000em$\u0019!D!\u0007\u001f\u000b\u0001\"\u001e8jm\u0016\u00148/Z\u000b\u0003\u0003\u0017A\u0011ba%\u0001\u0001\u0004%\u0009a!&\u0002\u001f}{\u0007/\u001a8NC\u000e\u0014xn]0%KF$2AJBL\u0011)\u0009yi!%\u0002\u0002\u0003\u00071q\u000e\u0005\u0008\u00077\u0003A\u0011AB7\u0003)y\u0007/\u001a8NC\u000e\u0014xn\u001d\u0005\u0008\u0007?\u0003A\u0011ABQ\u0003A\u0001Xo\u001d5NC\u000e\u0014xnQ8oi\u0016DH\u000fF\u0002'\u0007GC\u0001Ba8\u0004\u001e\u0002\u0007!1\u0019\u0005\u0007\u0007O\u0003A\u0011A\u0013\u0002\u001fA|\u0007/T1de>\u001cuN\u001c;fqRDqaa+\u0001\u0009\u0003\u0019i+\u0001\u000cf]\u000edwn]5oO6\u000b7M]8Q_NLG/[8o+\u0009\u0019y\u000b\u0005\u0003\u00042\u000eUVBABZ\u0015\ri\u0012QD\u0005\u0005\u0007o\u001b\u0019L\u0001\u0005Q_NLG/[8o\r\u001d\u0019Y\u000cAA\u0001\u0007{\u0013Q\"T1de>,\u0005\u0010]1oI\u0016\u00148cAB]\u0019!Y!QUB]\u0005\u000b\u0007I\u0011ABa+\u0009\u00119\u000bC\u0006\u0004F\u000ee&\u0011!Q\u0001\n\u0009\u001d\u0016A\u0002;za\u0016\u0014\u0008\u0005C\u0006\u0003r\re&Q1A\u0005\u0002\r%WCAA\u0005\u0011-\u0019im!/\u0003\u0002\u0003\u0006I!!\u0003\u0002\u0013\u0015D\u0008/\u00198eK\u0016\u0004\u0003\u0002CA\u0014\u0007s#\u0009a!5\u0015\r\rM7Q[Bl!\r\u00094\u0011\u0018\u0005\u0009\u0005K\u001by\r1\u0001\u0003(\"A!\u0011OBh\u0001\u0004\u0009I\u0001\u0003\u0005\u0004\\\u000eef\u0011ABo\u0003%ygnU;dG\u0016\u001c8\u000f\u0006\u0003\u0002\n\r}\u0007\u0002CBq\u00073\u0004\r!!\u0003\u0002\u0011\u0015D\u0008/\u00198eK\u0012D\u0001b!:\u0004:\u001a\u00051q]\u0001\u000b_:4\u0015\r\u001c7cC\u000e\\G\u0003BA\u0005\u0007SD\u0001b!9\u0004d\u0002\u0007\u0011\u0011\u0002\u0005\u0009\u0007[\u001cI\u000c\"\u0001\u0004p\u0006aqN\\*vaB\u0014Xm]:fIR!\u0011\u0011BBy\u0011!\u0011\u0009ha;A\u0002\u0005%\u0001\u0002CB{\u0007s#\u0009aa>\u0002\u0013=tG)\u001a7bs\u0016$G\u0003BA\u0005\u0007sD\u0001b!9\u0004t\u0002\u0007\u0011\u0011\u0002\u0005\u0009\u0007{\u001cI\u000c\"\u0001\u0004\u0000\u0006IqN\\*lSB\u0004X\r\u001a\u000b\u0005\u0003\u0013!\u0009\u0001\u0003\u0005\u0004b\u000em\u0008\u0019AA\u0005\u0011!!)a!/\u0005\u0002\u0011\u001d\u0011!C8o\r\u0006LG.\u001e:f)\u0011\u0009I\u0001\"\u0003\u0009\u0011\r\u0005H1\u0001a\u0001\u0003\u0013A\u0001B!\u0009\u0004:\u0012\u0005AQ\u0002\u000b\u0005\u0003\u0013!y\u0001\u0003\u0005\u0005\u0012\u0011-\u0001\u0019AA\u0005\u0003%!Wm];hCJ,G\r\u0003\u0005\u0005\u0016\reF\u0011\u0003C\u000c\u0003\u0019)\u0007\u0010]1oIR!\u0011\u0011\u0002C\r\u0011!!\u0009\u0002b\u0005A\u0002\u0005%aA\u0002C\u000f\u0001\u0001!yB\u0001\u0009EK\u001al\u0015m\u0019:p\u000bb\u0004\u0018M\u001c3feN!A1DBj\u00115\u0011)\u000bb\u0007\u0003\u0002\u0003\u0006IAa*\u0004@\"i!\u0011\u000fC\u000e\u0005\u0003\u0005\u000b\u0011BA\u0005\u0007\u000fD1\u0002b\n\u0005\u001c\u0009\u0005\u0009\u0015!\u0003\u0005*\u0005!Qn\u001c3f!\u0011!Y\u0003b\u000c\u000f\u0007Y\"i#\u0003\u0002v\u0009%!A\u0011\u0007C\u001a\u0005\u0011iu\u000eZ3\u000b\u0005U$\u0001b\u0003C\u001c\u00097\u0011\u0009\u0011)A\u0005\u0005\u000f\u000bqa\\;uKJ\u0004F\u000f\u0003\u0005\u0002(\u0011mA\u0011\u0001C\u001e))!i\u0004b\u0010\u0005B\u0011\rCQ\u0009\u0009\u0004c\u0011m\u0001\u0002\u0003BS\u0009s\u0001\rAa*\u0009\u0011\u0009ED\u0011\u0008a\u0001\u0003\u0013A\u0001\u0002b\n\u0005:\u0001\u0007A\u0011\u0006\u0005\u0009\u0009o!I\u00041\u0001\u0003\u0008\"YA\u0011\nC\u000e\u0011\u000b\u0007I\u0011\u0001C&\u0003\u001dIgN\\3s!R,\"Aa\"\u0009\u0011\rmG1\u0004C!\u0009\u001f\"B!!\u0003\u0005R!AA1\u000bC'\u0001\u0004\u0009I!A\u0005fqB\u000cg\u000eZ3ea!A1Q\u001fC\u000e\u0009\u0003\"9\u0006\u0006\u0003\u0002\n\u0011e\u0003\u0002\u0003C.\u0009+\u0002\r!!\u0003\u0002\u000f\u0011,G.Y=fI\"A1Q\u001dC\u000e\u0009\u0003\"y\u0006\u0006\u0003\u0002\n\u0011\u0005\u0004\u0002\u0003C2\u0009;\u0002\r!!\u0003\u0002\u0011\u0019\u000cG\u000e\u001c2bG.Dq\u0002b\u001a\u0005\u001cA\u0005\u0019\u0011!A\u0005\n\r\u00057qX\u0001\u000cgV\u0004XM\u001d\u0013usB,'\u000fC\u0004\u0005l\u0001!\u0009\u0001\"\u001c\u0002\u00175\u000c7M]8FqB\u000cg\u000e\u001a\u000b\u000b\u0003\u0013!y\u0007\"\u001d\u0005t\u0011U\u0004\u0002\u0003BS\u0009S\u0002\rAa*\u0009\u0011\u0009ED\u0011\u000ea\u0001\u0003\u0013A\u0001\u0002b\n\u0005j\u0001\u0007A\u0011\u0006\u0005\u0009\u0009o\"I\u00071\u0001\u0003\u0008\u0006\u0011\u0001\u000f\u001e\u0005\u0008\u0009w\u0002A\u0011\u0001C?\u0003M\u0019H/\u00198eCJ$W*Y2s_\u0016C\u0008/\u00198e))\u0009I\u0001b \u0005\u0002\u0012\rEQ\u0011\u0005\u0009\u0005K#I\u00081\u0001\u0003(\"A!\u0011\u000fC=\u0001\u0004\u0009I\u0001\u0003\u0005\u0005(\u0011e\u0004\u0019\u0001C\u0015\u0011!!9\u0008\"\u001fA\u0002\u0009\u001dea\u0002CE\u0001\u0005\u0005B1\u0012\u0002\u000c\u001b\u0006\u001c'o\\*uCR,8oE\u0002\u0005\u00082A1\u0002b$\u0005\u0008\n\u0015\r\u0011\"\u0001\u0004J\u00061!/Z:vYRD1\u0002b%\u0005\u0008\n\u0005\u0009\u0015!\u0003\u0002\n\u00059!/Z:vYR\u0004\u0003\u0002CA\u0014\u0009\u000f#\u0009\u0001b&\u0015\u0009\u0011eE1\u0014\u0009\u0004c\u0011\u001d\u0005\u0002\u0003CH\u0009+\u0003\r!!\u0003*\u0019\u0011\u001dEq\u0014Cl\u000b#)I%b!\u0007\r\u0011\u0005\u0006\u0001\u0011CR\u0005\u001d!U\r\\1zK\u0012\u001cb\u0001b(\u0005\u001a\u001eS\u0005b\u0003C.\u0009?\u0013)\u001a!C\u0001\u0007\u0013DQ\u0002\"+\u0005 \nE\u0009\u0015!\u0003\u0002\n\u00115\u0015\u0001\u00033fY\u0006LX\r\u001a\u0011\u0009\u0011\u0005\u001dBq\u0014C\u0001\u0009[#B\u0001b,\u00052B\u0019\u0011\u0007b(\u0009\u0011\u0011mC1\u0016a\u0001\u0003\u0013A!\"a\u0011\u0005 \u0006\u0005I\u0011\u0001C[)\u0011!y\u000bb.\u0009\u0015\u0011mC1\u0017I\u0001\u0002\u0004\u0009I\u0001\u0003\u0006\u0002V\u0011}\u0015\u0011!C\u0001\u0007\u0013D!\"!\u001c\u0005 \u0006\u0005I\u0011IA8\u0011)\u00099\u0008b(\u0002\u0002\u0013\u0005\u0011\u0011\u0010\u0005\u000b\u0003\u0007#y*!A\u0005\u0002\u0011\u0005G\u0003BAD\u0009\u0007D!\"a$\u0005@\u0006\u0005\u0009\u0019AA>\u0011)\u0009\u0019\nb(\u0002\u0002\u0013\u0005\u0013Q\u0013\u0005\u000b\u0003K#y*!A\u0005\u0002\u0011%Gc\u0001)\u0005L\"Q\u0011q\u0012Cd\u0003\u0003\u0005\r!a\"\u0009\u0015\u00055FqTA\u0001\n\u0003\ny\u000b\u0003\u0006\u00024\u0012}\u0015\u0011!C!\u0003kC!\"!/\u0005 \u0006\u0005I\u0011\u0009Cj)\r\u0001FQ\u001b\u0005\u000b\u0003\u001f#\u0009.!AA\u0002\u0005\u001deA\u0002Cm\u0001\u0001#YNA\u0004GC&dWO]3\u0014\r\u0011]G\u0011T$K\u0011-!y\u000eb6\u0003\u0016\u0004%\u0009a!3\u0002\u000f\u0019\u000c\u0017\u000e\\;sK\"iA1\u001dCl\u0005#\u0005\u000b\u0011BA\u0005\u0009\u001b\u000b\u0001BZ1jYV\u0014X\r\u0009\u0005\u0009\u0003O!9\u000e\"\u0001\u0005hR!A\u0011\u001eCv!\r\u0009Dq\u001b\u0005\u0009\u0009?$)\u000f1\u0001\u0002\n!Q\u00111\u0009Cl\u0003\u0003%\u0009\u0001b<\u0015\u0009\u0011%H\u0011\u001f\u0005\u000b\u0009?$i\u000f%AA\u0002\u0005%\u0001BCA+\u0009/\u000c\u0009\u0011\"\u0001\u0004J\"Q\u0011Q\u000eCl\u0003\u0003%\u0009%a\u001c\u0009\u0015\u0005]Dq[A\u0001\n\u0003\u0009I\u0008\u0003\u0006\u0002\u0004\u0012]\u0017\u0011!C\u0001\u0009w$B!a\"\u0005~\"Q\u0011q\u0012C}\u0003\u0003\u0005\r!a\u001f\u0009\u0015\u0005MEq[A\u0001\n\u0003\n)\n\u0003\u0006\u0002&\u0012]\u0017\u0011!C\u0001\u000b\u0007!2\u0001UC\u0003\u0011)\u0009y)\"\u0001\u0002\u0002\u0003\u0007\u0011q\u0011\u0005\u000b\u0003[#9.!A\u0005B\u0005=\u0006BCAZ\u0009/\u000c\u0009\u0011\"\u0011\u00026\"Q\u0011\u0011\u0018Cl\u0003\u0003%\u0009%\"\u0004\u0015\u0007A+y\u0001\u0003\u0006\u0002\u0010\u0016-\u0011\u0011!a\u0001\u0003\u000f3a!b\u0005\u0001\u0001\u0016U!\u0001\u0003$bY2\u0014\u0017mY6\u0014\r\u0015EA\u0011T$K\u0011-!\u0019'\"\u0005\u0003\u0016\u0004%\u0009a!3\u0009\u001b\u0015mQ\u0011\u0003B\u0009B\u0003%\u0011\u0011\u0002CG\u0003%1\u0017\r\u001c7cC\u000e\\\u0007\u0005\u0003\u0005\u0002(\u0015EA\u0011AC\u0010)\u0011)\u0009#b\u0009\u0011\u0007E*\u0009\u0002\u0003\u0005\u0005d\u0015u\u0001\u0019AA\u0005\u0011)\u0009\u0019%\"\u0005\u0002\u0002\u0013\u0005Qq\u0005\u000b\u0005\u000bC)I\u0003\u0003\u0006\u0005d\u0015\u0015\u0002\u0013!a\u0001\u0003\u0013A!\"!\u0016\u0006\u0012\u0005\u0005I\u0011ABe\u0011)\u0009i'\"\u0005\u0002\u0002\u0013\u0005\u0013q\u000e\u0005\u000b\u0003o*\u0009\"!A\u0005\u0002\u0005e\u0004BCAB\u000b#\u0009\u0009\u0011\"\u0001\u00064Q!\u0011qQC\u001b\u0011)\u0009y)\"\r\u0002\u0002\u0003\u0007\u00111\u0010\u0005\u000b\u0003'+\u0009\"!A\u0005B\u0005U\u0005BCAS\u000b#\u0009\u0009\u0011\"\u0001\u0006<Q\u0019\u0001+\"\u0010\u0009\u0015\u0005=U\u0011HA\u0001\u0002\u0004\u00099\u0009\u0003\u0006\u0002.\u0016E\u0011\u0011!C!\u0003_C!\"a-\u0006\u0012\u0005\u0005I\u0011IA[\u0011)\u0009I,\"\u0005\u0002\u0002\u0013\u0005SQ\u0009\u000b\u0004!\u0016\u001d\u0003BCAH\u000b\u0007\n\u0009\u00111\u0001\u0002\u0008\u001a1Q1\n\u0001A\u000b\u001b\u0012qaU6jaB,Gm\u0005\u0004\u0006J\u0011euI\u0013\u0005\u000c\u000b#*IE!f\u0001\n\u0003\u0019I-A\u0004tW&\u0004\u0008/\u001a3\u0009\u001b\u0015US\u0011\nB\u0009B\u0003%\u0011\u0011\u0002CG\u0003!\u00198.\u001b9qK\u0012\u0004\u0003\u0002CA\u0014\u000b\u0013\"\u0009!\"\u0017\u0015\u0009\u0015mSQ\u000c\u0009\u0004c\u0015%\u0003\u0002CC)\u000b/\u0002\r!!\u0003\u0009\u0015\u0005\rS\u0011JA\u0001\n\u0003)\u0009\u0007\u0006\u0003\u0006\\\u0015\r\u0004BCC)\u000b?\u0002\n\u00111\u0001\u0002\n!Q\u0011QKC%\u0003\u0003%\u0009a!3\u0009\u0015\u00055T\u0011JA\u0001\n\u0003\ny\u0007\u0003\u0006\u0002x\u0015%\u0013\u0011!C\u0001\u0003sB!\"a!\u0006J\u0005\u0005I\u0011AC7)\u0011\u00099)b\u001c\u0009\u0015\u0005=U1NA\u0001\u0002\u0004\u0009Y\u0008\u0003\u0006\u0002\u0014\u0016%\u0013\u0011!C!\u0003+C!\"!*\u0006J\u0005\u0005I\u0011AC;)\r\u0001Vq\u000f\u0005\u000b\u0003\u001f+\u0019(!AA\u0002\u0005\u001d\u0005BCAW\u000b\u0013\n\u0009\u0011\"\u0011\u00020\"Q\u00111WC%\u0003\u0003%\u0009%!.\u0009\u0015\u0005eV\u0011JA\u0001\n\u0003*y\u0008F\u0002Q\u000b\u0003C!\"a$\u0006~\u0005\u0005\u0009\u0019AAD\r\u0019))\u0009\u0001!\u0006\u0008\n91+^2dKN\u001c8CBCB\u00093;%\nC\u0006\u0004b\u0016\r%Q3A\u0005\u0002\r%\u0007\"DCG\u000b\u0007\u0013\u0009\u0012)A\u0005\u0003\u0013!i)A\u0005fqB\u000cg\u000eZ3eA!A\u0011qECB\u0009\u0003)\u0009\n\u0006\u0003\u0006\u0014\u0016U\u0005cA\u0019\u0006\u0004\"A1\u0011]CH\u0001\u0004\u0009I\u0001\u0003\u0006\u0002D\u0015\r\u0015\u0011!C\u0001\u000b3#B!b%\u0006\u001c\"Q1\u0011]CL!\u0003\u0005\r!!\u0003\u0009\u0015\u0005US1QA\u0001\n\u0003\u0019I\r\u0003\u0006\u0002n\u0015\r\u0015\u0011!C!\u0003_B!\"a\u001e\u0006\u0004\u0006\u0005I\u0011AA=\u0011)\u0009\u0019)b!\u0002\u0002\u0013\u0005QQ\u0015\u000b\u0005\u0003\u000f+9\u000b\u0003\u0006\u0002\u0010\u0016\r\u0016\u0011!a\u0001\u0003wB!\"a%\u0006\u0004\u0006\u0005I\u0011IAK\u0011)\u0009)+b!\u0002\u0002\u0013\u0005QQ\u0016\u000b\u0004!\u0016=\u0006BCAH\u000bW\u000b\u0009\u00111\u0001\u0002\u0008\"Q\u0011QVCB\u0003\u0003%\u0009%a,\u0009\u0015\u0005MV1QA\u0001\n\u0003\n)\u000c\u0003\u0006\u0002:\u0016\r\u0015\u0011!C!\u000bo#2\u0001UC]\u0011)\u0009y)\".\u0002\u0002\u0003\u0007\u0011qQ\u0004\n\u000b{\u0003\u0011\u0011!E\u0001\u000b\u000bqaU;dG\u0016\u001c8\u000fE\u00022\u000b\u00034\u0011\"\"\"\u0001\u0003\u0003E\u0009!b1\u0014\u000b\u0015\u0005WQ\u0019&\u0011\u0011\rERqYA\u0005\u000b'KA!\"3\u00044\u0009\u0009\u0012IY:ue\u0006\u001cGOR;oGRLwN\\\u0019\u0009\u0011\u0005\u001dR\u0011\u0019C\u0001\u000b\u001b$\"!b0\u0009\u0015\u0005MV\u0011YA\u0001\n\u000b\n)\u000c\u0003\u0006\u0003\"\u0015\u0005\u0017\u0011!CA\u000b'$B!b%\u0006V\"A1\u0011]Ci\u0001\u0004\u0009I\u0001\u0003\u0006\u00034\u0015\u0005\u0017\u0011!CA\u000b3$B!b7\u0006^B)QB!\u000f\u0002\n!Q!QICl\u0003\u0003\u0005\r!b%\u0008\u0013\u0015\u0005\u0008!!A\u0009\u0002\u0015\r\u0018\u0001\u0003$bY2\u0014\u0017mY6\u0011\u0007E*)OB\u0005\u0006\u0014\u0001\u0009\u0009\u0011#\u0001\u0006hN)QQ]Cu\u0015BA1\u0011GCd\u0003\u0013)\u0009\u0003\u0003\u0005\u0002(\u0015\u0015H\u0011ACw)\u0009)\u0019\u000f\u0003\u0006\u00024\u0016\u0015\u0018\u0011!C#\u0003kC!B!\u0009\u0006f\u0006\u0005I\u0011QCz)\u0011)\u0009#\">\u0009\u0011\u0011\rT\u0011\u001fa\u0001\u0003\u0013A!Ba\r\u0006f\u0006\u0005I\u0011QC})\u0011)Y.b?\u0009\u0015\u0009\u0015Sq_A\u0001\u0002\u0004)\u0009cB\u0005\u0006\u0000\u0002\u0009\u0009\u0011#\u0001\u0007\u0002\u00059A)\u001a7bs\u0016$\u0007cA\u0019\u0007\u0004\u0019IA\u0011\u0015\u0001\u0002\u0002#\u0005aQA\n\u0006\r\u000719A\u0013\u0009\u0009\u0007c)9-!\u0003\u00050\"A\u0011q\u0005D\u0002\u0009\u00031Y\u0001\u0006\u0002\u0007\u0002!Q\u00111\u0017D\u0002\u0003\u0003%)%!.\u0009\u0015\u0009\u0005b1AA\u0001\n\u00033\u0009\u0002\u0006\u0003\u00050\u001aM\u0001\u0002\u0003C.\r\u001f\u0001\r!!\u0003\u0009\u0015\u0009Mb1AA\u0001\n\u000339\u0002\u0006\u0003\u0006\\\u001ae\u0001B\u0003B#\r+\u0009\u0009\u00111\u0001\u00050\u001eIaQ\u0004\u0001\u0002\u0002#\u0005aqD\u0001\u0008'.L\u0007\u000f]3e!\r\u0009d\u0011\u0005\u0004\n\u000b\u0017\u0002\u0011\u0011!E\u0001\rG\u0019RA\"\u0009\u0007&)\u0003\u0002b!\r\u0006H\u0006%Q1\u000c\u0005\u0009\u0003O1\u0009\u0003\"\u0001\u0007*Q\u0011aq\u0004\u0005\u000b\u0003g3\u0009#!A\u0005F\u0005U\u0006B\u0003B\u0011\rC\u0009\u0009\u0011\"!\u00070Q!Q1\u000cD\u0019\u0011!)\u0009F\"\u000cA\u0002\u0005%\u0001B\u0003B\u001a\rC\u0009\u0009\u0011\"!\u00076Q!Q1\u001cD\u001c\u0011)\u0011)Eb\r\u0002\u0002\u0003\u0007Q1L\u0004\n\rw\u0001\u0011\u0011!E\u0001\r{\u0009qAR1jYV\u0014X\rE\u00022\r1\u0011\u0002\"7\u0001\u0003\u0003E\u0009A\"\u0011\u0014\u000b\u0019}b1\u0009&\u0011\u0011\rERqYA\u0005\u0009SD\u0001\"a\n\u0007@\u0011\u0005aq\u0009\u000b\u0003\r{A!\"a-\u0007@\u0005\u0005IQIA[\u0011)\u0011\u0009Cb\u0010\u0002\u0002\u0013\u0005eQ\n\u000b\u0005\u0009S4y\u0005\u0003\u0005\u0005`\u001a-\u0003\u0019AA\u0005\u0011)\u0011\u0019Db\u0010\u0002\u0002\u0013\u0005e1\u000b\u000b\u0005\u000b74)\u0006\u0003\u0006\u0003F\u0019E\u0013\u0011!a\u0001\u0009SDqA\"\u0017\u0001\u0009\u00031Y&A\u0003EK2\u000c\u0017\u0010\u0006\u0003\u00050\u001au\u0003\u0002CBq\r/\u0002\r!!\u0003\u0009\u000f\u0019\u0005\u0004\u0001\"\u0001\u0007d\u0005!1k[5q)\u0011)YF\"\u001a\u0009\u0011\r\u0005hq\u000ca\u0001\u0003\u0013AqA\"\u001b\u0001\u0009\u00031Y'\u0001\u000cnC\u000e\u0014x.\u0012=qC:$w+\u001b;i%VtG/[7f)!!IJ\"\u001c\u0007p\u0019E\u0004\u0002\u0003BS\rO\u0002\rAa*\u0009\u0011\u0009Edq\ra\u0001\u0003\u0013Aqa\u0005D4\u0001\u00041\u0019\u0008E\u00022\rkJ1Ab\u001e\u0019\u00051i\u0015m\u0019:p%VtG/[7f\u0011\u001d1Y\u0008\u0001C\u0001\r{\n\u0011$\\1de>,\u0005\u0010]1oI^KG\u000f[8viJ+h\u000e^5nKR1A\u0011\u0014D@\r\u0003C\u0001B!*\u0007z\u0001\u0007!q\u0015\u0005\u0009\u0005c2I\u00081\u0001\u0002\n!AaQ\u0011\u0001A\u0002\u0013\u0005q*A\riCN\u0004VM\u001c3j]\u001el\u0015m\u0019:p\u000bb\u0004\u0018M\\:j_:\u001c\u0008\"\u0003DE\u0001\u0001\u0007I\u0011\u0001DF\u0003uA\u0017m\u001d)f]\u0012LgnZ'bGJ|W\u0009\u001f9b]NLwN\\:`I\u0015\u000cHc\u0001\u0014\u0007\u000e\"I\u0011q\u0012DD\u0003\u0003\u0005\r\u0001\u0015\u0005\u0007\r#\u0003A\u0011A(\u0002?QL\u0008/\u001a:TQ>,H\u000eZ#ya\u0006tG\rR3gKJ\u0014X\rZ'bGJ|7\u000fC\u0005\u0007\u0016\u0002\u0011\r\u0011\"\u0003\u0007\u0018\u00061am\u001c:dK\u0012,\"A\"'\u0011\r\rEf1TA\u0005\u0013\u00111ija-\u0003\u0017]+\u0017m\u001b%bg\"\u001cV\r\u001e\u0005\n\u00097\u0002!\u0019!C\u0005\rC+\"Ab)\u0011\u0011\u0019\u0015f1VA\u0005\r_k!Ab*\u000b\u0009\u0019%\u00161T\u0001\u0008[V$\u0018M\u00197f\u0013\u00111iKb*\u0003\u0017]+\u0017m\u001b%bg\"l\u0015\r\u001d\u0009\u0007\rK3\u0009,a\u001f\n\u0009\u0019Mfq\u0015\u0002\u0004'\u0016$\u0008b\u0002D\\\u0001\u0011%a\u0011X\u0001\nSN$U\r\\1zK\u0012$2\u0001\u0015D^\u0011!\u0011\u0009H\".A\u0002\u0005%\u0001B\u0002D`\u0001\u0011\u0005Q%\u0001\u0007dY\u0016\u000c'\u000fR3mCf,G\rC\u0004\u0007D\u0002!IA\"2\u0002)\r\u000cGnY;mCR,WK\u001c3fiB\u000c'/Y7t)\u00111yKb2\u0009\u0011\u0009Ed\u0011\u0019a\u0001\u0003\u0013A\u0011Bb3\u0001\u0005\u0004%IA\"4\u0002\u0017UtG-\u001a;qCJ\u000cWn]\u000b\u0003\r\u001f\u0004bA\"*\u0007R\u0006m\u0014\u0002\u0002Dj\rO\u0013q\u0001S1tQN+G\u000fC\u0004\u0007X\u0002!\u0009A\"7\u0002-9|G/\u001b4z+:$W\r\u001e9be\u0006l7/\u00113eK\u0012$2A\nDn\u0011!1iN\"6A\u0002\u0019}\u0017!\u00038foVsG-\u001a;t!\u0011\u0009hO!\u0016\u0009\u000f\u0019\r\u0008\u0001\"\u0001\u0007f\u0006Ibn\u001c;jMf,f\u000eZ3ua\u0006\u0014\u0018-\\:J]\u001a,'O]3e)\u00151cq\u001dDv\u0011!1IO\"9A\u0002\u0019}\u0017aC;oI\u0016$hj\\'pe\u0016D\u0001B\"<\u0007b\u0002\u0007aq^\u0001\nS:4WM\u001d:fIN\u0004B!\u001d<\u0003\u0008\"9a1\u001f\u0001\u0005\u0002\u0019U\u0018AD7bGJ|W\u0009\u001f9b]\u0012\u000cE\u000e\u001c\u000b\u0007\u0003\u001319P\"?\u0009\u0011\u0009\u0015f\u0011\u001fa\u0001\u0005OC\u0001B!\u001d\u0007r\u0002\u0007\u0011\u0011\u0002\u0009\u0004w\u0006E\u0001"
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 57660b37bd..fd63fdc943 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -192,11 +192,13 @@ abstract class UnPickler {
protected def readName(): Name = {
val tag = readByte()
val len = readNat()
- tag match {
+ val result = tag match {
case TERMname => newTermName(bytes, readIndex, len)
case TYPEname => newTypeName(bytes, readIndex, len)
case _ => errorBadSignature("bad name tag: " + tag)
}
+ println(result)
+ result
}
private def readEnd() = readNat() + readIndex
@@ -328,6 +330,7 @@ abstract class UnPickler {
)
if (shouldEnterInOwnerScope)
symScope(sym.owner) enter sym
+ println(sym.name + " " + sym.debugFlagString)
sym
}
--- /tmp/a.log 2018-01-22 17:03:37.000000000 +1000
+++ /tmp/b.log 2018-01-22 17:03:38.000000000 +1000
@@ -562,7 +562,7 @@
<refinement>
universe
<refinement>
-universe <method> <deferred> <stable> <accessor>
+universe <method> <deferred> override <stable> <accessor>
_openMacros_$eq
_openMacros_$eq <method> <accessor>
x$1 <param> <synthetic>
This looks likely to be a player:
Minimized as:
âš¡ tail sandbox/{a,b}.scala && (echo "== a.scala b.scala"; qscalac -d /tmp -Ydebug -Xprint:typer sandbox/{a,b}.scala; echo "== b.scala a.scala";qscalac -d /tmp -Ydebug -Xprint:typer sandbox/{b,a}.scala && echo "== b.scala" ; qscalac -d /tmp -Ydebug -Xprint:typer sandbox/b.scala) 2>&1 | egrep '==|def foo'
==> sandbox/a.scala <==
trait Context {
val universe: Global
}
trait StdAttachments {
self: Analyzer =>
type UnaffiliatedMacroContext = Context
type MacroContext = UnaffiliatedMacroContext { val universe: self.global.type }
}
==> sandbox/b.scala <==
class Macros {
self: Analyzer =>
def foo = List.apply[MacroContext]()
}
== a.scala b.scala
<method> def foo: immutable.this.List[<empty>.this.Context{<method> <deferred> override <stable> <accessor> val universe: Macros.this.global.type}] = scala.collection.immutable.Nil
== b.scala a.scala
<method> def foo: immutable.this.List[<empty>.this.Context{<method> <deferred> <stable> <accessor> val universe: Macros.this.global.type}] = scala.collection.immutable.Nil
== b.scala
<method> def foo: immutable.this.List[<empty>.this.Context{<method> <deferred> override <stable> <accessor> val universe: Macros.this.global.type}] = scala.collection.immutable.Nil
The instability in the order of module vars/accessors in, e.g MatchTranslator
, is due to the fact that the order of decls in a class info type is not explicitly pickled. After unpickling, the decls are ordered based on the order of entries in the pickle index, and that order is influenced by references, not just definitions.
We could update pickler to walk and enter decls before considering references (basically make it two pass). Another alternative might be to modify the pickle format to explicitly write the decl order.
one of the sources of instability in builds that we encountered is non-determinism in macros we're building tooling to catch these problems more systematically (in bazel setting)
Quick progress update: I've submitted all the changes in my prototype branch as PRs. See https://github.com/scala/scala-dev/issues/405 for links.
Mostly they are against 2.13.x. If the set of changes prove stable and comprehensive in that branch, we might consider a 2.12 backport, but no guarantees.
I'm gathering test cases for unstable output for Scalac with a view to improving the compiler to make them stable. See the README for the tests I've come up with so far.
This ticket is a 🦇 -signal to some people that might be interested in this effort, and hopefully might be able to help me come up with additional test cases.
I'm also interested in what "stability" means to you.
@dragos (who fixed an bug if this ilk in https://github.com/scala/scala/pull/5965 and might be able to exploit from stability in https://triplequote.com/hydra) @johnynek @ittaiz (from https://github.com/bazelbuild/rules_scala) @jvican (from Scala Center, and who I recall is interested in this topic) @eed3si9n / @dwijnand (from sbt)