diff --git a/.claude/SKILL.md b/.claude/SKILL.md index d812631c1..ffaba343b 100644 --- a/.claude/SKILL.md +++ b/.claude/SKILL.md @@ -1,6 +1,6 @@ # async-test-lib — Usage Guide -**async-test-lib** is a JUnit 5 extension for stress-testing concurrent Java code. It forces real thread collisions using a `CyclicBarrier`, then runs 148 specialized detectors across 18 phases to identify exactly what went wrong — including six JDK 25/26 detectors (Phases 16 and 18: `StableValue`, `StructuredTaskScope`, parallel `Gatherer`, `LazyConstant`, final-field mutation, shared `KDF`) you can also drive directly via AsyncTestContext accessors. +**async-test-lib** is a JUnit 5 extension for stress-testing concurrent Java code. It forces real thread collisions using a `CyclicBarrier`, then runs 149 specialized detectors across 18 phases to identify exactly what went wrong — including six JDK 25/26 detectors (Phases 16 and 18: `StableValue`, `StructuredTaskScope`, parallel `Gatherer`, `LazyConstant`, final-field mutation, shared `KDF`) you can also drive directly via AsyncTestContext accessors. - Replaces `@Test` with `@AsyncTest` — zero other changes needed - Requires Java 21 and JUnit 5 (Jupiter 6.0.3+) diff --git a/.claude/skills/regression-test/SKILL.md b/.claude/skills/regression-test/SKILL.md index 306d1b9e1..d9f10d3cf 100644 --- a/.claude/skills/regression-test/SKILL.md +++ b/.claude/skills/regression-test/SKILL.md @@ -82,7 +82,7 @@ you are on a clean branch. Anything it prints that section 3 does not describe is a new consumer. Add it there. Most of its output is not consumers. It also lists every checkout under `/c/dev/private`, -including this repo's own worktrees (the fixtures, corpus-eval and 150 examples each, repeated +including this repo's own worktrees (the fixtures, corpus-eval and 151 examples each, repeated per worktree) and stale worktrees of consumers such as `vibetags-cov`, which still pin old versions. Filter to the repo names in section 3 before reading versions. diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md index 5fa443d7f..a5886c345 100644 --- a/.claude/skills/release/SKILL.md +++ b/.claude/skills/release/SKILL.md @@ -63,7 +63,7 @@ The script rewrites the exact current version string where it is a pin, in an al `docs/QUICK_REFERENCE.md`, `docs/DISTRIBUTION.md`, `.claude/SKILL.md`. `versions/pom.xml`'s `` is the one pin every build outside the reactor -resolves: the 150 examples, both consumer fixtures and the corpus inherit it, and their Gradle +resolves: the 151 examples, both consumer fixtures and the corpus inherit it, and their Gradle builds read it. It must move with the release. Those builds resolve `mavenLocal()` before `mavenCentral()`, and CI publishes the working tree there before building them, so a pin left on an older version silently resolves that **old release from Central** and passes while proving diff --git a/.gemini/rules/async-test-detectors.md b/.gemini/rules/async-test-detectors.md index 24f42eb35..3027ca16e 100644 --- a/.gemini/rules/async-test-detectors.md +++ b/.gemini/rules/async-test-detectors.md @@ -51,6 +51,9 @@ ### se.deversity.asynctest.diagnostics.JdbcConnectionSharedDetector - **Test Location**: src/test/java/se/deversity/asynctest/diagnostics/JdbcConnectionSharedDetectorTest.java +### se.deversity.asynctest.diagnostics.KotlinMutexReentrancyDetector +- **Test Location**: src/test/java/se/deversity/asynctest/diagnostics/KotlinMutexReentrancyDetectorTest.java + ### se.deversity.asynctest.diagnostics.LambdaLostUpdateDetector - **Test Location**: src/test/java/se/deversity/asynctest/diagnostics/LambdaLostUpdateDetectorTest.java @@ -210,6 +213,10 @@ - **Strategy**: OTHER - **Note**: ConcurrentHashMap-backed JDBC-resource tracking; per-resource State holds ConcurrentHashMap.newKeySet() for accessing threads. +### se.deversity.asynctest.diagnostics.KotlinMutexReentrancyDetector +- **Strategy**: OTHER +- **Note**: Per-mutex state in the weakly keyed ConcurrentHashMap of AbstractInstanceDetector; the holdings are a ConcurrentLinkedDeque of weakly held Jobs, and a reentry writes its description before its count. + ### se.deversity.asynctest.diagnostics.LambdaLostUpdateDetector - **Strategy**: OTHER - **Note**: ConcurrentHashMap keyed on lambda identity plus captured name; events are appended to a copy-on-write list. The rule groups by observed pre-value and needs no ordering. holdsLock is sampled on the recording thread at record time, which is the only place it means anything. diff --git a/.gemini/rules/async-test-instrumentation.md b/.gemini/rules/async-test-instrumentation.md index 64b486a9a..bc24491f8 100644 --- a/.gemini/rules/async-test-instrumentation.md +++ b/.gemini/rules/async-test-instrumentation.md @@ -6,7 +6,7 @@ ### se.deversity.asynctest.agent.AsyncTestAgent - **Sensitivity**: Critical -- **Note**: The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. +- **Note**: The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). KotlinMutexWeaver replaces a kotlinx.coroutines.sync.Mutex lock, unlock or tryLock call, or its static $default bridge, matched by owner, name and descriptor, with a static hook consuming the same stack and returning the same result, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. ## Contract-Frozen Signature - **Constraint**: You may change internal logic, but MUST NOT modify the method name, parameters, return type, or checked exceptions. diff --git a/.github/workflows/corpus.yml b/.github/workflows/corpus.yml index f7aa6ef5f..9843f753d 100644 --- a/.github/workflows/corpus.yml +++ b/.github/workflows/corpus.yml @@ -16,7 +16,7 @@ name: Corpus Eval # # Its own workflow rather than a job in e2e-tests.yml, because this eval answers a question about # the product rather than about the build: whether a finding on somebody else's code means their -# code is wrong. It publishes numbers that the README and the trust tiers both rest on - 34 +# code is wrong. It publishes numbers that the README and the trust tiers both rest on - 35 # detectors carry VERDICT on the strength of pairs measured here - so it earns a history and a # badge of its own, and a workflow_dispatch for running it against a library change without waiting # for the whole end-to-end suite. diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 70c5891bb..5429fb745 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -316,7 +316,7 @@ jobs: # 2. A library change edits no examples/** path, but every example consumes the built # artifact, so one can break all of them while this filter sees nothing. Run a - # deterministic every-4th sample, 38 of the 150 examples: enough to catch a + # deterministic every-4th sample, 38 of the 151 examples: enough to catch a # systemic break at PR time, cheap enough to afford on every library PR. The full # reactor still runs on push and nightly, so this moves discovery earlier rather # than adding coverage. diff --git a/.github/workflows/gradle-tests.yml b/.github/workflows/gradle-tests.yml index 2ce7bb865..ac9237ba2 100644 --- a/.github/workflows/gradle-tests.yml +++ b/.github/workflows/gradle-tests.yml @@ -368,7 +368,7 @@ jobs: # 2. A library change edits no examples/** path, but every example consumes the built # artifact, so one can break all of them while this filter sees nothing. Run a - # deterministic every-4th sample, 38 of the 150 examples: enough to catch a + # deterministic every-4th sample, 38 of the 151 examples: enough to catch a # systemic break at PR time, cheap enough to afford on every library PR. The full # reactor still runs on push and nightly, so this moves discovery earlier rather # than adding coverage. diff --git a/.vibetags-mod-async-test-agent b/.vibetags-mod-async-test-agent index af4c6bb5e..92a810207 100644 --- a/.vibetags-mod-async-test-agent +++ b/.vibetags-mod-async-test-agent @@ -2,14 +2,14 @@ moduleId=async-test-agent modulePath=async-test-agent regionId=async-test-agent -claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxsb2NrZWRfZmlsZXM+CiAgPC9sb2NrZWRfZmlsZXM+CiAgPGNvbnRleHR1YWxfaW5zdHJ1Y3Rpb25zPgogIDwvY29udGV4dHVhbF9pbnN0cnVjdGlvbnM+CiAgPGNvcmVfZWxlbWVudHM+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkFzeW5jVGVzdEFnZW50Ij4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+VGhlIElOU1RBTExFRCBnYXRlIG11c3Qgc3RheSBhdC1tb3N0LW9uY2UgcGVyIEpWTTogZXZlcnkgZW50cnkgcG9pbnQgKHByZW1haW4sIGFnZW50bWFpbiwgc2VsZkF0dGFjaCkgcmFjZXMgb24gdGhlIHNhbWUgY29tcGFyZUFuZFNldCwgYW5kIGEgc2Vjb25kIHRyYW5zZm9ybWVyIHdvdWxkIGRvdWJsZS13ZWF2ZSBhY2Nlc3NlcyBhbmQgZG91YmxlLWNvdW50IGV2ZXJ5IG9uZS4gcHJlbWFpbiBpbnN0YWxscyB3aXRob3V0IHJldHJhbnNmb3JtYXRpb24gYmVjYXVzZSBjbGFzc2VzIGFyZSB3b3ZlbiBhcyB0aGV5IGxvYWQ7IGFnZW50bWFpbiBtdXN0IGtlZXAgUkVUUkFOU0ZPUk1BVElPTiArIGRpc2FibGVDbGFzc0Zvcm1hdENoYW5nZXMoKSwgd2hpY2ggaXMgb25seSBzYWZlIHdoaWxlIG5vIHdlYXZlciBhZGRzIGEgbWVtYmVyLCBhbmQgdGhlcmUgYXJlIGZvdXIgYmVzaWRlcyB0aGUgQWR2aWNlLCB3aGljaCBpcyBhIG1ldGhvZC1lbnRyeSBwcm9sb2d1ZS4gRmllbGRBY2Nlc3NXZWF2ZXIgaW5zZXJ0cyBhIHN0YWNrLW5ldXRyYWwsIGJyYW5jaC1mcmVlIGNhbGwgYmVmb3JlIGVhY2ggZmllbGQgaW5zdHJ1Y3Rpb24sIGEgbG9hZCBvZiB0aGUgbW9uaXRvciBwbHVzIGEgY2FsbCBhdCB0aGUgZW50cnkgb2YgYSBzeW5jaHJvbml6ZWQgbWV0aG9kIGFuZCBiZWZvcmUgZWFjaCBvZiBpdHMgcmV0dXJucyAoIzgyMiksIGEgRFVQIG9mIHRoZSBtb25pdG9yLCBhbiBBTE9BRCBvZiB0aGUgbG9jYWwgdGhlIG93bmVyIHdhcyBsb2FkZWQgZnJvbSwgYW4gTERDIG9mIHRoZSBmaWVsZCBhbmQgYSBjYWxsIGJlZm9yZSBhIE1PTklUT1JFTlRFUiB3aG9zZSBtb25pdG9yIHRoZSBmb3VyIGluc3RydWN0aW9ucyBiZWZvcmUgaXQgcmVhZCBmcm9tIGFuIGluc3RhbmNlIGZpZWxkIChBTE9BRCwgR0VURklFTEQsIERVUCwgQVNUT1JFLCB3aXRoIG5vIGxhYmVsIGJldHdlZW4sICM3OTMpLCBhIERVUCBwbHVzIGNhbGwgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBpdCBkb2VzIG5vdCBzdWJzdGl0dXRlICh0aGUgb3duZXJzaGlwIHRha2UsICM1NTUpLCBEVVAyIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGJlZm9yZSBhIEpDVG9vbHMgb2ZmZXIsIGFuZCBhIERVUCBiZWZvcmUgcGx1cyBEVVBfWDEgYW5kIFNXQVAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBKQ1Rvb2xzIHBvbGwgKCM2NjQpLCBhIGNvcHkgb2Ygb3duZXIgYW5kIHZhbHVlIHBsdXMgYSBjYWxsIGJlZm9yZSBhIHZvbGF0aWxlIGZpZWxkIHN0b3JlIGFuZCBhZnRlciBhIHZvbGF0aWxlIGZpZWxkIGxvYWQsIHdpdGggYSBEVVAgb2YgdGhlIHJlY2VpdmVyIGJlZm9yZSBhbiBpbnN0YW5jZSBsb2FkICgjNzQyKSwgYW5kIHJlcGxhY2VzIGFuIGludCBWYXJIYW5kbGUsIEF0b21pY0ludGVnZXJGaWVsZFVwZGF0ZXIsIEF0b21pY0Jvb2xlYW4gb3IgQXRvbWljSW50ZWdlciBzdG9yZSwgc3dhcCBvciB2YWx1ZS1yZXR1cm5pbmcgcmVsZWFzZSwgb3IgYSByZWZlcmVuY2Utc2xvdCBzdG9yZSBvciBnZXRBbmRTZXQgb24gYW4gQXRvbWljUmVmZXJlbmNlLCBpdHMgdXBkYXRlciwgaXRzIGFycmF5IG9yIGFuIGluc3RhbmNlLWZpZWxkIFZhckhhbmRsZSwgb3IgYW4gYWNxdWlyaW5nIHJlZmVyZW5jZSByZWFkLCBhbiBBdG9taWNSZWZlcmVuY2UgZ2V0IG9yIGdldEFjcXVpcmUsIGFuIHVwZGF0ZXIgZ2V0LCBhbiBBdG9taWNSZWZlcmVuY2VBcnJheSBnZXQgb3IgZ2V0QWNxdWlyZSBvciBhIFZhckhhbmRsZSBnZXRWb2xhdGlsZSBvciBnZXRBY3F1aXJlICh0aGUgYWNxdWlyZSBvZiB0aGUgc3RvcmUgaXQgcmV0dXJuZWQsICM3NDEpLCBvciBhbiBBdG9taWNTdGFtcGVkUmVmZXJlbmNlIGdldCwgZ2V0UmVmZXJlbmNlLCBzZXQsIGNvbXBhcmVBbmRTZXQsIHdlYWtDb21wYXJlQW5kU2V0IG9yIGF0dGVtcHRTdGFtcCAoIzgxNyksIG9yIGFuIEF0b21pY0ludGVnZXIgZ2V0IG9yIGFuIEF0b21pY0xvbmcgZ2V0LCBzdG9yZSBvciBjb21wYXJlLWFuZC1zZXQgKGEgZ2V0IHRoZW4gc2V0LCAjMTE1NyksIHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2sgYW5kIHJldHVybmluZyB0aGUgc2FtZSByZXN1bHQsIHBsdXMgb25lIFBPUCB3aGVyZSBhIFZhckhhbmRsZSBjYWxsIHNpdGUgZGVjbGFyZWQgYSB2b2lkIHJlc3VsdCBhbmQgb25lIENIRUNLQ0FTVCB0byB0aGUgZGVjbGFyZWQgdHlwZSBhZnRlciBhIFZhckhhbmRsZSByZWZlcmVuY2UgZ2V0QW5kU2V0IG9yIGFjcXVpcmluZyByZWFkICh0aGUgc3BpbmxvY2ssICM1NTQsICM1NTgsICM2NTgsICM2Njc7IHRoZSBvd25lcnNoaXAgb2ZmZXIgYW5kIHRha2UsICM2NjQpLiBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyIHJlcGxhY2VzIGVhY2ggY2FsbCBpdHMgdGFibGVzIGxpc3Qgd2l0aCBhIHN0YXRpYyBob29rIGNvbnN1bWluZyB0aGUgc2FtZSBzdGFjaywgYW5kIGluc2VydHMgb25seSB0aGUgbW9uaXRvciBsb2FkcyBhbmQgdGhlIGxvb3AgYmFjay1lZGdlIGNhbGwgaXRzIG93biBydWxlcyBkZXNjcmliZS4gVGhyZWFkQ29uc3RydWN0aW9uV2VhdmVyIGluc2VydHMgYSBEVVAgcGx1cyBhIGNhbGwgYWZ0ZXIgdGhlIGNvbnN0cnVjdG9yIGNhbGwgb2YgYSBuZXcgVGhyZWFkKC4uLiksIGFuZCBhbiBBTE9BRCAwIHBsdXMgYSBjYWxsIGFmdGVyIGEgVGhyZWFkIHN1YmNsYXNzIGNvbnN0cnVjdG9yJiMzOTtzIHN1cGVyY2xhc3MgY2FsbCAoIzczNykuIENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgY2FsbCB0aGF0IGNvbnN1bWVzIGFuZCByZXR1cm5zIHRoZSBvcmRlciBhcmd1bWVudCBiZWZvcmUgYSBMaW5rZWRIYXNoTWFwKGludCwgZmxvYXQsIGJvb2xlYW4pIGNvbnN0cnVjdG9yIGNhbGwgYW5kIGEgRFVQIG9yIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgaXQgKCM4MDcpLCBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciBhIG5ldyBDb21wbGV0YWJsZUZ1dHVyZSgpIGNvbnN0cnVjdG9yIGNhbGwgKCMxMDU0KSwgYW5kIGFuIEFMT0FEIDAsIGFuIExEQyBvZiB0aGUgY2xhc3MgbmFtZSBhbmQgYSBjYWxsIGJlZm9yZSBlYWNoIFJFVFVSTiBvZiBhIGNvbnN0cnVjdG9yIGFuZCBhZnRlciBhIHRoaXMoLi4uKSBkZWxlZ2F0aW9uICgjNzkxKTsgaXQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gSW50ZXJydXB0SGFuZGxlcldlYXZlciBpbnNlcnRzIGFuIExEQyBvZiB0aGUgbG9jYXRpb25zIG9mIGEgbWV0aG9kJiMzOTtzIEludGVycnVwdGVkRXhjZXB0aW9uIGhhbmRsZXJzIHRoYXQgbmVpdGhlciByZXRocm93IG5vciByZXN0b3JlIHRoZSBmbGFnLCBhbmQgYSBjYWxsLCBiZWZvcmUgdGhlIGZpcnN0IGluc3RydWN0aW9uIG9mIGEgbWV0aG9kIHRoYXQgZGVjbGFyZXMgb25lLCBhbmQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gUGVyc2lzdGVuY2VIYW5kbGVXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgY2FsbCB3aG9zZSBvd25lciBpcyBhIEpQQSBFbnRpdHlNYW5hZ2VyIG9yIEhpYmVybmF0ZSBTZXNzaW9uIGJ5IG5hbWUsIGEgc3RhY2stbmV1dHJhbCBjb3B5IG9mIHRoZSByZWNlaXZlciAoRFVQOyBTV0FQLCBEVVBfWDE7IG9yIERVUDJfWDEsIFBPUDIsIERVUF9YMiBmb3IgemVybywgb25lIG9yIHR3byBvbmUtc2xvdCBhcmd1bWVudHMpIGFuZCBhIGNhbGwsIGFuZCBsZWF2ZXMgY2FsbHMgd2l0aCBtb3JlIG9yIHdpZGVyIGFyZ3VtZW50cyBhbG9uZSAoIzk5MikuIFJ1bkJsb2NraW5nV2VhdmVyIGluc2VydHMsIGJlZm9yZSBhIHN0YXRpYyBjYWxsIG9mIGtvdGxpbnguY29yb3V0aW5lcy5CdWlsZGVyc0t0LnJ1bkJsb2NraW5nSywgcnVuQmxvY2tpbmcgb3IgdGhlaXIgJGRlZmF1bHQgYnJpZGdlcyBieSBuYW1lLCBvbmUgY2FsbCBvZiBhICgpViBob29rIHRoYXQgdGFrZXMgYW5kIGxlYXZlcyBub3RoaW5nLCBpbiBldmVyeSB3b3ZlbiBjbGFzcyBvdXRzaWRlIGtvdGxpbnguY29yb3V0aW5lcyAoIzEwMDcpLiBTbyBmcmFtZXMgc3RheSB2YWxpZCBhbmQgb25seSBtYXhTdGFjayBncm93cyAoQ09NUFVURV9NQVhTLCBuZXZlciBDT01QVVRFX0ZSQU1FUywgd2hpY2ggd291bGQgbG9hZCBjbGFzc2VzIGZyb20gaW5zaWRlIHRoZSBhZ2VudCkuIEluIGV2ZXJ5IG1vZGUsIGluc3RhbGwgYW5kIHRoZSB0cmFuc2Zvcm1lciBvcGVuIGphdmEudXRpbC5jb25jdXJyZW50LmxvY2tzLCB3aXRoIGZpZWxkcz10cnVlIGFsc28gamF2YS51dGlsLmNvbmN1cnJlbnQuYXRvbWljLCBhbmQgd2l0aCBjb2xsZWN0aW9ucz10cnVlIGFsc28gamF2YS51dGlsIGFuZCBqYXZhLmlvIChhIHN5bmNocm9uaXplZCB3cmFwcGVyJiMzOTtzIG11dGV4LCAjOTk2OyBhIHBpcGVkIHdyaXRlciYjMzk7cyBzaW5rLCAjOTk0KSwgdG8gb25lIG1vZHVsZSBwZXIgd292ZW4gbG9hZGVyIGFuZCB0byBub3RoaW5nIGVsc2U6IHRoZSBtb2R1bGUgb2YgdGhlIFRlbGVtZXRyeVJlZ2lzdHJ5IGNvcHkgdGhhdCBsb2FkZXIgcmVzb2x2ZXMsIG5ldmVyIHRoZSB3b3ZlbiBsb2FkZXIgb3IgaXRzIGFuY2VzdG9ycyBhcyBzdWNoIChVcGRhdGVyQWNjZXNzLCAjNjU5LCAjNjY4LCAjODU1KTsgdGhlIGxvY2tzIG9wZW5pbmcgbGV0cyB0aGUgbGlicmFyeSByZWFkIGEgUmVlbnRyYW50TG9jayBvd25lciBhdCBhbmFseXNpcy4gSW4gZXZlcnkgbW9kZSwgYSB3b3ZlbiBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSBnZXRzIGEgcmVhZCBlZGdlIHRvIHRoZSBsaWJyYXJ5IGNvcHkgaXRzIGxvYWRlciByZXNvbHZlcyAoVXBkYXRlckFjY2Vzcy5sZXRSZWFkLCAjODYyKTogdGhlIEpWTSYjMzk7cyBvd24gZWRnZSBmb3IgYSB0cmFuc2Zvcm1lZCBjbGFzcyByZWFjaGVzIG9ubHkgdGhlIGFnZW50IGxvYWRlciYjMzk7cyB1bm5hbWVkIG1vZHVsZS4gVGhlIGxpYnJhcnkgcmVzb2x2ZXMgYW4gdXBkYXRlciBib3VuZCBiZWZvcmUgdGhlIGF0dGFjaCBieSByZWFkaW5nIHRoZSBKREsgaW1wbGVtZW50YXRpb24gZnJvbSB0aGF0IGNvcHkgKEpka1VwZGF0ZXJTaGFwZUNhbmFyeVRlc3QgcGlucyB0aGUgc2hhcGUgaXQgcmVhZHMpLCBhbmQgdGhlIG9wZW5pbmcgbXVzdCBmYWlsIHNpbGVudGx5IGxpa2UgdGhlIHJlc3Qgb2YgaW5zdGFsbC4gTm90aGluZyBtYXkgdGhyb3cgb3V0IG9mIHByZW1haW4g4oCUIGFuIGV4Y2VwdGlvbiB0aGVyZSBhYm9ydHMgSlZNIHN0YXJ0dXAsIHdoaWNoIGlzIHdoeSBpbnN0YWxsKCkgY2F0Y2hlcyBUaHJvd2FibGUgYW5kIHJlbGVhc2VzIHRoZSBnYXRlIHJhdGhlciB0aGFuIHByb3BhZ2F0aW5nLiBCb3RoIG1vZGVzIHVzZSBBZ2VudEJ1aWxkZXIuSW5pdGlhbGl6YXRpb25TdHJhdGVneS5Ob09wOiBubyB3ZWF2ZXIgbmVlZHMgYSBsb2FkZWQtdHlwZSBpbml0aWFsaXplciwgYW5kIEJ5dGUgQnVkZHkmIzM5O3MgZGVmYXVsdCBzZWxmLWluamVjdGlvbiBnYXZlIGV2ZXJ5IGNsYXNzIHdvdmVuIGF0IGxvYWQgYSAmbHQ7Y2xpbml0Jmd0OyB0aGF0IGxvYWRzIG5ldC5ieXRlYnVkZHkuZHluYW1pYy5OZXh1cyB0aHJvdWdoIHRoZSBzeXN0ZW0gY2xhc3MgbG9hZGVyLCB3aG9zZSBsb2NrIHZpcnR1YWwgdGhyZWFkcyBpbml0aWFsaXppbmcgY2xhc3NlcyBhdCBvbmNlIGNvbnRlbmQgb24gYW5kIHBpbiAoIzk4NCkuIFRoZSBQcmVtYWluLUNsYXNzIC8gQWdlbnQtQ2xhc3MgbWFuaWZlc3QgZW50cmllcyBsaXZlIGluIHRoaXMgbW9kdWxlJiMzOTtzIGphciwgd2hpY2ggaXMgd2h5IGF0dGFjaGluZyB1c2VzIC1qYXZhYWdlbnQ6YXN5bmMtdGVzdC1hZ2VudC5qYXIuPC9ub3RlPgogICAgPC9lbGVtZW50PgogIDwvY29yZV9lbGVtZW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8Y29yZV9lbGVtZW50cz4gYXJlIHdlbGwtdGVzdGVkIGNvcmUgY29tcG9uZW50cy4gTWFrZSBjaGFuZ2VzIHdpdGggZXh0cmVtZSBjYXV0aW9uIGFuZCB2ZXJpZnkgY29tcHJlaGVuc2l2ZSB0ZXN0IGNvdmVyYWdlIGJlZm9yZSBwcm9wb3NpbmcgbW9kaWZpY2F0aW9ucy48L3J1bGU+CiAgPGNvbnRyYWN0X3NpZ25hdHVyZXM+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkFnZW50T3B0aW9ucyI+CiAgICAgIDxyZWFzb24+VGhlIGNsYXNzIGlzIHBhY2thZ2UtcHJpdmF0ZSBidXQgdGhlIGFnZW50QXJncyBncmFtbWFyIGl0IHBhcnNlcyBpcyBwdWJsaWMgc3VyZmFjZTogdXNlcnMgdHlwZSBpdCBvbiB0aGUgLWphdmFhZ2VudDogY29tbWFuZCBsaW5lLiBLZXkgbmFtZXMgKGluY2x1ZGVzL2V4Y2x1ZGVzL2RlYnVnKSwgdGhlIGNvbW1hLW9yLXNlbWljb2xvbiBzZXBhcmF0b3IsIHRoZSBiYXJlLXRva2VuIGNvbnRpbnVhdGlvbiB0aGF0IGxldHMgb25lIGtleSBjYXJyeSBzZXZlcmFsIHZhbHVlcywgYW5kIGNhc2UtaW5zZW5zaXRpdmUga2V5IG1hdGNoaW5nIGFyZSBhbGwgcGFydCBvZiB0aGF0IGNvbnRyYWN0IOKAlCBjaGFuZ2luZyBhbnkgb2YgdGhlbSBicmVha3MgZXhpc3RpbmcgbGF1bmNoIHNjcmlwdHMgc2lsZW50bHkuIFBhcnNpbmcgbXVzdCBzdGF5IHRvdGFsOiBpdCBpcyBjYWxsZWQgZnJvbSBwcmVtYWluLCB3aGVyZSBhIHRocm93biBleGNlcHRpb24gYWJvcnRzIEpWTSBzdGFydHVwLCBzbyB1bmtub3duIGtleXMgYXJlIGlnbm9yZWQgYW5kIG1hbGZvcm1lZCBpbnB1dCBkZWdyYWRlcyB0byB0aGUgZGVmYXVsdCBpbnN0cnVtZW50LWV2ZXJ5dGhpbmcgYmVoYXZpb3VyIHJhdGhlciB0aGFuIGZhaWxpbmcuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkF0b21pY0ZpZWxkUmVnaXN0cnkiPgogICAgICA8cmVhc29uPlJlc29sdmVkIHJlZmxlY3RpdmVseSBzbyBhc3luYy10ZXN0LWFnZW50IGtlZXBzIGl0cyB6ZXJvLWRlcGVuZGVuY3kgYm91bmRhcnkgb24gYXN5bmMtdGVzdC1saWIsIHdoaWNoIEFyY2hpdGVjdHVyZVRlc3QgZW5mb3JjZXMgaW4gYm90aCBkaXJlY3Rpb25zLiBUaGUgbWV0aG9kIG5hbWUgYW5kIHNpZ25hdHVyZSBtdXN0IG1hdGNoIFRlbGVtZXRyeVJlZ2lzdHJ5LmF0b21pY2FsbHlNYW5hZ2VkKFN0cmluZykuIEV2ZXJ5IGZhaWx1cmUgcGF0aCBoZXJlIG11c3Qgc3RheSBzaWxlbnQ6IHRoaXMgb25seSBldmVyIHN1cHByZXNzZXMgZmluZGluZ3MsIHNvIGxvc2luZyBpdCBkZWdyYWRlcyBwcmVjaXNpb24gcmF0aGVyIHRoYW4gY29ycmVjdG5lc3MsIHdoaWxlIHRocm93aW5nIG91dCBvZiBhIGNsYXNzIHRyYW5zZm9ybWF0aW9uIHdvdWxkIGZhaWwgdGhlIHVzZXImIzM5O3MgdGVzdCBydW4uPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkNvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIiPgogICAgICA8cmVhc29uPlRoZSBob29rIGNsYXNzIG5hbWUgYW5kIHRoZSBtZXRob2QgbmFtZXMgaGVyZSBhcmUgdGhlIG90aGVyIGhhbGYgb2YgQWdlbnRDb2xsZWN0aW9uSG9va3MgYW5kIEFnZW50TG9ja0hvb2tzOiB0aGV5IGFyZSBtYXRjaGVkIGJ5IGVyYXNlZCBzaWduYXR1cmUgYXQgd2VhdmUgdGltZSwgc28gcmVuYW1pbmcgYSBob29rIG9yIGNoYW5naW5nIGEgcGFyYW1ldGVyIHR5cGUgYnJlYWtzIHdlYXZpbmcgd2l0aCBhIE5vU3VjaE1ldGhvZEVycm9yIGluc2lkZSB1c2VyIGNvZGUgcmF0aGVyIHRoYW4gYXQgY29tcGlsZSB0aW1lLiBFYWNoIHN1YnN0aXR1dGlvbiBtdXN0IGNvbnN1bWUgZXhhY3RseSB0aGUgc3RhY2sgaXRzIG9yaWdpbmFsIGludm9jYXRpb24gY29uc3VtZWQgLSBzdGFjay1zaGFwZS1uZXV0cmFsIGFuZCBtZW1iZXItZnJlZSBpcyB3aGF0IGtlZXBzIHJldHJhbnNmb3JtYXRpb24gc2FmZSB1bmRlciBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCkuIFRoZSB2aXNpdG9yIGNoYW5nZXMgZXhhY3RseSBvbmUga2luZCBvZiBpbnZva2VkeW5hbWljOiBhIExhbWJkYU1ldGFmYWN0b3J5IG1ldGFmYWN0b3J5IG9yIG5vbi1zZXJpYWxpemFibGUgYWx0TWV0YWZhY3Rvcnkgd2hvc2UgaW1wbGVtZW50YXRpb24gaGFuZGxlIG1hdGNoZXMgYSB0YWJsZSBlbnRyeSBpcyBwb2ludGVkIGF0IHRoYXQgZW50cnkmIzM5O3MgaG9vaywgc28gYSBtZXRob2QgcmVmZXJlbmNlIHN1Y2ggYXMgYnVpbGRlcjo6YXBwZW5kIGlzIG9ic2VydmVkICgjNTUwKS4gRXZlcnkgb3RoZXIgYm9vdHN0cmFwLCBPYmplY3RNZXRob2RzIGZvciByZWNvcmRzIGFib3ZlIGFsbCwgbXVzdCBwYXNzIHRocm91Z2ggYXMgdGhlIHNhbWUgYXJndW1lbnQgYXJyYXksIHJlYWQgb25seSB0aHJvdWdoIEFTTSYjMzk7cyBIYW5kbGU6IHBhcnNpbmcgYm9vdHN0cmFwIGNvbnN0YW50cyBpcyB3aGF0IG1hZGUgZXZlcnkgSmF2YSByZWNvcmQgZmFpbCB0byBpbnN0cnVtZW50IHdoZW4gdGhpcyB3ZW50IHRocm91Z2ggTWVtYmVyU3Vic3RpdHV0aW9uLCBhbmQgYSByZXdyaXR0ZW4gc2VyaWFsaXphYmxlIGxhbWJkYSB3b3VsZCBmYWlsIHRvIGRlc2VyaWFsaXplLiBDb2xsZWN0aW9uIHdlYXZpbmcgaXMgb3B0LWluIChjb2xsZWN0aW9ucz10cnVlKSBiZWNhdXNlIGl0IGluc3RydW1lbnRzIGV2ZXJ5IGxpc3RlZCBjYWxsIGluIGV2ZXJ5IG1hdGNoZWQgY2xhc3MuIFRoZSBvbmUtaW5zdHJ1Y3Rpb24gbG9va2FoZWFkIGJlaGluZCB3aGVuUmVzdWx0RGlzY2FyZGVkIGlzIGEgZmxhZyBtZWFuaW5nIHRoZSBpbnN0cnVjdGlvbiBqdXN0IGVtaXR0ZWQgd2FzIGEgc3Vic3RpdHV0ZWQgY2FsbCB3aG9zZSByZXN1bHQgbWF5IGJlIGRpc2NhcmRlZDogdmlzaXRJbnNuKFBPUCkgaXMgaXRzIG9ubHkgY29uc3VtZXIgYW5kIGV2ZXJ5IG90aGVyIHZpc2l0IG1ldGhvZCBtdXN0IGNsZWFyIGl0LCBiZWNhdXNlIGEgc3RhbGUgZmxhZyB3b3VsZCB0dXJuIGFuIHVucmVsYXRlZCBQT1AgaW50byBhIGNhbGwgd2hvc2UgcGFyYW1ldGVyIGRvZXMgbm90IG1hdGNoIHRoZSB2YWx1ZSBvbiB0aGUgc3RhY2ssIHdoaWNoIGlzIGEgVmVyaWZ5RXJyb3IgaW4gdGhlIHVzZXImIzM5O3MgY2xhc3MgYXQgbG9hZCB0aW1lLiBTdWJzdGl0dXRpbmdWaXNpdG9yQ2xlYXJzTG9va2FoZWFkRXZlcnl3aGVyZVRlc3QgZW51bWVyYXRlcyBNZXRob2RWaXNpdG9yIHRvIGtlZXAgdGhhdCBvdmVycmlkZSBsaXN0IGNvbXBsZXRlLiBJbnNpZGUgYSBzeW5jaHJvbml6ZWQgbWV0aG9kLCBhbiBlbnRyeSB3aXRoIGEgc3luY2hyb25pemVkIHZhcmlhbnQgKHRoZSBzbGVlcHMsIGFuZCB0aGUgcXVldWUgb2ZmZXJzIGFuZCB0YWtlcywgIzc5NikgZmlyc3QgbG9hZHMgdGhlIG1ldGhvZCYjMzk7cyBtb25pdG9yLCBBTE9BRCAwIG9yIGFuIExEQyBvZiB0aGUgY2xhc3MgZm9yIGEgc3RhdGljIG1ldGhvZCwgd2hpY2ggdGhlIHZhcmlhbnQgY29uc3VtZXMgYXMgaXRzIGxhc3QgcGFyYW1ldGVyOiBvbmUgbW9yZSB2YWx1ZSBhbmQgbm8gYnJhbmNoLCBzbyBvbmx5IG1heFN0YWNrIGdyb3dzLCBhbmQgdGhlIHN1YnN0aXR1dGlvbiB3cmFwcGVyIGFza3MgZm9yIENPTVBVVEVfTUFYUyBpdHNlbGYuIEEgcXVldWUgb2ZmZXIgb3IgdGFrZSBpbiBhbnkgb3RoZXIgaW5zdGFuY2UgbWV0aG9kIGxvYWRzIHRoaXMgdGhlIHNhbWUgd2F5IGZvciBpdHMgaG9vayB0byBwcm9iZSAoIzc1MSksIGV4Y2VwdCBpbiBhIGNvbnN0cnVjdG9yLCB3aGVyZSB0aGlzIG1heSBiZSB1bmluaXRpYWxpc2VkIGFuZCB3b3VsZCBub3QgdmVyaWZ5LCBhbmQgYWZ0ZXIgYSBzdG9yZSB0byBsb2NhbCAwLiBUaGUgb25lIGluc3RydWN0aW9uIHRoZSB2aXNpdG9yIGluc2VydHMgb3V0c2lkZSBhIHN1YnN0aXR1dGlvbiBpcyB0aGUgbG9vcCBiYWNrLWVkZ2UgY2FsbCBpbiBmcm9udCBvZiBhIGp1bXAgdGhhdCBjb21lcyBiYWNrIG92ZXIgYSB3b3ZlbiBPYmplY3Qud2FpdCAoIzY5NCk6IGl0IG11c3Qgc3RheSBhIHN0YXRpYyAoKVYgY2FsbCwgYmVjYXVzZSB0aGUganVtcCYjMzk7cyBvcGVyYW5kcyBhcmUgYWxyZWFkeSBvbiB0aGUgc3RhY2sgYmVuZWF0aCBpdCBhbmQgYW55dGhpbmcgdGhhdCB0b29rIG9yIGxlZnQgYSB2YWx1ZSwgb3IgYWRkZWQgYSBicmFuY2gsIHdvdWxkIG5lZWQgdGhlIGZyYW1lcyBDT01QVVRFX01BWFMgZG9lcyBub3QgcmVjb21wdXRlLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogIDwvY29udHJhY3Rfc2lnbmF0dXJlcz4KCjxydWxlPllvdSBtYXkgcmVmYWN0b3IgdGhlIGludGVybmFsIGxvZ2ljIG9mIGVsZW1lbnRzIGxpc3RlZCBpbiA8Y29udHJhY3Rfc2lnbmF0dXJlcz4sIGJ1dCB5b3UgTVVTVCBOT1QgY2hhbmdlIHRoZWlyIHB1YmxpYyBzaWduYXR1cmVzOiBtZXRob2QgbmFtZXMsIHBhcmFtZXRlciB0eXBlcywgcGFyYW1ldGVyIG9yZGVyLCByZXR1cm4gdHlwZXMsIG9yIGNoZWNrZWQgZXhjZXB0aW9ucy48L3J1bGU+CjwvcHJvamVjdF9ndWFyZHJhaWxzPgoKPHJ1bGU+TmV2ZXIgcHJvcG9zZSBlZGl0cyB0byBmaWxlcyBsaXN0ZWQgaW4gPGxvY2tlZF9maWxlcz4uPC9ydWxlPgo= -gemini_md=IyBHRU1JTkkgQUkgSU5TVFJVQ1RJT05TCiMgR2VuZXJhdGVkIGJ5IFZpYmVUYWdzIHwgaHR0cHM6Ly9naXRodWIuY29tL1BJc2JlcmcvdmliZXRhZ3MKCiMjIENPUkUgRlVOQ1RJT05BTElUWSAoRVhUUkVNRSBDQVVUSU9OKQpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbjoKCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYWdlbnQuQXN5bmNUZXN0QWdlbnRgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IFRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvcidzIHN1cGVyY2xhc3MgY2FsbCAoIzczNykuIENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgY2FsbCB0aGF0IGNvbnN1bWVzIGFuZCByZXR1cm5zIHRoZSBvcmRlciBhcmd1bWVudCBiZWZvcmUgYSBMaW5rZWRIYXNoTWFwKGludCwgZmxvYXQsIGJvb2xlYW4pIGNvbnN0cnVjdG9yIGNhbGwgYW5kIGEgRFVQIG9yIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgaXQgKCM4MDcpLCBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciBhIG5ldyBDb21wbGV0YWJsZUZ1dHVyZSgpIGNvbnN0cnVjdG9yIGNhbGwgKCMxMDU0KSwgYW5kIGFuIEFMT0FEIDAsIGFuIExEQyBvZiB0aGUgY2xhc3MgbmFtZSBhbmQgYSBjYWxsIGJlZm9yZSBlYWNoIFJFVFVSTiBvZiBhIGNvbnN0cnVjdG9yIGFuZCBhZnRlciBhIHRoaXMoLi4uKSBkZWxlZ2F0aW9uICgjNzkxKTsgaXQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gSW50ZXJydXB0SGFuZGxlcldlYXZlciBpbnNlcnRzIGFuIExEQyBvZiB0aGUgbG9jYXRpb25zIG9mIGEgbWV0aG9kJ3MgSW50ZXJydXB0ZWRFeGNlcHRpb24gaGFuZGxlcnMgdGhhdCBuZWl0aGVyIHJldGhyb3cgbm9yIHJlc3RvcmUgdGhlIGZsYWcsIGFuZCBhIGNhbGwsIGJlZm9yZSB0aGUgZmlyc3QgaW5zdHJ1Y3Rpb24gb2YgYSBtZXRob2QgdGhhdCBkZWNsYXJlcyBvbmUsIGFuZCBsZWF2ZXMgYWxvbmUgYSBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSB0aGF0IGNhbm5vdCByZWFkIHRoZSBsaWJyYXJ5LiBQZXJzaXN0ZW5jZUhhbmRsZVdlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBjYWxsIHdob3NlIG93bmVyIGlzIGEgSlBBIEVudGl0eU1hbmFnZXIgb3IgSGliZXJuYXRlIFNlc3Npb24gYnkgbmFtZSwgYSBzdGFjay1uZXV0cmFsIGNvcHkgb2YgdGhlIHJlY2VpdmVyIChEVVA7IFNXQVAsIERVUF9YMTsgb3IgRFVQMl9YMSwgUE9QMiwgRFVQX1gyIGZvciB6ZXJvLCBvbmUgb3IgdHdvIG9uZS1zbG90IGFyZ3VtZW50cykgYW5kIGEgY2FsbCwgYW5kIGxlYXZlcyBjYWxscyB3aXRoIG1vcmUgb3Igd2lkZXIgYXJndW1lbnRzIGFsb25lICgjOTkyKS4gUnVuQmxvY2tpbmdXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgc3RhdGljIGNhbGwgb2Yga290bGlueC5jb3JvdXRpbmVzLkJ1aWxkZXJzS3QucnVuQmxvY2tpbmdLLCBydW5CbG9ja2luZyBvciB0aGVpciAkZGVmYXVsdCBicmlkZ2VzIGJ5IG5hbWUsIG9uZSBjYWxsIG9mIGEgKClWIGhvb2sgdGhhdCB0YWtlcyBhbmQgbGVhdmVzIG5vdGhpbmcsIGluIGV2ZXJ5IHdvdmVuIGNsYXNzIG91dHNpZGUga290bGlueC5jb3JvdXRpbmVzICgjMTAwNykuIFNvIGZyYW1lcyBzdGF5IHZhbGlkIGFuZCBvbmx5IG1heFN0YWNrIGdyb3dzIChDT01QVVRFX01BWFMsIG5ldmVyIENPTVBVVEVfRlJBTUVTLCB3aGljaCB3b3VsZCBsb2FkIGNsYXNzZXMgZnJvbSBpbnNpZGUgdGhlIGFnZW50KS4gSW4gZXZlcnkgbW9kZSwgaW5zdGFsbCBhbmQgdGhlIHRyYW5zZm9ybWVyIG9wZW4gamF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MsIHdpdGggZmllbGRzPXRydWUgYWxzbyBqYXZhLnV0aWwuY29uY3VycmVudC5hdG9taWMsIGFuZCB3aXRoIGNvbGxlY3Rpb25zPXRydWUgYWxzbyBqYXZhLnV0aWwgYW5kIGphdmEuaW8gKGEgc3luY2hyb25pemVkIHdyYXBwZXIncyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXIncyBzaW5rLCAjOTk0KSwgdG8gb25lIG1vZHVsZSBwZXIgd292ZW4gbG9hZGVyIGFuZCB0byBub3RoaW5nIGVsc2U6IHRoZSBtb2R1bGUgb2YgdGhlIFRlbGVtZXRyeVJlZ2lzdHJ5IGNvcHkgdGhhdCBsb2FkZXIgcmVzb2x2ZXMsIG5ldmVyIHRoZSB3b3ZlbiBsb2FkZXIgb3IgaXRzIGFuY2VzdG9ycyBhcyBzdWNoIChVcGRhdGVyQWNjZXNzLCAjNjU5LCAjNjY4LCAjODU1KTsgdGhlIGxvY2tzIG9wZW5pbmcgbGV0cyB0aGUgbGlicmFyeSByZWFkIGEgUmVlbnRyYW50TG9jayBvd25lciBhdCBhbmFseXNpcy4gSW4gZXZlcnkgbW9kZSwgYSB3b3ZlbiBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSBnZXRzIGEgcmVhZCBlZGdlIHRvIHRoZSBsaWJyYXJ5IGNvcHkgaXRzIGxvYWRlciByZXNvbHZlcyAoVXBkYXRlckFjY2Vzcy5sZXRSZWFkLCAjODYyKTogdGhlIEpWTSdzIG93biBlZGdlIGZvciBhIHRyYW5zZm9ybWVkIGNsYXNzIHJlYWNoZXMgb25seSB0aGUgYWdlbnQgbG9hZGVyJ3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5J3MgZGVmYXVsdCBzZWxmLWluamVjdGlvbiBnYXZlIGV2ZXJ5IGNsYXNzIHdvdmVuIGF0IGxvYWQgYSA8Y2xpbml0PiB0aGF0IGxvYWRzIG5ldC5ieXRlYnVkZHkuZHluYW1pYy5OZXh1cyB0aHJvdWdoIHRoZSBzeXN0ZW0gY2xhc3MgbG9hZGVyLCB3aG9zZSBsb2NrIHZpcnR1YWwgdGhyZWFkcyBpbml0aWFsaXppbmcgY2xhc3NlcyBhdCBvbmNlIGNvbnRlbmQgb24gYW5kIHBpbiAoIzk4NCkuIFRoZSBQcmVtYWluLUNsYXNzIC8gQWdlbnQtQ2xhc3MgbWFuaWZlc3QgZW50cmllcyBsaXZlIGluIHRoaXMgbW9kdWxlJ3MgamFyLCB3aGljaCBpcyB3aHkgYXR0YWNoaW5nIHVzZXMgLWphdmFhZ2VudDphc3luYy10ZXN0LWFnZW50Lmphci4KCiMjIFNjb3BlZCBSdWxlcyBJbmRleApEZXRhaWxlZCBwZXItZWxlbWVudCBndWFyZHJhaWxzIGxpdmUgaW4gc2NvcGVkIHJ1bGUgZmlsZXMgdGhhdCBHZW1pbmkgQ0xJIGRvZXMgbm90IGxvYWQgb24gaXRzIG93bi4gQSBsaW5lIGBhLmJgOiBgQ2AsIGBEYCBuYW1lcyBhLmIuQyBhbmQgYS5iLkQuIFVubGVzcyBhbiBlbnRyeSBjYXJyaWVzIGFuIGV4cGxpY2l0IHBhdGgsIGl0cyBmaWxlIGlzIC5nZW1pbmkvcnVsZXMve3BhdGgsIGV2ZXJ5IG5vbi1hbHBoYW51bWVyaWMgY2hhcmFjdGVyIHJlcGxhY2VkIGJ5ICctJ30ubWQuIEJlZm9yZSBtb2RpZnlpbmcgYW4gZWxlbWVudCBsaXN0ZWQgYmVsb3csIG9wZW4gaXRzIGZpbGUgd2l0aCByZWFkX2ZpbGUgYW5kIGFwcGx5IHRoZSBndWFyZHJhaWxzIHRoZXJlOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5hZ2VudGA6IGBBZ2VudE9wdGlvbnNgLCBgQXRvbWljRmllbGRSZWdpc3RyeWAsIGBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24ubWRgCg== -~mod~claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxjb3JlX2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5hZ2VudC5Bc3luY1Rlc3RBZ2VudCI+CiAgICAgIDxzZW5zaXRpdml0eT5Dcml0aWNhbDwvc2Vuc2l0aXZpdHk+CiAgICAgIDxub3RlPlRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvciYjMzk7cyBzdXBlcmNsYXNzIGNhbGwgKCM3MzcpLiBDb25zdHJ1Y3Rpb25XZWF2ZXIgaW5zZXJ0cyBhIGNhbGwgdGhhdCBjb25zdW1lcyBhbmQgcmV0dXJucyB0aGUgb3JkZXIgYXJndW1lbnQgYmVmb3JlIGEgTGlua2VkSGFzaE1hcChpbnQsIGZsb2F0LCBib29sZWFuKSBjb25zdHJ1Y3RvciBjYWxsIGFuZCBhIERVUCBvciBhbiBBTE9BRCAwIHBsdXMgYSBjYWxsIGFmdGVyIGl0ICgjODA3KSwgYSBEVVAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBuZXcgQ29tcGxldGFibGVGdXR1cmUoKSBjb25zdHJ1Y3RvciBjYWxsICgjMTA1NCksIGFuZCBhbiBBTE9BRCAwLCBhbiBMREMgb2YgdGhlIGNsYXNzIG5hbWUgYW5kIGEgY2FsbCBiZWZvcmUgZWFjaCBSRVRVUk4gb2YgYSBjb25zdHJ1Y3RvciBhbmQgYWZ0ZXIgYSB0aGlzKC4uLikgZGVsZWdhdGlvbiAoIzc5MSk7IGl0IGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIEludGVycnVwdEhhbmRsZXJXZWF2ZXIgaW5zZXJ0cyBhbiBMREMgb2YgdGhlIGxvY2F0aW9ucyBvZiBhIG1ldGhvZCYjMzk7cyBJbnRlcnJ1cHRlZEV4Y2VwdGlvbiBoYW5kbGVycyB0aGF0IG5laXRoZXIgcmV0aHJvdyBub3IgcmVzdG9yZSB0aGUgZmxhZywgYW5kIGEgY2FsbCwgYmVmb3JlIHRoZSBmaXJzdCBpbnN0cnVjdGlvbiBvZiBhIG1ldGhvZCB0aGF0IGRlY2xhcmVzIG9uZSwgYW5kIGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIFBlcnNpc3RlbmNlSGFuZGxlV2VhdmVyIGluc2VydHMsIGJlZm9yZSBhIGNhbGwgd2hvc2Ugb3duZXIgaXMgYSBKUEEgRW50aXR5TWFuYWdlciBvciBIaWJlcm5hdGUgU2Vzc2lvbiBieSBuYW1lLCBhIHN0YWNrLW5ldXRyYWwgY29weSBvZiB0aGUgcmVjZWl2ZXIgKERVUDsgU1dBUCwgRFVQX1gxOyBvciBEVVAyX1gxLCBQT1AyLCBEVVBfWDIgZm9yIHplcm8sIG9uZSBvciB0d28gb25lLXNsb3QgYXJndW1lbnRzKSBhbmQgYSBjYWxsLCBhbmQgbGVhdmVzIGNhbGxzIHdpdGggbW9yZSBvciB3aWRlciBhcmd1bWVudHMgYWxvbmUgKCM5OTIpLiBSdW5CbG9ja2luZ1dlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBzdGF0aWMgY2FsbCBvZiBrb3RsaW54LmNvcm91dGluZXMuQnVpbGRlcnNLdC5ydW5CbG9ja2luZ0ssIHJ1bkJsb2NraW5nIG9yIHRoZWlyICRkZWZhdWx0IGJyaWRnZXMgYnkgbmFtZSwgb25lIGNhbGwgb2YgYSAoKVYgaG9vayB0aGF0IHRha2VzIGFuZCBsZWF2ZXMgbm90aGluZywgaW4gZXZlcnkgd292ZW4gY2xhc3Mgb3V0c2lkZSBrb3RsaW54LmNvcm91dGluZXMgKCMxMDA3KS4gU28gZnJhbWVzIHN0YXkgdmFsaWQgYW5kIG9ubHkgbWF4U3RhY2sgZ3Jvd3MgKENPTVBVVEVfTUFYUywgbmV2ZXIgQ09NUFVURV9GUkFNRVMsIHdoaWNoIHdvdWxkIGxvYWQgY2xhc3NlcyBmcm9tIGluc2lkZSB0aGUgYWdlbnQpLiBJbiBldmVyeSBtb2RlLCBpbnN0YWxsIGFuZCB0aGUgdHJhbnNmb3JtZXIgb3BlbiBqYXZhLnV0aWwuY29uY3VycmVudC5sb2Nrcywgd2l0aCBmaWVsZHM9dHJ1ZSBhbHNvIGphdmEudXRpbC5jb25jdXJyZW50LmF0b21pYywgYW5kIHdpdGggY29sbGVjdGlvbnM9dHJ1ZSBhbHNvIGphdmEudXRpbCBhbmQgamF2YS5pbyAoYSBzeW5jaHJvbml6ZWQgd3JhcHBlciYjMzk7cyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXImIzM5O3Mgc2luaywgIzk5NCksIHRvIG9uZSBtb2R1bGUgcGVyIHdvdmVuIGxvYWRlciBhbmQgdG8gbm90aGluZyBlbHNlOiB0aGUgbW9kdWxlIG9mIHRoZSBUZWxlbWV0cnlSZWdpc3RyeSBjb3B5IHRoYXQgbG9hZGVyIHJlc29sdmVzLCBuZXZlciB0aGUgd292ZW4gbG9hZGVyIG9yIGl0cyBhbmNlc3RvcnMgYXMgc3VjaCAoVXBkYXRlckFjY2VzcywgIzY1OSwgIzY2OCwgIzg1NSk7IHRoZSBsb2NrcyBvcGVuaW5nIGxldHMgdGhlIGxpYnJhcnkgcmVhZCBhIFJlZW50cmFudExvY2sgb3duZXIgYXQgYW5hbHlzaXMuIEluIGV2ZXJ5IG1vZGUsIGEgd292ZW4gY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgZ2V0cyBhIHJlYWQgZWRnZSB0byB0aGUgbGlicmFyeSBjb3B5IGl0cyBsb2FkZXIgcmVzb2x2ZXMgKFVwZGF0ZXJBY2Nlc3MubGV0UmVhZCwgIzg2Mik6IHRoZSBKVk0mIzM5O3Mgb3duIGVkZ2UgZm9yIGEgdHJhbnNmb3JtZWQgY2xhc3MgcmVhY2hlcyBvbmx5IHRoZSBhZ2VudCBsb2FkZXImIzM5O3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5JiMzOTtzIGRlZmF1bHQgc2VsZi1pbmplY3Rpb24gZ2F2ZSBldmVyeSBjbGFzcyB3b3ZlbiBhdCBsb2FkIGEgJmx0O2NsaW5pdCZndDsgdGhhdCBsb2FkcyBuZXQuYnl0ZWJ1ZGR5LmR5bmFtaWMuTmV4dXMgdGhyb3VnaCB0aGUgc3lzdGVtIGNsYXNzIGxvYWRlciwgd2hvc2UgbG9jayB2aXJ0dWFsIHRocmVhZHMgaW5pdGlhbGl6aW5nIGNsYXNzZXMgYXQgb25jZSBjb250ZW5kIG9uIGFuZCBwaW4gKCM5ODQpLiBUaGUgUHJlbWFpbi1DbGFzcyAvIEFnZW50LUNsYXNzIG1hbmlmZXN0IGVudHJpZXMgbGl2ZSBpbiB0aGlzIG1vZHVsZSYjMzk7cyBqYXIsIHdoaWNoIGlzIHdoeSBhdHRhY2hpbmcgdXNlcyAtamF2YWFnZW50OmFzeW5jLXRlc3QtYWdlbnQuamFyLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICA8L2NvcmVfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBsaXN0ZWQgaW4gPGNvcmVfZWxlbWVudHM+IGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbiBhbmQgdmVyaWZ5IGNvbXByZWhlbnNpdmUgdGVzdCBjb3ZlcmFnZSBiZWZvcmUgcHJvcG9zaW5nIG1vZGlmaWNhdGlvbnMuPC9ydWxlPgogIDxzY29wZWRfcnVsZXM+CiAgICA8bm90ZT5EZXRhaWxlZCBwZXItZWxlbWVudCBndWFyZHJhaWxzIGZvciB0aGUgZWxlbWVudHMgYmVsb3cgbGl2ZSBpbiBzY29wZWQgcnVsZSBmaWxlcyB0aGF0IGxvYWQgYXV0b21hdGljYWxseSB3aGVuIHRoZSBtYXRjaGluZyBzb3VyY2UgZmlsZSBpcyBvcGVuZWQuIEFuIGVsZW1lbnRzIGVudHJ5IGxpc3RzIG5hbWVzIHVuZGVyIGEgc2hhcmVkIHByZWZpeDogaW49ImEuYiIgbGlzdGluZyBDLCBEIG1lYW5zIGEuYi5DIGFuZCBhLmIuRC4gVW5sZXNzIGFuIGVudHJ5IGNhcnJpZXMgYW4gZXhwbGljaXQgcGF0aCwgaXRzIGZpbGUgaXMgLmNsYXVkZS9ydWxlcy97cGF0aCwgZXZlcnkgbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXIgcmVwbGFjZWQgYnkgJiMzOTstJiMzOTt9Lm1kLiBDb25zdWx0IHRoZSBmaWxlIGJlZm9yZSBtb2RpZnlpbmcgYW4gZWxlbWVudC48L25vdGU+CiAgICA8ZWxlbWVudHMgaW49InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYWdlbnQiPkFnZW50T3B0aW9ucywgQXRvbWljRmllbGRSZWdpc3RyeSwgQ29sbGVjdGlvbkFjY2Vzc1dlYXZlcjwvZWxlbWVudHM+CiAgPC9zY29wZWRfcnVsZXM+Cgo8cnVsZT5XaGVuIHlvdSB3b3JrIG9uIGFueSBlbGVtZW50IGxpc3RlZCBpbiA8c2NvcGVkX3J1bGVzPiwgb3BlbiBpdHMgcmVmZXJlbmNlZCBydWxlIGZpbGUgYW5kIGFwcGx5IHRoZSBndWFyZHJhaWxzIHRoZXJlLiBUaGUgcnVsZSBmaWxlcyBhcmUgdGhlIGF1dGhvcml0YXRpdmUgc291cmNlIGZvciB0aG9zZSBlbGVtZW50cy48L3J1bGU+CjwvcHJvamVjdF9ndWFyZHJhaWxzPgo= -~idx~claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxjb3JlX2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5hZ2VudC5Bc3luY1Rlc3RBZ2VudCI+CiAgICAgIDxzZW5zaXRpdml0eT5Dcml0aWNhbDwvc2Vuc2l0aXZpdHk+CiAgICAgIDxub3RlPlRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvciYjMzk7cyBzdXBlcmNsYXNzIGNhbGwgKCM3MzcpLiBDb25zdHJ1Y3Rpb25XZWF2ZXIgaW5zZXJ0cyBhIGNhbGwgdGhhdCBjb25zdW1lcyBhbmQgcmV0dXJucyB0aGUgb3JkZXIgYXJndW1lbnQgYmVmb3JlIGEgTGlua2VkSGFzaE1hcChpbnQsIGZsb2F0LCBib29sZWFuKSBjb25zdHJ1Y3RvciBjYWxsIGFuZCBhIERVUCBvciBhbiBBTE9BRCAwIHBsdXMgYSBjYWxsIGFmdGVyIGl0ICgjODA3KSwgYSBEVVAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBuZXcgQ29tcGxldGFibGVGdXR1cmUoKSBjb25zdHJ1Y3RvciBjYWxsICgjMTA1NCksIGFuZCBhbiBBTE9BRCAwLCBhbiBMREMgb2YgdGhlIGNsYXNzIG5hbWUgYW5kIGEgY2FsbCBiZWZvcmUgZWFjaCBSRVRVUk4gb2YgYSBjb25zdHJ1Y3RvciBhbmQgYWZ0ZXIgYSB0aGlzKC4uLikgZGVsZWdhdGlvbiAoIzc5MSk7IGl0IGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIEludGVycnVwdEhhbmRsZXJXZWF2ZXIgaW5zZXJ0cyBhbiBMREMgb2YgdGhlIGxvY2F0aW9ucyBvZiBhIG1ldGhvZCYjMzk7cyBJbnRlcnJ1cHRlZEV4Y2VwdGlvbiBoYW5kbGVycyB0aGF0IG5laXRoZXIgcmV0aHJvdyBub3IgcmVzdG9yZSB0aGUgZmxhZywgYW5kIGEgY2FsbCwgYmVmb3JlIHRoZSBmaXJzdCBpbnN0cnVjdGlvbiBvZiBhIG1ldGhvZCB0aGF0IGRlY2xhcmVzIG9uZSwgYW5kIGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIFBlcnNpc3RlbmNlSGFuZGxlV2VhdmVyIGluc2VydHMsIGJlZm9yZSBhIGNhbGwgd2hvc2Ugb3duZXIgaXMgYSBKUEEgRW50aXR5TWFuYWdlciBvciBIaWJlcm5hdGUgU2Vzc2lvbiBieSBuYW1lLCBhIHN0YWNrLW5ldXRyYWwgY29weSBvZiB0aGUgcmVjZWl2ZXIgKERVUDsgU1dBUCwgRFVQX1gxOyBvciBEVVAyX1gxLCBQT1AyLCBEVVBfWDIgZm9yIHplcm8sIG9uZSBvciB0d28gb25lLXNsb3QgYXJndW1lbnRzKSBhbmQgYSBjYWxsLCBhbmQgbGVhdmVzIGNhbGxzIHdpdGggbW9yZSBvciB3aWRlciBhcmd1bWVudHMgYWxvbmUgKCM5OTIpLiBSdW5CbG9ja2luZ1dlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBzdGF0aWMgY2FsbCBvZiBrb3RsaW54LmNvcm91dGluZXMuQnVpbGRlcnNLdC5ydW5CbG9ja2luZ0ssIHJ1bkJsb2NraW5nIG9yIHRoZWlyICRkZWZhdWx0IGJyaWRnZXMgYnkgbmFtZSwgb25lIGNhbGwgb2YgYSAoKVYgaG9vayB0aGF0IHRha2VzIGFuZCBsZWF2ZXMgbm90aGluZywgaW4gZXZlcnkgd292ZW4gY2xhc3Mgb3V0c2lkZSBrb3RsaW54LmNvcm91dGluZXMgKCMxMDA3KS4gU28gZnJhbWVzIHN0YXkgdmFsaWQgYW5kIG9ubHkgbWF4U3RhY2sgZ3Jvd3MgKENPTVBVVEVfTUFYUywgbmV2ZXIgQ09NUFVURV9GUkFNRVMsIHdoaWNoIHdvdWxkIGxvYWQgY2xhc3NlcyBmcm9tIGluc2lkZSB0aGUgYWdlbnQpLiBJbiBldmVyeSBtb2RlLCBpbnN0YWxsIGFuZCB0aGUgdHJhbnNmb3JtZXIgb3BlbiBqYXZhLnV0aWwuY29uY3VycmVudC5sb2Nrcywgd2l0aCBmaWVsZHM9dHJ1ZSBhbHNvIGphdmEudXRpbC5jb25jdXJyZW50LmF0b21pYywgYW5kIHdpdGggY29sbGVjdGlvbnM9dHJ1ZSBhbHNvIGphdmEudXRpbCBhbmQgamF2YS5pbyAoYSBzeW5jaHJvbml6ZWQgd3JhcHBlciYjMzk7cyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXImIzM5O3Mgc2luaywgIzk5NCksIHRvIG9uZSBtb2R1bGUgcGVyIHdvdmVuIGxvYWRlciBhbmQgdG8gbm90aGluZyBlbHNlOiB0aGUgbW9kdWxlIG9mIHRoZSBUZWxlbWV0cnlSZWdpc3RyeSBjb3B5IHRoYXQgbG9hZGVyIHJlc29sdmVzLCBuZXZlciB0aGUgd292ZW4gbG9hZGVyIG9yIGl0cyBhbmNlc3RvcnMgYXMgc3VjaCAoVXBkYXRlckFjY2VzcywgIzY1OSwgIzY2OCwgIzg1NSk7IHRoZSBsb2NrcyBvcGVuaW5nIGxldHMgdGhlIGxpYnJhcnkgcmVhZCBhIFJlZW50cmFudExvY2sgb3duZXIgYXQgYW5hbHlzaXMuIEluIGV2ZXJ5IG1vZGUsIGEgd292ZW4gY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgZ2V0cyBhIHJlYWQgZWRnZSB0byB0aGUgbGlicmFyeSBjb3B5IGl0cyBsb2FkZXIgcmVzb2x2ZXMgKFVwZGF0ZXJBY2Nlc3MubGV0UmVhZCwgIzg2Mik6IHRoZSBKVk0mIzM5O3Mgb3duIGVkZ2UgZm9yIGEgdHJhbnNmb3JtZWQgY2xhc3MgcmVhY2hlcyBvbmx5IHRoZSBhZ2VudCBsb2FkZXImIzM5O3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5JiMzOTtzIGRlZmF1bHQgc2VsZi1pbmplY3Rpb24gZ2F2ZSBldmVyeSBjbGFzcyB3b3ZlbiBhdCBsb2FkIGEgJmx0O2NsaW5pdCZndDsgdGhhdCBsb2FkcyBuZXQuYnl0ZWJ1ZGR5LmR5bmFtaWMuTmV4dXMgdGhyb3VnaCB0aGUgc3lzdGVtIGNsYXNzIGxvYWRlciwgd2hvc2UgbG9jayB2aXJ0dWFsIHRocmVhZHMgaW5pdGlhbGl6aW5nIGNsYXNzZXMgYXQgb25jZSBjb250ZW5kIG9uIGFuZCBwaW4gKCM5ODQpLiBUaGUgUHJlbWFpbi1DbGFzcyAvIEFnZW50LUNsYXNzIG1hbmlmZXN0IGVudHJpZXMgbGl2ZSBpbiB0aGlzIG1vZHVsZSYjMzk7cyBqYXIsIHdoaWNoIGlzIHdoeSBhdHRhY2hpbmcgdXNlcyAtamF2YWFnZW50OmFzeW5jLXRlc3QtYWdlbnQuamFyLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICA8L2NvcmVfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBsaXN0ZWQgaW4gPGNvcmVfZWxlbWVudHM+IGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbiBhbmQgdmVyaWZ5IGNvbXByZWhlbnNpdmUgdGVzdCBjb3ZlcmFnZSBiZWZvcmUgcHJvcG9zaW5nIG1vZGlmaWNhdGlvbnMuPC9ydWxlPgo8L3Byb2plY3RfZ3VhcmRyYWlscz4K -~idx~gemini_md=IyBHRU1JTkkgQUkgSU5TVFJVQ1RJT05TCiMgR2VuZXJhdGVkIGJ5IFZpYmVUYWdzIHwgaHR0cHM6Ly9naXRodWIuY29tL1BJc2JlcmcvdmliZXRhZ3MKCiMjIENPUkUgRlVOQ1RJT05BTElUWSAoRVhUUkVNRSBDQVVUSU9OKQpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbjoKCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYWdlbnQuQXN5bmNUZXN0QWdlbnRgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IFRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvcidzIHN1cGVyY2xhc3MgY2FsbCAoIzczNykuIENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgY2FsbCB0aGF0IGNvbnN1bWVzIGFuZCByZXR1cm5zIHRoZSBvcmRlciBhcmd1bWVudCBiZWZvcmUgYSBMaW5rZWRIYXNoTWFwKGludCwgZmxvYXQsIGJvb2xlYW4pIGNvbnN0cnVjdG9yIGNhbGwgYW5kIGEgRFVQIG9yIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgaXQgKCM4MDcpLCBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciBhIG5ldyBDb21wbGV0YWJsZUZ1dHVyZSgpIGNvbnN0cnVjdG9yIGNhbGwgKCMxMDU0KSwgYW5kIGFuIEFMT0FEIDAsIGFuIExEQyBvZiB0aGUgY2xhc3MgbmFtZSBhbmQgYSBjYWxsIGJlZm9yZSBlYWNoIFJFVFVSTiBvZiBhIGNvbnN0cnVjdG9yIGFuZCBhZnRlciBhIHRoaXMoLi4uKSBkZWxlZ2F0aW9uICgjNzkxKTsgaXQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gSW50ZXJydXB0SGFuZGxlcldlYXZlciBpbnNlcnRzIGFuIExEQyBvZiB0aGUgbG9jYXRpb25zIG9mIGEgbWV0aG9kJ3MgSW50ZXJydXB0ZWRFeGNlcHRpb24gaGFuZGxlcnMgdGhhdCBuZWl0aGVyIHJldGhyb3cgbm9yIHJlc3RvcmUgdGhlIGZsYWcsIGFuZCBhIGNhbGwsIGJlZm9yZSB0aGUgZmlyc3QgaW5zdHJ1Y3Rpb24gb2YgYSBtZXRob2QgdGhhdCBkZWNsYXJlcyBvbmUsIGFuZCBsZWF2ZXMgYWxvbmUgYSBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSB0aGF0IGNhbm5vdCByZWFkIHRoZSBsaWJyYXJ5LiBQZXJzaXN0ZW5jZUhhbmRsZVdlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBjYWxsIHdob3NlIG93bmVyIGlzIGEgSlBBIEVudGl0eU1hbmFnZXIgb3IgSGliZXJuYXRlIFNlc3Npb24gYnkgbmFtZSwgYSBzdGFjay1uZXV0cmFsIGNvcHkgb2YgdGhlIHJlY2VpdmVyIChEVVA7IFNXQVAsIERVUF9YMTsgb3IgRFVQMl9YMSwgUE9QMiwgRFVQX1gyIGZvciB6ZXJvLCBvbmUgb3IgdHdvIG9uZS1zbG90IGFyZ3VtZW50cykgYW5kIGEgY2FsbCwgYW5kIGxlYXZlcyBjYWxscyB3aXRoIG1vcmUgb3Igd2lkZXIgYXJndW1lbnRzIGFsb25lICgjOTkyKS4gUnVuQmxvY2tpbmdXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgc3RhdGljIGNhbGwgb2Yga290bGlueC5jb3JvdXRpbmVzLkJ1aWxkZXJzS3QucnVuQmxvY2tpbmdLLCBydW5CbG9ja2luZyBvciB0aGVpciAkZGVmYXVsdCBicmlkZ2VzIGJ5IG5hbWUsIG9uZSBjYWxsIG9mIGEgKClWIGhvb2sgdGhhdCB0YWtlcyBhbmQgbGVhdmVzIG5vdGhpbmcsIGluIGV2ZXJ5IHdvdmVuIGNsYXNzIG91dHNpZGUga290bGlueC5jb3JvdXRpbmVzICgjMTAwNykuIFNvIGZyYW1lcyBzdGF5IHZhbGlkIGFuZCBvbmx5IG1heFN0YWNrIGdyb3dzIChDT01QVVRFX01BWFMsIG5ldmVyIENPTVBVVEVfRlJBTUVTLCB3aGljaCB3b3VsZCBsb2FkIGNsYXNzZXMgZnJvbSBpbnNpZGUgdGhlIGFnZW50KS4gSW4gZXZlcnkgbW9kZSwgaW5zdGFsbCBhbmQgdGhlIHRyYW5zZm9ybWVyIG9wZW4gamF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MsIHdpdGggZmllbGRzPXRydWUgYWxzbyBqYXZhLnV0aWwuY29uY3VycmVudC5hdG9taWMsIGFuZCB3aXRoIGNvbGxlY3Rpb25zPXRydWUgYWxzbyBqYXZhLnV0aWwgYW5kIGphdmEuaW8gKGEgc3luY2hyb25pemVkIHdyYXBwZXIncyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXIncyBzaW5rLCAjOTk0KSwgdG8gb25lIG1vZHVsZSBwZXIgd292ZW4gbG9hZGVyIGFuZCB0byBub3RoaW5nIGVsc2U6IHRoZSBtb2R1bGUgb2YgdGhlIFRlbGVtZXRyeVJlZ2lzdHJ5IGNvcHkgdGhhdCBsb2FkZXIgcmVzb2x2ZXMsIG5ldmVyIHRoZSB3b3ZlbiBsb2FkZXIgb3IgaXRzIGFuY2VzdG9ycyBhcyBzdWNoIChVcGRhdGVyQWNjZXNzLCAjNjU5LCAjNjY4LCAjODU1KTsgdGhlIGxvY2tzIG9wZW5pbmcgbGV0cyB0aGUgbGlicmFyeSByZWFkIGEgUmVlbnRyYW50TG9jayBvd25lciBhdCBhbmFseXNpcy4gSW4gZXZlcnkgbW9kZSwgYSB3b3ZlbiBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSBnZXRzIGEgcmVhZCBlZGdlIHRvIHRoZSBsaWJyYXJ5IGNvcHkgaXRzIGxvYWRlciByZXNvbHZlcyAoVXBkYXRlckFjY2Vzcy5sZXRSZWFkLCAjODYyKTogdGhlIEpWTSdzIG93biBlZGdlIGZvciBhIHRyYW5zZm9ybWVkIGNsYXNzIHJlYWNoZXMgb25seSB0aGUgYWdlbnQgbG9hZGVyJ3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5J3MgZGVmYXVsdCBzZWxmLWluamVjdGlvbiBnYXZlIGV2ZXJ5IGNsYXNzIHdvdmVuIGF0IGxvYWQgYSA8Y2xpbml0PiB0aGF0IGxvYWRzIG5ldC5ieXRlYnVkZHkuZHluYW1pYy5OZXh1cyB0aHJvdWdoIHRoZSBzeXN0ZW0gY2xhc3MgbG9hZGVyLCB3aG9zZSBsb2NrIHZpcnR1YWwgdGhyZWFkcyBpbml0aWFsaXppbmcgY2xhc3NlcyBhdCBvbmNlIGNvbnRlbmQgb24gYW5kIHBpbiAoIzk4NCkuIFRoZSBQcmVtYWluLUNsYXNzIC8gQWdlbnQtQ2xhc3MgbWFuaWZlc3QgZW50cmllcyBsaXZlIGluIHRoaXMgbW9kdWxlJ3MgamFyLCB3aGljaCBpcyB3aHkgYXR0YWNoaW5nIHVzZXMgLWphdmFhZ2VudDphc3luYy10ZXN0LWFnZW50Lmphci4K -~gran~async-test-instrumentation=KiovYmVuY2htYXJrLyoqCSoqL3RlbGVtZXRyeS8qKgkqKi9hZ2VudC8qKgkqKi9hbmFseXNpcy8qKgojIyBDb3JlIEZ1bmN0aW9uYWxpdHkKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkFzeW5jVGVzdEFnZW50Ci0gKipTZW5zaXRpdml0eSoqOiBDcml0aWNhbAotICoqTm90ZSoqOiBUaGUgSU5TVEFMTEVEIGdhdGUgbXVzdCBzdGF5IGF0LW1vc3Qtb25jZSBwZXIgSlZNOiBldmVyeSBlbnRyeSBwb2ludCAocHJlbWFpbiwgYWdlbnRtYWluLCBzZWxmQXR0YWNoKSByYWNlcyBvbiB0aGUgc2FtZSBjb21wYXJlQW5kU2V0LCBhbmQgYSBzZWNvbmQgdHJhbnNmb3JtZXIgd291bGQgZG91YmxlLXdlYXZlIGFjY2Vzc2VzIGFuZCBkb3VibGUtY291bnQgZXZlcnkgb25lLiBwcmVtYWluIGluc3RhbGxzIHdpdGhvdXQgcmV0cmFuc2Zvcm1hdGlvbiBiZWNhdXNlIGNsYXNzZXMgYXJlIHdvdmVuIGFzIHRoZXkgbG9hZDsgYWdlbnRtYWluIG11c3Qga2VlcCBSRVRSQU5TRk9STUFUSU9OICsgZGlzYWJsZUNsYXNzRm9ybWF0Q2hhbmdlcygpLCB3aGljaCBpcyBvbmx5IHNhZmUgd2hpbGUgbm8gd2VhdmVyIGFkZHMgYSBtZW1iZXIsIGFuZCB0aGVyZSBhcmUgZm91ciBiZXNpZGVzIHRoZSBBZHZpY2UsIHdoaWNoIGlzIGEgbWV0aG9kLWVudHJ5IHByb2xvZ3VlLiBGaWVsZEFjY2Vzc1dlYXZlciBpbnNlcnRzIGEgc3RhY2stbmV1dHJhbCwgYnJhbmNoLWZyZWUgY2FsbCBiZWZvcmUgZWFjaCBmaWVsZCBpbnN0cnVjdGlvbiwgYSBsb2FkIG9mIHRoZSBtb25pdG9yIHBsdXMgYSBjYWxsIGF0IHRoZSBlbnRyeSBvZiBhIHN5bmNocm9uaXplZCBtZXRob2QgYW5kIGJlZm9yZSBlYWNoIG9mIGl0cyByZXR1cm5zICgjODIyKSwgYSBEVVAgb2YgdGhlIG1vbml0b3IsIGFuIEFMT0FEIG9mIHRoZSBsb2NhbCB0aGUgb3duZXIgd2FzIGxvYWRlZCBmcm9tLCBhbiBMREMgb2YgdGhlIGZpZWxkIGFuZCBhIGNhbGwgYmVmb3JlIGEgTU9OSVRPUkVOVEVSIHdob3NlIG1vbml0b3IgdGhlIGZvdXIgaW5zdHJ1Y3Rpb25zIGJlZm9yZSBpdCByZWFkIGZyb20gYW4gaW5zdGFuY2UgZmllbGQgKEFMT0FELCBHRVRGSUVMRCwgRFVQLCBBU1RPUkUsIHdpdGggbm8gbGFiZWwgYmV0d2VlbiwgIzc5MyksIGEgRFVQIHBsdXMgY2FsbCBhZnRlciBhIFZhckhhbmRsZSByZWZlcmVuY2UgZ2V0QW5kU2V0IGl0IGRvZXMgbm90IHN1YnN0aXR1dGUgKHRoZSBvd25lcnNoaXAgdGFrZSwgIzU1NSksIERVUDIgYW5kIFNXQVAgcGx1cyBhIGNhbGwgYmVmb3JlIGEgSkNUb29scyBvZmZlciwgYW5kIGEgRFVQIGJlZm9yZSBwbHVzIERVUF9YMSBhbmQgU1dBUCBwbHVzIGEgY2FsbCBhZnRlciBhIEpDVG9vbHMgcG9sbCAoIzY2NCksIGEgY29weSBvZiBvd25lciBhbmQgdmFsdWUgcGx1cyBhIGNhbGwgYmVmb3JlIGEgdm9sYXRpbGUgZmllbGQgc3RvcmUgYW5kIGFmdGVyIGEgdm9sYXRpbGUgZmllbGQgbG9hZCwgd2l0aCBhIERVUCBvZiB0aGUgcmVjZWl2ZXIgYmVmb3JlIGFuIGluc3RhbmNlIGxvYWQgKCM3NDIpLCBhbmQgcmVwbGFjZXMgYW4gaW50IFZhckhhbmRsZSwgQXRvbWljSW50ZWdlckZpZWxkVXBkYXRlciwgQXRvbWljQm9vbGVhbiBvciBBdG9taWNJbnRlZ2VyIHN0b3JlLCBzd2FwIG9yIHZhbHVlLXJldHVybmluZyByZWxlYXNlLCBvciBhIHJlZmVyZW5jZS1zbG90IHN0b3JlIG9yIGdldEFuZFNldCBvbiBhbiBBdG9taWNSZWZlcmVuY2UsIGl0cyB1cGRhdGVyLCBpdHMgYXJyYXkgb3IgYW4gaW5zdGFuY2UtZmllbGQgVmFySGFuZGxlLCBvciBhbiBhY3F1aXJpbmcgcmVmZXJlbmNlIHJlYWQsIGFuIEF0b21pY1JlZmVyZW5jZSBnZXQgb3IgZ2V0QWNxdWlyZSwgYW4gdXBkYXRlciBnZXQsIGFuIEF0b21pY1JlZmVyZW5jZUFycmF5IGdldCBvciBnZXRBY3F1aXJlIG9yIGEgVmFySGFuZGxlIGdldFZvbGF0aWxlIG9yIGdldEFjcXVpcmUgKHRoZSBhY3F1aXJlIG9mIHRoZSBzdG9yZSBpdCByZXR1cm5lZCwgIzc0MSksIG9yIGFuIEF0b21pY1N0YW1wZWRSZWZlcmVuY2UgZ2V0LCBnZXRSZWZlcmVuY2UsIHNldCwgY29tcGFyZUFuZFNldCwgd2Vha0NvbXBhcmVBbmRTZXQgb3IgYXR0ZW1wdFN0YW1wICgjODE3KSwgb3IgYW4gQXRvbWljSW50ZWdlciBnZXQgb3IgYW4gQXRvbWljTG9uZyBnZXQsIHN0b3JlIG9yIGNvbXBhcmUtYW5kLXNldCAoYSBnZXQgdGhlbiBzZXQsICMxMTU3KSwgd2l0aCBhIHN0YXRpYyBob29rIGNvbnN1bWluZyB0aGUgc2FtZSBzdGFjayBhbmQgcmV0dXJuaW5nIHRoZSBzYW1lIHJlc3VsdCwgcGx1cyBvbmUgUE9QIHdoZXJlIGEgVmFySGFuZGxlIGNhbGwgc2l0ZSBkZWNsYXJlZCBhIHZvaWQgcmVzdWx0IGFuZCBvbmUgQ0hFQ0tDQVNUIHRvIHRoZSBkZWNsYXJlZCB0eXBlIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgb3IgYWNxdWlyaW5nIHJlYWQgKHRoZSBzcGlubG9jaywgIzU1NCwgIzU1OCwgIzY1OCwgIzY2NzsgdGhlIG93bmVyc2hpcCBvZmZlciBhbmQgdGFrZSwgIzY2NCkuIENvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIgcmVwbGFjZXMgZWFjaCBjYWxsIGl0cyB0YWJsZXMgbGlzdCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrLCBhbmQgaW5zZXJ0cyBvbmx5IHRoZSBtb25pdG9yIGxvYWRzIGFuZCB0aGUgbG9vcCBiYWNrLWVkZ2UgY2FsbCBpdHMgb3duIHJ1bGVzIGRlc2NyaWJlLiBUaHJlYWRDb25zdHJ1Y3Rpb25XZWF2ZXIgaW5zZXJ0cyBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciB0aGUgY29uc3RydWN0b3IgY2FsbCBvZiBhIG5ldyBUaHJlYWQoLi4uKSwgYW5kIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBUaHJlYWQgc3ViY2xhc3MgY29uc3RydWN0b3IncyBzdXBlcmNsYXNzIGNhbGwgKCM3MzcpLiBDb25zdHJ1Y3Rpb25XZWF2ZXIgaW5zZXJ0cyBhIGNhbGwgdGhhdCBjb25zdW1lcyBhbmQgcmV0dXJucyB0aGUgb3JkZXIgYXJndW1lbnQgYmVmb3JlIGEgTGlua2VkSGFzaE1hcChpbnQsIGZsb2F0LCBib29sZWFuKSBjb25zdHJ1Y3RvciBjYWxsIGFuZCBhIERVUCBvciBhbiBBTE9BRCAwIHBsdXMgYSBjYWxsIGFmdGVyIGl0ICgjODA3KSwgYSBEVVAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBuZXcgQ29tcGxldGFibGVGdXR1cmUoKSBjb25zdHJ1Y3RvciBjYWxsICgjMTA1NCksIGFuZCBhbiBBTE9BRCAwLCBhbiBMREMgb2YgdGhlIGNsYXNzIG5hbWUgYW5kIGEgY2FsbCBiZWZvcmUgZWFjaCBSRVRVUk4gb2YgYSBjb25zdHJ1Y3RvciBhbmQgYWZ0ZXIgYSB0aGlzKC4uLikgZGVsZWdhdGlvbiAoIzc5MSk7IGl0IGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIEludGVycnVwdEhhbmRsZXJXZWF2ZXIgaW5zZXJ0cyBhbiBMREMgb2YgdGhlIGxvY2F0aW9ucyBvZiBhIG1ldGhvZCdzIEludGVycnVwdGVkRXhjZXB0aW9uIGhhbmRsZXJzIHRoYXQgbmVpdGhlciByZXRocm93IG5vciByZXN0b3JlIHRoZSBmbGFnLCBhbmQgYSBjYWxsLCBiZWZvcmUgdGhlIGZpcnN0IGluc3RydWN0aW9uIG9mIGEgbWV0aG9kIHRoYXQgZGVjbGFyZXMgb25lLCBhbmQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gUGVyc2lzdGVuY2VIYW5kbGVXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgY2FsbCB3aG9zZSBvd25lciBpcyBhIEpQQSBFbnRpdHlNYW5hZ2VyIG9yIEhpYmVybmF0ZSBTZXNzaW9uIGJ5IG5hbWUsIGEgc3RhY2stbmV1dHJhbCBjb3B5IG9mIHRoZSByZWNlaXZlciAoRFVQOyBTV0FQLCBEVVBfWDE7IG9yIERVUDJfWDEsIFBPUDIsIERVUF9YMiBmb3IgemVybywgb25lIG9yIHR3byBvbmUtc2xvdCBhcmd1bWVudHMpIGFuZCBhIGNhbGwsIGFuZCBsZWF2ZXMgY2FsbHMgd2l0aCBtb3JlIG9yIHdpZGVyIGFyZ3VtZW50cyBhbG9uZSAoIzk5MikuIFJ1bkJsb2NraW5nV2VhdmVyIGluc2VydHMsIGJlZm9yZSBhIHN0YXRpYyBjYWxsIG9mIGtvdGxpbnguY29yb3V0aW5lcy5CdWlsZGVyc0t0LnJ1bkJsb2NraW5nSywgcnVuQmxvY2tpbmcgb3IgdGhlaXIgJGRlZmF1bHQgYnJpZGdlcyBieSBuYW1lLCBvbmUgY2FsbCBvZiBhICgpViBob29rIHRoYXQgdGFrZXMgYW5kIGxlYXZlcyBub3RoaW5nLCBpbiBldmVyeSB3b3ZlbiBjbGFzcyBvdXRzaWRlIGtvdGxpbnguY29yb3V0aW5lcyAoIzEwMDcpLiBTbyBmcmFtZXMgc3RheSB2YWxpZCBhbmQgb25seSBtYXhTdGFjayBncm93cyAoQ09NUFVURV9NQVhTLCBuZXZlciBDT01QVVRFX0ZSQU1FUywgd2hpY2ggd291bGQgbG9hZCBjbGFzc2VzIGZyb20gaW5zaWRlIHRoZSBhZ2VudCkuIEluIGV2ZXJ5IG1vZGUsIGluc3RhbGwgYW5kIHRoZSB0cmFuc2Zvcm1lciBvcGVuIGphdmEudXRpbC5jb25jdXJyZW50LmxvY2tzLCB3aXRoIGZpZWxkcz10cnVlIGFsc28gamF2YS51dGlsLmNvbmN1cnJlbnQuYXRvbWljLCBhbmQgd2l0aCBjb2xsZWN0aW9ucz10cnVlIGFsc28gamF2YS51dGlsIGFuZCBqYXZhLmlvIChhIHN5bmNocm9uaXplZCB3cmFwcGVyJ3MgbXV0ZXgsICM5OTY7IGEgcGlwZWQgd3JpdGVyJ3Mgc2luaywgIzk5NCksIHRvIG9uZSBtb2R1bGUgcGVyIHdvdmVuIGxvYWRlciBhbmQgdG8gbm90aGluZyBlbHNlOiB0aGUgbW9kdWxlIG9mIHRoZSBUZWxlbWV0cnlSZWdpc3RyeSBjb3B5IHRoYXQgbG9hZGVyIHJlc29sdmVzLCBuZXZlciB0aGUgd292ZW4gbG9hZGVyIG9yIGl0cyBhbmNlc3RvcnMgYXMgc3VjaCAoVXBkYXRlckFjY2VzcywgIzY1OSwgIzY2OCwgIzg1NSk7IHRoZSBsb2NrcyBvcGVuaW5nIGxldHMgdGhlIGxpYnJhcnkgcmVhZCBhIFJlZW50cmFudExvY2sgb3duZXIgYXQgYW5hbHlzaXMuIEluIGV2ZXJ5IG1vZGUsIGEgd292ZW4gY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgZ2V0cyBhIHJlYWQgZWRnZSB0byB0aGUgbGlicmFyeSBjb3B5IGl0cyBsb2FkZXIgcmVzb2x2ZXMgKFVwZGF0ZXJBY2Nlc3MubGV0UmVhZCwgIzg2Mik6IHRoZSBKVk0ncyBvd24gZWRnZSBmb3IgYSB0cmFuc2Zvcm1lZCBjbGFzcyByZWFjaGVzIG9ubHkgdGhlIGFnZW50IGxvYWRlcidzIHVubmFtZWQgbW9kdWxlLiBUaGUgbGlicmFyeSByZXNvbHZlcyBhbiB1cGRhdGVyIGJvdW5kIGJlZm9yZSB0aGUgYXR0YWNoIGJ5IHJlYWRpbmcgdGhlIEpESyBpbXBsZW1lbnRhdGlvbiBmcm9tIHRoYXQgY29weSAoSmRrVXBkYXRlclNoYXBlQ2FuYXJ5VGVzdCBwaW5zIHRoZSBzaGFwZSBpdCByZWFkcyksIGFuZCB0aGUgb3BlbmluZyBtdXN0IGZhaWwgc2lsZW50bHkgbGlrZSB0aGUgcmVzdCBvZiBpbnN0YWxsLiBOb3RoaW5nIG1heSB0aHJvdyBvdXQgb2YgcHJlbWFpbiDigJQgYW4gZXhjZXB0aW9uIHRoZXJlIGFib3J0cyBKVk0gc3RhcnR1cCwgd2hpY2ggaXMgd2h5IGluc3RhbGwoKSBjYXRjaGVzIFRocm93YWJsZSBhbmQgcmVsZWFzZXMgdGhlIGdhdGUgcmF0aGVyIHRoYW4gcHJvcGFnYXRpbmcuIEJvdGggbW9kZXMgdXNlIEFnZW50QnVpbGRlci5Jbml0aWFsaXphdGlvblN0cmF0ZWd5Lk5vT3A6IG5vIHdlYXZlciBuZWVkcyBhIGxvYWRlZC10eXBlIGluaXRpYWxpemVyLCBhbmQgQnl0ZSBCdWRkeSdzIGRlZmF1bHQgc2VsZi1pbmplY3Rpb24gZ2F2ZSBldmVyeSBjbGFzcyB3b3ZlbiBhdCBsb2FkIGEgPGNsaW5pdD4gdGhhdCBsb2FkcyBuZXQuYnl0ZWJ1ZGR5LmR5bmFtaWMuTmV4dXMgdGhyb3VnaCB0aGUgc3lzdGVtIGNsYXNzIGxvYWRlciwgd2hvc2UgbG9jayB2aXJ0dWFsIHRocmVhZHMgaW5pdGlhbGl6aW5nIGNsYXNzZXMgYXQgb25jZSBjb250ZW5kIG9uIGFuZCBwaW4gKCM5ODQpLiBUaGUgUHJlbWFpbi1DbGFzcyAvIEFnZW50LUNsYXNzIG1hbmlmZXN0IGVudHJpZXMgbGl2ZSBpbiB0aGlzIG1vZHVsZSdzIGphciwgd2hpY2ggaXMgd2h5IGF0dGFjaGluZyB1c2VzIC1qYXZhYWdlbnQ6YXN5bmMtdGVzdC1hZ2VudC5qYXIuCgojIyBDb250cmFjdC1Gcm96ZW4gU2lnbmF0dXJlCi0gKipDb25zdHJhaW50Kio6IFlvdSBtYXkgY2hhbmdlIGludGVybmFsIGxvZ2ljLCBidXQgTVVTVCBOT1QgbW9kaWZ5IHRoZSBtZXRob2QgbmFtZSwgcGFyYW1ldGVycywgcmV0dXJuIHR5cGUsIG9yIGNoZWNrZWQgZXhjZXB0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkFnZW50T3B0aW9ucwotICoqUmVhc29uKio6IFRoZSBjbGFzcyBpcyBwYWNrYWdlLXByaXZhdGUgYnV0IHRoZSBhZ2VudEFyZ3MgZ3JhbW1hciBpdCBwYXJzZXMgaXMgcHVibGljIHN1cmZhY2U6IHVzZXJzIHR5cGUgaXQgb24gdGhlIC1qYXZhYWdlbnQ6IGNvbW1hbmQgbGluZS4gS2V5IG5hbWVzIChpbmNsdWRlcy9leGNsdWRlcy9kZWJ1ZyksIHRoZSBjb21tYS1vci1zZW1pY29sb24gc2VwYXJhdG9yLCB0aGUgYmFyZS10b2tlbiBjb250aW51YXRpb24gdGhhdCBsZXRzIG9uZSBrZXkgY2Fycnkgc2V2ZXJhbCB2YWx1ZXMsIGFuZCBjYXNlLWluc2Vuc2l0aXZlIGtleSBtYXRjaGluZyBhcmUgYWxsIHBhcnQgb2YgdGhhdCBjb250cmFjdCDigJQgY2hhbmdpbmcgYW55IG9mIHRoZW0gYnJlYWtzIGV4aXN0aW5nIGxhdW5jaCBzY3JpcHRzIHNpbGVudGx5LiBQYXJzaW5nIG11c3Qgc3RheSB0b3RhbDogaXQgaXMgY2FsbGVkIGZyb20gcHJlbWFpbiwgd2hlcmUgYSB0aHJvd24gZXhjZXB0aW9uIGFib3J0cyBKVk0gc3RhcnR1cCwgc28gdW5rbm93biBrZXlzIGFyZSBpZ25vcmVkIGFuZCBtYWxmb3JtZWQgaW5wdXQgZGVncmFkZXMgdG8gdGhlIGRlZmF1bHQgaW5zdHJ1bWVudC1ldmVyeXRoaW5nIGJlaGF2aW91ciByYXRoZXIgdGhhbiBmYWlsaW5nLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYWdlbnQuQXRvbWljRmllbGRSZWdpc3RyeQotICoqUmVhc29uKio6IFJlc29sdmVkIHJlZmxlY3RpdmVseSBzbyBhc3luYy10ZXN0LWFnZW50IGtlZXBzIGl0cyB6ZXJvLWRlcGVuZGVuY3kgYm91bmRhcnkgb24gYXN5bmMtdGVzdC1saWIsIHdoaWNoIEFyY2hpdGVjdHVyZVRlc3QgZW5mb3JjZXMgaW4gYm90aCBkaXJlY3Rpb25zLiBUaGUgbWV0aG9kIG5hbWUgYW5kIHNpZ25hdHVyZSBtdXN0IG1hdGNoIFRlbGVtZXRyeVJlZ2lzdHJ5LmF0b21pY2FsbHlNYW5hZ2VkKFN0cmluZykuIEV2ZXJ5IGZhaWx1cmUgcGF0aCBoZXJlIG11c3Qgc3RheSBzaWxlbnQ6IHRoaXMgb25seSBldmVyIHN1cHByZXNzZXMgZmluZGluZ3MsIHNvIGxvc2luZyBpdCBkZWdyYWRlcyBwcmVjaXNpb24gcmF0aGVyIHRoYW4gY29ycmVjdG5lc3MsIHdoaWxlIHRocm93aW5nIG91dCBvZiBhIGNsYXNzIHRyYW5zZm9ybWF0aW9uIHdvdWxkIGZhaWwgdGhlIHVzZXIncyB0ZXN0IHJ1bi4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkNvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIKLSAqKlJlYXNvbioqOiBUaGUgaG9vayBjbGFzcyBuYW1lIGFuZCB0aGUgbWV0aG9kIG5hbWVzIGhlcmUgYXJlIHRoZSBvdGhlciBoYWxmIG9mIEFnZW50Q29sbGVjdGlvbkhvb2tzIGFuZCBBZ2VudExvY2tIb29rczogdGhleSBhcmUgbWF0Y2hlZCBieSBlcmFzZWQgc2lnbmF0dXJlIGF0IHdlYXZlIHRpbWUsIHNvIHJlbmFtaW5nIGEgaG9vayBvciBjaGFuZ2luZyBhIHBhcmFtZXRlciB0eXBlIGJyZWFrcyB3ZWF2aW5nIHdpdGggYSBOb1N1Y2hNZXRob2RFcnJvciBpbnNpZGUgdXNlciBjb2RlIHJhdGhlciB0aGFuIGF0IGNvbXBpbGUgdGltZS4gRWFjaCBzdWJzdGl0dXRpb24gbXVzdCBjb25zdW1lIGV4YWN0bHkgdGhlIHN0YWNrIGl0cyBvcmlnaW5hbCBpbnZvY2F0aW9uIGNvbnN1bWVkIC0gc3RhY2stc2hhcGUtbmV1dHJhbCBhbmQgbWVtYmVyLWZyZWUgaXMgd2hhdCBrZWVwcyByZXRyYW5zZm9ybWF0aW9uIHNhZmUgdW5kZXIgZGlzYWJsZUNsYXNzRm9ybWF0Q2hhbmdlcygpLiBUaGUgdmlzaXRvciBjaGFuZ2VzIGV4YWN0bHkgb25lIGtpbmQgb2YgaW52b2tlZHluYW1pYzogYSBMYW1iZGFNZXRhZmFjdG9yeSBtZXRhZmFjdG9yeSBvciBub24tc2VyaWFsaXphYmxlIGFsdE1ldGFmYWN0b3J5IHdob3NlIGltcGxlbWVudGF0aW9uIGhhbmRsZSBtYXRjaGVzIGEgdGFibGUgZW50cnkgaXMgcG9pbnRlZCBhdCB0aGF0IGVudHJ5J3MgaG9vaywgc28gYSBtZXRob2QgcmVmZXJlbmNlIHN1Y2ggYXMgYnVpbGRlcjo6YXBwZW5kIGlzIG9ic2VydmVkICgjNTUwKS4gRXZlcnkgb3RoZXIgYm9vdHN0cmFwLCBPYmplY3RNZXRob2RzIGZvciByZWNvcmRzIGFib3ZlIGFsbCwgbXVzdCBwYXNzIHRocm91Z2ggYXMgdGhlIHNhbWUgYXJndW1lbnQgYXJyYXksIHJlYWQgb25seSB0aHJvdWdoIEFTTSdzIEhhbmRsZTogcGFyc2luZyBib290c3RyYXAgY29uc3RhbnRzIGlzIHdoYXQgbWFkZSBldmVyeSBKYXZhIHJlY29yZCBmYWlsIHRvIGluc3RydW1lbnQgd2hlbiB0aGlzIHdlbnQgdGhyb3VnaCBNZW1iZXJTdWJzdGl0dXRpb24sIGFuZCBhIHJld3JpdHRlbiBzZXJpYWxpemFibGUgbGFtYmRhIHdvdWxkIGZhaWwgdG8gZGVzZXJpYWxpemUuIENvbGxlY3Rpb24gd2VhdmluZyBpcyBvcHQtaW4gKGNvbGxlY3Rpb25zPXRydWUpIGJlY2F1c2UgaXQgaW5zdHJ1bWVudHMgZXZlcnkgbGlzdGVkIGNhbGwgaW4gZXZlcnkgbWF0Y2hlZCBjbGFzcy4gVGhlIG9uZS1pbnN0cnVjdGlvbiBsb29rYWhlYWQgYmVoaW5kIHdoZW5SZXN1bHREaXNjYXJkZWQgaXMgYSBmbGFnIG1lYW5pbmcgdGhlIGluc3RydWN0aW9uIGp1c3QgZW1pdHRlZCB3YXMgYSBzdWJzdGl0dXRlZCBjYWxsIHdob3NlIHJlc3VsdCBtYXkgYmUgZGlzY2FyZGVkOiB2aXNpdEluc24oUE9QKSBpcyBpdHMgb25seSBjb25zdW1lciBhbmQgZXZlcnkgb3RoZXIgdmlzaXQgbWV0aG9kIG11c3QgY2xlYXIgaXQsIGJlY2F1c2UgYSBzdGFsZSBmbGFnIHdvdWxkIHR1cm4gYW4gdW5yZWxhdGVkIFBPUCBpbnRvIGEgY2FsbCB3aG9zZSBwYXJhbWV0ZXIgZG9lcyBub3QgbWF0Y2ggdGhlIHZhbHVlIG9uIHRoZSBzdGFjaywgd2hpY2ggaXMgYSBWZXJpZnlFcnJvciBpbiB0aGUgdXNlcidzIGNsYXNzIGF0IGxvYWQgdGltZS4gU3Vic3RpdHV0aW5nVmlzaXRvckNsZWFyc0xvb2thaGVhZEV2ZXJ5d2hlcmVUZXN0IGVudW1lcmF0ZXMgTWV0aG9kVmlzaXRvciB0byBrZWVwIHRoYXQgb3ZlcnJpZGUgbGlzdCBjb21wbGV0ZS4gSW5zaWRlIGEgc3luY2hyb25pemVkIG1ldGhvZCwgYW4gZW50cnkgd2l0aCBhIHN5bmNocm9uaXplZCB2YXJpYW50ICh0aGUgc2xlZXBzLCBhbmQgdGhlIHF1ZXVlIG9mZmVycyBhbmQgdGFrZXMsICM3OTYpIGZpcnN0IGxvYWRzIHRoZSBtZXRob2QncyBtb25pdG9yLCBBTE9BRCAwIG9yIGFuIExEQyBvZiB0aGUgY2xhc3MgZm9yIGEgc3RhdGljIG1ldGhvZCwgd2hpY2ggdGhlIHZhcmlhbnQgY29uc3VtZXMgYXMgaXRzIGxhc3QgcGFyYW1ldGVyOiBvbmUgbW9yZSB2YWx1ZSBhbmQgbm8gYnJhbmNoLCBzbyBvbmx5IG1heFN0YWNrIGdyb3dzLCBhbmQgdGhlIHN1YnN0aXR1dGlvbiB3cmFwcGVyIGFza3MgZm9yIENPTVBVVEVfTUFYUyBpdHNlbGYuIEEgcXVldWUgb2ZmZXIgb3IgdGFrZSBpbiBhbnkgb3RoZXIgaW5zdGFuY2UgbWV0aG9kIGxvYWRzIHRoaXMgdGhlIHNhbWUgd2F5IGZvciBpdHMgaG9vayB0byBwcm9iZSAoIzc1MSksIGV4Y2VwdCBpbiBhIGNvbnN0cnVjdG9yLCB3aGVyZSB0aGlzIG1heSBiZSB1bmluaXRpYWxpc2VkIGFuZCB3b3VsZCBub3QgdmVyaWZ5LCBhbmQgYWZ0ZXIgYSBzdG9yZSB0byBsb2NhbCAwLiBUaGUgb25lIGluc3RydWN0aW9uIHRoZSB2aXNpdG9yIGluc2VydHMgb3V0c2lkZSBhIHN1YnN0aXR1dGlvbiBpcyB0aGUgbG9vcCBiYWNrLWVkZ2UgY2FsbCBpbiBmcm9udCBvZiBhIGp1bXAgdGhhdCBjb21lcyBiYWNrIG92ZXIgYSB3b3ZlbiBPYmplY3Qud2FpdCAoIzY5NCk6IGl0IG11c3Qgc3RheSBhIHN0YXRpYyAoKVYgY2FsbCwgYmVjYXVzZSB0aGUganVtcCdzIG9wZXJhbmRzIGFyZSBhbHJlYWR5IG9uIHRoZSBzdGFjayBiZW5lYXRoIGl0IGFuZCBhbnl0aGluZyB0aGF0IHRvb2sgb3IgbGVmdCBhIHZhbHVlLCBvciBhZGRlZCBhIGJyYW5jaCwgd291bGQgbmVlZCB0aGUgZnJhbWVzIENPTVBVVEVfTUFYUyBkb2VzIG5vdCByZWNvbXB1dGUu +claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxsb2NrZWRfZmlsZXM+CiAgPC9sb2NrZWRfZmlsZXM+CiAgPGNvbnRleHR1YWxfaW5zdHJ1Y3Rpb25zPgogIDwvY29udGV4dHVhbF9pbnN0cnVjdGlvbnM+CiAgPGNvcmVfZWxlbWVudHM+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkFzeW5jVGVzdEFnZW50Ij4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+VGhlIElOU1RBTExFRCBnYXRlIG11c3Qgc3RheSBhdC1tb3N0LW9uY2UgcGVyIEpWTTogZXZlcnkgZW50cnkgcG9pbnQgKHByZW1haW4sIGFnZW50bWFpbiwgc2VsZkF0dGFjaCkgcmFjZXMgb24gdGhlIHNhbWUgY29tcGFyZUFuZFNldCwgYW5kIGEgc2Vjb25kIHRyYW5zZm9ybWVyIHdvdWxkIGRvdWJsZS13ZWF2ZSBhY2Nlc3NlcyBhbmQgZG91YmxlLWNvdW50IGV2ZXJ5IG9uZS4gcHJlbWFpbiBpbnN0YWxscyB3aXRob3V0IHJldHJhbnNmb3JtYXRpb24gYmVjYXVzZSBjbGFzc2VzIGFyZSB3b3ZlbiBhcyB0aGV5IGxvYWQ7IGFnZW50bWFpbiBtdXN0IGtlZXAgUkVUUkFOU0ZPUk1BVElPTiArIGRpc2FibGVDbGFzc0Zvcm1hdENoYW5nZXMoKSwgd2hpY2ggaXMgb25seSBzYWZlIHdoaWxlIG5vIHdlYXZlciBhZGRzIGEgbWVtYmVyLCBhbmQgdGhlcmUgYXJlIGZvdXIgYmVzaWRlcyB0aGUgQWR2aWNlLCB3aGljaCBpcyBhIG1ldGhvZC1lbnRyeSBwcm9sb2d1ZS4gRmllbGRBY2Nlc3NXZWF2ZXIgaW5zZXJ0cyBhIHN0YWNrLW5ldXRyYWwsIGJyYW5jaC1mcmVlIGNhbGwgYmVmb3JlIGVhY2ggZmllbGQgaW5zdHJ1Y3Rpb24sIGEgbG9hZCBvZiB0aGUgbW9uaXRvciBwbHVzIGEgY2FsbCBhdCB0aGUgZW50cnkgb2YgYSBzeW5jaHJvbml6ZWQgbWV0aG9kIGFuZCBiZWZvcmUgZWFjaCBvZiBpdHMgcmV0dXJucyAoIzgyMiksIGEgRFVQIG9mIHRoZSBtb25pdG9yLCBhbiBBTE9BRCBvZiB0aGUgbG9jYWwgdGhlIG93bmVyIHdhcyBsb2FkZWQgZnJvbSwgYW4gTERDIG9mIHRoZSBmaWVsZCBhbmQgYSBjYWxsIGJlZm9yZSBhIE1PTklUT1JFTlRFUiB3aG9zZSBtb25pdG9yIHRoZSBmb3VyIGluc3RydWN0aW9ucyBiZWZvcmUgaXQgcmVhZCBmcm9tIGFuIGluc3RhbmNlIGZpZWxkIChBTE9BRCwgR0VURklFTEQsIERVUCwgQVNUT1JFLCB3aXRoIG5vIGxhYmVsIGJldHdlZW4sICM3OTMpLCBhIERVUCBwbHVzIGNhbGwgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBpdCBkb2VzIG5vdCBzdWJzdGl0dXRlICh0aGUgb3duZXJzaGlwIHRha2UsICM1NTUpLCBEVVAyIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGJlZm9yZSBhIEpDVG9vbHMgb2ZmZXIsIGFuZCBhIERVUCBiZWZvcmUgcGx1cyBEVVBfWDEgYW5kIFNXQVAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBKQ1Rvb2xzIHBvbGwgKCM2NjQpLCBhIGNvcHkgb2Ygb3duZXIgYW5kIHZhbHVlIHBsdXMgYSBjYWxsIGJlZm9yZSBhIHZvbGF0aWxlIGZpZWxkIHN0b3JlIGFuZCBhZnRlciBhIHZvbGF0aWxlIGZpZWxkIGxvYWQsIHdpdGggYSBEVVAgb2YgdGhlIHJlY2VpdmVyIGJlZm9yZSBhbiBpbnN0YW5jZSBsb2FkICgjNzQyKSwgYW5kIHJlcGxhY2VzIGFuIGludCBWYXJIYW5kbGUsIEF0b21pY0ludGVnZXJGaWVsZFVwZGF0ZXIsIEF0b21pY0Jvb2xlYW4gb3IgQXRvbWljSW50ZWdlciBzdG9yZSwgc3dhcCBvciB2YWx1ZS1yZXR1cm5pbmcgcmVsZWFzZSwgb3IgYSByZWZlcmVuY2Utc2xvdCBzdG9yZSBvciBnZXRBbmRTZXQgb24gYW4gQXRvbWljUmVmZXJlbmNlLCBpdHMgdXBkYXRlciwgaXRzIGFycmF5IG9yIGFuIGluc3RhbmNlLWZpZWxkIFZhckhhbmRsZSwgb3IgYW4gYWNxdWlyaW5nIHJlZmVyZW5jZSByZWFkLCBhbiBBdG9taWNSZWZlcmVuY2UgZ2V0IG9yIGdldEFjcXVpcmUsIGFuIHVwZGF0ZXIgZ2V0LCBhbiBBdG9taWNSZWZlcmVuY2VBcnJheSBnZXQgb3IgZ2V0QWNxdWlyZSBvciBhIFZhckhhbmRsZSBnZXRWb2xhdGlsZSBvciBnZXRBY3F1aXJlICh0aGUgYWNxdWlyZSBvZiB0aGUgc3RvcmUgaXQgcmV0dXJuZWQsICM3NDEpLCBvciBhbiBBdG9taWNTdGFtcGVkUmVmZXJlbmNlIGdldCwgZ2V0UmVmZXJlbmNlLCBzZXQsIGNvbXBhcmVBbmRTZXQsIHdlYWtDb21wYXJlQW5kU2V0IG9yIGF0dGVtcHRTdGFtcCAoIzgxNyksIG9yIGFuIEF0b21pY0ludGVnZXIgZ2V0IG9yIGFuIEF0b21pY0xvbmcgZ2V0LCBzdG9yZSBvciBjb21wYXJlLWFuZC1zZXQgKGEgZ2V0IHRoZW4gc2V0LCAjMTE1NyksIHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2sgYW5kIHJldHVybmluZyB0aGUgc2FtZSByZXN1bHQsIHBsdXMgb25lIFBPUCB3aGVyZSBhIFZhckhhbmRsZSBjYWxsIHNpdGUgZGVjbGFyZWQgYSB2b2lkIHJlc3VsdCBhbmQgb25lIENIRUNLQ0FTVCB0byB0aGUgZGVjbGFyZWQgdHlwZSBhZnRlciBhIFZhckhhbmRsZSByZWZlcmVuY2UgZ2V0QW5kU2V0IG9yIGFjcXVpcmluZyByZWFkICh0aGUgc3BpbmxvY2ssICM1NTQsICM1NTgsICM2NTgsICM2Njc7IHRoZSBvd25lcnNoaXAgb2ZmZXIgYW5kIHRha2UsICM2NjQpLiBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyIHJlcGxhY2VzIGVhY2ggY2FsbCBpdHMgdGFibGVzIGxpc3Qgd2l0aCBhIHN0YXRpYyBob29rIGNvbnN1bWluZyB0aGUgc2FtZSBzdGFjaywgYW5kIGluc2VydHMgb25seSB0aGUgbW9uaXRvciBsb2FkcyBhbmQgdGhlIGxvb3AgYmFjay1lZGdlIGNhbGwgaXRzIG93biBydWxlcyBkZXNjcmliZS4gVGhyZWFkQ29uc3RydWN0aW9uV2VhdmVyIGluc2VydHMgYSBEVVAgcGx1cyBhIGNhbGwgYWZ0ZXIgdGhlIGNvbnN0cnVjdG9yIGNhbGwgb2YgYSBuZXcgVGhyZWFkKC4uLiksIGFuZCBhbiBBTE9BRCAwIHBsdXMgYSBjYWxsIGFmdGVyIGEgVGhyZWFkIHN1YmNsYXNzIGNvbnN0cnVjdG9yJiMzOTtzIHN1cGVyY2xhc3MgY2FsbCAoIzczNykuIENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgY2FsbCB0aGF0IGNvbnN1bWVzIGFuZCByZXR1cm5zIHRoZSBvcmRlciBhcmd1bWVudCBiZWZvcmUgYSBMaW5rZWRIYXNoTWFwKGludCwgZmxvYXQsIGJvb2xlYW4pIGNvbnN0cnVjdG9yIGNhbGwgYW5kIGEgRFVQIG9yIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgaXQgKCM4MDcpLCBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciBhIG5ldyBDb21wbGV0YWJsZUZ1dHVyZSgpIGNvbnN0cnVjdG9yIGNhbGwgKCMxMDU0KSwgYW5kIGFuIEFMT0FEIDAsIGFuIExEQyBvZiB0aGUgY2xhc3MgbmFtZSBhbmQgYSBjYWxsIGJlZm9yZSBlYWNoIFJFVFVSTiBvZiBhIGNvbnN0cnVjdG9yIGFuZCBhZnRlciBhIHRoaXMoLi4uKSBkZWxlZ2F0aW9uICgjNzkxKTsgaXQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gSW50ZXJydXB0SGFuZGxlcldlYXZlciBpbnNlcnRzIGFuIExEQyBvZiB0aGUgbG9jYXRpb25zIG9mIGEgbWV0aG9kJiMzOTtzIEludGVycnVwdGVkRXhjZXB0aW9uIGhhbmRsZXJzIHRoYXQgbmVpdGhlciByZXRocm93IG5vciByZXN0b3JlIHRoZSBmbGFnLCBhbmQgYSBjYWxsLCBiZWZvcmUgdGhlIGZpcnN0IGluc3RydWN0aW9uIG9mIGEgbWV0aG9kIHRoYXQgZGVjbGFyZXMgb25lLCBhbmQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gUGVyc2lzdGVuY2VIYW5kbGVXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgY2FsbCB3aG9zZSBvd25lciBpcyBhIEpQQSBFbnRpdHlNYW5hZ2VyIG9yIEhpYmVybmF0ZSBTZXNzaW9uIGJ5IG5hbWUsIGEgc3RhY2stbmV1dHJhbCBjb3B5IG9mIHRoZSByZWNlaXZlciAoRFVQOyBTV0FQLCBEVVBfWDE7IG9yIERVUDJfWDEsIFBPUDIsIERVUF9YMiBmb3IgemVybywgb25lIG9yIHR3byBvbmUtc2xvdCBhcmd1bWVudHMpIGFuZCBhIGNhbGwsIGFuZCBsZWF2ZXMgY2FsbHMgd2l0aCBtb3JlIG9yIHdpZGVyIGFyZ3VtZW50cyBhbG9uZSAoIzk5MikuIFJ1bkJsb2NraW5nV2VhdmVyIGluc2VydHMsIGJlZm9yZSBhIHN0YXRpYyBjYWxsIG9mIGtvdGxpbnguY29yb3V0aW5lcy5CdWlsZGVyc0t0LnJ1bkJsb2NraW5nSywgcnVuQmxvY2tpbmcgb3IgdGhlaXIgJGRlZmF1bHQgYnJpZGdlcyBieSBuYW1lLCBvbmUgY2FsbCBvZiBhICgpViBob29rIHRoYXQgdGFrZXMgYW5kIGxlYXZlcyBub3RoaW5nLCBpbiBldmVyeSB3b3ZlbiBjbGFzcyBvdXRzaWRlIGtvdGxpbnguY29yb3V0aW5lcyAoIzEwMDcpLiBLb3RsaW5NdXRleFdlYXZlciByZXBsYWNlcyBhIGtvdGxpbnguY29yb3V0aW5lcy5zeW5jLk11dGV4IGxvY2ssIHVubG9jayBvciB0cnlMb2NrIGNhbGwsIG9yIGl0cyBzdGF0aWMgJGRlZmF1bHQgYnJpZGdlLCBtYXRjaGVkIGJ5IG93bmVyLCBuYW1lIGFuZCBkZXNjcmlwdG9yLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBpbiBldmVyeSB3b3ZlbiBjbGFzcyBvdXRzaWRlIGtvdGxpbnguY29yb3V0aW5lcyAoIzEwMDcpLiBTbyBmcmFtZXMgc3RheSB2YWxpZCBhbmQgb25seSBtYXhTdGFjayBncm93cyAoQ09NUFVURV9NQVhTLCBuZXZlciBDT01QVVRFX0ZSQU1FUywgd2hpY2ggd291bGQgbG9hZCBjbGFzc2VzIGZyb20gaW5zaWRlIHRoZSBhZ2VudCkuIEluIGV2ZXJ5IG1vZGUsIGluc3RhbGwgYW5kIHRoZSB0cmFuc2Zvcm1lciBvcGVuIGphdmEudXRpbC5jb25jdXJyZW50LmxvY2tzLCB3aXRoIGZpZWxkcz10cnVlIGFsc28gamF2YS51dGlsLmNvbmN1cnJlbnQuYXRvbWljLCBhbmQgd2l0aCBjb2xsZWN0aW9ucz10cnVlIGFsc28gamF2YS51dGlsIGFuZCBqYXZhLmlvIChhIHN5bmNocm9uaXplZCB3cmFwcGVyJiMzOTtzIG11dGV4LCAjOTk2OyBhIHBpcGVkIHdyaXRlciYjMzk7cyBzaW5rLCAjOTk0KSwgdG8gb25lIG1vZHVsZSBwZXIgd292ZW4gbG9hZGVyIGFuZCB0byBub3RoaW5nIGVsc2U6IHRoZSBtb2R1bGUgb2YgdGhlIFRlbGVtZXRyeVJlZ2lzdHJ5IGNvcHkgdGhhdCBsb2FkZXIgcmVzb2x2ZXMsIG5ldmVyIHRoZSB3b3ZlbiBsb2FkZXIgb3IgaXRzIGFuY2VzdG9ycyBhcyBzdWNoIChVcGRhdGVyQWNjZXNzLCAjNjU5LCAjNjY4LCAjODU1KTsgdGhlIGxvY2tzIG9wZW5pbmcgbGV0cyB0aGUgbGlicmFyeSByZWFkIGEgUmVlbnRyYW50TG9jayBvd25lciBhdCBhbmFseXNpcy4gSW4gZXZlcnkgbW9kZSwgYSB3b3ZlbiBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSBnZXRzIGEgcmVhZCBlZGdlIHRvIHRoZSBsaWJyYXJ5IGNvcHkgaXRzIGxvYWRlciByZXNvbHZlcyAoVXBkYXRlckFjY2Vzcy5sZXRSZWFkLCAjODYyKTogdGhlIEpWTSYjMzk7cyBvd24gZWRnZSBmb3IgYSB0cmFuc2Zvcm1lZCBjbGFzcyByZWFjaGVzIG9ubHkgdGhlIGFnZW50IGxvYWRlciYjMzk7cyB1bm5hbWVkIG1vZHVsZS4gVGhlIGxpYnJhcnkgcmVzb2x2ZXMgYW4gdXBkYXRlciBib3VuZCBiZWZvcmUgdGhlIGF0dGFjaCBieSByZWFkaW5nIHRoZSBKREsgaW1wbGVtZW50YXRpb24gZnJvbSB0aGF0IGNvcHkgKEpka1VwZGF0ZXJTaGFwZUNhbmFyeVRlc3QgcGlucyB0aGUgc2hhcGUgaXQgcmVhZHMpLCBhbmQgdGhlIG9wZW5pbmcgbXVzdCBmYWlsIHNpbGVudGx5IGxpa2UgdGhlIHJlc3Qgb2YgaW5zdGFsbC4gTm90aGluZyBtYXkgdGhyb3cgb3V0IG9mIHByZW1haW4g4oCUIGFuIGV4Y2VwdGlvbiB0aGVyZSBhYm9ydHMgSlZNIHN0YXJ0dXAsIHdoaWNoIGlzIHdoeSBpbnN0YWxsKCkgY2F0Y2hlcyBUaHJvd2FibGUgYW5kIHJlbGVhc2VzIHRoZSBnYXRlIHJhdGhlciB0aGFuIHByb3BhZ2F0aW5nLiBCb3RoIG1vZGVzIHVzZSBBZ2VudEJ1aWxkZXIuSW5pdGlhbGl6YXRpb25TdHJhdGVneS5Ob09wOiBubyB3ZWF2ZXIgbmVlZHMgYSBsb2FkZWQtdHlwZSBpbml0aWFsaXplciwgYW5kIEJ5dGUgQnVkZHkmIzM5O3MgZGVmYXVsdCBzZWxmLWluamVjdGlvbiBnYXZlIGV2ZXJ5IGNsYXNzIHdvdmVuIGF0IGxvYWQgYSAmbHQ7Y2xpbml0Jmd0OyB0aGF0IGxvYWRzIG5ldC5ieXRlYnVkZHkuZHluYW1pYy5OZXh1cyB0aHJvdWdoIHRoZSBzeXN0ZW0gY2xhc3MgbG9hZGVyLCB3aG9zZSBsb2NrIHZpcnR1YWwgdGhyZWFkcyBpbml0aWFsaXppbmcgY2xhc3NlcyBhdCBvbmNlIGNvbnRlbmQgb24gYW5kIHBpbiAoIzk4NCkuIFRoZSBQcmVtYWluLUNsYXNzIC8gQWdlbnQtQ2xhc3MgbWFuaWZlc3QgZW50cmllcyBsaXZlIGluIHRoaXMgbW9kdWxlJiMzOTtzIGphciwgd2hpY2ggaXMgd2h5IGF0dGFjaGluZyB1c2VzIC1qYXZhYWdlbnQ6YXN5bmMtdGVzdC1hZ2VudC5qYXIuPC9ub3RlPgogICAgPC9lbGVtZW50PgogIDwvY29yZV9lbGVtZW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8Y29yZV9lbGVtZW50cz4gYXJlIHdlbGwtdGVzdGVkIGNvcmUgY29tcG9uZW50cy4gTWFrZSBjaGFuZ2VzIHdpdGggZXh0cmVtZSBjYXV0aW9uIGFuZCB2ZXJpZnkgY29tcHJlaGVuc2l2ZSB0ZXN0IGNvdmVyYWdlIGJlZm9yZSBwcm9wb3NpbmcgbW9kaWZpY2F0aW9ucy48L3J1bGU+CiAgPGNvbnRyYWN0X3NpZ25hdHVyZXM+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkFnZW50T3B0aW9ucyI+CiAgICAgIDxyZWFzb24+VGhlIGNsYXNzIGlzIHBhY2thZ2UtcHJpdmF0ZSBidXQgdGhlIGFnZW50QXJncyBncmFtbWFyIGl0IHBhcnNlcyBpcyBwdWJsaWMgc3VyZmFjZTogdXNlcnMgdHlwZSBpdCBvbiB0aGUgLWphdmFhZ2VudDogY29tbWFuZCBsaW5lLiBLZXkgbmFtZXMgKGluY2x1ZGVzL2V4Y2x1ZGVzL2RlYnVnKSwgdGhlIGNvbW1hLW9yLXNlbWljb2xvbiBzZXBhcmF0b3IsIHRoZSBiYXJlLXRva2VuIGNvbnRpbnVhdGlvbiB0aGF0IGxldHMgb25lIGtleSBjYXJyeSBzZXZlcmFsIHZhbHVlcywgYW5kIGNhc2UtaW5zZW5zaXRpdmUga2V5IG1hdGNoaW5nIGFyZSBhbGwgcGFydCBvZiB0aGF0IGNvbnRyYWN0IOKAlCBjaGFuZ2luZyBhbnkgb2YgdGhlbSBicmVha3MgZXhpc3RpbmcgbGF1bmNoIHNjcmlwdHMgc2lsZW50bHkuIFBhcnNpbmcgbXVzdCBzdGF5IHRvdGFsOiBpdCBpcyBjYWxsZWQgZnJvbSBwcmVtYWluLCB3aGVyZSBhIHRocm93biBleGNlcHRpb24gYWJvcnRzIEpWTSBzdGFydHVwLCBzbyB1bmtub3duIGtleXMgYXJlIGlnbm9yZWQgYW5kIG1hbGZvcm1lZCBpbnB1dCBkZWdyYWRlcyB0byB0aGUgZGVmYXVsdCBpbnN0cnVtZW50LWV2ZXJ5dGhpbmcgYmVoYXZpb3VyIHJhdGhlciB0aGFuIGZhaWxpbmcuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkF0b21pY0ZpZWxkUmVnaXN0cnkiPgogICAgICA8cmVhc29uPlJlc29sdmVkIHJlZmxlY3RpdmVseSBzbyBhc3luYy10ZXN0LWFnZW50IGtlZXBzIGl0cyB6ZXJvLWRlcGVuZGVuY3kgYm91bmRhcnkgb24gYXN5bmMtdGVzdC1saWIsIHdoaWNoIEFyY2hpdGVjdHVyZVRlc3QgZW5mb3JjZXMgaW4gYm90aCBkaXJlY3Rpb25zLiBUaGUgbWV0aG9kIG5hbWUgYW5kIHNpZ25hdHVyZSBtdXN0IG1hdGNoIFRlbGVtZXRyeVJlZ2lzdHJ5LmF0b21pY2FsbHlNYW5hZ2VkKFN0cmluZykuIEV2ZXJ5IGZhaWx1cmUgcGF0aCBoZXJlIG11c3Qgc3RheSBzaWxlbnQ6IHRoaXMgb25seSBldmVyIHN1cHByZXNzZXMgZmluZGluZ3MsIHNvIGxvc2luZyBpdCBkZWdyYWRlcyBwcmVjaXNpb24gcmF0aGVyIHRoYW4gY29ycmVjdG5lc3MsIHdoaWxlIHRocm93aW5nIG91dCBvZiBhIGNsYXNzIHRyYW5zZm9ybWF0aW9uIHdvdWxkIGZhaWwgdGhlIHVzZXImIzM5O3MgdGVzdCBydW4uPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkNvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIiPgogICAgICA8cmVhc29uPlRoZSBob29rIGNsYXNzIG5hbWUgYW5kIHRoZSBtZXRob2QgbmFtZXMgaGVyZSBhcmUgdGhlIG90aGVyIGhhbGYgb2YgQWdlbnRDb2xsZWN0aW9uSG9va3MgYW5kIEFnZW50TG9ja0hvb2tzOiB0aGV5IGFyZSBtYXRjaGVkIGJ5IGVyYXNlZCBzaWduYXR1cmUgYXQgd2VhdmUgdGltZSwgc28gcmVuYW1pbmcgYSBob29rIG9yIGNoYW5naW5nIGEgcGFyYW1ldGVyIHR5cGUgYnJlYWtzIHdlYXZpbmcgd2l0aCBhIE5vU3VjaE1ldGhvZEVycm9yIGluc2lkZSB1c2VyIGNvZGUgcmF0aGVyIHRoYW4gYXQgY29tcGlsZSB0aW1lLiBFYWNoIHN1YnN0aXR1dGlvbiBtdXN0IGNvbnN1bWUgZXhhY3RseSB0aGUgc3RhY2sgaXRzIG9yaWdpbmFsIGludm9jYXRpb24gY29uc3VtZWQgLSBzdGFjay1zaGFwZS1uZXV0cmFsIGFuZCBtZW1iZXItZnJlZSBpcyB3aGF0IGtlZXBzIHJldHJhbnNmb3JtYXRpb24gc2FmZSB1bmRlciBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCkuIFRoZSB2aXNpdG9yIGNoYW5nZXMgZXhhY3RseSBvbmUga2luZCBvZiBpbnZva2VkeW5hbWljOiBhIExhbWJkYU1ldGFmYWN0b3J5IG1ldGFmYWN0b3J5IG9yIG5vbi1zZXJpYWxpemFibGUgYWx0TWV0YWZhY3Rvcnkgd2hvc2UgaW1wbGVtZW50YXRpb24gaGFuZGxlIG1hdGNoZXMgYSB0YWJsZSBlbnRyeSBpcyBwb2ludGVkIGF0IHRoYXQgZW50cnkmIzM5O3MgaG9vaywgc28gYSBtZXRob2QgcmVmZXJlbmNlIHN1Y2ggYXMgYnVpbGRlcjo6YXBwZW5kIGlzIG9ic2VydmVkICgjNTUwKS4gRXZlcnkgb3RoZXIgYm9vdHN0cmFwLCBPYmplY3RNZXRob2RzIGZvciByZWNvcmRzIGFib3ZlIGFsbCwgbXVzdCBwYXNzIHRocm91Z2ggYXMgdGhlIHNhbWUgYXJndW1lbnQgYXJyYXksIHJlYWQgb25seSB0aHJvdWdoIEFTTSYjMzk7cyBIYW5kbGU6IHBhcnNpbmcgYm9vdHN0cmFwIGNvbnN0YW50cyBpcyB3aGF0IG1hZGUgZXZlcnkgSmF2YSByZWNvcmQgZmFpbCB0byBpbnN0cnVtZW50IHdoZW4gdGhpcyB3ZW50IHRocm91Z2ggTWVtYmVyU3Vic3RpdHV0aW9uLCBhbmQgYSByZXdyaXR0ZW4gc2VyaWFsaXphYmxlIGxhbWJkYSB3b3VsZCBmYWlsIHRvIGRlc2VyaWFsaXplLiBDb2xsZWN0aW9uIHdlYXZpbmcgaXMgb3B0LWluIChjb2xsZWN0aW9ucz10cnVlKSBiZWNhdXNlIGl0IGluc3RydW1lbnRzIGV2ZXJ5IGxpc3RlZCBjYWxsIGluIGV2ZXJ5IG1hdGNoZWQgY2xhc3MuIFRoZSBvbmUtaW5zdHJ1Y3Rpb24gbG9va2FoZWFkIGJlaGluZCB3aGVuUmVzdWx0RGlzY2FyZGVkIGlzIGEgZmxhZyBtZWFuaW5nIHRoZSBpbnN0cnVjdGlvbiBqdXN0IGVtaXR0ZWQgd2FzIGEgc3Vic3RpdHV0ZWQgY2FsbCB3aG9zZSByZXN1bHQgbWF5IGJlIGRpc2NhcmRlZDogdmlzaXRJbnNuKFBPUCkgaXMgaXRzIG9ubHkgY29uc3VtZXIgYW5kIGV2ZXJ5IG90aGVyIHZpc2l0IG1ldGhvZCBtdXN0IGNsZWFyIGl0LCBiZWNhdXNlIGEgc3RhbGUgZmxhZyB3b3VsZCB0dXJuIGFuIHVucmVsYXRlZCBQT1AgaW50byBhIGNhbGwgd2hvc2UgcGFyYW1ldGVyIGRvZXMgbm90IG1hdGNoIHRoZSB2YWx1ZSBvbiB0aGUgc3RhY2ssIHdoaWNoIGlzIGEgVmVyaWZ5RXJyb3IgaW4gdGhlIHVzZXImIzM5O3MgY2xhc3MgYXQgbG9hZCB0aW1lLiBTdWJzdGl0dXRpbmdWaXNpdG9yQ2xlYXJzTG9va2FoZWFkRXZlcnl3aGVyZVRlc3QgZW51bWVyYXRlcyBNZXRob2RWaXNpdG9yIHRvIGtlZXAgdGhhdCBvdmVycmlkZSBsaXN0IGNvbXBsZXRlLiBJbnNpZGUgYSBzeW5jaHJvbml6ZWQgbWV0aG9kLCBhbiBlbnRyeSB3aXRoIGEgc3luY2hyb25pemVkIHZhcmlhbnQgKHRoZSBzbGVlcHMsIGFuZCB0aGUgcXVldWUgb2ZmZXJzIGFuZCB0YWtlcywgIzc5NikgZmlyc3QgbG9hZHMgdGhlIG1ldGhvZCYjMzk7cyBtb25pdG9yLCBBTE9BRCAwIG9yIGFuIExEQyBvZiB0aGUgY2xhc3MgZm9yIGEgc3RhdGljIG1ldGhvZCwgd2hpY2ggdGhlIHZhcmlhbnQgY29uc3VtZXMgYXMgaXRzIGxhc3QgcGFyYW1ldGVyOiBvbmUgbW9yZSB2YWx1ZSBhbmQgbm8gYnJhbmNoLCBzbyBvbmx5IG1heFN0YWNrIGdyb3dzLCBhbmQgdGhlIHN1YnN0aXR1dGlvbiB3cmFwcGVyIGFza3MgZm9yIENPTVBVVEVfTUFYUyBpdHNlbGYuIEEgcXVldWUgb2ZmZXIgb3IgdGFrZSBpbiBhbnkgb3RoZXIgaW5zdGFuY2UgbWV0aG9kIGxvYWRzIHRoaXMgdGhlIHNhbWUgd2F5IGZvciBpdHMgaG9vayB0byBwcm9iZSAoIzc1MSksIGV4Y2VwdCBpbiBhIGNvbnN0cnVjdG9yLCB3aGVyZSB0aGlzIG1heSBiZSB1bmluaXRpYWxpc2VkIGFuZCB3b3VsZCBub3QgdmVyaWZ5LCBhbmQgYWZ0ZXIgYSBzdG9yZSB0byBsb2NhbCAwLiBUaGUgb25lIGluc3RydWN0aW9uIHRoZSB2aXNpdG9yIGluc2VydHMgb3V0c2lkZSBhIHN1YnN0aXR1dGlvbiBpcyB0aGUgbG9vcCBiYWNrLWVkZ2UgY2FsbCBpbiBmcm9udCBvZiBhIGp1bXAgdGhhdCBjb21lcyBiYWNrIG92ZXIgYSB3b3ZlbiBPYmplY3Qud2FpdCAoIzY5NCk6IGl0IG11c3Qgc3RheSBhIHN0YXRpYyAoKVYgY2FsbCwgYmVjYXVzZSB0aGUganVtcCYjMzk7cyBvcGVyYW5kcyBhcmUgYWxyZWFkeSBvbiB0aGUgc3RhY2sgYmVuZWF0aCBpdCBhbmQgYW55dGhpbmcgdGhhdCB0b29rIG9yIGxlZnQgYSB2YWx1ZSwgb3IgYWRkZWQgYSBicmFuY2gsIHdvdWxkIG5lZWQgdGhlIGZyYW1lcyBDT01QVVRFX01BWFMgZG9lcyBub3QgcmVjb21wdXRlLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogIDwvY29udHJhY3Rfc2lnbmF0dXJlcz4KCjxydWxlPllvdSBtYXkgcmVmYWN0b3IgdGhlIGludGVybmFsIGxvZ2ljIG9mIGVsZW1lbnRzIGxpc3RlZCBpbiA8Y29udHJhY3Rfc2lnbmF0dXJlcz4sIGJ1dCB5b3UgTVVTVCBOT1QgY2hhbmdlIHRoZWlyIHB1YmxpYyBzaWduYXR1cmVzOiBtZXRob2QgbmFtZXMsIHBhcmFtZXRlciB0eXBlcywgcGFyYW1ldGVyIG9yZGVyLCByZXR1cm4gdHlwZXMsIG9yIGNoZWNrZWQgZXhjZXB0aW9ucy48L3J1bGU+CjwvcHJvamVjdF9ndWFyZHJhaWxzPgoKPHJ1bGU+TmV2ZXIgcHJvcG9zZSBlZGl0cyB0byBmaWxlcyBsaXN0ZWQgaW4gPGxvY2tlZF9maWxlcz4uPC9ydWxlPgo= +gemini_md=IyBHRU1JTkkgQUkgSU5TVFJVQ1RJT05TCiMgR2VuZXJhdGVkIGJ5IFZpYmVUYWdzIHwgaHR0cHM6Ly9naXRodWIuY29tL1BJc2JlcmcvdmliZXRhZ3MKCiMjIENPUkUgRlVOQ1RJT05BTElUWSAoRVhUUkVNRSBDQVVUSU9OKQpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbjoKCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYWdlbnQuQXN5bmNUZXN0QWdlbnRgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IFRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvcidzIHN1cGVyY2xhc3MgY2FsbCAoIzczNykuIENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgY2FsbCB0aGF0IGNvbnN1bWVzIGFuZCByZXR1cm5zIHRoZSBvcmRlciBhcmd1bWVudCBiZWZvcmUgYSBMaW5rZWRIYXNoTWFwKGludCwgZmxvYXQsIGJvb2xlYW4pIGNvbnN0cnVjdG9yIGNhbGwgYW5kIGEgRFVQIG9yIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgaXQgKCM4MDcpLCBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciBhIG5ldyBDb21wbGV0YWJsZUZ1dHVyZSgpIGNvbnN0cnVjdG9yIGNhbGwgKCMxMDU0KSwgYW5kIGFuIEFMT0FEIDAsIGFuIExEQyBvZiB0aGUgY2xhc3MgbmFtZSBhbmQgYSBjYWxsIGJlZm9yZSBlYWNoIFJFVFVSTiBvZiBhIGNvbnN0cnVjdG9yIGFuZCBhZnRlciBhIHRoaXMoLi4uKSBkZWxlZ2F0aW9uICgjNzkxKTsgaXQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gSW50ZXJydXB0SGFuZGxlcldlYXZlciBpbnNlcnRzIGFuIExEQyBvZiB0aGUgbG9jYXRpb25zIG9mIGEgbWV0aG9kJ3MgSW50ZXJydXB0ZWRFeGNlcHRpb24gaGFuZGxlcnMgdGhhdCBuZWl0aGVyIHJldGhyb3cgbm9yIHJlc3RvcmUgdGhlIGZsYWcsIGFuZCBhIGNhbGwsIGJlZm9yZSB0aGUgZmlyc3QgaW5zdHJ1Y3Rpb24gb2YgYSBtZXRob2QgdGhhdCBkZWNsYXJlcyBvbmUsIGFuZCBsZWF2ZXMgYWxvbmUgYSBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSB0aGF0IGNhbm5vdCByZWFkIHRoZSBsaWJyYXJ5LiBQZXJzaXN0ZW5jZUhhbmRsZVdlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBjYWxsIHdob3NlIG93bmVyIGlzIGEgSlBBIEVudGl0eU1hbmFnZXIgb3IgSGliZXJuYXRlIFNlc3Npb24gYnkgbmFtZSwgYSBzdGFjay1uZXV0cmFsIGNvcHkgb2YgdGhlIHJlY2VpdmVyIChEVVA7IFNXQVAsIERVUF9YMTsgb3IgRFVQMl9YMSwgUE9QMiwgRFVQX1gyIGZvciB6ZXJvLCBvbmUgb3IgdHdvIG9uZS1zbG90IGFyZ3VtZW50cykgYW5kIGEgY2FsbCwgYW5kIGxlYXZlcyBjYWxscyB3aXRoIG1vcmUgb3Igd2lkZXIgYXJndW1lbnRzIGFsb25lICgjOTkyKS4gUnVuQmxvY2tpbmdXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgc3RhdGljIGNhbGwgb2Yga290bGlueC5jb3JvdXRpbmVzLkJ1aWxkZXJzS3QucnVuQmxvY2tpbmdLLCBydW5CbG9ja2luZyBvciB0aGVpciAkZGVmYXVsdCBicmlkZ2VzIGJ5IG5hbWUsIG9uZSBjYWxsIG9mIGEgKClWIGhvb2sgdGhhdCB0YWtlcyBhbmQgbGVhdmVzIG5vdGhpbmcsIGluIGV2ZXJ5IHdvdmVuIGNsYXNzIG91dHNpZGUga290bGlueC5jb3JvdXRpbmVzICgjMTAwNykuIEtvdGxpbk11dGV4V2VhdmVyIHJlcGxhY2VzIGEga290bGlueC5jb3JvdXRpbmVzLnN5bmMuTXV0ZXggbG9jaywgdW5sb2NrIG9yIHRyeUxvY2sgY2FsbCwgb3IgaXRzIHN0YXRpYyAkZGVmYXVsdCBicmlkZ2UsIG1hdGNoZWQgYnkgb3duZXIsIG5hbWUgYW5kIGRlc2NyaXB0b3IsIHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2sgYW5kIHJldHVybmluZyB0aGUgc2FtZSByZXN1bHQsIGluIGV2ZXJ5IHdvdmVuIGNsYXNzIG91dHNpZGUga290bGlueC5jb3JvdXRpbmVzICgjMTAwNykuIFNvIGZyYW1lcyBzdGF5IHZhbGlkIGFuZCBvbmx5IG1heFN0YWNrIGdyb3dzIChDT01QVVRFX01BWFMsIG5ldmVyIENPTVBVVEVfRlJBTUVTLCB3aGljaCB3b3VsZCBsb2FkIGNsYXNzZXMgZnJvbSBpbnNpZGUgdGhlIGFnZW50KS4gSW4gZXZlcnkgbW9kZSwgaW5zdGFsbCBhbmQgdGhlIHRyYW5zZm9ybWVyIG9wZW4gamF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MsIHdpdGggZmllbGRzPXRydWUgYWxzbyBqYXZhLnV0aWwuY29uY3VycmVudC5hdG9taWMsIGFuZCB3aXRoIGNvbGxlY3Rpb25zPXRydWUgYWxzbyBqYXZhLnV0aWwgYW5kIGphdmEuaW8gKGEgc3luY2hyb25pemVkIHdyYXBwZXIncyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXIncyBzaW5rLCAjOTk0KSwgdG8gb25lIG1vZHVsZSBwZXIgd292ZW4gbG9hZGVyIGFuZCB0byBub3RoaW5nIGVsc2U6IHRoZSBtb2R1bGUgb2YgdGhlIFRlbGVtZXRyeVJlZ2lzdHJ5IGNvcHkgdGhhdCBsb2FkZXIgcmVzb2x2ZXMsIG5ldmVyIHRoZSB3b3ZlbiBsb2FkZXIgb3IgaXRzIGFuY2VzdG9ycyBhcyBzdWNoIChVcGRhdGVyQWNjZXNzLCAjNjU5LCAjNjY4LCAjODU1KTsgdGhlIGxvY2tzIG9wZW5pbmcgbGV0cyB0aGUgbGlicmFyeSByZWFkIGEgUmVlbnRyYW50TG9jayBvd25lciBhdCBhbmFseXNpcy4gSW4gZXZlcnkgbW9kZSwgYSB3b3ZlbiBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSBnZXRzIGEgcmVhZCBlZGdlIHRvIHRoZSBsaWJyYXJ5IGNvcHkgaXRzIGxvYWRlciByZXNvbHZlcyAoVXBkYXRlckFjY2Vzcy5sZXRSZWFkLCAjODYyKTogdGhlIEpWTSdzIG93biBlZGdlIGZvciBhIHRyYW5zZm9ybWVkIGNsYXNzIHJlYWNoZXMgb25seSB0aGUgYWdlbnQgbG9hZGVyJ3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5J3MgZGVmYXVsdCBzZWxmLWluamVjdGlvbiBnYXZlIGV2ZXJ5IGNsYXNzIHdvdmVuIGF0IGxvYWQgYSA8Y2xpbml0PiB0aGF0IGxvYWRzIG5ldC5ieXRlYnVkZHkuZHluYW1pYy5OZXh1cyB0aHJvdWdoIHRoZSBzeXN0ZW0gY2xhc3MgbG9hZGVyLCB3aG9zZSBsb2NrIHZpcnR1YWwgdGhyZWFkcyBpbml0aWFsaXppbmcgY2xhc3NlcyBhdCBvbmNlIGNvbnRlbmQgb24gYW5kIHBpbiAoIzk4NCkuIFRoZSBQcmVtYWluLUNsYXNzIC8gQWdlbnQtQ2xhc3MgbWFuaWZlc3QgZW50cmllcyBsaXZlIGluIHRoaXMgbW9kdWxlJ3MgamFyLCB3aGljaCBpcyB3aHkgYXR0YWNoaW5nIHVzZXMgLWphdmFhZ2VudDphc3luYy10ZXN0LWFnZW50Lmphci4KCiMjIFNjb3BlZCBSdWxlcyBJbmRleApEZXRhaWxlZCBwZXItZWxlbWVudCBndWFyZHJhaWxzIGxpdmUgaW4gc2NvcGVkIHJ1bGUgZmlsZXMgdGhhdCBHZW1pbmkgQ0xJIGRvZXMgbm90IGxvYWQgb24gaXRzIG93bi4gQSBsaW5lIGBhLmJgOiBgQ2AsIGBEYCBuYW1lcyBhLmIuQyBhbmQgYS5iLkQuIFVubGVzcyBhbiBlbnRyeSBjYXJyaWVzIGFuIGV4cGxpY2l0IHBhdGgsIGl0cyBmaWxlIGlzIC5nZW1pbmkvcnVsZXMve3BhdGgsIGV2ZXJ5IG5vbi1hbHBoYW51bWVyaWMgY2hhcmFjdGVyIHJlcGxhY2VkIGJ5ICctJ30ubWQuIEJlZm9yZSBtb2RpZnlpbmcgYW4gZWxlbWVudCBsaXN0ZWQgYmVsb3csIG9wZW4gaXRzIGZpbGUgd2l0aCByZWFkX2ZpbGUgYW5kIGFwcGx5IHRoZSBndWFyZHJhaWxzIHRoZXJlOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5hZ2VudGA6IGBBZ2VudE9wdGlvbnNgLCBgQXRvbWljRmllbGRSZWdpc3RyeWAsIGBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24ubWRgCg== +~mod~claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxjb3JlX2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5hZ2VudC5Bc3luY1Rlc3RBZ2VudCI+CiAgICAgIDxzZW5zaXRpdml0eT5Dcml0aWNhbDwvc2Vuc2l0aXZpdHk+CiAgICAgIDxub3RlPlRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvciYjMzk7cyBzdXBlcmNsYXNzIGNhbGwgKCM3MzcpLiBDb25zdHJ1Y3Rpb25XZWF2ZXIgaW5zZXJ0cyBhIGNhbGwgdGhhdCBjb25zdW1lcyBhbmQgcmV0dXJucyB0aGUgb3JkZXIgYXJndW1lbnQgYmVmb3JlIGEgTGlua2VkSGFzaE1hcChpbnQsIGZsb2F0LCBib29sZWFuKSBjb25zdHJ1Y3RvciBjYWxsIGFuZCBhIERVUCBvciBhbiBBTE9BRCAwIHBsdXMgYSBjYWxsIGFmdGVyIGl0ICgjODA3KSwgYSBEVVAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBuZXcgQ29tcGxldGFibGVGdXR1cmUoKSBjb25zdHJ1Y3RvciBjYWxsICgjMTA1NCksIGFuZCBhbiBBTE9BRCAwLCBhbiBMREMgb2YgdGhlIGNsYXNzIG5hbWUgYW5kIGEgY2FsbCBiZWZvcmUgZWFjaCBSRVRVUk4gb2YgYSBjb25zdHJ1Y3RvciBhbmQgYWZ0ZXIgYSB0aGlzKC4uLikgZGVsZWdhdGlvbiAoIzc5MSk7IGl0IGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIEludGVycnVwdEhhbmRsZXJXZWF2ZXIgaW5zZXJ0cyBhbiBMREMgb2YgdGhlIGxvY2F0aW9ucyBvZiBhIG1ldGhvZCYjMzk7cyBJbnRlcnJ1cHRlZEV4Y2VwdGlvbiBoYW5kbGVycyB0aGF0IG5laXRoZXIgcmV0aHJvdyBub3IgcmVzdG9yZSB0aGUgZmxhZywgYW5kIGEgY2FsbCwgYmVmb3JlIHRoZSBmaXJzdCBpbnN0cnVjdGlvbiBvZiBhIG1ldGhvZCB0aGF0IGRlY2xhcmVzIG9uZSwgYW5kIGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIFBlcnNpc3RlbmNlSGFuZGxlV2VhdmVyIGluc2VydHMsIGJlZm9yZSBhIGNhbGwgd2hvc2Ugb3duZXIgaXMgYSBKUEEgRW50aXR5TWFuYWdlciBvciBIaWJlcm5hdGUgU2Vzc2lvbiBieSBuYW1lLCBhIHN0YWNrLW5ldXRyYWwgY29weSBvZiB0aGUgcmVjZWl2ZXIgKERVUDsgU1dBUCwgRFVQX1gxOyBvciBEVVAyX1gxLCBQT1AyLCBEVVBfWDIgZm9yIHplcm8sIG9uZSBvciB0d28gb25lLXNsb3QgYXJndW1lbnRzKSBhbmQgYSBjYWxsLCBhbmQgbGVhdmVzIGNhbGxzIHdpdGggbW9yZSBvciB3aWRlciBhcmd1bWVudHMgYWxvbmUgKCM5OTIpLiBSdW5CbG9ja2luZ1dlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBzdGF0aWMgY2FsbCBvZiBrb3RsaW54LmNvcm91dGluZXMuQnVpbGRlcnNLdC5ydW5CbG9ja2luZ0ssIHJ1bkJsb2NraW5nIG9yIHRoZWlyICRkZWZhdWx0IGJyaWRnZXMgYnkgbmFtZSwgb25lIGNhbGwgb2YgYSAoKVYgaG9vayB0aGF0IHRha2VzIGFuZCBsZWF2ZXMgbm90aGluZywgaW4gZXZlcnkgd292ZW4gY2xhc3Mgb3V0c2lkZSBrb3RsaW54LmNvcm91dGluZXMgKCMxMDA3KS4gS290bGluTXV0ZXhXZWF2ZXIgcmVwbGFjZXMgYSBrb3RsaW54LmNvcm91dGluZXMuc3luYy5NdXRleCBsb2NrLCB1bmxvY2sgb3IgdHJ5TG9jayBjYWxsLCBvciBpdHMgc3RhdGljICRkZWZhdWx0IGJyaWRnZSwgbWF0Y2hlZCBieSBvd25lciwgbmFtZSBhbmQgZGVzY3JpcHRvciwgd2l0aCBhIHN0YXRpYyBob29rIGNvbnN1bWluZyB0aGUgc2FtZSBzdGFjayBhbmQgcmV0dXJuaW5nIHRoZSBzYW1lIHJlc3VsdCwgaW4gZXZlcnkgd292ZW4gY2xhc3Mgb3V0c2lkZSBrb3RsaW54LmNvcm91dGluZXMgKCMxMDA3KS4gU28gZnJhbWVzIHN0YXkgdmFsaWQgYW5kIG9ubHkgbWF4U3RhY2sgZ3Jvd3MgKENPTVBVVEVfTUFYUywgbmV2ZXIgQ09NUFVURV9GUkFNRVMsIHdoaWNoIHdvdWxkIGxvYWQgY2xhc3NlcyBmcm9tIGluc2lkZSB0aGUgYWdlbnQpLiBJbiBldmVyeSBtb2RlLCBpbnN0YWxsIGFuZCB0aGUgdHJhbnNmb3JtZXIgb3BlbiBqYXZhLnV0aWwuY29uY3VycmVudC5sb2Nrcywgd2l0aCBmaWVsZHM9dHJ1ZSBhbHNvIGphdmEudXRpbC5jb25jdXJyZW50LmF0b21pYywgYW5kIHdpdGggY29sbGVjdGlvbnM9dHJ1ZSBhbHNvIGphdmEudXRpbCBhbmQgamF2YS5pbyAoYSBzeW5jaHJvbml6ZWQgd3JhcHBlciYjMzk7cyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXImIzM5O3Mgc2luaywgIzk5NCksIHRvIG9uZSBtb2R1bGUgcGVyIHdvdmVuIGxvYWRlciBhbmQgdG8gbm90aGluZyBlbHNlOiB0aGUgbW9kdWxlIG9mIHRoZSBUZWxlbWV0cnlSZWdpc3RyeSBjb3B5IHRoYXQgbG9hZGVyIHJlc29sdmVzLCBuZXZlciB0aGUgd292ZW4gbG9hZGVyIG9yIGl0cyBhbmNlc3RvcnMgYXMgc3VjaCAoVXBkYXRlckFjY2VzcywgIzY1OSwgIzY2OCwgIzg1NSk7IHRoZSBsb2NrcyBvcGVuaW5nIGxldHMgdGhlIGxpYnJhcnkgcmVhZCBhIFJlZW50cmFudExvY2sgb3duZXIgYXQgYW5hbHlzaXMuIEluIGV2ZXJ5IG1vZGUsIGEgd292ZW4gY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgZ2V0cyBhIHJlYWQgZWRnZSB0byB0aGUgbGlicmFyeSBjb3B5IGl0cyBsb2FkZXIgcmVzb2x2ZXMgKFVwZGF0ZXJBY2Nlc3MubGV0UmVhZCwgIzg2Mik6IHRoZSBKVk0mIzM5O3Mgb3duIGVkZ2UgZm9yIGEgdHJhbnNmb3JtZWQgY2xhc3MgcmVhY2hlcyBvbmx5IHRoZSBhZ2VudCBsb2FkZXImIzM5O3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5JiMzOTtzIGRlZmF1bHQgc2VsZi1pbmplY3Rpb24gZ2F2ZSBldmVyeSBjbGFzcyB3b3ZlbiBhdCBsb2FkIGEgJmx0O2NsaW5pdCZndDsgdGhhdCBsb2FkcyBuZXQuYnl0ZWJ1ZGR5LmR5bmFtaWMuTmV4dXMgdGhyb3VnaCB0aGUgc3lzdGVtIGNsYXNzIGxvYWRlciwgd2hvc2UgbG9jayB2aXJ0dWFsIHRocmVhZHMgaW5pdGlhbGl6aW5nIGNsYXNzZXMgYXQgb25jZSBjb250ZW5kIG9uIGFuZCBwaW4gKCM5ODQpLiBUaGUgUHJlbWFpbi1DbGFzcyAvIEFnZW50LUNsYXNzIG1hbmlmZXN0IGVudHJpZXMgbGl2ZSBpbiB0aGlzIG1vZHVsZSYjMzk7cyBqYXIsIHdoaWNoIGlzIHdoeSBhdHRhY2hpbmcgdXNlcyAtamF2YWFnZW50OmFzeW5jLXRlc3QtYWdlbnQuamFyLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICA8L2NvcmVfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBsaXN0ZWQgaW4gPGNvcmVfZWxlbWVudHM+IGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbiBhbmQgdmVyaWZ5IGNvbXByZWhlbnNpdmUgdGVzdCBjb3ZlcmFnZSBiZWZvcmUgcHJvcG9zaW5nIG1vZGlmaWNhdGlvbnMuPC9ydWxlPgogIDxzY29wZWRfcnVsZXM+CiAgICA8bm90ZT5EZXRhaWxlZCBwZXItZWxlbWVudCBndWFyZHJhaWxzIGZvciB0aGUgZWxlbWVudHMgYmVsb3cgbGl2ZSBpbiBzY29wZWQgcnVsZSBmaWxlcyB0aGF0IGxvYWQgYXV0b21hdGljYWxseSB3aGVuIHRoZSBtYXRjaGluZyBzb3VyY2UgZmlsZSBpcyBvcGVuZWQuIEFuIGVsZW1lbnRzIGVudHJ5IGxpc3RzIG5hbWVzIHVuZGVyIGEgc2hhcmVkIHByZWZpeDogaW49ImEuYiIgbGlzdGluZyBDLCBEIG1lYW5zIGEuYi5DIGFuZCBhLmIuRC4gVW5sZXNzIGFuIGVudHJ5IGNhcnJpZXMgYW4gZXhwbGljaXQgcGF0aCwgaXRzIGZpbGUgaXMgLmNsYXVkZS9ydWxlcy97cGF0aCwgZXZlcnkgbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXIgcmVwbGFjZWQgYnkgJiMzOTstJiMzOTt9Lm1kLiBDb25zdWx0IHRoZSBmaWxlIGJlZm9yZSBtb2RpZnlpbmcgYW4gZWxlbWVudC48L25vdGU+CiAgICA8ZWxlbWVudHMgaW49InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYWdlbnQiPkFnZW50T3B0aW9ucywgQXRvbWljRmllbGRSZWdpc3RyeSwgQ29sbGVjdGlvbkFjY2Vzc1dlYXZlcjwvZWxlbWVudHM+CiAgPC9zY29wZWRfcnVsZXM+Cgo8cnVsZT5XaGVuIHlvdSB3b3JrIG9uIGFueSBlbGVtZW50IGxpc3RlZCBpbiA8c2NvcGVkX3J1bGVzPiwgb3BlbiBpdHMgcmVmZXJlbmNlZCBydWxlIGZpbGUgYW5kIGFwcGx5IHRoZSBndWFyZHJhaWxzIHRoZXJlLiBUaGUgcnVsZSBmaWxlcyBhcmUgdGhlIGF1dGhvcml0YXRpdmUgc291cmNlIGZvciB0aG9zZSBlbGVtZW50cy48L3J1bGU+CjwvcHJvamVjdF9ndWFyZHJhaWxzPgo= +~idx~claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxjb3JlX2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5hZ2VudC5Bc3luY1Rlc3RBZ2VudCI+CiAgICAgIDxzZW5zaXRpdml0eT5Dcml0aWNhbDwvc2Vuc2l0aXZpdHk+CiAgICAgIDxub3RlPlRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvciYjMzk7cyBzdXBlcmNsYXNzIGNhbGwgKCM3MzcpLiBDb25zdHJ1Y3Rpb25XZWF2ZXIgaW5zZXJ0cyBhIGNhbGwgdGhhdCBjb25zdW1lcyBhbmQgcmV0dXJucyB0aGUgb3JkZXIgYXJndW1lbnQgYmVmb3JlIGEgTGlua2VkSGFzaE1hcChpbnQsIGZsb2F0LCBib29sZWFuKSBjb25zdHJ1Y3RvciBjYWxsIGFuZCBhIERVUCBvciBhbiBBTE9BRCAwIHBsdXMgYSBjYWxsIGFmdGVyIGl0ICgjODA3KSwgYSBEVVAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBuZXcgQ29tcGxldGFibGVGdXR1cmUoKSBjb25zdHJ1Y3RvciBjYWxsICgjMTA1NCksIGFuZCBhbiBBTE9BRCAwLCBhbiBMREMgb2YgdGhlIGNsYXNzIG5hbWUgYW5kIGEgY2FsbCBiZWZvcmUgZWFjaCBSRVRVUk4gb2YgYSBjb25zdHJ1Y3RvciBhbmQgYWZ0ZXIgYSB0aGlzKC4uLikgZGVsZWdhdGlvbiAoIzc5MSk7IGl0IGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIEludGVycnVwdEhhbmRsZXJXZWF2ZXIgaW5zZXJ0cyBhbiBMREMgb2YgdGhlIGxvY2F0aW9ucyBvZiBhIG1ldGhvZCYjMzk7cyBJbnRlcnJ1cHRlZEV4Y2VwdGlvbiBoYW5kbGVycyB0aGF0IG5laXRoZXIgcmV0aHJvdyBub3IgcmVzdG9yZSB0aGUgZmxhZywgYW5kIGEgY2FsbCwgYmVmb3JlIHRoZSBmaXJzdCBpbnN0cnVjdGlvbiBvZiBhIG1ldGhvZCB0aGF0IGRlY2xhcmVzIG9uZSwgYW5kIGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIFBlcnNpc3RlbmNlSGFuZGxlV2VhdmVyIGluc2VydHMsIGJlZm9yZSBhIGNhbGwgd2hvc2Ugb3duZXIgaXMgYSBKUEEgRW50aXR5TWFuYWdlciBvciBIaWJlcm5hdGUgU2Vzc2lvbiBieSBuYW1lLCBhIHN0YWNrLW5ldXRyYWwgY29weSBvZiB0aGUgcmVjZWl2ZXIgKERVUDsgU1dBUCwgRFVQX1gxOyBvciBEVVAyX1gxLCBQT1AyLCBEVVBfWDIgZm9yIHplcm8sIG9uZSBvciB0d28gb25lLXNsb3QgYXJndW1lbnRzKSBhbmQgYSBjYWxsLCBhbmQgbGVhdmVzIGNhbGxzIHdpdGggbW9yZSBvciB3aWRlciBhcmd1bWVudHMgYWxvbmUgKCM5OTIpLiBSdW5CbG9ja2luZ1dlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBzdGF0aWMgY2FsbCBvZiBrb3RsaW54LmNvcm91dGluZXMuQnVpbGRlcnNLdC5ydW5CbG9ja2luZ0ssIHJ1bkJsb2NraW5nIG9yIHRoZWlyICRkZWZhdWx0IGJyaWRnZXMgYnkgbmFtZSwgb25lIGNhbGwgb2YgYSAoKVYgaG9vayB0aGF0IHRha2VzIGFuZCBsZWF2ZXMgbm90aGluZywgaW4gZXZlcnkgd292ZW4gY2xhc3Mgb3V0c2lkZSBrb3RsaW54LmNvcm91dGluZXMgKCMxMDA3KS4gS290bGluTXV0ZXhXZWF2ZXIgcmVwbGFjZXMgYSBrb3RsaW54LmNvcm91dGluZXMuc3luYy5NdXRleCBsb2NrLCB1bmxvY2sgb3IgdHJ5TG9jayBjYWxsLCBvciBpdHMgc3RhdGljICRkZWZhdWx0IGJyaWRnZSwgbWF0Y2hlZCBieSBvd25lciwgbmFtZSBhbmQgZGVzY3JpcHRvciwgd2l0aCBhIHN0YXRpYyBob29rIGNvbnN1bWluZyB0aGUgc2FtZSBzdGFjayBhbmQgcmV0dXJuaW5nIHRoZSBzYW1lIHJlc3VsdCwgaW4gZXZlcnkgd292ZW4gY2xhc3Mgb3V0c2lkZSBrb3RsaW54LmNvcm91dGluZXMgKCMxMDA3KS4gU28gZnJhbWVzIHN0YXkgdmFsaWQgYW5kIG9ubHkgbWF4U3RhY2sgZ3Jvd3MgKENPTVBVVEVfTUFYUywgbmV2ZXIgQ09NUFVURV9GUkFNRVMsIHdoaWNoIHdvdWxkIGxvYWQgY2xhc3NlcyBmcm9tIGluc2lkZSB0aGUgYWdlbnQpLiBJbiBldmVyeSBtb2RlLCBpbnN0YWxsIGFuZCB0aGUgdHJhbnNmb3JtZXIgb3BlbiBqYXZhLnV0aWwuY29uY3VycmVudC5sb2Nrcywgd2l0aCBmaWVsZHM9dHJ1ZSBhbHNvIGphdmEudXRpbC5jb25jdXJyZW50LmF0b21pYywgYW5kIHdpdGggY29sbGVjdGlvbnM9dHJ1ZSBhbHNvIGphdmEudXRpbCBhbmQgamF2YS5pbyAoYSBzeW5jaHJvbml6ZWQgd3JhcHBlciYjMzk7cyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXImIzM5O3Mgc2luaywgIzk5NCksIHRvIG9uZSBtb2R1bGUgcGVyIHdvdmVuIGxvYWRlciBhbmQgdG8gbm90aGluZyBlbHNlOiB0aGUgbW9kdWxlIG9mIHRoZSBUZWxlbWV0cnlSZWdpc3RyeSBjb3B5IHRoYXQgbG9hZGVyIHJlc29sdmVzLCBuZXZlciB0aGUgd292ZW4gbG9hZGVyIG9yIGl0cyBhbmNlc3RvcnMgYXMgc3VjaCAoVXBkYXRlckFjY2VzcywgIzY1OSwgIzY2OCwgIzg1NSk7IHRoZSBsb2NrcyBvcGVuaW5nIGxldHMgdGhlIGxpYnJhcnkgcmVhZCBhIFJlZW50cmFudExvY2sgb3duZXIgYXQgYW5hbHlzaXMuIEluIGV2ZXJ5IG1vZGUsIGEgd292ZW4gY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgZ2V0cyBhIHJlYWQgZWRnZSB0byB0aGUgbGlicmFyeSBjb3B5IGl0cyBsb2FkZXIgcmVzb2x2ZXMgKFVwZGF0ZXJBY2Nlc3MubGV0UmVhZCwgIzg2Mik6IHRoZSBKVk0mIzM5O3Mgb3duIGVkZ2UgZm9yIGEgdHJhbnNmb3JtZWQgY2xhc3MgcmVhY2hlcyBvbmx5IHRoZSBhZ2VudCBsb2FkZXImIzM5O3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5JiMzOTtzIGRlZmF1bHQgc2VsZi1pbmplY3Rpb24gZ2F2ZSBldmVyeSBjbGFzcyB3b3ZlbiBhdCBsb2FkIGEgJmx0O2NsaW5pdCZndDsgdGhhdCBsb2FkcyBuZXQuYnl0ZWJ1ZGR5LmR5bmFtaWMuTmV4dXMgdGhyb3VnaCB0aGUgc3lzdGVtIGNsYXNzIGxvYWRlciwgd2hvc2UgbG9jayB2aXJ0dWFsIHRocmVhZHMgaW5pdGlhbGl6aW5nIGNsYXNzZXMgYXQgb25jZSBjb250ZW5kIG9uIGFuZCBwaW4gKCM5ODQpLiBUaGUgUHJlbWFpbi1DbGFzcyAvIEFnZW50LUNsYXNzIG1hbmlmZXN0IGVudHJpZXMgbGl2ZSBpbiB0aGlzIG1vZHVsZSYjMzk7cyBqYXIsIHdoaWNoIGlzIHdoeSBhdHRhY2hpbmcgdXNlcyAtamF2YWFnZW50OmFzeW5jLXRlc3QtYWdlbnQuamFyLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICA8L2NvcmVfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBsaXN0ZWQgaW4gPGNvcmVfZWxlbWVudHM+IGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbiBhbmQgdmVyaWZ5IGNvbXByZWhlbnNpdmUgdGVzdCBjb3ZlcmFnZSBiZWZvcmUgcHJvcG9zaW5nIG1vZGlmaWNhdGlvbnMuPC9ydWxlPgo8L3Byb2plY3RfZ3VhcmRyYWlscz4K +~idx~gemini_md=IyBHRU1JTkkgQUkgSU5TVFJVQ1RJT05TCiMgR2VuZXJhdGVkIGJ5IFZpYmVUYWdzIHwgaHR0cHM6Ly9naXRodWIuY29tL1BJc2JlcmcvdmliZXRhZ3MKCiMjIENPUkUgRlVOQ1RJT05BTElUWSAoRVhUUkVNRSBDQVVUSU9OKQpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbjoKCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYWdlbnQuQXN5bmNUZXN0QWdlbnRgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IFRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvcidzIHN1cGVyY2xhc3MgY2FsbCAoIzczNykuIENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgY2FsbCB0aGF0IGNvbnN1bWVzIGFuZCByZXR1cm5zIHRoZSBvcmRlciBhcmd1bWVudCBiZWZvcmUgYSBMaW5rZWRIYXNoTWFwKGludCwgZmxvYXQsIGJvb2xlYW4pIGNvbnN0cnVjdG9yIGNhbGwgYW5kIGEgRFVQIG9yIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgaXQgKCM4MDcpLCBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciBhIG5ldyBDb21wbGV0YWJsZUZ1dHVyZSgpIGNvbnN0cnVjdG9yIGNhbGwgKCMxMDU0KSwgYW5kIGFuIEFMT0FEIDAsIGFuIExEQyBvZiB0aGUgY2xhc3MgbmFtZSBhbmQgYSBjYWxsIGJlZm9yZSBlYWNoIFJFVFVSTiBvZiBhIGNvbnN0cnVjdG9yIGFuZCBhZnRlciBhIHRoaXMoLi4uKSBkZWxlZ2F0aW9uICgjNzkxKTsgaXQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gSW50ZXJydXB0SGFuZGxlcldlYXZlciBpbnNlcnRzIGFuIExEQyBvZiB0aGUgbG9jYXRpb25zIG9mIGEgbWV0aG9kJ3MgSW50ZXJydXB0ZWRFeGNlcHRpb24gaGFuZGxlcnMgdGhhdCBuZWl0aGVyIHJldGhyb3cgbm9yIHJlc3RvcmUgdGhlIGZsYWcsIGFuZCBhIGNhbGwsIGJlZm9yZSB0aGUgZmlyc3QgaW5zdHJ1Y3Rpb24gb2YgYSBtZXRob2QgdGhhdCBkZWNsYXJlcyBvbmUsIGFuZCBsZWF2ZXMgYWxvbmUgYSBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSB0aGF0IGNhbm5vdCByZWFkIHRoZSBsaWJyYXJ5LiBQZXJzaXN0ZW5jZUhhbmRsZVdlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBjYWxsIHdob3NlIG93bmVyIGlzIGEgSlBBIEVudGl0eU1hbmFnZXIgb3IgSGliZXJuYXRlIFNlc3Npb24gYnkgbmFtZSwgYSBzdGFjay1uZXV0cmFsIGNvcHkgb2YgdGhlIHJlY2VpdmVyIChEVVA7IFNXQVAsIERVUF9YMTsgb3IgRFVQMl9YMSwgUE9QMiwgRFVQX1gyIGZvciB6ZXJvLCBvbmUgb3IgdHdvIG9uZS1zbG90IGFyZ3VtZW50cykgYW5kIGEgY2FsbCwgYW5kIGxlYXZlcyBjYWxscyB3aXRoIG1vcmUgb3Igd2lkZXIgYXJndW1lbnRzIGFsb25lICgjOTkyKS4gUnVuQmxvY2tpbmdXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgc3RhdGljIGNhbGwgb2Yga290bGlueC5jb3JvdXRpbmVzLkJ1aWxkZXJzS3QucnVuQmxvY2tpbmdLLCBydW5CbG9ja2luZyBvciB0aGVpciAkZGVmYXVsdCBicmlkZ2VzIGJ5IG5hbWUsIG9uZSBjYWxsIG9mIGEgKClWIGhvb2sgdGhhdCB0YWtlcyBhbmQgbGVhdmVzIG5vdGhpbmcsIGluIGV2ZXJ5IHdvdmVuIGNsYXNzIG91dHNpZGUga290bGlueC5jb3JvdXRpbmVzICgjMTAwNykuIEtvdGxpbk11dGV4V2VhdmVyIHJlcGxhY2VzIGEga290bGlueC5jb3JvdXRpbmVzLnN5bmMuTXV0ZXggbG9jaywgdW5sb2NrIG9yIHRyeUxvY2sgY2FsbCwgb3IgaXRzIHN0YXRpYyAkZGVmYXVsdCBicmlkZ2UsIG1hdGNoZWQgYnkgb3duZXIsIG5hbWUgYW5kIGRlc2NyaXB0b3IsIHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2sgYW5kIHJldHVybmluZyB0aGUgc2FtZSByZXN1bHQsIGluIGV2ZXJ5IHdvdmVuIGNsYXNzIG91dHNpZGUga290bGlueC5jb3JvdXRpbmVzICgjMTAwNykuIFNvIGZyYW1lcyBzdGF5IHZhbGlkIGFuZCBvbmx5IG1heFN0YWNrIGdyb3dzIChDT01QVVRFX01BWFMsIG5ldmVyIENPTVBVVEVfRlJBTUVTLCB3aGljaCB3b3VsZCBsb2FkIGNsYXNzZXMgZnJvbSBpbnNpZGUgdGhlIGFnZW50KS4gSW4gZXZlcnkgbW9kZSwgaW5zdGFsbCBhbmQgdGhlIHRyYW5zZm9ybWVyIG9wZW4gamF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MsIHdpdGggZmllbGRzPXRydWUgYWxzbyBqYXZhLnV0aWwuY29uY3VycmVudC5hdG9taWMsIGFuZCB3aXRoIGNvbGxlY3Rpb25zPXRydWUgYWxzbyBqYXZhLnV0aWwgYW5kIGphdmEuaW8gKGEgc3luY2hyb25pemVkIHdyYXBwZXIncyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXIncyBzaW5rLCAjOTk0KSwgdG8gb25lIG1vZHVsZSBwZXIgd292ZW4gbG9hZGVyIGFuZCB0byBub3RoaW5nIGVsc2U6IHRoZSBtb2R1bGUgb2YgdGhlIFRlbGVtZXRyeVJlZ2lzdHJ5IGNvcHkgdGhhdCBsb2FkZXIgcmVzb2x2ZXMsIG5ldmVyIHRoZSB3b3ZlbiBsb2FkZXIgb3IgaXRzIGFuY2VzdG9ycyBhcyBzdWNoIChVcGRhdGVyQWNjZXNzLCAjNjU5LCAjNjY4LCAjODU1KTsgdGhlIGxvY2tzIG9wZW5pbmcgbGV0cyB0aGUgbGlicmFyeSByZWFkIGEgUmVlbnRyYW50TG9jayBvd25lciBhdCBhbmFseXNpcy4gSW4gZXZlcnkgbW9kZSwgYSB3b3ZlbiBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSBnZXRzIGEgcmVhZCBlZGdlIHRvIHRoZSBsaWJyYXJ5IGNvcHkgaXRzIGxvYWRlciByZXNvbHZlcyAoVXBkYXRlckFjY2Vzcy5sZXRSZWFkLCAjODYyKTogdGhlIEpWTSdzIG93biBlZGdlIGZvciBhIHRyYW5zZm9ybWVkIGNsYXNzIHJlYWNoZXMgb25seSB0aGUgYWdlbnQgbG9hZGVyJ3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5J3MgZGVmYXVsdCBzZWxmLWluamVjdGlvbiBnYXZlIGV2ZXJ5IGNsYXNzIHdvdmVuIGF0IGxvYWQgYSA8Y2xpbml0PiB0aGF0IGxvYWRzIG5ldC5ieXRlYnVkZHkuZHluYW1pYy5OZXh1cyB0aHJvdWdoIHRoZSBzeXN0ZW0gY2xhc3MgbG9hZGVyLCB3aG9zZSBsb2NrIHZpcnR1YWwgdGhyZWFkcyBpbml0aWFsaXppbmcgY2xhc3NlcyBhdCBvbmNlIGNvbnRlbmQgb24gYW5kIHBpbiAoIzk4NCkuIFRoZSBQcmVtYWluLUNsYXNzIC8gQWdlbnQtQ2xhc3MgbWFuaWZlc3QgZW50cmllcyBsaXZlIGluIHRoaXMgbW9kdWxlJ3MgamFyLCB3aGljaCBpcyB3aHkgYXR0YWNoaW5nIHVzZXMgLWphdmFhZ2VudDphc3luYy10ZXN0LWFnZW50Lmphci4K +~gran~async-test-instrumentation=KiovYmVuY2htYXJrLyoqCSoqL3RlbGVtZXRyeS8qKgkqKi9hZ2VudC8qKgkqKi9hbmFseXNpcy8qKgojIyBDb3JlIEZ1bmN0aW9uYWxpdHkKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkFzeW5jVGVzdEFnZW50Ci0gKipTZW5zaXRpdml0eSoqOiBDcml0aWNhbAotICoqTm90ZSoqOiBUaGUgSU5TVEFMTEVEIGdhdGUgbXVzdCBzdGF5IGF0LW1vc3Qtb25jZSBwZXIgSlZNOiBldmVyeSBlbnRyeSBwb2ludCAocHJlbWFpbiwgYWdlbnRtYWluLCBzZWxmQXR0YWNoKSByYWNlcyBvbiB0aGUgc2FtZSBjb21wYXJlQW5kU2V0LCBhbmQgYSBzZWNvbmQgdHJhbnNmb3JtZXIgd291bGQgZG91YmxlLXdlYXZlIGFjY2Vzc2VzIGFuZCBkb3VibGUtY291bnQgZXZlcnkgb25lLiBwcmVtYWluIGluc3RhbGxzIHdpdGhvdXQgcmV0cmFuc2Zvcm1hdGlvbiBiZWNhdXNlIGNsYXNzZXMgYXJlIHdvdmVuIGFzIHRoZXkgbG9hZDsgYWdlbnRtYWluIG11c3Qga2VlcCBSRVRSQU5TRk9STUFUSU9OICsgZGlzYWJsZUNsYXNzRm9ybWF0Q2hhbmdlcygpLCB3aGljaCBpcyBvbmx5IHNhZmUgd2hpbGUgbm8gd2VhdmVyIGFkZHMgYSBtZW1iZXIsIGFuZCB0aGVyZSBhcmUgZm91ciBiZXNpZGVzIHRoZSBBZHZpY2UsIHdoaWNoIGlzIGEgbWV0aG9kLWVudHJ5IHByb2xvZ3VlLiBGaWVsZEFjY2Vzc1dlYXZlciBpbnNlcnRzIGEgc3RhY2stbmV1dHJhbCwgYnJhbmNoLWZyZWUgY2FsbCBiZWZvcmUgZWFjaCBmaWVsZCBpbnN0cnVjdGlvbiwgYSBsb2FkIG9mIHRoZSBtb25pdG9yIHBsdXMgYSBjYWxsIGF0IHRoZSBlbnRyeSBvZiBhIHN5bmNocm9uaXplZCBtZXRob2QgYW5kIGJlZm9yZSBlYWNoIG9mIGl0cyByZXR1cm5zICgjODIyKSwgYSBEVVAgb2YgdGhlIG1vbml0b3IsIGFuIEFMT0FEIG9mIHRoZSBsb2NhbCB0aGUgb3duZXIgd2FzIGxvYWRlZCBmcm9tLCBhbiBMREMgb2YgdGhlIGZpZWxkIGFuZCBhIGNhbGwgYmVmb3JlIGEgTU9OSVRPUkVOVEVSIHdob3NlIG1vbml0b3IgdGhlIGZvdXIgaW5zdHJ1Y3Rpb25zIGJlZm9yZSBpdCByZWFkIGZyb20gYW4gaW5zdGFuY2UgZmllbGQgKEFMT0FELCBHRVRGSUVMRCwgRFVQLCBBU1RPUkUsIHdpdGggbm8gbGFiZWwgYmV0d2VlbiwgIzc5MyksIGEgRFVQIHBsdXMgY2FsbCBhZnRlciBhIFZhckhhbmRsZSByZWZlcmVuY2UgZ2V0QW5kU2V0IGl0IGRvZXMgbm90IHN1YnN0aXR1dGUgKHRoZSBvd25lcnNoaXAgdGFrZSwgIzU1NSksIERVUDIgYW5kIFNXQVAgcGx1cyBhIGNhbGwgYmVmb3JlIGEgSkNUb29scyBvZmZlciwgYW5kIGEgRFVQIGJlZm9yZSBwbHVzIERVUF9YMSBhbmQgU1dBUCBwbHVzIGEgY2FsbCBhZnRlciBhIEpDVG9vbHMgcG9sbCAoIzY2NCksIGEgY29weSBvZiBvd25lciBhbmQgdmFsdWUgcGx1cyBhIGNhbGwgYmVmb3JlIGEgdm9sYXRpbGUgZmllbGQgc3RvcmUgYW5kIGFmdGVyIGEgdm9sYXRpbGUgZmllbGQgbG9hZCwgd2l0aCBhIERVUCBvZiB0aGUgcmVjZWl2ZXIgYmVmb3JlIGFuIGluc3RhbmNlIGxvYWQgKCM3NDIpLCBhbmQgcmVwbGFjZXMgYW4gaW50IFZhckhhbmRsZSwgQXRvbWljSW50ZWdlckZpZWxkVXBkYXRlciwgQXRvbWljQm9vbGVhbiBvciBBdG9taWNJbnRlZ2VyIHN0b3JlLCBzd2FwIG9yIHZhbHVlLXJldHVybmluZyByZWxlYXNlLCBvciBhIHJlZmVyZW5jZS1zbG90IHN0b3JlIG9yIGdldEFuZFNldCBvbiBhbiBBdG9taWNSZWZlcmVuY2UsIGl0cyB1cGRhdGVyLCBpdHMgYXJyYXkgb3IgYW4gaW5zdGFuY2UtZmllbGQgVmFySGFuZGxlLCBvciBhbiBhY3F1aXJpbmcgcmVmZXJlbmNlIHJlYWQsIGFuIEF0b21pY1JlZmVyZW5jZSBnZXQgb3IgZ2V0QWNxdWlyZSwgYW4gdXBkYXRlciBnZXQsIGFuIEF0b21pY1JlZmVyZW5jZUFycmF5IGdldCBvciBnZXRBY3F1aXJlIG9yIGEgVmFySGFuZGxlIGdldFZvbGF0aWxlIG9yIGdldEFjcXVpcmUgKHRoZSBhY3F1aXJlIG9mIHRoZSBzdG9yZSBpdCByZXR1cm5lZCwgIzc0MSksIG9yIGFuIEF0b21pY1N0YW1wZWRSZWZlcmVuY2UgZ2V0LCBnZXRSZWZlcmVuY2UsIHNldCwgY29tcGFyZUFuZFNldCwgd2Vha0NvbXBhcmVBbmRTZXQgb3IgYXR0ZW1wdFN0YW1wICgjODE3KSwgb3IgYW4gQXRvbWljSW50ZWdlciBnZXQgb3IgYW4gQXRvbWljTG9uZyBnZXQsIHN0b3JlIG9yIGNvbXBhcmUtYW5kLXNldCAoYSBnZXQgdGhlbiBzZXQsICMxMTU3KSwgd2l0aCBhIHN0YXRpYyBob29rIGNvbnN1bWluZyB0aGUgc2FtZSBzdGFjayBhbmQgcmV0dXJuaW5nIHRoZSBzYW1lIHJlc3VsdCwgcGx1cyBvbmUgUE9QIHdoZXJlIGEgVmFySGFuZGxlIGNhbGwgc2l0ZSBkZWNsYXJlZCBhIHZvaWQgcmVzdWx0IGFuZCBvbmUgQ0hFQ0tDQVNUIHRvIHRoZSBkZWNsYXJlZCB0eXBlIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgb3IgYWNxdWlyaW5nIHJlYWQgKHRoZSBzcGlubG9jaywgIzU1NCwgIzU1OCwgIzY1OCwgIzY2NzsgdGhlIG93bmVyc2hpcCBvZmZlciBhbmQgdGFrZSwgIzY2NCkuIENvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIgcmVwbGFjZXMgZWFjaCBjYWxsIGl0cyB0YWJsZXMgbGlzdCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrLCBhbmQgaW5zZXJ0cyBvbmx5IHRoZSBtb25pdG9yIGxvYWRzIGFuZCB0aGUgbG9vcCBiYWNrLWVkZ2UgY2FsbCBpdHMgb3duIHJ1bGVzIGRlc2NyaWJlLiBUaHJlYWRDb25zdHJ1Y3Rpb25XZWF2ZXIgaW5zZXJ0cyBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciB0aGUgY29uc3RydWN0b3IgY2FsbCBvZiBhIG5ldyBUaHJlYWQoLi4uKSwgYW5kIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBUaHJlYWQgc3ViY2xhc3MgY29uc3RydWN0b3IncyBzdXBlcmNsYXNzIGNhbGwgKCM3MzcpLiBDb25zdHJ1Y3Rpb25XZWF2ZXIgaW5zZXJ0cyBhIGNhbGwgdGhhdCBjb25zdW1lcyBhbmQgcmV0dXJucyB0aGUgb3JkZXIgYXJndW1lbnQgYmVmb3JlIGEgTGlua2VkSGFzaE1hcChpbnQsIGZsb2F0LCBib29sZWFuKSBjb25zdHJ1Y3RvciBjYWxsIGFuZCBhIERVUCBvciBhbiBBTE9BRCAwIHBsdXMgYSBjYWxsIGFmdGVyIGl0ICgjODA3KSwgYSBEVVAgcGx1cyBhIGNhbGwgYWZ0ZXIgYSBuZXcgQ29tcGxldGFibGVGdXR1cmUoKSBjb25zdHJ1Y3RvciBjYWxsICgjMTA1NCksIGFuZCBhbiBBTE9BRCAwLCBhbiBMREMgb2YgdGhlIGNsYXNzIG5hbWUgYW5kIGEgY2FsbCBiZWZvcmUgZWFjaCBSRVRVUk4gb2YgYSBjb25zdHJ1Y3RvciBhbmQgYWZ0ZXIgYSB0aGlzKC4uLikgZGVsZWdhdGlvbiAoIzc5MSk7IGl0IGxlYXZlcyBhbG9uZSBhIGNsYXNzIGluIGEgbmFtZWQgbW9kdWxlIHRoYXQgY2Fubm90IHJlYWQgdGhlIGxpYnJhcnkuIEludGVycnVwdEhhbmRsZXJXZWF2ZXIgaW5zZXJ0cyBhbiBMREMgb2YgdGhlIGxvY2F0aW9ucyBvZiBhIG1ldGhvZCdzIEludGVycnVwdGVkRXhjZXB0aW9uIGhhbmRsZXJzIHRoYXQgbmVpdGhlciByZXRocm93IG5vciByZXN0b3JlIHRoZSBmbGFnLCBhbmQgYSBjYWxsLCBiZWZvcmUgdGhlIGZpcnN0IGluc3RydWN0aW9uIG9mIGEgbWV0aG9kIHRoYXQgZGVjbGFyZXMgb25lLCBhbmQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gUGVyc2lzdGVuY2VIYW5kbGVXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgY2FsbCB3aG9zZSBvd25lciBpcyBhIEpQQSBFbnRpdHlNYW5hZ2VyIG9yIEhpYmVybmF0ZSBTZXNzaW9uIGJ5IG5hbWUsIGEgc3RhY2stbmV1dHJhbCBjb3B5IG9mIHRoZSByZWNlaXZlciAoRFVQOyBTV0FQLCBEVVBfWDE7IG9yIERVUDJfWDEsIFBPUDIsIERVUF9YMiBmb3IgemVybywgb25lIG9yIHR3byBvbmUtc2xvdCBhcmd1bWVudHMpIGFuZCBhIGNhbGwsIGFuZCBsZWF2ZXMgY2FsbHMgd2l0aCBtb3JlIG9yIHdpZGVyIGFyZ3VtZW50cyBhbG9uZSAoIzk5MikuIFJ1bkJsb2NraW5nV2VhdmVyIGluc2VydHMsIGJlZm9yZSBhIHN0YXRpYyBjYWxsIG9mIGtvdGxpbnguY29yb3V0aW5lcy5CdWlsZGVyc0t0LnJ1bkJsb2NraW5nSywgcnVuQmxvY2tpbmcgb3IgdGhlaXIgJGRlZmF1bHQgYnJpZGdlcyBieSBuYW1lLCBvbmUgY2FsbCBvZiBhICgpViBob29rIHRoYXQgdGFrZXMgYW5kIGxlYXZlcyBub3RoaW5nLCBpbiBldmVyeSB3b3ZlbiBjbGFzcyBvdXRzaWRlIGtvdGxpbnguY29yb3V0aW5lcyAoIzEwMDcpLiBLb3RsaW5NdXRleFdlYXZlciByZXBsYWNlcyBhIGtvdGxpbnguY29yb3V0aW5lcy5zeW5jLk11dGV4IGxvY2ssIHVubG9jayBvciB0cnlMb2NrIGNhbGwsIG9yIGl0cyBzdGF0aWMgJGRlZmF1bHQgYnJpZGdlLCBtYXRjaGVkIGJ5IG93bmVyLCBuYW1lIGFuZCBkZXNjcmlwdG9yLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBpbiBldmVyeSB3b3ZlbiBjbGFzcyBvdXRzaWRlIGtvdGxpbnguY29yb3V0aW5lcyAoIzEwMDcpLiBTbyBmcmFtZXMgc3RheSB2YWxpZCBhbmQgb25seSBtYXhTdGFjayBncm93cyAoQ09NUFVURV9NQVhTLCBuZXZlciBDT01QVVRFX0ZSQU1FUywgd2hpY2ggd291bGQgbG9hZCBjbGFzc2VzIGZyb20gaW5zaWRlIHRoZSBhZ2VudCkuIEluIGV2ZXJ5IG1vZGUsIGluc3RhbGwgYW5kIHRoZSB0cmFuc2Zvcm1lciBvcGVuIGphdmEudXRpbC5jb25jdXJyZW50LmxvY2tzLCB3aXRoIGZpZWxkcz10cnVlIGFsc28gamF2YS51dGlsLmNvbmN1cnJlbnQuYXRvbWljLCBhbmQgd2l0aCBjb2xsZWN0aW9ucz10cnVlIGFsc28gamF2YS51dGlsIGFuZCBqYXZhLmlvIChhIHN5bmNocm9uaXplZCB3cmFwcGVyJ3MgbXV0ZXgsICM5OTY7IGEgcGlwZWQgd3JpdGVyJ3Mgc2luaywgIzk5NCksIHRvIG9uZSBtb2R1bGUgcGVyIHdvdmVuIGxvYWRlciBhbmQgdG8gbm90aGluZyBlbHNlOiB0aGUgbW9kdWxlIG9mIHRoZSBUZWxlbWV0cnlSZWdpc3RyeSBjb3B5IHRoYXQgbG9hZGVyIHJlc29sdmVzLCBuZXZlciB0aGUgd292ZW4gbG9hZGVyIG9yIGl0cyBhbmNlc3RvcnMgYXMgc3VjaCAoVXBkYXRlckFjY2VzcywgIzY1OSwgIzY2OCwgIzg1NSk7IHRoZSBsb2NrcyBvcGVuaW5nIGxldHMgdGhlIGxpYnJhcnkgcmVhZCBhIFJlZW50cmFudExvY2sgb3duZXIgYXQgYW5hbHlzaXMuIEluIGV2ZXJ5IG1vZGUsIGEgd292ZW4gY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgZ2V0cyBhIHJlYWQgZWRnZSB0byB0aGUgbGlicmFyeSBjb3B5IGl0cyBsb2FkZXIgcmVzb2x2ZXMgKFVwZGF0ZXJBY2Nlc3MubGV0UmVhZCwgIzg2Mik6IHRoZSBKVk0ncyBvd24gZWRnZSBmb3IgYSB0cmFuc2Zvcm1lZCBjbGFzcyByZWFjaGVzIG9ubHkgdGhlIGFnZW50IGxvYWRlcidzIHVubmFtZWQgbW9kdWxlLiBUaGUgbGlicmFyeSByZXNvbHZlcyBhbiB1cGRhdGVyIGJvdW5kIGJlZm9yZSB0aGUgYXR0YWNoIGJ5IHJlYWRpbmcgdGhlIEpESyBpbXBsZW1lbnRhdGlvbiBmcm9tIHRoYXQgY29weSAoSmRrVXBkYXRlclNoYXBlQ2FuYXJ5VGVzdCBwaW5zIHRoZSBzaGFwZSBpdCByZWFkcyksIGFuZCB0aGUgb3BlbmluZyBtdXN0IGZhaWwgc2lsZW50bHkgbGlrZSB0aGUgcmVzdCBvZiBpbnN0YWxsLiBOb3RoaW5nIG1heSB0aHJvdyBvdXQgb2YgcHJlbWFpbiDigJQgYW4gZXhjZXB0aW9uIHRoZXJlIGFib3J0cyBKVk0gc3RhcnR1cCwgd2hpY2ggaXMgd2h5IGluc3RhbGwoKSBjYXRjaGVzIFRocm93YWJsZSBhbmQgcmVsZWFzZXMgdGhlIGdhdGUgcmF0aGVyIHRoYW4gcHJvcGFnYXRpbmcuIEJvdGggbW9kZXMgdXNlIEFnZW50QnVpbGRlci5Jbml0aWFsaXphdGlvblN0cmF0ZWd5Lk5vT3A6IG5vIHdlYXZlciBuZWVkcyBhIGxvYWRlZC10eXBlIGluaXRpYWxpemVyLCBhbmQgQnl0ZSBCdWRkeSdzIGRlZmF1bHQgc2VsZi1pbmplY3Rpb24gZ2F2ZSBldmVyeSBjbGFzcyB3b3ZlbiBhdCBsb2FkIGEgPGNsaW5pdD4gdGhhdCBsb2FkcyBuZXQuYnl0ZWJ1ZGR5LmR5bmFtaWMuTmV4dXMgdGhyb3VnaCB0aGUgc3lzdGVtIGNsYXNzIGxvYWRlciwgd2hvc2UgbG9jayB2aXJ0dWFsIHRocmVhZHMgaW5pdGlhbGl6aW5nIGNsYXNzZXMgYXQgb25jZSBjb250ZW5kIG9uIGFuZCBwaW4gKCM5ODQpLiBUaGUgUHJlbWFpbi1DbGFzcyAvIEFnZW50LUNsYXNzIG1hbmlmZXN0IGVudHJpZXMgbGl2ZSBpbiB0aGlzIG1vZHVsZSdzIGphciwgd2hpY2ggaXMgd2h5IGF0dGFjaGluZyB1c2VzIC1qYXZhYWdlbnQ6YXN5bmMtdGVzdC1hZ2VudC5qYXIuCgojIyBDb250cmFjdC1Gcm96ZW4gU2lnbmF0dXJlCi0gKipDb25zdHJhaW50Kio6IFlvdSBtYXkgY2hhbmdlIGludGVybmFsIGxvZ2ljLCBidXQgTVVTVCBOT1QgbW9kaWZ5IHRoZSBtZXRob2QgbmFtZSwgcGFyYW1ldGVycywgcmV0dXJuIHR5cGUsIG9yIGNoZWNrZWQgZXhjZXB0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkFnZW50T3B0aW9ucwotICoqUmVhc29uKio6IFRoZSBjbGFzcyBpcyBwYWNrYWdlLXByaXZhdGUgYnV0IHRoZSBhZ2VudEFyZ3MgZ3JhbW1hciBpdCBwYXJzZXMgaXMgcHVibGljIHN1cmZhY2U6IHVzZXJzIHR5cGUgaXQgb24gdGhlIC1qYXZhYWdlbnQ6IGNvbW1hbmQgbGluZS4gS2V5IG5hbWVzIChpbmNsdWRlcy9leGNsdWRlcy9kZWJ1ZyksIHRoZSBjb21tYS1vci1zZW1pY29sb24gc2VwYXJhdG9yLCB0aGUgYmFyZS10b2tlbiBjb250aW51YXRpb24gdGhhdCBsZXRzIG9uZSBrZXkgY2Fycnkgc2V2ZXJhbCB2YWx1ZXMsIGFuZCBjYXNlLWluc2Vuc2l0aXZlIGtleSBtYXRjaGluZyBhcmUgYWxsIHBhcnQgb2YgdGhhdCBjb250cmFjdCDigJQgY2hhbmdpbmcgYW55IG9mIHRoZW0gYnJlYWtzIGV4aXN0aW5nIGxhdW5jaCBzY3JpcHRzIHNpbGVudGx5LiBQYXJzaW5nIG11c3Qgc3RheSB0b3RhbDogaXQgaXMgY2FsbGVkIGZyb20gcHJlbWFpbiwgd2hlcmUgYSB0aHJvd24gZXhjZXB0aW9uIGFib3J0cyBKVk0gc3RhcnR1cCwgc28gdW5rbm93biBrZXlzIGFyZSBpZ25vcmVkIGFuZCBtYWxmb3JtZWQgaW5wdXQgZGVncmFkZXMgdG8gdGhlIGRlZmF1bHQgaW5zdHJ1bWVudC1ldmVyeXRoaW5nIGJlaGF2aW91ciByYXRoZXIgdGhhbiBmYWlsaW5nLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYWdlbnQuQXRvbWljRmllbGRSZWdpc3RyeQotICoqUmVhc29uKio6IFJlc29sdmVkIHJlZmxlY3RpdmVseSBzbyBhc3luYy10ZXN0LWFnZW50IGtlZXBzIGl0cyB6ZXJvLWRlcGVuZGVuY3kgYm91bmRhcnkgb24gYXN5bmMtdGVzdC1saWIsIHdoaWNoIEFyY2hpdGVjdHVyZVRlc3QgZW5mb3JjZXMgaW4gYm90aCBkaXJlY3Rpb25zLiBUaGUgbWV0aG9kIG5hbWUgYW5kIHNpZ25hdHVyZSBtdXN0IG1hdGNoIFRlbGVtZXRyeVJlZ2lzdHJ5LmF0b21pY2FsbHlNYW5hZ2VkKFN0cmluZykuIEV2ZXJ5IGZhaWx1cmUgcGF0aCBoZXJlIG11c3Qgc3RheSBzaWxlbnQ6IHRoaXMgb25seSBldmVyIHN1cHByZXNzZXMgZmluZGluZ3MsIHNvIGxvc2luZyBpdCBkZWdyYWRlcyBwcmVjaXNpb24gcmF0aGVyIHRoYW4gY29ycmVjdG5lc3MsIHdoaWxlIHRocm93aW5nIG91dCBvZiBhIGNsYXNzIHRyYW5zZm9ybWF0aW9uIHdvdWxkIGZhaWwgdGhlIHVzZXIncyB0ZXN0IHJ1bi4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkNvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIKLSAqKlJlYXNvbioqOiBUaGUgaG9vayBjbGFzcyBuYW1lIGFuZCB0aGUgbWV0aG9kIG5hbWVzIGhlcmUgYXJlIHRoZSBvdGhlciBoYWxmIG9mIEFnZW50Q29sbGVjdGlvbkhvb2tzIGFuZCBBZ2VudExvY2tIb29rczogdGhleSBhcmUgbWF0Y2hlZCBieSBlcmFzZWQgc2lnbmF0dXJlIGF0IHdlYXZlIHRpbWUsIHNvIHJlbmFtaW5nIGEgaG9vayBvciBjaGFuZ2luZyBhIHBhcmFtZXRlciB0eXBlIGJyZWFrcyB3ZWF2aW5nIHdpdGggYSBOb1N1Y2hNZXRob2RFcnJvciBpbnNpZGUgdXNlciBjb2RlIHJhdGhlciB0aGFuIGF0IGNvbXBpbGUgdGltZS4gRWFjaCBzdWJzdGl0dXRpb24gbXVzdCBjb25zdW1lIGV4YWN0bHkgdGhlIHN0YWNrIGl0cyBvcmlnaW5hbCBpbnZvY2F0aW9uIGNvbnN1bWVkIC0gc3RhY2stc2hhcGUtbmV1dHJhbCBhbmQgbWVtYmVyLWZyZWUgaXMgd2hhdCBrZWVwcyByZXRyYW5zZm9ybWF0aW9uIHNhZmUgdW5kZXIgZGlzYWJsZUNsYXNzRm9ybWF0Q2hhbmdlcygpLiBUaGUgdmlzaXRvciBjaGFuZ2VzIGV4YWN0bHkgb25lIGtpbmQgb2YgaW52b2tlZHluYW1pYzogYSBMYW1iZGFNZXRhZmFjdG9yeSBtZXRhZmFjdG9yeSBvciBub24tc2VyaWFsaXphYmxlIGFsdE1ldGFmYWN0b3J5IHdob3NlIGltcGxlbWVudGF0aW9uIGhhbmRsZSBtYXRjaGVzIGEgdGFibGUgZW50cnkgaXMgcG9pbnRlZCBhdCB0aGF0IGVudHJ5J3MgaG9vaywgc28gYSBtZXRob2QgcmVmZXJlbmNlIHN1Y2ggYXMgYnVpbGRlcjo6YXBwZW5kIGlzIG9ic2VydmVkICgjNTUwKS4gRXZlcnkgb3RoZXIgYm9vdHN0cmFwLCBPYmplY3RNZXRob2RzIGZvciByZWNvcmRzIGFib3ZlIGFsbCwgbXVzdCBwYXNzIHRocm91Z2ggYXMgdGhlIHNhbWUgYXJndW1lbnQgYXJyYXksIHJlYWQgb25seSB0aHJvdWdoIEFTTSdzIEhhbmRsZTogcGFyc2luZyBib290c3RyYXAgY29uc3RhbnRzIGlzIHdoYXQgbWFkZSBldmVyeSBKYXZhIHJlY29yZCBmYWlsIHRvIGluc3RydW1lbnQgd2hlbiB0aGlzIHdlbnQgdGhyb3VnaCBNZW1iZXJTdWJzdGl0dXRpb24sIGFuZCBhIHJld3JpdHRlbiBzZXJpYWxpemFibGUgbGFtYmRhIHdvdWxkIGZhaWwgdG8gZGVzZXJpYWxpemUuIENvbGxlY3Rpb24gd2VhdmluZyBpcyBvcHQtaW4gKGNvbGxlY3Rpb25zPXRydWUpIGJlY2F1c2UgaXQgaW5zdHJ1bWVudHMgZXZlcnkgbGlzdGVkIGNhbGwgaW4gZXZlcnkgbWF0Y2hlZCBjbGFzcy4gVGhlIG9uZS1pbnN0cnVjdGlvbiBsb29rYWhlYWQgYmVoaW5kIHdoZW5SZXN1bHREaXNjYXJkZWQgaXMgYSBmbGFnIG1lYW5pbmcgdGhlIGluc3RydWN0aW9uIGp1c3QgZW1pdHRlZCB3YXMgYSBzdWJzdGl0dXRlZCBjYWxsIHdob3NlIHJlc3VsdCBtYXkgYmUgZGlzY2FyZGVkOiB2aXNpdEluc24oUE9QKSBpcyBpdHMgb25seSBjb25zdW1lciBhbmQgZXZlcnkgb3RoZXIgdmlzaXQgbWV0aG9kIG11c3QgY2xlYXIgaXQsIGJlY2F1c2UgYSBzdGFsZSBmbGFnIHdvdWxkIHR1cm4gYW4gdW5yZWxhdGVkIFBPUCBpbnRvIGEgY2FsbCB3aG9zZSBwYXJhbWV0ZXIgZG9lcyBub3QgbWF0Y2ggdGhlIHZhbHVlIG9uIHRoZSBzdGFjaywgd2hpY2ggaXMgYSBWZXJpZnlFcnJvciBpbiB0aGUgdXNlcidzIGNsYXNzIGF0IGxvYWQgdGltZS4gU3Vic3RpdHV0aW5nVmlzaXRvckNsZWFyc0xvb2thaGVhZEV2ZXJ5d2hlcmVUZXN0IGVudW1lcmF0ZXMgTWV0aG9kVmlzaXRvciB0byBrZWVwIHRoYXQgb3ZlcnJpZGUgbGlzdCBjb21wbGV0ZS4gSW5zaWRlIGEgc3luY2hyb25pemVkIG1ldGhvZCwgYW4gZW50cnkgd2l0aCBhIHN5bmNocm9uaXplZCB2YXJpYW50ICh0aGUgc2xlZXBzLCBhbmQgdGhlIHF1ZXVlIG9mZmVycyBhbmQgdGFrZXMsICM3OTYpIGZpcnN0IGxvYWRzIHRoZSBtZXRob2QncyBtb25pdG9yLCBBTE9BRCAwIG9yIGFuIExEQyBvZiB0aGUgY2xhc3MgZm9yIGEgc3RhdGljIG1ldGhvZCwgd2hpY2ggdGhlIHZhcmlhbnQgY29uc3VtZXMgYXMgaXRzIGxhc3QgcGFyYW1ldGVyOiBvbmUgbW9yZSB2YWx1ZSBhbmQgbm8gYnJhbmNoLCBzbyBvbmx5IG1heFN0YWNrIGdyb3dzLCBhbmQgdGhlIHN1YnN0aXR1dGlvbiB3cmFwcGVyIGFza3MgZm9yIENPTVBVVEVfTUFYUyBpdHNlbGYuIEEgcXVldWUgb2ZmZXIgb3IgdGFrZSBpbiBhbnkgb3RoZXIgaW5zdGFuY2UgbWV0aG9kIGxvYWRzIHRoaXMgdGhlIHNhbWUgd2F5IGZvciBpdHMgaG9vayB0byBwcm9iZSAoIzc1MSksIGV4Y2VwdCBpbiBhIGNvbnN0cnVjdG9yLCB3aGVyZSB0aGlzIG1heSBiZSB1bmluaXRpYWxpc2VkIGFuZCB3b3VsZCBub3QgdmVyaWZ5LCBhbmQgYWZ0ZXIgYSBzdG9yZSB0byBsb2NhbCAwLiBUaGUgb25lIGluc3RydWN0aW9uIHRoZSB2aXNpdG9yIGluc2VydHMgb3V0c2lkZSBhIHN1YnN0aXR1dGlvbiBpcyB0aGUgbG9vcCBiYWNrLWVkZ2UgY2FsbCBpbiBmcm9udCBvZiBhIGp1bXAgdGhhdCBjb21lcyBiYWNrIG92ZXIgYSB3b3ZlbiBPYmplY3Qud2FpdCAoIzY5NCk6IGl0IG11c3Qgc3RheSBhIHN0YXRpYyAoKVYgY2FsbCwgYmVjYXVzZSB0aGUganVtcCdzIG9wZXJhbmRzIGFyZSBhbHJlYWR5IG9uIHRoZSBzdGFjayBiZW5lYXRoIGl0IGFuZCBhbnl0aGluZyB0aGF0IHRvb2sgb3IgbGVmdCBhIHZhbHVlLCBvciBhZGRlZCBhIGJyYW5jaCwgd291bGQgbmVlZCB0aGUgZnJhbWVzIENPTVBVVEVfTUFYUyBkb2VzIG5vdCByZWNvbXB1dGUu ~granname~async-test-instrumentation=YXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24KQUkgcnVsZXMgZm9yIHJvbGUgYXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24= -~modgran~se-deversity-asynctest-agent-AsyncTestAgent=KiovQXN5bmNUZXN0QWdlbnQuamF2YQojIyBDb3JlIEZ1bmN0aW9uYWxpdHkKLSAqKlNlbnNpdGl2aXR5Kio6IENyaXRpY2FsCi0gKipOb3RlKio6IFRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvcidzIHN1cGVyY2xhc3MgY2FsbCAoIzczNykuIENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgY2FsbCB0aGF0IGNvbnN1bWVzIGFuZCByZXR1cm5zIHRoZSBvcmRlciBhcmd1bWVudCBiZWZvcmUgYSBMaW5rZWRIYXNoTWFwKGludCwgZmxvYXQsIGJvb2xlYW4pIGNvbnN0cnVjdG9yIGNhbGwgYW5kIGEgRFVQIG9yIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgaXQgKCM4MDcpLCBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciBhIG5ldyBDb21wbGV0YWJsZUZ1dHVyZSgpIGNvbnN0cnVjdG9yIGNhbGwgKCMxMDU0KSwgYW5kIGFuIEFMT0FEIDAsIGFuIExEQyBvZiB0aGUgY2xhc3MgbmFtZSBhbmQgYSBjYWxsIGJlZm9yZSBlYWNoIFJFVFVSTiBvZiBhIGNvbnN0cnVjdG9yIGFuZCBhZnRlciBhIHRoaXMoLi4uKSBkZWxlZ2F0aW9uICgjNzkxKTsgaXQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gSW50ZXJydXB0SGFuZGxlcldlYXZlciBpbnNlcnRzIGFuIExEQyBvZiB0aGUgbG9jYXRpb25zIG9mIGEgbWV0aG9kJ3MgSW50ZXJydXB0ZWRFeGNlcHRpb24gaGFuZGxlcnMgdGhhdCBuZWl0aGVyIHJldGhyb3cgbm9yIHJlc3RvcmUgdGhlIGZsYWcsIGFuZCBhIGNhbGwsIGJlZm9yZSB0aGUgZmlyc3QgaW5zdHJ1Y3Rpb24gb2YgYSBtZXRob2QgdGhhdCBkZWNsYXJlcyBvbmUsIGFuZCBsZWF2ZXMgYWxvbmUgYSBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSB0aGF0IGNhbm5vdCByZWFkIHRoZSBsaWJyYXJ5LiBQZXJzaXN0ZW5jZUhhbmRsZVdlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBjYWxsIHdob3NlIG93bmVyIGlzIGEgSlBBIEVudGl0eU1hbmFnZXIgb3IgSGliZXJuYXRlIFNlc3Npb24gYnkgbmFtZSwgYSBzdGFjay1uZXV0cmFsIGNvcHkgb2YgdGhlIHJlY2VpdmVyIChEVVA7IFNXQVAsIERVUF9YMTsgb3IgRFVQMl9YMSwgUE9QMiwgRFVQX1gyIGZvciB6ZXJvLCBvbmUgb3IgdHdvIG9uZS1zbG90IGFyZ3VtZW50cykgYW5kIGEgY2FsbCwgYW5kIGxlYXZlcyBjYWxscyB3aXRoIG1vcmUgb3Igd2lkZXIgYXJndW1lbnRzIGFsb25lICgjOTkyKS4gUnVuQmxvY2tpbmdXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgc3RhdGljIGNhbGwgb2Yga290bGlueC5jb3JvdXRpbmVzLkJ1aWxkZXJzS3QucnVuQmxvY2tpbmdLLCBydW5CbG9ja2luZyBvciB0aGVpciAkZGVmYXVsdCBicmlkZ2VzIGJ5IG5hbWUsIG9uZSBjYWxsIG9mIGEgKClWIGhvb2sgdGhhdCB0YWtlcyBhbmQgbGVhdmVzIG5vdGhpbmcsIGluIGV2ZXJ5IHdvdmVuIGNsYXNzIG91dHNpZGUga290bGlueC5jb3JvdXRpbmVzICgjMTAwNykuIFNvIGZyYW1lcyBzdGF5IHZhbGlkIGFuZCBvbmx5IG1heFN0YWNrIGdyb3dzIChDT01QVVRFX01BWFMsIG5ldmVyIENPTVBVVEVfRlJBTUVTLCB3aGljaCB3b3VsZCBsb2FkIGNsYXNzZXMgZnJvbSBpbnNpZGUgdGhlIGFnZW50KS4gSW4gZXZlcnkgbW9kZSwgaW5zdGFsbCBhbmQgdGhlIHRyYW5zZm9ybWVyIG9wZW4gamF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MsIHdpdGggZmllbGRzPXRydWUgYWxzbyBqYXZhLnV0aWwuY29uY3VycmVudC5hdG9taWMsIGFuZCB3aXRoIGNvbGxlY3Rpb25zPXRydWUgYWxzbyBqYXZhLnV0aWwgYW5kIGphdmEuaW8gKGEgc3luY2hyb25pemVkIHdyYXBwZXIncyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXIncyBzaW5rLCAjOTk0KSwgdG8gb25lIG1vZHVsZSBwZXIgd292ZW4gbG9hZGVyIGFuZCB0byBub3RoaW5nIGVsc2U6IHRoZSBtb2R1bGUgb2YgdGhlIFRlbGVtZXRyeVJlZ2lzdHJ5IGNvcHkgdGhhdCBsb2FkZXIgcmVzb2x2ZXMsIG5ldmVyIHRoZSB3b3ZlbiBsb2FkZXIgb3IgaXRzIGFuY2VzdG9ycyBhcyBzdWNoIChVcGRhdGVyQWNjZXNzLCAjNjU5LCAjNjY4LCAjODU1KTsgdGhlIGxvY2tzIG9wZW5pbmcgbGV0cyB0aGUgbGlicmFyeSByZWFkIGEgUmVlbnRyYW50TG9jayBvd25lciBhdCBhbmFseXNpcy4gSW4gZXZlcnkgbW9kZSwgYSB3b3ZlbiBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSBnZXRzIGEgcmVhZCBlZGdlIHRvIHRoZSBsaWJyYXJ5IGNvcHkgaXRzIGxvYWRlciByZXNvbHZlcyAoVXBkYXRlckFjY2Vzcy5sZXRSZWFkLCAjODYyKTogdGhlIEpWTSdzIG93biBlZGdlIGZvciBhIHRyYW5zZm9ybWVkIGNsYXNzIHJlYWNoZXMgb25seSB0aGUgYWdlbnQgbG9hZGVyJ3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5J3MgZGVmYXVsdCBzZWxmLWluamVjdGlvbiBnYXZlIGV2ZXJ5IGNsYXNzIHdvdmVuIGF0IGxvYWQgYSA8Y2xpbml0PiB0aGF0IGxvYWRzIG5ldC5ieXRlYnVkZHkuZHluYW1pYy5OZXh1cyB0aHJvdWdoIHRoZSBzeXN0ZW0gY2xhc3MgbG9hZGVyLCB3aG9zZSBsb2NrIHZpcnR1YWwgdGhyZWFkcyBpbml0aWFsaXppbmcgY2xhc3NlcyBhdCBvbmNlIGNvbnRlbmQgb24gYW5kIHBpbiAoIzk4NCkuIFRoZSBQcmVtYWluLUNsYXNzIC8gQWdlbnQtQ2xhc3MgbWFuaWZlc3QgZW50cmllcyBsaXZlIGluIHRoaXMgbW9kdWxlJ3MgamFyLCB3aGljaCBpcyB3aHkgYXR0YWNoaW5nIHVzZXMgLWphdmFhZ2VudDphc3luYy10ZXN0LWFnZW50Lmphci4= +~modgran~se-deversity-asynctest-agent-AsyncTestAgent=KiovQXN5bmNUZXN0QWdlbnQuamF2YQojIyBDb3JlIEZ1bmN0aW9uYWxpdHkKLSAqKlNlbnNpdGl2aXR5Kio6IENyaXRpY2FsCi0gKipOb3RlKio6IFRoZSBJTlNUQUxMRUQgZ2F0ZSBtdXN0IHN0YXkgYXQtbW9zdC1vbmNlIHBlciBKVk06IGV2ZXJ5IGVudHJ5IHBvaW50IChwcmVtYWluLCBhZ2VudG1haW4sIHNlbGZBdHRhY2gpIHJhY2VzIG9uIHRoZSBzYW1lIGNvbXBhcmVBbmRTZXQsIGFuZCBhIHNlY29uZCB0cmFuc2Zvcm1lciB3b3VsZCBkb3VibGUtd2VhdmUgYWNjZXNzZXMgYW5kIGRvdWJsZS1jb3VudCBldmVyeSBvbmUuIHByZW1haW4gaW5zdGFsbHMgd2l0aG91dCByZXRyYW5zZm9ybWF0aW9uIGJlY2F1c2UgY2xhc3NlcyBhcmUgd292ZW4gYXMgdGhleSBsb2FkOyBhZ2VudG1haW4gbXVzdCBrZWVwIFJFVFJBTlNGT1JNQVRJT04gKyBkaXNhYmxlQ2xhc3NGb3JtYXRDaGFuZ2VzKCksIHdoaWNoIGlzIG9ubHkgc2FmZSB3aGlsZSBubyB3ZWF2ZXIgYWRkcyBhIG1lbWJlciwgYW5kIHRoZXJlIGFyZSBmb3VyIGJlc2lkZXMgdGhlIEFkdmljZSwgd2hpY2ggaXMgYSBtZXRob2QtZW50cnkgcHJvbG9ndWUuIEZpZWxkQWNjZXNzV2VhdmVyIGluc2VydHMgYSBzdGFjay1uZXV0cmFsLCBicmFuY2gtZnJlZSBjYWxsIGJlZm9yZSBlYWNoIGZpZWxkIGluc3RydWN0aW9uLCBhIGxvYWQgb2YgdGhlIG1vbml0b3IgcGx1cyBhIGNhbGwgYXQgdGhlIGVudHJ5IG9mIGEgc3luY2hyb25pemVkIG1ldGhvZCBhbmQgYmVmb3JlIGVhY2ggb2YgaXRzIHJldHVybnMgKCM4MjIpLCBhIERVUCBvZiB0aGUgbW9uaXRvciwgYW4gQUxPQUQgb2YgdGhlIGxvY2FsIHRoZSBvd25lciB3YXMgbG9hZGVkIGZyb20sIGFuIExEQyBvZiB0aGUgZmllbGQgYW5kIGEgY2FsbCBiZWZvcmUgYSBNT05JVE9SRU5URVIgd2hvc2UgbW9uaXRvciB0aGUgZm91ciBpbnN0cnVjdGlvbnMgYmVmb3JlIGl0IHJlYWQgZnJvbSBhbiBpbnN0YW5jZSBmaWVsZCAoQUxPQUQsIEdFVEZJRUxELCBEVVAsIEFTVE9SRSwgd2l0aCBubyBsYWJlbCBiZXR3ZWVuLCAjNzkzKSwgYSBEVVAgcGx1cyBjYWxsIGFmdGVyIGEgVmFySGFuZGxlIHJlZmVyZW5jZSBnZXRBbmRTZXQgaXQgZG9lcyBub3Qgc3Vic3RpdHV0ZSAodGhlIG93bmVyc2hpcCB0YWtlLCAjNTU1KSwgRFVQMiBhbmQgU1dBUCBwbHVzIGEgY2FsbCBiZWZvcmUgYSBKQ1Rvb2xzIG9mZmVyLCBhbmQgYSBEVVAgYmVmb3JlIHBsdXMgRFVQX1gxIGFuZCBTV0FQIHBsdXMgYSBjYWxsIGFmdGVyIGEgSkNUb29scyBwb2xsICgjNjY0KSwgYSBjb3B5IG9mIG93bmVyIGFuZCB2YWx1ZSBwbHVzIGEgY2FsbCBiZWZvcmUgYSB2b2xhdGlsZSBmaWVsZCBzdG9yZSBhbmQgYWZ0ZXIgYSB2b2xhdGlsZSBmaWVsZCBsb2FkLCB3aXRoIGEgRFVQIG9mIHRoZSByZWNlaXZlciBiZWZvcmUgYW4gaW5zdGFuY2UgbG9hZCAoIzc0MiksIGFuZCByZXBsYWNlcyBhbiBpbnQgVmFySGFuZGxlLCBBdG9taWNJbnRlZ2VyRmllbGRVcGRhdGVyLCBBdG9taWNCb29sZWFuIG9yIEF0b21pY0ludGVnZXIgc3RvcmUsIHN3YXAgb3IgdmFsdWUtcmV0dXJuaW5nIHJlbGVhc2UsIG9yIGEgcmVmZXJlbmNlLXNsb3Qgc3RvcmUgb3IgZ2V0QW5kU2V0IG9uIGFuIEF0b21pY1JlZmVyZW5jZSwgaXRzIHVwZGF0ZXIsIGl0cyBhcnJheSBvciBhbiBpbnN0YW5jZS1maWVsZCBWYXJIYW5kbGUsIG9yIGFuIGFjcXVpcmluZyByZWZlcmVuY2UgcmVhZCwgYW4gQXRvbWljUmVmZXJlbmNlIGdldCBvciBnZXRBY3F1aXJlLCBhbiB1cGRhdGVyIGdldCwgYW4gQXRvbWljUmVmZXJlbmNlQXJyYXkgZ2V0IG9yIGdldEFjcXVpcmUgb3IgYSBWYXJIYW5kbGUgZ2V0Vm9sYXRpbGUgb3IgZ2V0QWNxdWlyZSAodGhlIGFjcXVpcmUgb2YgdGhlIHN0b3JlIGl0IHJldHVybmVkLCAjNzQxKSwgb3IgYW4gQXRvbWljU3RhbXBlZFJlZmVyZW5jZSBnZXQsIGdldFJlZmVyZW5jZSwgc2V0LCBjb21wYXJlQW5kU2V0LCB3ZWFrQ29tcGFyZUFuZFNldCBvciBhdHRlbXB0U3RhbXAgKCM4MTcpLCBvciBhbiBBdG9taWNJbnRlZ2VyIGdldCBvciBhbiBBdG9taWNMb25nIGdldCwgc3RvcmUgb3IgY29tcGFyZS1hbmQtc2V0IChhIGdldCB0aGVuIHNldCwgIzExNTcpLCB3aXRoIGEgc3RhdGljIGhvb2sgY29uc3VtaW5nIHRoZSBzYW1lIHN0YWNrIGFuZCByZXR1cm5pbmcgdGhlIHNhbWUgcmVzdWx0LCBwbHVzIG9uZSBQT1Agd2hlcmUgYSBWYXJIYW5kbGUgY2FsbCBzaXRlIGRlY2xhcmVkIGEgdm9pZCByZXN1bHQgYW5kIG9uZSBDSEVDS0NBU1QgdG8gdGhlIGRlY2xhcmVkIHR5cGUgYWZ0ZXIgYSBWYXJIYW5kbGUgcmVmZXJlbmNlIGdldEFuZFNldCBvciBhY3F1aXJpbmcgcmVhZCAodGhlIHNwaW5sb2NrLCAjNTU0LCAjNTU4LCAjNjU4LCAjNjY3OyB0aGUgb3duZXJzaGlwIG9mZmVyIGFuZCB0YWtlLCAjNjY0KS4gQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciByZXBsYWNlcyBlYWNoIGNhbGwgaXRzIHRhYmxlcyBsaXN0IHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2ssIGFuZCBpbnNlcnRzIG9ubHkgdGhlIG1vbml0b3IgbG9hZHMgYW5kIHRoZSBsb29wIGJhY2stZWRnZSBjYWxsIGl0cyBvd24gcnVsZXMgZGVzY3JpYmUuIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgRFVQIHBsdXMgYSBjYWxsIGFmdGVyIHRoZSBjb25zdHJ1Y3RvciBjYWxsIG9mIGEgbmV3IFRocmVhZCguLi4pLCBhbmQgYW4gQUxPQUQgMCBwbHVzIGEgY2FsbCBhZnRlciBhIFRocmVhZCBzdWJjbGFzcyBjb25zdHJ1Y3RvcidzIHN1cGVyY2xhc3MgY2FsbCAoIzczNykuIENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGEgY2FsbCB0aGF0IGNvbnN1bWVzIGFuZCByZXR1cm5zIHRoZSBvcmRlciBhcmd1bWVudCBiZWZvcmUgYSBMaW5rZWRIYXNoTWFwKGludCwgZmxvYXQsIGJvb2xlYW4pIGNvbnN0cnVjdG9yIGNhbGwgYW5kIGEgRFVQIG9yIGFuIEFMT0FEIDAgcGx1cyBhIGNhbGwgYWZ0ZXIgaXQgKCM4MDcpLCBhIERVUCBwbHVzIGEgY2FsbCBhZnRlciBhIG5ldyBDb21wbGV0YWJsZUZ1dHVyZSgpIGNvbnN0cnVjdG9yIGNhbGwgKCMxMDU0KSwgYW5kIGFuIEFMT0FEIDAsIGFuIExEQyBvZiB0aGUgY2xhc3MgbmFtZSBhbmQgYSBjYWxsIGJlZm9yZSBlYWNoIFJFVFVSTiBvZiBhIGNvbnN0cnVjdG9yIGFuZCBhZnRlciBhIHRoaXMoLi4uKSBkZWxlZ2F0aW9uICgjNzkxKTsgaXQgbGVhdmVzIGFsb25lIGEgY2xhc3MgaW4gYSBuYW1lZCBtb2R1bGUgdGhhdCBjYW5ub3QgcmVhZCB0aGUgbGlicmFyeS4gSW50ZXJydXB0SGFuZGxlcldlYXZlciBpbnNlcnRzIGFuIExEQyBvZiB0aGUgbG9jYXRpb25zIG9mIGEgbWV0aG9kJ3MgSW50ZXJydXB0ZWRFeGNlcHRpb24gaGFuZGxlcnMgdGhhdCBuZWl0aGVyIHJldGhyb3cgbm9yIHJlc3RvcmUgdGhlIGZsYWcsIGFuZCBhIGNhbGwsIGJlZm9yZSB0aGUgZmlyc3QgaW5zdHJ1Y3Rpb24gb2YgYSBtZXRob2QgdGhhdCBkZWNsYXJlcyBvbmUsIGFuZCBsZWF2ZXMgYWxvbmUgYSBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSB0aGF0IGNhbm5vdCByZWFkIHRoZSBsaWJyYXJ5LiBQZXJzaXN0ZW5jZUhhbmRsZVdlYXZlciBpbnNlcnRzLCBiZWZvcmUgYSBjYWxsIHdob3NlIG93bmVyIGlzIGEgSlBBIEVudGl0eU1hbmFnZXIgb3IgSGliZXJuYXRlIFNlc3Npb24gYnkgbmFtZSwgYSBzdGFjay1uZXV0cmFsIGNvcHkgb2YgdGhlIHJlY2VpdmVyIChEVVA7IFNXQVAsIERVUF9YMTsgb3IgRFVQMl9YMSwgUE9QMiwgRFVQX1gyIGZvciB6ZXJvLCBvbmUgb3IgdHdvIG9uZS1zbG90IGFyZ3VtZW50cykgYW5kIGEgY2FsbCwgYW5kIGxlYXZlcyBjYWxscyB3aXRoIG1vcmUgb3Igd2lkZXIgYXJndW1lbnRzIGFsb25lICgjOTkyKS4gUnVuQmxvY2tpbmdXZWF2ZXIgaW5zZXJ0cywgYmVmb3JlIGEgc3RhdGljIGNhbGwgb2Yga290bGlueC5jb3JvdXRpbmVzLkJ1aWxkZXJzS3QucnVuQmxvY2tpbmdLLCBydW5CbG9ja2luZyBvciB0aGVpciAkZGVmYXVsdCBicmlkZ2VzIGJ5IG5hbWUsIG9uZSBjYWxsIG9mIGEgKClWIGhvb2sgdGhhdCB0YWtlcyBhbmQgbGVhdmVzIG5vdGhpbmcsIGluIGV2ZXJ5IHdvdmVuIGNsYXNzIG91dHNpZGUga290bGlueC5jb3JvdXRpbmVzICgjMTAwNykuIEtvdGxpbk11dGV4V2VhdmVyIHJlcGxhY2VzIGEga290bGlueC5jb3JvdXRpbmVzLnN5bmMuTXV0ZXggbG9jaywgdW5sb2NrIG9yIHRyeUxvY2sgY2FsbCwgb3IgaXRzIHN0YXRpYyAkZGVmYXVsdCBicmlkZ2UsIG1hdGNoZWQgYnkgb3duZXIsIG5hbWUgYW5kIGRlc2NyaXB0b3IsIHdpdGggYSBzdGF0aWMgaG9vayBjb25zdW1pbmcgdGhlIHNhbWUgc3RhY2sgYW5kIHJldHVybmluZyB0aGUgc2FtZSByZXN1bHQsIGluIGV2ZXJ5IHdvdmVuIGNsYXNzIG91dHNpZGUga290bGlueC5jb3JvdXRpbmVzICgjMTAwNykuIFNvIGZyYW1lcyBzdGF5IHZhbGlkIGFuZCBvbmx5IG1heFN0YWNrIGdyb3dzIChDT01QVVRFX01BWFMsIG5ldmVyIENPTVBVVEVfRlJBTUVTLCB3aGljaCB3b3VsZCBsb2FkIGNsYXNzZXMgZnJvbSBpbnNpZGUgdGhlIGFnZW50KS4gSW4gZXZlcnkgbW9kZSwgaW5zdGFsbCBhbmQgdGhlIHRyYW5zZm9ybWVyIG9wZW4gamF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MsIHdpdGggZmllbGRzPXRydWUgYWxzbyBqYXZhLnV0aWwuY29uY3VycmVudC5hdG9taWMsIGFuZCB3aXRoIGNvbGxlY3Rpb25zPXRydWUgYWxzbyBqYXZhLnV0aWwgYW5kIGphdmEuaW8gKGEgc3luY2hyb25pemVkIHdyYXBwZXIncyBtdXRleCwgIzk5NjsgYSBwaXBlZCB3cml0ZXIncyBzaW5rLCAjOTk0KSwgdG8gb25lIG1vZHVsZSBwZXIgd292ZW4gbG9hZGVyIGFuZCB0byBub3RoaW5nIGVsc2U6IHRoZSBtb2R1bGUgb2YgdGhlIFRlbGVtZXRyeVJlZ2lzdHJ5IGNvcHkgdGhhdCBsb2FkZXIgcmVzb2x2ZXMsIG5ldmVyIHRoZSB3b3ZlbiBsb2FkZXIgb3IgaXRzIGFuY2VzdG9ycyBhcyBzdWNoIChVcGRhdGVyQWNjZXNzLCAjNjU5LCAjNjY4LCAjODU1KTsgdGhlIGxvY2tzIG9wZW5pbmcgbGV0cyB0aGUgbGlicmFyeSByZWFkIGEgUmVlbnRyYW50TG9jayBvd25lciBhdCBhbmFseXNpcy4gSW4gZXZlcnkgbW9kZSwgYSB3b3ZlbiBjbGFzcyBpbiBhIG5hbWVkIG1vZHVsZSBnZXRzIGEgcmVhZCBlZGdlIHRvIHRoZSBsaWJyYXJ5IGNvcHkgaXRzIGxvYWRlciByZXNvbHZlcyAoVXBkYXRlckFjY2Vzcy5sZXRSZWFkLCAjODYyKTogdGhlIEpWTSdzIG93biBlZGdlIGZvciBhIHRyYW5zZm9ybWVkIGNsYXNzIHJlYWNoZXMgb25seSB0aGUgYWdlbnQgbG9hZGVyJ3MgdW5uYW1lZCBtb2R1bGUuIFRoZSBsaWJyYXJ5IHJlc29sdmVzIGFuIHVwZGF0ZXIgYm91bmQgYmVmb3JlIHRoZSBhdHRhY2ggYnkgcmVhZGluZyB0aGUgSkRLIGltcGxlbWVudGF0aW9uIGZyb20gdGhhdCBjb3B5IChKZGtVcGRhdGVyU2hhcGVDYW5hcnlUZXN0IHBpbnMgdGhlIHNoYXBlIGl0IHJlYWRzKSwgYW5kIHRoZSBvcGVuaW5nIG11c3QgZmFpbCBzaWxlbnRseSBsaWtlIHRoZSByZXN0IG9mIGluc3RhbGwuIE5vdGhpbmcgbWF5IHRocm93IG91dCBvZiBwcmVtYWluIOKAlCBhbiBleGNlcHRpb24gdGhlcmUgYWJvcnRzIEpWTSBzdGFydHVwLCB3aGljaCBpcyB3aHkgaW5zdGFsbCgpIGNhdGNoZXMgVGhyb3dhYmxlIGFuZCByZWxlYXNlcyB0aGUgZ2F0ZSByYXRoZXIgdGhhbiBwcm9wYWdhdGluZy4gQm90aCBtb2RlcyB1c2UgQWdlbnRCdWlsZGVyLkluaXRpYWxpemF0aW9uU3RyYXRlZ3kuTm9PcDogbm8gd2VhdmVyIG5lZWRzIGEgbG9hZGVkLXR5cGUgaW5pdGlhbGl6ZXIsIGFuZCBCeXRlIEJ1ZGR5J3MgZGVmYXVsdCBzZWxmLWluamVjdGlvbiBnYXZlIGV2ZXJ5IGNsYXNzIHdvdmVuIGF0IGxvYWQgYSA8Y2xpbml0PiB0aGF0IGxvYWRzIG5ldC5ieXRlYnVkZHkuZHluYW1pYy5OZXh1cyB0aHJvdWdoIHRoZSBzeXN0ZW0gY2xhc3MgbG9hZGVyLCB3aG9zZSBsb2NrIHZpcnR1YWwgdGhyZWFkcyBpbml0aWFsaXppbmcgY2xhc3NlcyBhdCBvbmNlIGNvbnRlbmQgb24gYW5kIHBpbiAoIzk4NCkuIFRoZSBQcmVtYWluLUNsYXNzIC8gQWdlbnQtQ2xhc3MgbWFuaWZlc3QgZW50cmllcyBsaXZlIGluIHRoaXMgbW9kdWxlJ3MgamFyLCB3aGljaCBpcyB3aHkgYXR0YWNoaW5nIHVzZXMgLWphdmFhZ2VudDphc3luYy10ZXN0LWFnZW50Lmphci4= ~modgranname~se-deversity-asynctest-agent-AsyncTestAgent=QXN5bmNUZXN0QWdlbnQKQUkgcnVsZXMgZm9yIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYWdlbnQuQXN5bmNUZXN0QWdlbnQ= ~modgran~se-deversity-asynctest-agent-AgentOptions=KiovQWdlbnRPcHRpb25zLmphdmEKIyMgQ29udHJhY3QtRnJvemVuIFNpZ25hdHVyZQotICoqQ29uc3RyYWludCoqOiBZb3UgbWF5IGNoYW5nZSBpbnRlcm5hbCBsb2dpYywgYnV0IE1VU1QgTk9UIG1vZGlmeSB0aGUgbWV0aG9kIG5hbWUsIHBhcmFtZXRlcnMsIHJldHVybiB0eXBlLCBvciBjaGVja2VkIGV4Y2VwdGlvbnMuCi0gKipSZWFzb24qKjogVGhlIGNsYXNzIGlzIHBhY2thZ2UtcHJpdmF0ZSBidXQgdGhlIGFnZW50QXJncyBncmFtbWFyIGl0IHBhcnNlcyBpcyBwdWJsaWMgc3VyZmFjZTogdXNlcnMgdHlwZSBpdCBvbiB0aGUgLWphdmFhZ2VudDogY29tbWFuZCBsaW5lLiBLZXkgbmFtZXMgKGluY2x1ZGVzL2V4Y2x1ZGVzL2RlYnVnKSwgdGhlIGNvbW1hLW9yLXNlbWljb2xvbiBzZXBhcmF0b3IsIHRoZSBiYXJlLXRva2VuIGNvbnRpbnVhdGlvbiB0aGF0IGxldHMgb25lIGtleSBjYXJyeSBzZXZlcmFsIHZhbHVlcywgYW5kIGNhc2UtaW5zZW5zaXRpdmUga2V5IG1hdGNoaW5nIGFyZSBhbGwgcGFydCBvZiB0aGF0IGNvbnRyYWN0IOKAlCBjaGFuZ2luZyBhbnkgb2YgdGhlbSBicmVha3MgZXhpc3RpbmcgbGF1bmNoIHNjcmlwdHMgc2lsZW50bHkuIFBhcnNpbmcgbXVzdCBzdGF5IHRvdGFsOiBpdCBpcyBjYWxsZWQgZnJvbSBwcmVtYWluLCB3aGVyZSBhIHRocm93biBleGNlcHRpb24gYWJvcnRzIEpWTSBzdGFydHVwLCBzbyB1bmtub3duIGtleXMgYXJlIGlnbm9yZWQgYW5kIG1hbGZvcm1lZCBpbnB1dCBkZWdyYWRlcyB0byB0aGUgZGVmYXVsdCBpbnN0cnVtZW50LWV2ZXJ5dGhpbmcgYmVoYXZpb3VyIHJhdGhlciB0aGFuIGZhaWxpbmcu ~modgranname~se-deversity-asynctest-agent-AgentOptions=QWdlbnRPcHRpb25zCkFJIHJ1bGVzIGZvciBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFnZW50LkFnZW50T3B0aW9ucw== diff --git a/.vibetags-mod-async-test-lib b/.vibetags-mod-async-test-lib index 22dc3b556..f534488a2 100644 --- a/.vibetags-mod-async-test-lib +++ b/.vibetags-mod-async-test-lib @@ -2,9 +2,9 @@ moduleId=async-test-lib modulePath=async-test-lib regionId=async-test-lib -claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxsb2NrZWRfZmlsZXM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSI+CiAgICAgIDxyZWFzb24+QWRkaW5nIG9yIHJlbW92aW5nIGEgY29uc3RhbnQgcmVxdWlyZXMgc3luY2hyb25pemVkIGNoYW5nZXMgaW4gdGhyZWUgcGxhY2VzOiAoMSkgdGhlIEFzeW5jVGVzdENvbmZpZyBwdWJsaWMgZmxhZyBhbmQgaXRzIGRlcml2YXRpb24gZW5hYmxlZC5jb250YWlucyhUWVBFKSwgd2l0aCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpLCAoMikgdGhlIERldGVjdG9yUmVnaXN0cnkgZmllbGQgYW5kIGl0cyBmYWN0b3J5IHJvdyBjcmVhdGUoRGV0ZWN0b3JUeXBlLlRZUEUsIFg6Om5ldyksIGFuZCAoMykgdGhlIHJlZ2lzdHJ5JiMzOTtzIGlmSXNzdWUgYW5hbHlzaXMgY2FsbC4gQWRkaW5nIGEgdmFsdWUgaGVyZSBpbiBpc29sYXRpb24gY29tcGlsZXMgYW5kIGRldGVjdHMgbm90aGluZy4gVGhlIEBBc3luY1Rlc3QgYXR0cmlidXRlIGFuZCB0aGUgYnVpbGQoKSByZXNvbHV0aW9uIGxpbmUgaXQgb25jZSBhbHNvIG5lZWRlZCBhcmUgZ29uZSAoIzkxNywgIzkyMCkuIFRoZSBsb2NrIGlzIG9uIHRoZSBjb25zdGFudCBzZXQsIG5vdCB0aGUgZmlsZTogZWRpdGluZyBqYXZhZG9jIG9uIGV4aXN0aW5nIGNvbnN0YW50cyBjYW5ub3QgYnJlYWsgdGhhdCBpbnZhcmlhbnQgYW5kIG5lZWRzIG5vIGNlcmVtb255LjwvcmVhc29uPgogICAgPC9maWxlPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2UuVkVORE9SX1ZFUklGWV9LRVlfQjY0Ij4KICAgICAgPHJlYXNvbj5FdmVyeSBvZmZsaW5lIGxpY2VuY2UgZmlsZSBhbHJlYWR5IGlzc3VlZCB0byBhIGN1c3RvbWVyIHZlcmlmaWVzIGFnYWluc3QgdGhpcyBrZXksIGFuZCBpdHMgcHJpdmF0ZSBoYWxmIGV4aXN0cyBvbmx5IG9uIHRoZSBvcGVyYXRvciBtYWNoaW5lLiBBIGNoYW5nZWQgdmFsdWUgZGVuaWVzIGVhY2ggb2YgdGhvc2UgZmlsZXMgd2l0aCBPRkZMSU5FX0ZJTEVfU0lHTkFUVVJFX0lOVkFMSUQgb24gdGhlIGN1c3RvbWVyJiMzOTtzIG5leHQgYnVpbGQuIFJvdGF0aW9uIG1lYW5zIHJlLWlzc3VpbmcgZXZlcnkgZmlsZSBmaXJzdDogYSByZWxlYXNlIGRlY2lzaW9uLCBub3QgYSBjb2RlIGVkaXQuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9sb2NrZWRfZmlsZXM+CiAgPGNvbnRleHR1YWxfaW5zdHJ1Y3Rpb25zPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb25maWciPgogICAgICA8Zm9jdXM+S2VlcCBvbmUgcHVibGljIGZsYWcgcGVyIERldGVjdG9yVHlwZSwgZWFjaCBkZXJpdmVkIGZyb20gdGhlIGVuYWJsZWQgc2V0LCBhbmQgdGhlIHNlbGVjdGlvbiBpbiBmcm9tKEFzeW5jVGVzdCkgYW5kIGJ1aWxkKCkgZXhwcmVzc2VkIG9ubHkgdGhyb3VnaCBpbmNsdWRlcywgZXhjbHVkZXMsIHByZXNldCBhbmQgZGV0ZWN0QWxsPC9mb2N1cz4KICAgICAgPGF2b2lkcz5tdXRhYmxlIHN0YXRlIOKAlCB0aGlzIGNsYXNzIG11c3QgcmVtYWluIGltbXV0YWJsZSBhZnRlciBjb25zdHJ1Y3Rpb248L2F2b2lkcz4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JSZWdpc3RyeSI+CiAgICAgIDxmb2N1cz5FYWNoIG5ldyBkZXRlY3RvciByZXF1aXJlcyBleGFjdGx5IHRocmVlIHN0ZXBzIGluIHRoaXMgY2xhc3M6ICgxKSBhIGZpbmFsIGZpZWxkIGRlY2xhcmF0aW9uLCAoMikgaXRzIGZhY3RvcnktdGFibGUgcm93IGluIHRoZSBjb25zdHJ1Y3RvciwgZmllbGQgPSBjcmVhdGUoRGV0ZWN0b3JUeXBlLlRZUEUsIERldGVjdG9yOjpuZXcpLCBrZXllZCBvbiB0aGUgdHlwZSBhbmQgbmV2ZXIgb24gYSBjb25maWcgZmxhZyAoIzkxNiksICgzKSBhbiBhbmFseXplQWxsKCkgY2FsbCBpbiB0aGUgY29ycmVjdCBwaGFzZSBibG9jay4gQWxsIHRocmVlIHN0ZXBzIG11c3QgYmUgYWRkZWQgdG9nZXRoZXIuPC9mb2N1cz4KICAgICAgPGF2b2lkcz5wYXJ0aWFsIHBhdHRlcm5zIOKAlCBhIGZpZWxkIHdpdGhvdXQgY29uc3RydWN0aW9uIG9yIGFuYWx5c2lzIHNpbGVudGx5IHNraXBzIGRldGVjdGlvbjwvYXZvaWRzPgogICAgPC9maWxlPgogIDwvY29udGV4dHVhbF9pbnN0cnVjdGlvbnM+CgogIDxhdWRpdF9yZXF1aXJlbWVudHM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQiPgogICAgICA8dnVsbmVyYWJpbGl0eV9jaGVjaz5UaHJlYWQgU2FmZXR5IGlzc3VlczwvdnVsbmVyYWJpbGl0eV9jaGVjaz4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkNvbmN1cnJlbmN5UnVubmVyIj4KICAgICAgPHZ1bG5lcmFiaWxpdHlfY2hlY2s+VGhyZWFkIFNhZmV0eSBpc3N1ZXM8L3Z1bG5lcmFiaWxpdHlfY2hlY2s+CiAgICAgIDx2dWxuZXJhYmlsaXR5X2NoZWNrPlJlc291cmNlIExlYWtzPC92dWxuZXJhYmlsaXR5X2NoZWNrPgogICAgPC9maWxlPgogIDwvYXVkaXRfcmVxdWlyZW1lbnRzPgoKPHJ1bGU+CiAgSWYgeW91IGFyZSBhc2tlZCB0byBtb2RpZnkgYW55IGZpbGUgbGlzdGVkIGluIDxhdWRpdF9yZXF1aXJlbWVudHM+LCB5b3UgbXVzdCBmaXJzdCBzaWxlbnRseSBhbmFseXplIHlvdXIgcHJvcG9zZWQgY29kZSBmb3IgdGhlIGxpc3RlZCA8dnVsbmVyYWJpbGl0eV9jaGVjaz4gaXRlbXMuIElmIHlvdXIgY29kZSBpbnRyb2R1Y2VzIHRoZXNlIHZ1bG5lcmFiaWxpdGllcywgeW91IG11c3QgcmV3cml0ZSBpdCBiZWZvcmUgZGlzcGxheWluZyBpdCB0byB0aGUgdXNlci4KPC9ydWxlPgogIDxpZ25vcmVkX2VsZW1lbnRzPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Ob29wQXN5bmNUZXN0TGlzdGVuZXIiPgogICAgICA8cmVhc29uPlRyaXZpYWwgbm8tb3AgaW1wbGVtZW50YXRpb24gb2YgQXN5bmNUZXN0TGlzdGVuZXIuIEFsbCBtZXRob2RzIGFyZSBpbnRlbnRpb25hbGx5IGVtcHR5IOKAlCBubyBsb2dpYyB0byByZXZpZXcgb3IgY2hhbmdlIGhlcmUuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9pZ25vcmVkX2VsZW1lbnRzPgoKPHJ1bGU+TmV2ZXIgcmVmZXJlbmNlIG9yIHN1Z2dlc3QgY2hhbmdlcyB0byBhbnkgZWxlbWVudCBsaXN0ZWQgaW4gPGlnbm9yZWRfZWxlbWVudHM+LiBUcmVhdCB0aGVzZSBhcyBpZiB0aGV5IGRvIG5vdCBleGlzdC48L3J1bGU+CiAgPHBpaV9ndWFyZHJhaWxzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZUd1YXJkLkZpbmdlcnByaW50Ij4KICAgICAgPHJlYXNvbj5Ib2xkcyB0aGUgbGljZW5jZSBrZXkgYW5kIHRoZSBsaWNlbnNlZCB1c2VyJiMzOTtzIGVtYWlsLCBhbmQgdGhlIHJlY29yZCYjMzk7cyBnZW5lcmF0ZWQgdG9TdHJpbmcoKSBwcmludHMgYm90aCwgc28gbmV2ZXIgbG9nIG9yIGZvcm1hdCBhIEZpbmdlcnByaW50IHdob2xlLiBUaGUgZW1haWwgbWF5IHJlYWNoIHRoZSBsaWNlbmNlIHByb3ZpZGVyIChLZXlnZW4gdXNlciBzY29wZSwgTGVtb25TcXVlZXp5IGJpbmRpbmcpIGFuZCBhIGRlbmlhbCBtZXNzYWdlIGluIHRoYXQgdXNlciYjMzk7cyBvd24gYnVpbGQ7IGRpc2sgc2VlcyBlaXRoZXIgdmFsdWUgb25seSBpbnNpZGUgdGhlIFNIQS0yNTYgTGljZW5zZVZhbGlkYXRpb25DYWNoZSBzdG9yZXMuIE5ldmVyIHB1dCBvbmUgaW4gYW4gSU5GTyBsaW5lLCBhIHJlcG9ydCwgU0FSSUYgb3IgSlVuaXQgWE1MOiB0aG9zZSBlbmQgdXAgaW4gQ0kgbG9ncyBhbmQgcHVibGlzaGVkIGFydGlmYWN0cy48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICA8L3BpaV9ndWFyZHJhaWxzPgoKPHJ1bGU+CiAgTmV2ZXIgaW5jbHVkZSBydW50aW1lIHZhbHVlcyBvZiBlbGVtZW50cyBsaXN0ZWQgaW4gPHBpaV9ndWFyZHJhaWxzPiBpbiBsb2dzLCBjb25zb2xlIG91dHB1dCwgZXh0ZXJuYWwgQVBJIGNhbGxzLCB0ZXN0IGZpeHR1cmVzLCBtb2NrIGRhdGEsIG9yIGNvZGUgc3VnZ2VzdGlvbnMuIFRyZWF0IHRoZWlyIHZhbHVlcyBhcyBzdHJpY3RseSBjb25maWRlbnRpYWwuCjwvcnVsZT4KICA8Y29yZV9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnIj4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+U2VsZWN0aW9uIGlzIG9uZSBFbnVtU2V0IHJlc29sdmVkIG9uY2UgaW4gYnVpbGQoKSAoIzkxNyk7IGV2ZXJ5IHB1YmxpYyBkZXRlY3RvciBmbGFnIGlzIGFzc2lnbmVkIGVuYWJsZWQuY29udGFpbnMoVFlQRSkgaW4gdGhlIGNvbnN0cnVjdG9yIGFuZCBub3doZXJlIGVsc2UsIHNvIGEgZmxhZyBjYW5ub3QgZGlzYWdyZWUgd2l0aCBlbmFibGVkRGV0ZWN0b3JzKCkuIEEgbmV3IGRldGVjdG9yIGhlcmUgaXMgdGhlIGZsYWcgYW5kIGl0cyBkZXJpdmF0aW9uIGFuZCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpOyBAQXN5bmNUZXN0IGhhcyBubyBwZXItZGV0ZWN0b3IgYXR0cmlidXRlIHRvIHJlYWQgc2luY2UgMS4xMy4wICgjOTIwKS4gTmV2ZXIgcmVpbnRyb2R1Y2UgYSBwZXItZGV0ZWN0b3IgcmVzb2x1dGlvbiBleHByZXNzaW9uIGluIGJ1aWxkKCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0Ij4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+VGhyZWFkTG9jYWwgaW5zdGFsbC91bmluc3RhbGwgbXVzdCBhbHdheXMgYmUgc3ltbWV0cmljLiBBIGxlYWsgcHJvcGFnYXRlcyBzdGFsZSBkZXRlY3RvciBzdGF0ZSBhY3Jvc3MgdGVzdCBpbnZvY2F0aW9ucyBhbmQgY2F1c2VzIGZhbHNlIHBvc2l0aXZlcyBvciBtaXNzZWQgZGV0ZWN0aW9ucy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RJbnZvY2F0aW9uSW50ZXJjZXB0b3IiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5pbnZvY2F0aW9uLnNraXAoKSBpcyBpbnRlbnRpb25hbCDigJQgQ29uY3VycmVuY3lSdW5uZXIgb3ducyB0aGUgZnVsbCBOw5dNIGV4ZWN1dGlvbiBhbmQgbXVzdCBuZXZlciBjYWxsIGludm9jYXRpb24ucHJvY2VlZCgpLiBSZXN0b3JpbmcgcHJvY2VlZCgpIHdvdWxkIHJ1biB0aGUgdGVzdCBib2R5IG9uY2Ugb3V0c2lkZSB0aGUgQ3ljbGljQmFycmllciwgYnlwYXNzaW5nIGFsbCBkZXRlY3RvcnMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXIiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5Db3JlIHN0cmVzcy10ZXN0IGV4ZWN1dGlvbiBlbmdpbmUuIFRoZSBDeWNsaWNCYXJyaWVyIHBhdHRlcm4gZm9yY2VzIG1heGltdW0gdGhyZWFkIGNvbnRlbnRpb24uIFRpbWVvdXQgbG9naWMgYW5kIEFzeW5jVGVzdENvbnRleHQgaW5zdGFsbC91bmluc3RhbGwgYXJlIGNhcmVmdWxseSBjYWxpYnJhdGVkIOKAlCBzdWJ0bGUgY2hhbmdlcyBpbnRyb2R1Y2UgZmxha3kgdGVzdHMgb3IgbWlzc2VkIGRldGVjdG9yIGFjdGl2YXRpb25zLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LkNvbnRyb2xsZWRTY2hlZHVsZSI+CiAgICAgIDxzZW5zaXRpdml0eT5IaWdoPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+QSBzZWVkIHJlcGxheXMgYSByb3VuZCBvbmx5IHdoaWxlIGV2ZXJ5IGRlY2lzaW9uIG9mIHdobyBydW5zIG5leHQgZGVwZW5kcyBvbiBzdGF0ZSBjaGFuZ2VkIGF0IHNjaGVkdWxpbmcgcG9pbnRzOiB0aGUgc3RhdHVzZXMsIHByaW9yaXRpZXMgYW5kIHN0ZXAgY291bnQgdGhhdCBncmFudCgpIGFuZCBzdGVwKCkgcmVhZCwgYW5kIHRoZSBsb2NrIGhvbGRzIGFuZCBwZW5kaW5nIGFjcXVpc2l0aW9ucyBncmFudCgpIGNvbnN1bHRzICgjMTAyMiksIHdoaWNoIGNoYW5nZSBvbmx5IGF0IGFjcXVpcmluZygpLCBpdHNlbGYgYSBwb2ludCwgYW5kIGluIGFjcXVpcmVkKCkgYW5kIHJlbGVhc2VkKCksIHdoaWNoIGEgd29ya2VyIGNhbGxzIGluIGl0cyBvd24gcHJvZ3JhbSBvcmRlcjsgYW4gZXNjYXBlZCB3b3JrZXImIzM5O3MgYWNxdWlyZSBvciByZWxlYXNlIGxhbmRzIG91dHNpZGUgYSB0dXJuLCBidXQgaXRzIHJvdW5kIGhhcyBhbHJlYWR5IGNvdW50ZWQgdGhlIGVzY2FwZS4gZ3JhbnQoKSBtdXN0IGtlZXAgaGFuZGluZyB0aGUgcm91bmQgb3V0IHdoZW4gZXZlcnkgcmVhZHkgd29ya2VyIHdhaXRzIG9uIGEgaGVsZCBsb2NrOiB0aGUgaG9sZCBtYXkgYmUgc3RhbGUgKGEgbW9uaXRvciByZWxlYXNlZCBpbnNpZGUgT2JqZWN0LndhaXQgaXMgbm90IHNlZW4pLCBhbmQgd2l0aGhvbGRpbmcgdGhlIHJvdW5kIHRoZW4gc3RhbGxzIGNvcnJlY3Qgd2FpdC9ub3RpZnkgY29kZSB1bnRpbCB0aGUgcm91bmQgdGltZXMgb3V0IChDb250cm9sbGVkU2NoZWR1bGVMb2NrVGVzdCk7IGVhY2ggc3VjaCBncmFudCBpcyBjb3VudGVkIGFzIGEgZmFsbGJhY2suIFRvIGtlZXAgaG9sZHMgZnJvbSBnb2luZyBzdGFsZSwgYSB3b3ZlbiBPYmplY3Qud2FpdCBvciBDb25kaXRpb24uYXdhaXQgaGFuZHMgaXRzIGhvbGRzIGJhY2sgYmVmb3JlIHdhaXRpbmcgYW5kIHRha2VzIHRoZW0gYWdhaW4gYWZ0ZXIgKHJlbGVhc2luZ0ZvcldhaXQsIHJlYWNxdWlyZWRBZnRlcldhaXQ7IGxvY2tPZiBmaW5kcyBhIGNvbmRpdGlvbiYjMzk7cyBSZWVudHJhbnRMb2NrIGJ5IGFza2luZyBpdCksIGFuZCBhIHdvcmtlciByZS1jb25maXJtcyBpdHMgb3duIHJlY29yZGVkIGhvbGRzIHdpdGggVGhyZWFkLmhvbGRzTG9jayBvciBpc0hlbGRCeUN1cnJlbnRUaHJlYWQgYXQgZWFjaCBvZiBpdHMgcG9pbnRzIGFuZCBhdCBsZWF2ZSgpLCBvbiBpdHMgb3duIHRocmVhZCwgc28gdGhlIGFuc3dlciBmb2xsb3dzIGl0cyBwcm9ncmFtIG9yZGVyIGFuZCBncmFudCgpIHN0aWxsIHJlYWRzIG5vIHRocmVhZCBzdGF0ZSAoIzEwNDgpLiBPbmx5IHdhdGNoKCkgbWF5IHJlYWQgdGhlIGNsb2NrIG9yIFRocmVhZC5nZXRTdGF0ZSgpLCBhbmQgaXQgcmVhZHMgdGhlIHN0YXRlIGJlZm9yZSBhc2tpbmcgd2hldGhlciB0aGUgcnVubmluZyB3b3JrZXIsIG9yIGFuIGFkb3B0ZWQgY2hpbGQgc3RpbGwgYXJyaXZpbmcsIGlzIHF1ZXVlZCBvbiB0aGUgc2NoZWR1bGUmIzM5O3Mgb3duIGxvY2ssIHdoaWNoIGlzIHRoZSBzY2hlZHVsZXImIzM5O3Mgd2FpdCBhbmQgbmV2ZXIgYW4gZXNjYXBlICgjMTA2NSwgIzEwNzIpOyBlYWNoIGRlY2lzaW9uIGl0IG1ha2VzIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCB3aGljaCBpcyB3aGF0IHRlbGxzIHRoZSBydW5uZXIgdGhlIHNlZWQgbm8gbG9uZ2VyIHJlcGxheXMgZXhhY3RseSwgd2l0aCBvbmUgZXhjZXB0aW9uOiBhbiBhZG9wdGVkIGNoaWxkIHdob3NlIHRocmVhZCBoYXMgdGVybWluYXRlZCBpcyBtYXJrZWQgZG9uZSwgbm90IGVzY2FwZWQgKCMxMDI0KSwgYmVjYXVzZSB3aGlsZSBpdCByYW4gdG8gaXRzIGVuZCBldmVyeSBwZWVyIHdhcyB3YWl0aW5nLCBzbyB0aGUgc3RhdGUgdGhlIG5leHQgZ3JhbnQgcmVhZHMgaXMgdGhlIHNhbWUgd2hlbmV2ZXIgd2F0Y2goKSBub3RpY2VzLiBBZG9wdGVkIGNoaWxkcmVuIGFyZSByZWFkeSBmcm9tIHRoZSBtb21lbnQgdGhleSBhcmUgYWRvcHRlZCwgc28gYSBncmFudCBuZXZlciBkZXBlbmRzIG9uIGhvdyBsb25nIHRoZSBPUyB0YWtlcyB0byBzdGFydCBhIHRocmVhZDsgYW4gYWRvcHRlZCBleGVjdXRvciB0YXNrICgjMTA0OSkgaXMgcmVhZHkgZnJvbSBpdHMgd292ZW4gc3VibWlzc2lvbiB0aGUgc2FtZSB3YXksIGpvaW5zIGF0IHRhc2tTdGFydGluZyBvbiB0aGUgcG9vbCB0aHJlYWQgYW5kIGxlYXZlcyBhdCB0YXNrRW5kZWQsIGFuZCBvbmUgdGhhdCBoYXMgbm90IHN0YXJ0ZWQgd2l0aGluIFNUQUxMX05BTk9TIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCBzaW5jZSBpdHMgZXhlY3V0b3IgbWF5IG5ldmVyIHJ1biBpdC4gQSB3b3JrZXIgd2FpdGluZyBhdCBhIHJlbmRlenZvdXMgaXMgT1VUU0lERSwgbm90IGVzY2FwZWQgKCMxMDIxKSwgYW5kIG5vIGdyYW50IGlzIG1hZGUgd2hpbGUgb25lIGlzIG91dHNpZGUgb24gaXRzIHdheSBiYWNrIG9yIHdoZW4gdGhlIGxhc3Qgd29ya2VyIHN0ZXBzIG91dCwgc28gdGhlIG9yZGVyIGEgcmVuZGV6dm91cyByZWxlYXNlcyB3b3JrZXJzIGluIG5ldmVyIGRlY2lkZXMgd2hvIHJ1bnMgbmV4dC4gQSBncmFudCgpIHRoYXQgcmVhZCB0aW1lIG9yIHRocmVhZCBzdGF0ZSwgb3IgYW4gZXNjYXBlIGxlZnQgdW5jb3VudGVkLCBzdGlsbCBwYXNzZXMgZXZlcnkgcnVuIGFuZCBtYWtlcyB0aGUgcHJpbnRlZCByZXBsYXkgbGluZSBhIGZhbHNlIHByb21pc2UuPC9ub3RlPgogICAgPC9lbGVtZW50PgogIDwvY29yZV9lbGVtZW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8Y29yZV9lbGVtZW50cz4gYXJlIHdlbGwtdGVzdGVkIGNvcmUgY29tcG9uZW50cy4gTWFrZSBjaGFuZ2VzIHdpdGggZXh0cmVtZSBjYXV0aW9uIGFuZCB2ZXJpZnkgY29tcHJlaGVuc2l2ZSB0ZXN0IGNvdmVyYWdlIGJlZm9yZSBwcm9wb3NpbmcgbW9kaWZpY2F0aW9ucy48L3J1bGU+CiAgPHBlcmZvcm1hbmNlX2NvbnN0cmFpbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIiPgogICAgICA8Y29uc3RyYWludD5yZWNvcmRJbnZvY2F0aW9uU3RhcnQoKSBhbmQgcmVjb3JkSW52b2NhdGlvbkVuZCgpIGFyZSBjYWxsZWQgb24gdGhlIGhvdCBwYXRoIGluc2lkZSBldmVyeSBpbnZvY2F0aW9uIHJvdW5kLiBLZWVwIHRoZW0gYWxsb2NhdGlvbi1mcmVlIGFuZCBhdm9pZCBhY3F1aXJpbmcgbG9ja3MgaW4gdGhlIGNvbW1vbiBjYXNlLjwvY29uc3RyYWludD4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2l0ZUNhcHR1cmUiPgogICAgICA8Y29uc3RyYWludD5DYWxsZWQgZnJvbSBkZXRlY3RvciByZWNvcmRBY2Nlc3MgcGF0aHM7IGRvIG5vdCBhbGxvY2F0ZSB3aGVuIGEgc2l0ZSBpcyBhbHJlYWR5IGNhcHR1cmVkIGZvciBhIGdpdmVuIGtleS48L2NvbnN0cmFpbnQ+CiAgICA8L2VsZW1lbnQ+CiAgPC9wZXJmb3JtYW5jZV9jb25zdHJhaW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8cGVyZm9ybWFuY2VfY29uc3RyYWludHM+IGFyZSBvbiBhIGhvdCBwYXRoLiBOZXZlciBpbnRyb2R1Y2UgTyhuwrIpIG9yIHdvcnNlIGNvbXBsZXhpdHkuIEFsd2F5cyByZWFzb24gYWJvdXQgdGltZSBhbmQgc3BhY2UgY29tcGxleGl0eSBiZWZvcmUgc3VnZ2VzdGluZyBjaGFuZ2VzLjwvcnVsZT4KICA8Y29udHJhY3Rfc2lnbmF0dXJlcz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRDb2xsZWN0aW9uSG9va3MiPgogICAgICA8cmVhc29uPkNhbGxlZCBmcm9tIGJ5dGVjb2RlIHRoZSBhZ2VudCByZXdyaXRlcywgbm90IGZyb20gc291cmNlOiB0aGUgbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBhcmUgbWF0Y2hlZCBieSBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyIGFuZCBjYW5ub3QgY2hhbmdlIGluZGVwZW5kZW50bHkgb2YgaXQuIEV2ZXJ5IGhvb2sgbXVzdCBlbmQgYnkgcGVyZm9ybWluZyB0aGUgb3JpZ2luYWwgb3BlcmF0aW9uIGFuZCBtdXN0IG5ldmVyIHRocm93IG9uIHRoZSByZWNvcmRpbmcgcGF0aCAtIGl0IHJ1bnMgaW5zaWRlIHRoZSB1c2VyJiMzOTtzIGNvZGUsIHNvIGFuIGV4Y2VwdGlvbiBoZXJlIHN1cmZhY2VzIGFzIGEgZmFpbHVyZSBpbiB0aGVpciB0ZXN0LiBSZWNvcmRpbmcgaXMgYmVzdC1lZmZvcnQgYnkgZGVzaWduOiBubyBjb250ZXh0LCBhIGRpc2FibGVkIGRldGVjdG9yLCBvciBhIHR5cGUgdGhlIGxpYnJhcnkga25vd3MgaXMgdGhyZWFkLXNhZmUgYWxsIG1lYW4gcmVjb3JkIG5vdGhpbmcgYW5kIGRlbGVnYXRlLiBBIHF1ZXVlIG9mZmVyIG9yIHRha2UgaG9vayB3aXRoIGEgdHJhaWxpbmcgT2JqZWN0IHBhcmFtZXRlciBpcyB0aGUgdmFyaWFudCB0aGUgd2VhdmVyIGNhbGxzIHdpdGggdGhlIGVuY2xvc2luZyBtZXRob2QmIzM5O3Mgb3duIG1vbml0b3I6IHRoaXMgaW4gYW4gaW5zdGFuY2UgbWV0aG9kLCB0aGUgY2xhc3MgaW4gYSBzdGF0aWMgc3luY2hyb25pemVkIG9uZS4gQSBzeW5jaHJvbml6ZWQgbWV0aG9kIGhvbGRzIGl0IHdpdGggbm8gaW5zdHJ1Y3Rpb24gdG8gc2F5IHNvICgjNzk2KSwgYW5kIGEgaGVscGVyIHRoYXQgbWV0aG9kIGNhbGxzIGhvbGRzIGl0IHRvbyAoIzc1MSksIHNvIHRoZSBob29rIGNvdW50cyBpdCBhbW9uZyB0aGUgaGVsZCBsb2NrcyBleGFjdGx5IHdoZW4gVGhyZWFkLmhvbGRzTG9jayBzYXlzIHNvLCBhbmQgdGhlIHR3by1hcmd1bWVudCBmb3JtIGRlbGVnYXRlcyB3aXRoIG51bGwuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFnZW50Q29uY3VycmVuY3lVdGlsSG9va3MiPgogICAgICA8cmVhc29uPkNhbGxlZCBmcm9tIGJ5dGVjb2RlIHRoZSBhZ2VudCByZXdyaXRlczogbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBoZXJlIGFyZSBtYXRjaGVkIGJ5IENvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIuQ09OQ1VSUkVOQ1lfRU5UUklFUyBhbmQgY2Fubm90IGNoYW5nZSBpbmRlcGVuZGVudGx5IG9mIGl0LiBFdmVyeSBob29rIG11c3QgcGVyZm9ybSB0aGUgb3JpZ2luYWwgb3BlcmF0aW9uIGFuZCBwcm9wYWdhdGUgaXRzIGV4Y2VwdGlvbnMgdW5jaGFuZ2VkLCBJbnRlcnJ1cHRlZEV4Y2VwdGlvbiBpbmNsdWRlZCAtIHRoZXNlIHR5cGVzIHRocm93IGl0IGFzIGEgbWF0dGVyIG9mIGNvdXJzZSBhbmQgc3dhbGxvd2luZyBvbmUgd291bGQgY2hhbmdlIHRoZSBpbnRlcnJ1cHRpb24gc2VtYW50aWNzIG9mIHRoZSBjb2RlIHVuZGVyIHRlc3QuIFJlY29yZCBhZnRlciBhY3F1aXJpbmcgYW5kIGJlZm9yZSByZWxlYXNpbmcsIHRoZSBjb250YWlubWVudCBydWxlIEFnZW50TG9ja0hvb2tzIGRvY3VtZW50cywgYW5kIHJlY29yZCBub3RoaW5nIHdoZW4gdGhlIHVuZGVybHlpbmcgY2FsbCB0aHJvd3MsIGV4Y2VwdCB0aGF0IGEgc3VibWl0IG9yIGV4ZWN1dGUgdGhlIGV4ZWN1dG9yIHJlZnVzZXMgcmVjb3JkcyB0aGUgUmVqZWN0ZWRFeGVjdXRpb25FeGNlcHRpb24gd2l0aCBUaHJlYWRQb29sTW9uaXRvciBiZWZvcmUgcmV0aHJvd2luZyB0aGF0IHNhbWUgZXhjZXB0aW9uICgjMTA1NSkuIG9mZmVyLCBwb2xsIGFuZCB0aGUgdGltZWQgYXdhaXQgbXVzdCByZWNvcmQgdGhlaXIgYWN0dWFsIHJldHVybiB2YWx1ZTogdGhlIGJvb2xlYW4gYSBjYWxsZXIgZGlzY2FyZHMgaXMgdGhlIHdob2xlIGJ1ZyB0aGVzZSBkZXRlY3RvcnMgcmVwb3J0LiBUaGUgb2JzZXJ2ZSogY2FsbCBtdXN0IHN0YXkgYWhlYWQgb2YgdGhlIG9wZXJhdGlvbjogaXQgaXMgd2hlcmUgTGF0Y2hNaXN1c2VEZXRlY3RvciBhbmQgQmxvY2tpbmdRdWV1ZURldGVjdG9yIGxlYXJuIGEgc3ViamVjdCBleGlzdHMgYXQgYWxsLCBhbmQgdGhlIGxhdGNoJiMzOTtzIHN0YXJ0aW5nIGNvdW50IGlzIG9ubHkgcmVhZGFibGUgYmVmb3JlIHRoaXMgY2FsbCBkZWNyZW1lbnRzIGl0LiBvZmZlclJlc3VsdERpc2NhcmRlZCBpcyBub3QgYW4gb3BlcmF0aW9uOiB0aGUgd2VhdmVyIHN1YnN0aXR1dGVzIGl0IGZvciB0aGUgUE9QIHRoYXQgZm9sbG93cyBhbiBvZmZlciB3aG9zZSBib29sZWFuIHRoZSBjYWxsZXIgbmV2ZXIgcmVhZCwgc28gaXQgaXMgYWx3YXlzIHRoZSBpbnN0cnVjdGlvbiBhZnRlciBvbmUgb2YgdGhlIG9mZmVyIGhvb2tzIG9uIHRoZSBzYW1lIHRocmVhZCwgYW5kIGl0IG11c3Qgc3RheSB0aGF0IHdheSAtIHRoZSBkZXRlY3RvciBjb3JyZWxhdGVzIGl0IHRvIHRoZSBvZmZlciByZWNvcmRlZCBpbW1lZGlhdGVseSBiZWZvcmUsIGFuZCB0aGF0IGNvcnJlbGF0aW9uIGlzIGV4YWN0IG9ubHkgYmVjYXVzZSB0aGUgd2VhdmVyIGVtaXRzIGl0IGluIHBsYWNlIG9mIHRoZSBQT1AgYW5kIG5vd2hlcmUgZWxzZS48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRDb25zdHJ1Y3Rpb25Ib29rcyI+CiAgICAgIDxyZWFzb24+Q2FsbGVkIGZyb20gYnl0ZWNvZGUgdGhlIGFnZW50IGluc2VydHMsIG5vdCBmcm9tIHNvdXJjZTogQ29uc3RydWN0aW9uV2VhdmVyIG1hdGNoZXMgdGhlc2UgbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBhdCB3ZWF2ZSB0aW1lLCBzbyBub25lIGNhbiBjaGFuZ2UgaW5kZXBlbmRlbnRseSBvZiBpdC4gVGhlc2UgYXJlIGluc2VydGVkIGNhbGxzLCBub3Qgc3Vic3RpdHV0aW9uczogdGhlcmUgaXMgbm8gb3JpZ2luYWwgb3BlcmF0aW9uIHRvIHBlcmZvcm0sIGFuZCBlYWNoIG11c3QgaGFuZCBiYWNrIGV4YWN0bHkgd2hhdCB0aGUgc3RhY2sgaGVsZCAobGlua2VkSGFzaE1hcEFjY2Vzc09yZGVyIHJldHVybnMgaXRzIGFyZ3VtZW50IHVuY2hhbmdlZCwgb3IgdGhlIGNvbnN0cnVjdG9yIHdvdWxkIGJ1aWxkIGEgbWFwIGluIHRoZSB3cm9uZyBvcmRlcikuIFRoZXkgcnVuIGluc2lkZSB1c2VyIGNvbnN0cnVjdG9ycywgc28gdGhleSBtdXN0IG5ldmVyIHRocm93LiBjb25zdHJ1Y3RvclJldHVybmVkIGFuZCBjb25zdHJ1Y3RvclJlc3VtZWQgcnVuIGZvciBldmVyeSBvYmplY3QgYW55IHdvdmVuIGNsYXNzIGJ1aWxkczogd2hpbGUgbm8gY29uc3RydWN0aW9uIGlzIHRyYWNrZWQgdGhleSBtdXN0IHN0YXkgYSBjaGVjayBvZiBhbiBlbXB0eSBtYXAsIHdpdGggbm8gYWxsb2NhdGlvbiBhbmQgbm8gc3RhY2sgd2Fsay4gY29tcGxldGFibGVGdXR1cmVDb25zdHJ1Y3RlZCBydW5zIGZvciBldmVyeSBuZXcgQ29tcGxldGFibGVGdXR1cmUoKSBpbiB3b3ZlbiBjb2RlIGFuZCBtdXN0IGNvc3Qgb25lIGNvbnRleHQgbG9va3VwIG91dHNpZGUgYSBydW4gKCMxMDU0KS48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRHY0hvb2tzIj4KICAgICAgPHJlYXNvbj5DYWxsZWQgZnJvbSBieXRlY29kZSB0aGUgYWdlbnQgcmV3cml0ZXM6IHRoZSBtZXRob2QgbmFtZXMgYW5kIGVyYXNlZCBzaWduYXR1cmVzIGhlcmUgKGdjKCkgZm9yIFN5c3RlbS5nYywgcnVudGltZUdjKFJ1bnRpbWUpIGZvciBSdW50aW1lLmdjKSBhcmUgbWF0Y2hlZCBieSBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyLkdDX0VOVFJJRVMgYW5kIGNhbm5vdCBjaGFuZ2UgaW5kZXBlbmRlbnRseSBvZiBpdC4gUmVjb3JkIGJlZm9yZSBjb2xsZWN0aW5nLCBub3QgYWZ0ZXI6IHRoZSBmaW5kaW5nIGlzIHRoYXQgdGhlIGNhbGwgd2FzIG1hZGUsIGFuZCBhIGhvb2sgdGhhdCByZWNvcmRlZCBhZnRlcndhcmRzIHdvdWxkIGxvc2UgdGhlIGV2ZW50IGlmIHRoZSBjb2xsZWN0aW9uIG5ldmVyIHJldHVybmVkLiBFYWNoIGhvb2sgbXVzdCBwZXJmb3JtIHRoZSBvcmlnaW5hbCBjYWxsLCBTeXN0ZW0uZ2MoKSBvciB0aGUgcmVjZWl2ZXImIzM5O3MgZ2MoKSwgc28gdGhhdCB3ZWF2aW5nIGRvZXMgbm90IGNoYW5nZSB3aGF0IHRoZSBwcm9ncmFtIGRvZXMgLSBhIHN1YnN0aXR1dGlvbiB0aGF0IHNpbGVudGx5IGRyb3BwZWQgdGhlIGNvbGxlY3Rpb24gd291bGQgYWx0ZXIgYmVoYXZpb3VyIHRoZSB0ZXN0IG1heSBkZXBlbmQgb24sIHdoaWNoIGlzIHRoZSBvbmUgdGhpbmcgbm8gd2VhdmUgbWF5IGRvLiBVbmxpa2UgQWdlbnRTbGVlcEhvb2tzIHRoZXJlIGlzIGRlbGliZXJhdGVseSBubyBIZWxkTG9ja3MgZ3VhcmQ6IGFuIGV4cGxpY2l0IGNvbGxlY3Rpb24gaXMgdGhlIGJ1ZyB3aGV0aGVyIG9yIG5vdCBhIGxvY2sgaXMgaGVsZCwgYW5kIGFkZGluZyBhIGd1YXJkIHdvdWxkIHNpbGVuY2UgdGhlIGNvbW1vbiBjYXNlLiBUaGUgc3RhY2sgd2FsayBtdXN0IHNraXAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdCBmcmFtZXMsIG9yIGV2ZXJ5IGZpbmRpbmcgd291bGQgbmFtZSB0aGlzIGNsYXNzIGluc3RlYWQgb2YgdGhlIGNhbGxlci48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRMb2NrSG9va3MiPgogICAgICA8cmVhc29uPkNhbGxlZCBmcm9tIGJ5dGVjb2RlIHRoZSBhZ2VudCByZXdyaXRlczogbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBhcmUgbWF0Y2hlZCBieSBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyLmxvY2tTdWJzdGl0dXRpb25zIGFuZCBjYW5ub3QgY2hhbmdlIGluZGVwZW5kZW50bHkgb2YgaXQuIFRoZSBhY3F1aXJlLWFmdGVyIC8gcmVsZWFzZS1iZWZvcmUgb3JkZXJpbmcgaXMgYSBzYWZldHkgcHJvcGVydHksIG5vdCBhIHN0eWxlIGNob2ljZSAtIHJlY29yZGluZyBhIGxvY2sgYXMgaGVsZCBiZWZvcmUgaXQgaXMgYWN0dWFsbHkgaGVsZCB3b3VsZCBtYWtlIGFub3RoZXIgdGhyZWFkJiMzOTtzIHJhY2luZyBhY2Nlc3MgcmVhZCBhcyBndWFyZGVkLCB3aGljaCBpcyB0aGUgb25lIGVycm9yIGRpcmVjdGlvbiB0aGlzIGxpYnJhcnkgbXVzdCBuZXZlciB0YWtlLiBFdmVyeSBob29rIG11c3QgcGVyZm9ybSB0aGUgb3JpZ2luYWwgb3BlcmF0aW9uIGFuZCBwcm9wYWdhdGUgaXRzIGV4Y2VwdGlvbnMgdW5jaGFuZ2VkLiBUaGUgZGV0ZWN0b3IgZGVsaXZlcnkgaW5oZXJpdHMgdGhlIHNhbWUgYWNxdWlyZS1hZnRlciAvIHJlbGVhc2UtYmVmb3JlIG9yZGVyaW5nIGFzIHRoZSBsb2Nrc2V0IGFuZCBtdXN0IGtlZXAgaXQ6IExvY2tPcmRlclZhbGlkYXRvciBidWlsZHMgaXRzIG5lc3RpbmcgZWRnZXMgZnJvbSB0aGUgb3JkZXIgdGhlc2UgY2FsbHMgYXJyaXZlIGluLCBzbyBkZWxpdmVyaW5nIGFuIGFjcXVpc2l0aW9uIGVhcmx5IHdvdWxkIGludmVudCBhIGhvbGQtYW5kLXdhaXQgZWRnZSB0aGF0IG5ldmVyIGV4aXN0ZWQuIEl0IHJlc29sdmVzIGVhY2ggZGV0ZWN0b3IgdGhyb3VnaCBhIG51bGwtcmV0dXJuaW5nIEFzeW5jVGVzdENvbnRleHQgYWNjZXNzb3IgYmVjYXVzZSBhIHdvdmVuIGNhbGwgc2l0ZSBydW5zIGluIGNvZGUgdGhhdCBkb2VzIG5vdCBrbm93IGEgdGVzdCBleGlzdHMsIHNvIG5vIGNvbnRleHQgaXMgdGhlIG9yZGluYXJ5IGNhc2UgYW5kIG11c3QgY29zdCBhIG51bGwgY2hlY2sgcmF0aGVyIHRoYW4gYW4gZXhjZXB0aW9uLiBEZXRlY3RvckZlZWRzIGxpc3RzIHRoZXNlIHRocmVlIGFzIEFHRU5ULWZlZCBhbmQgRGV0ZWN0b3JGZWVkQ292ZXJhZ2VUZXN0IHJlYWRzIHRoaXMgZmlsZSB0byBjaGVjayB0aGUgZGVsaXZlcnkgaXMgc3RpbGwgaGVyZSwgc28gcmVtb3ZpbmcgYSBjYWxsIG1lYW5zIHJlY2xhc3NpZnlpbmcgdGhlIGRldGVjdG9yIGluIHRoZSBzYW1lIGNoYW5nZS48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRNb25pdG9ySG9va3MiPgogICAgICA8cmVhc29uPkNhbGxlZCBmcm9tIGJ5dGVjb2RlIHRoZSBhZ2VudCByZXdyaXRlczogbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBoZXJlIGFyZSBtYXRjaGVkIGJ5IENvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIuTU9OSVRPUl9FTlRSSUVTLCBsb29wQmFja0VkZ2UgYnkgbmFtZSB3aXRoIGEgKClWIGRlc2NyaXB0b3IsIGFuZCBtb25pdG9yRmllbGRFbnRlcmVkIGJ5IEZpZWxkQWNjZXNzV2VhdmVyIHdpdGggYW4gKE9iamVjdCwgT2JqZWN0LCBTdHJpbmcpViBkZXNjcmlwdG9yLCBzbyBub25lIGNhbiBjaGFuZ2UgaW5kZXBlbmRlbnRseSBvZiB0aGUgd2VhdmVyLiBtb25pdG9yRmllbGRFbnRlcmVkIHJ1bnMgYmVmb3JlIGEgTU9OSVRPUkVOVEVSIGFuZCBtdXN0IG5vdCB0aHJvdzogYSBudWxsIG1vbml0b3IgaXMgbGVmdCBmb3IgdGhlIE1PTklUT1JFTlRFUiB0byByZWplY3Qgd2l0aCBpdHMgb3duIE51bGxQb2ludGVyRXhjZXB0aW9uLiBFdmVyeSBob29rIG11c3QgcGVyZm9ybSB0aGUgb3JpZ2luYWwgY2FsbCBvbiB0aGUgcmVjZWl2ZXIgYW5kIHByb3BhZ2F0ZSB3aGF0IGl0IHRocm93cyB1bmNoYW5nZWQ6IEludGVycnVwdGVkRXhjZXB0aW9uLCBhbmQgdGhlIElsbGVnYWxNb25pdG9yU3RhdGVFeGNlcHRpb24gb2YgYSBjYWxsIG1hZGUgd2l0aG91dCB0aGUgbW9uaXRvciwgd2hpY2ggaXMgd2h5IG5vdGhpbmcgaXMgcmVjb3JkZWQgdW5sZXNzIFRocmVhZC5ob2xkc0xvY2socmVjZWl2ZXIpLiBSZWNvcmQgdGhlIHdhaXQgYmVmb3JlIHdhaXQoKSByZWxlYXNlcyB0aGUgbW9uaXRvciBhbmQgdGhlIHdha2V1cCBhZnRlciBpdCBpcyByZWFjcXVpcmVkLCBpbiBhIGZpbmFsbHksIHNvIGEgbm90aWZ5IGlzIGp1ZGdlZCBhZ2FpbnN0IHRoZSB0aHJlYWRzIHJlYWxseSB3YWl0aW5nOyByZWNvcmQgYSBub3RpZnkgYmVmb3JlIG1ha2luZyBpdC4gVGhlIHNhbWUgZ29lcyBmb3IgYSBjb250cm9sbGVkIHNjaGVkdWxlJiMzOTtzIHJlY29yZCBvZiB0aGUgaG9sZDogcmVsZWFzaW5nRm9yV2FpdCBiZWZvcmUgd2FpdCgpLCByZWFjcXVpcmVkQWZ0ZXJXYWl0IGluIGFuIG91dGVyIGZpbmFsbHksIHNvIGEgcGVlciB3YWl0aW5nIHRvIGVudGVyIHRoZSBtb25pdG9yIGlzIG5vdCBwYXNzZWQgb3ZlciB3aGlsZSBpdCBpcyBmcmVlICgjMTA0OCkuIGxvb3BCYWNrRWRnZSB0YWtlcyBub3RoaW5nIGFuZCByZXR1cm5zIG5vdGhpbmcgYmVjYXVzZSB0aGUgd2VhdmVyIGluc2VydHMgaXQgaW4gZnJvbnQgb2YgYSBqdW1wIHdob3NlIG9wZXJhbmRzIGFyZSBhbHJlYWR5IG9uIHRoZSBzdGFjay48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRTaGFyZWRJbnN0YW5jZUhvb2tzIj4KICAgICAgPHJlYXNvbj5DYWxsZWQgZnJvbSBieXRlY29kZSB0aGUgYWdlbnQgcmV3cml0ZXM6IHRoZSBtZXRob2QgbmFtZXMgYW5kIGVyYXNlZCBzaWduYXR1cmVzIGhlcmUgYXJlIG1hdGNoZWQgYnkgQ29sbGVjdGlvbkFjY2Vzc1dlYXZlci5TSEFSRURfSU5TVEFOQ0VfRU5UUklFUyBhbmQgY2Fubm90IGNoYW5nZSBpbmRlcGVuZGVudGx5IG9mIGl0LiBFdmVyeSBob29rIG11c3QgcGVyZm9ybSB0aGUgb3JpZ2luYWwgb3BlcmF0aW9uIGFuZCBwcm9wYWdhdGUgaXRzIGV4Y2VwdGlvbnMgdW5jaGFuZ2VkLCBhbmQgbXVzdCByZWNvcmQgYmVmb3JlIGRlbGVnYXRpbmcgb25seSB3aGVyZSB0aGUgb3JpZ2luYWwgY2Fubm90IHRocm93IGZpcnN0IC0gdGhlIGRldGVjdG9yJiMzOTtzIHF1ZXN0aW9uIGlzICYjMzk7ZGlkIHR3byB0aHJlYWRzIHRvdWNoIHRoaXMgaW5zdGFuY2UmIzM5Oywgd2hpY2ggYSBjYWxsIHRoYXQgdGhyZXcgc3RpbGwgYW5zd2Vycy4gQSByZWNlaXZlciB0eXBlIHRoYXQgaGFzIHRocmVhZC1zYWZlIHN1YmNsYXNzZXMgbWF5IGJlIHdvdmVuIG9ubHkgd2hlbiBpdHMgaG9vayBjaGVja3MgdGhlIHJ1bnRpbWUgdHlwZSBiZWZvcmUgcmVjb3JkaW5nOiBEYXRlRm9ybWF0IHJlY29yZHMgb25seSBhIFNpbXBsZURhdGVGb3JtYXQgYW5kIEFwcGVuZGFibGUgb25seSBhIFN0cmluZ0J1aWxkZXIgKCM1NDIpLiBXaXRob3V0IHRoYXQgY2hlY2ssIFJhbmRvbSBiZWluZyB0aGUgc3RhbmRpbmcgZXhhbXBsZSB3aXRoIFRocmVhZExvY2FsUmFuZG9tLCBldmVyeSBzdWJzdGl0dXRlZCBjYWxsIHNpdGUgYmVjb21lcyBhIHBvdGVudGlhbCBmYWxzZSBwb3NpdGl2ZSBvbiBjb3JyZWN0IGNvZGUuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFnZW50U2xlZXBIb29rcyI+CiAgICAgIDxyZWFzb24+Q2FsbGVkIGZyb20gYnl0ZWNvZGUgdGhlIGFnZW50IHJld3JpdGVzLCB0aHJvdWdoIHRoZSBzdGF0aWMgc3Vic3RpdHV0aW9uIHBhdGg6IHRoZSBtZXRob2QgbmFtZSBhbmQgZXJhc2VkIHNpZ25hdHVyZSBoZXJlIGFyZSBtYXRjaGVkIGJ5IENvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIuU1RBVElDX0VOVFJJRVMgYW5kIGNhbm5vdCBjaGFuZ2UgaW5kZXBlbmRlbnRseSBvZiBpdC4gVGhlIGd1YXJkIGlzIHRoZSBwb2ludCAtIHJlY29yZGluZyBvbmx5IHdoZW4gdGhlIHRocmVhZCYjMzk7cyBsb2Nrc2V0IGhvbGRzIGEgbG9jayB0aGUgZGV0ZWN0b3IgY2FuIGNvbmZpcm0gaXMgd2hhdCBzZXBhcmF0ZXMgdGhlIGJ1ZyBmcm9tIHJhdGUgbGltaXRpbmcsIGJhY2stb2ZmIGFuZCBwb2xsaW5nLCB3aGljaCBhcmUgb3JkaW5hcnkgdXNlcyBvZiBUaHJlYWQuc2xlZXAgYW5kIHZhc3RseSBtb3JlIGNvbW1vbi4gUmVjb3JkIGJlZm9yZSBzbGVlcGluZywgbm90IGFmdGVyOiBhIHNsZWVwIGludGVycnVwdGVkIG1pZC13YXkgc3RpbGwgaGVsZCB0aGUgbG9jayBmb3IgYXMgbG9uZyBhcyBpdCBsYXN0ZWQsIGFuZCB0aGUgZmluZGluZyBpcyBhYm91dCB0aGUgaG9sZGluZyByYXRoZXIgdGhhbiB0aGUgY29tcGxldGluZy4gVGhlIGhvb2sgbXVzdCBwZXJmb3JtIHRoZSBvcmlnaW5hbCBzbGVlcCBhbmQgcHJvcGFnYXRlIEludGVycnVwdGVkRXhjZXB0aW9uIHVuY2hhbmdlZC4gSXQgbXVzdCBuZXZlciBjYWxsIHRoZSBzaW5nbGUtYXJndW1lbnQgcmVjb3JkU2xlZXA6IHRoYXQgb25lIHJlc29sdmVzIHRoZSBoZWxkIG1vbml0b3JzIHRocm91Z2ggVGhyZWFkTVhCZWFuLCB3aGljaCBkb2VzIG5vdCByZXBvcnQgdmlydHVhbCB0aHJlYWRzLCBzbyBvbiB0aGUgcnVubmVyJiMzOTtzIGRlZmF1bHQgd29ya2VycyBpdCBhbnN3ZXJzIG5vbmUgYW5kIHRoZSBkZXRlY3RvciBuZXZlciBmaXJlcy4gVGhlIHBsYWluIGZvcm1zIG11c3QgaGFuZCB0aGUgZGV0ZWN0b3IgdGhlIHdob2xlIGxvY2tzZXQgKHJlY29yZFNsZWVwVW5kZXJIZWxkTG9ja3MpIHJhdGhlciB0aGFuIGl0cyB0b3AgZW50cnksIHdoaWNoIGRyb3BwZWQgYSBTdGFtcGVkTG9jayBvbiB0b3AgYW5kIGEgY29uZmlybWFibGUgbG9jayBiZWxvdyBhbiB1bmNvbmZpcm1hYmxlIG9uZSAoIzU0MykuIEEgc3ViLW1pbGxpc2Vjb25kIHNsZWVwIG11c3Qgcm91bmQgdXAgdG8gb25lIHJhdGhlciB0aGFuIHRydW5jYXRlIHRvIHplcm86IHRoZSBkZXRlY3RvciBkcm9wcyBhbnl0aGluZyBhdCBvciBiZWxvdyB6ZXJvLCBzbyB0cnVuY2F0aW5nIHR1cm5zIGEgcmVhbCBsb2NrLWhvbGRpbmcgcGF1c2UgaW50byB0aGUgc2FtZSBzaWxlbmNlIGFuIHVud292ZW4gY2FsbCBzaXRlIHByb2R1Y2VzLiBUaGUgcHJvY2Vzcy1nbG9iYWwgd3JpdGVzIChTeXN0ZW0uc2V0UHJvcGVydHkgYW5kIGNsZWFyUHJvcGVydHksIExvY2FsZS5zZXREZWZhdWx0LCBUaW1lWm9uZS5zZXREZWZhdWx0KSBhcmUgdGhlIHNhbWUga2luZCBvZiBzdGF0aWMgc3Vic3RpdHV0aW9uOiBlYWNoIHJlY29yZHMgdGhlIHdyaXRlIGJlZm9yZSBwZXJmb3JtaW5nIGl0LCBzbyB0aGUgbG9ja3NldCB0aGUgZGV0ZWN0b3IgcHJvYmVzIGlzIHRoZSBvbmUgdGhlIHdyaXRlIHJhbiB1bmRlciwgYW5kIHJldHVybnMgd2hhdCB0aGUgSkRLIG1ldGhvZCByZXR1cm5lZC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRUaHJlYWRIb29rcyI+CiAgICAgIDxyZWFzb24+Q2FsbGVkIGZyb20gYnl0ZWNvZGUgdGhlIGFnZW50IHJld3JpdGVzOiBtZXRob2QgbmFtZXMgYW5kIGVyYXNlZCBzaWduYXR1cmVzIG9mIHRoZSBob29rcyBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyLlRIUkVBRF9FTlRSSUVTIHN1YnN0aXR1dGVzICh0aHJlYWRTdGFydCwgdGhyZWFkSm9pbiwgdGhyZWFkSXNBbGl2ZSwgdGhyZWFkU2V0RGFlbW9uLCB0aHJlYWRTdGFydFZpcnR1YWwgYW5kIHRoZSBidWlsZGVyJiMzOTtzIHRocmVhZEJ1aWxkZXJTdGFydCwgdGhyZWFkQnVpbGRlckRhZW1vbiwgdGhyZWFkQnVpbGRlclVuc3RhcnRlZCBhbmQgdGhyZWFkQnVpbGRlckZhY3RvcnksIGFuZCB0aHJlYWRGYWN0b3J5TmV3VGhyZWFkKSBhbmQgb2YgdGhyZWFkQ29uc3RydWN0ZWQsIHdoaWNoIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGFmdGVyIGVhY2ggdGhyZWFkIGEgd292ZW4gY2xhc3MgY29uc3RydWN0cywgYW5kIG9mIGludGVycnVwdFN3YWxsb3dpbmdNZXRob2RFbnRlcmVkLCB3aGljaCBJbnRlcnJ1cHRIYW5kbGVyV2VhdmVyIGluc2VydHMgYXQgdGhlIHN0YXJ0IG9mIGEgbWV0aG9kIGhvbGRpbmcgYW4gSW50ZXJydXB0ZWRFeGNlcHRpb24gaGFuZGxlciB0aGF0IG5laXRoZXIgcmV0aHJvd3Mgbm9yIHJlc3RvcmVzIHRoZSBmbGFnLCBhcmUgbWF0Y2hlZCBhdCB3ZWF2ZSB0aW1lLCBhbmQgdGhyZWFkV2VhdmluZ0luc3RhbGxlZCBpcyBpbnZva2VkIGJ5IG5hbWUgZnJvbSBBc3luY1Rlc3RBZ2VudCBhZnRlciB0aGUgdHJhbnNmb3JtZXIgaXMgaW5zdGFsbGVkOyBub25lIG9mIHRoZW0gY2FuIGNoYW5nZSBpbmRlcGVuZGVudGx5IG9mIHRoZSBhZ2VudC4gRXZlcnkgc3Vic3RpdHV0aW5nIGhvb2sgbXVzdCBwZXJmb3JtIHRoZSBvcmlnaW5hbCBjYWxsIG9uIHRoZSByZWNlaXZlciwgb3Igd2hhdCB0aGUgSkRLIGRvZXMgZm9yIGl0IChhIGJ1aWxkZXImIzM5O3Mgc3RhcnQgaXMgdW5zdGFydGVkIHRoZW4gc3RhcnQpLCBhbmQgcHJvcGFnYXRlIHdoYXQgaXQgdGhyb3dzIHVuY2hhbmdlZDsgdGhyZWFkRmFjdG9yeU5ld1RocmVhZCByZXR1cm5zIHdoYXQgdGhlIGZhY3RvcnkgcmV0dXJuZWQsIG51bGwgaW5jbHVkZWQuIHRocmVhZENvbnN0cnVjdGVkIHJlcGxhY2VzIG5vdGhpbmcgYW5kIHJ1bnMgaW5zaWRlIHVzZXIgY29uc3RydWN0b3JzLCBzbyBpdCBwZXJmb3JtcyBubyBjYWxsIGFuZCBtdXN0IG5vdCB0aHJvdzsgaW50ZXJydXB0U3dhbGxvd2luZ01ldGhvZEVudGVyZWQgcmVwbGFjZXMgbm90aGluZyBlaXRoZXIsIHJ1bnMgb24gZXZlcnkgZW50cnkgb2YgdGhlIG1ldGhvZCBpdCB3YXMgaW5zZXJ0ZWQgaW50bywgYW5kIG11c3QgY29zdCBvbmUgc2V0IGxvb2t1cCBvbmNlIGEgcnVuIGhhcyBzZWVuIGl0cyBsb2NhdGlvbnMuIHRocmVhZFNldERhZW1vbiByZWNvcmRzIHRoZSBkZWNpc2lvbiBvbmx5IGFmdGVyIHNldERhZW1vbiByZXR1cm5lZCwgc28gYSBjYWxsIHRoYXQgdGhyb3dzIChhbiBhbHJlYWR5IHN0YXJ0ZWQgdGhyZWFkKSByZWNvcmRzIG5vdGhpbmcuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jQXNzZXJ0Ij4KICAgICAgPHJlYXNvbj5QdWJsaWMgYXNzZXJ0aW9uIHV0aWxpdHkgQVBJIGZvciBBc3luY1Rlc3QgY29uc3VtZXJzLiBhd2FpdFVudGlsKCkgYW5kIGNhcHR1cmUoKSBhcmUgdXNlZCBkaXJlY3RseSBpbiB1c2VyIHRlc3QgY29kZSDigJQgbWV0aG9kIHNpZ25hdHVyZXMgYW5kIHNlbWFudGljcyBtdXN0IG5vdCBjaGFuZ2Ugd2l0aG91dCBhIG1ham9yIHZlcnNpb24gYnVtcC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNGaW5kaW5ncyI+CiAgICAgIDxyZWFzb24+UHVibGljIGFzc2VydGlvbiBBUEkgZm9yIGRldGVjdG9yIGZpbmRpbmdzLiBjb2xsZWN0KCksIHZpb2xhdGlvbnMoKSBhbmQgdGhlIGFzc2VydFh4eCBtZXRob2RzIGFyZSBjYWxsZWQgZGlyZWN0bHkgZnJvbSB1c2VyIHRlc3QgY29kZSDigJQgc2lnbmF0dXJlcyBhbmQgbWF0Y2hpbmcgc2VtYW50aWNzIG11c3Qgbm90IGNoYW5nZSB3aXRob3V0IGEgbWFqb3IgdmVyc2lvbiBidW1wLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3QiPgogICAgICA8cmVhc29uPlB1YmxpYyBhbm5vdGF0aW9uIEFQSSB1c2VkIGRpcmVjdGx5IGluIHVzZXIgdGVzdCBtZXRob2RzLiBBdHRyaWJ1dGUgbmFtZXMsIHR5cGVzLCBhbmQgZGVmYXVsdHMgYXJlIHBhcnQgb2YgdGhlIHN0YWJsZSBwdWJsaWMgQVBJIOKAlCBhbnkgY2hhbmdlIGlzIGEgYnJlYWtpbmcgY2hhbmdlIGZvciBhbGwgY29uc3VtZXJzLiBEZXRlY3RvciBzZWxlY3Rpb24gaXMgYnkgRGV0ZWN0b3JUeXBlIHRocm91Z2ggaW5jbHVkZXMvZXhjbHVkZXMvcHJlc2V0L2RldGVjdEFsbDsgbmV2ZXIgcmVpbnRyb2R1Y2UgYSBwZXItZGV0ZWN0b3IgYm9vbGVhbiBhdHRyaWJ1dGUgKHJlbW92ZWQgaW4gMS4xMy4wLCAjOTIwKS4gVGhlIGJhcmUtYW5ub3RhdGlvbiBzZWxlY3Rpb24gaXMgUHJlc2V0LkVTU0VOVElBTFMgd2l0aCBkZXRlY3RBbGwgPSBmYWxzZSAoMS4xMy4wLCAjOTIzKTogYSBkaWZmZXJlbnQgZGVmYXVsdCBjaGFuZ2VzIHdoYXQgZXZlcnkgdW5jaGFuZ2VkIHRlc3QgaW4gZXZlcnkgY29uc3VtZXIgZGV0ZWN0cy48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0TGlzdGVuZXIiPgogICAgICA8cmVhc29uPlB1YmxpYyBTUEkgaW50ZXJmYWNlIGZvciBvYnNlcnZpbmcgYXN5bmMtdGVzdCBsaWZlY3ljbGUgZXZlbnRzLiBNZXRob2Qgc2lnbmF0dXJlcyBhcmUgcGFydCBvZiB0aGUgc3RhYmxlIEFQSSDigJQgaW1wbGVtZW50b3JzIGJpbmQgdG8gdGhlc2UgZXhhY3QgbmFtZXMgYW5kIHBhcmFtZXRlciB0eXBlcy48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0TGlzdGVuZXJSZWdpc3RyeSI+CiAgICAgIDxyZWFzb24+UHVibGljIEFQSSBmb3IgcmVnaXN0ZXJpbmcgYW5kIHVucmVnaXN0ZXJpbmcgQXN5bmNUZXN0TGlzdGVuZXIgaW5zdGFuY2VzLiByZWdpc3RlcigpLCB1bnJlZ2lzdGVyKCksIGNsZWFyQWxsKCksIGFuZCBmaXJlWHh4KCkgbWV0aG9kcyBhcmUgY2FsbGVkIGJ5IHVzZXIgY29kZSBhbmQgaW5mcmFzdHJ1Y3R1cmUg4oCUIHNpZ25hdHVyZXMgbXVzdCBub3QgY2hhbmdlLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RSdW5uZXIiPgogICAgICA8cmVhc29uPlB1YmxpYyBwcm9ncmFtbWF0aWMgZW50cnkgcG9pbnQgZm9yIHRoZSBOIHggTSBlbmdpbmUsIGNhbGxlZCBmcm9tIG5vbi1KdXBpdGVyIHRlc3QgZnJhbWV3b3JrcyBpbiBLb3RsaW4sIFNjYWxhLCBHcm9vdnkgYW5kIENsb2p1cmUuIHJ1biguLi4pIHNpZ25hdHVyZXMgYW5kIHRoZSBydWxlIHRoYXQgaXQgdGhyb3dzIGV4YWN0bHkgd2hhdCB0aGUgYW5ub3RhdGVkIHBhdGggdGhyb3dzIG11c3Qgbm90IGNoYW5nZSB3aXRob3V0IGEgbWFqb3IgdmVyc2lvbiBidW1wLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5leHRlbnNpb24uQXN5bmNUZXN0RXh0ZW5zaW9uIj4KICAgICAgPHJlYXNvbj5KVW5pdCA1IFRlc3RUZW1wbGF0ZUludm9jYXRpb25Db250ZXh0UHJvdmlkZXIgU1BJLiBUaGUgdHdvIG92ZXJyaWRkZW4gbWV0aG9kcyAoc3VwcG9ydHNUZXN0VGVtcGxhdGUsIHByb3ZpZGVUZXN0VGVtcGxhdGVJbnZvY2F0aW9uQ29udGV4dHMpIG11c3QgcHJlc2VydmUgdGhlaXIgZXhhY3Qgc2lnbmF0dXJlcyBhcyBtYW5kYXRlZCBieSBKVW5pdC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0LkZvcm1hdHRlciI+CiAgICAgIDxyZWFzb24+UHVibGljIGZvcm1hdHRlciBTUEkuIGZvcm1hdChMaXN0Jmx0O1Zpb2xhdGlvbiZndDspIHNpZ25hdHVyZSBtdXN0IG5vdCBjaGFuZ2Ug4oCUIGJ1aWx0LWluIGZvcm1hdHRlcnMgYW5kIHVzZXItcHJvdmlkZWQgbGFtYmRhcyBiaW5kIHRvIHRoaXMgZXhhY3QgdHlwZS48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkFnZW50QXV0b0F0dGFjaCI+CiAgICAgIDxyZWFzb24+VGhlIC1EYXN5bmN0ZXN0LmFnZW50IHZhbHVlcyBhcmUgdHlwZWQgaW4gdXNlcnMmIzM5OyBidWlsZHMgYW5kIGluIHRoaXMgcmVwb3NpdG9yeSYjMzk7cyBvd246IGNvcnB1cy1ldmFsJiMzOTtzIHJlY29yZGluZyBhbmQgYWdlbnQtb2ZmIGxhbmVzIHNldCBpdCB0byBvZmYsIGFuZCBlYWNoIGxhbmUgaXMgdmFsaWQgb25seSB3aGlsZSB0aGUgYWdlbnQgc3RheXMgZGV0YWNoZWQsIHNvIHJlbmFtaW5nIG9yIGRyb3BwaW5nIHRoZSBvcHQtb3V0IHNpbGVudGx5IGF0dGFjaGVzIHRoZSBhZ2VudCB0aGVyZSBhbmQgdm9pZHMgYm90aCBsYW5lcyYjMzk7IG1lYXN1cmVtZW50cy4gVGhpcyBpcyB0aGUgZmFsbGJhY2ssIG5vdCB0aGUgcmVjb21tZW5kZWQgcm91dGU6IGxvYWRpbmcgYW4gYWdlbnQgaW50byBhIHJ1bm5pbmcgSlZNIHdhcm5zIG9uIEpESyAyMSsgYW5kIEpFUCA0NTEgc2F5cyBhIGZ1dHVyZSBKREsgd2lsbCByZWZ1c2UgaXQsIHNvIHRoZSBSRUFETUUgcXVpY2sgc3RhcnQgYXR0YWNoZXMgYXQgc3RhcnR1cCB3aXRoIC1qYXZhYWdlbnQgYW5kIHRoaXMgY2xhc3MgbXVzdCBrZWVwIGxvZ2dpbmcgbW9kZT1ydW50aW1lIHdpdGggYSBoaW50IG5hbWluZyB0aGF0IHJvdXRlIChBdHRhY2hlZEJ5RGVmYXVsdFRlc3QpLiBJdHMgZGVmYXVsdCBhcmd1bWVudHMgKGZpZWxkcz10cnVlLGNvbGxlY3Rpb25zPXRydWUsIGluY2x1ZGVzPSB0aGUgZmlyc3QgdGhyZWUgc2VnbWVudHMgb2YgdGhlIHRlc3QgY2xhc3MmIzM5O3MgcGFja2FnZSwgb3Igb2YgdGhlIGJvZHkmIzM5O3MgY2xhc3MgZm9yIEFzeW5jVGVzdFJ1bm5lci5ydW4sICMxMDQyKSBhcmUgZG9jdW1lbnRlZCBpbiBkb2NzL2FnZW50L2F0dGFjaGluZy5tZCBzZWN0aW9uIDMuMC4xIHdpdGggbWVhc3VyZWQgY29zdHMuIFRoZSBkZWZhdWx0IG11c3QgbmV2ZXIgYXR0YWNoIHdpdGhvdXQgYW4gaW5jbHVkZTogYW4gZW1wdHkgaW5jbHVkZXM9IHdlYXZlcyBKVW5pdCBhbmQgdGhlIGJ1aWxkIHRvb2wgaW4gZXZlcnkgY29uc3VtZXImIzM5O3MgdGVzdCBKVk0uPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnNwaS5EZXRlY3RvciI+CiAgICAgIDxyZWFzb24+UHVibGljIFNQSSBpbnRlcmZhY2UuIGlkKCksIHR5cGUoKSwgYW5hbHl6ZSgpLCBvblRlc3RTdGFydCgpLCBhbmQgb25UZXN0RW5kKCkgc2lnbmF0dXJlcyBhcmUgcGFydCBvZiB0aGUgc3RhYmxlIGV4dGVuc2lvbiBjb250cmFjdCDigJQgaW1wbGVtZW50b3JzIGJpbmQgdG8gdGhlc2UgZXhhY3QgbmFtZXMgYW5kIHBhcmFtZXRlciB0eXBlcy4gaWQoKSBhbmQgdHlwZSgpIGFyZSBkZWZhdWx0cyBzbyBhIGRldGVjdG9yIGNhbiBkZWNsYXJlIGFuIGlkZW50aXR5IG9mIGl0cyBvd24gKCM5MTkpOyBtYWtpbmcgZWl0aGVyIGFic3RyYWN0IGFnYWluIGJyZWFrcyBldmVyeSBpbXBsZW1lbnRvciB0aGF0IG92ZXJyaWRlcyBvbmx5IHRoZSBvdGhlci48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3Quc3BpLkRldGVjdG9yRmFjdG9yeSI+CiAgICAgIDxyZWFzb24+UHVibGljIFNQSSBpbnRlcmZhY2UgZm9yIFNlcnZpY2VMb2FkZXItYmFzZWQgZGV0ZWN0b3IgZGlzY292ZXJ5LiBpZCgpLCB0eXBlKCksIGlzRW5hYmxlZEZvcigpLCBhbmQgY3JlYXRlKCkgc2lnbmF0dXJlcyBhcmUgcGFydCBvZiB0aGUgc3RhYmxlIGZhY3RvcnkgY29udHJhY3Qg4oCUIGltcGxlbWVudG9ycyBiaW5kIHRvIHRoZXNlIGV4YWN0IG5hbWVzIGFuZCBwYXJhbWV0ZXIgdHlwZXMuIGlkKCksIHR5cGUoKSBhbmQgaXNFbmFibGVkRm9yKCkgYXJlIGRlZmF1bHRzICgjOTE5KTsgbWFraW5nIG9uZSBhYnN0cmFjdCBhZ2FpbiBicmVha3MgZXZlcnkgZmFjdG9yeSB0aGF0IHJlbGllcyBvbiBpdC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICA8L2NvbnRyYWN0X3NpZ25hdHVyZXM+Cgo8cnVsZT5Zb3UgbWF5IHJlZmFjdG9yIHRoZSBpbnRlcm5hbCBsb2dpYyBvZiBlbGVtZW50cyBsaXN0ZWQgaW4gPGNvbnRyYWN0X3NpZ25hdHVyZXM+LCBidXQgeW91IE1VU1QgTk9UIGNoYW5nZSB0aGVpciBwdWJsaWMgc2lnbmF0dXJlczogbWV0aG9kIG5hbWVzLCBwYXJhbWV0ZXIgdHlwZXMsIHBhcmFtZXRlciBvcmRlciwgcmV0dXJuIHR5cGVzLCBvciBjaGVja2VkIGV4Y2VwdGlvbnMuPC9ydWxlPgogIDx0ZXN0X2RyaXZlbl9yZXF1aXJlbWVudHM+CiAgICA8dGVzdF9kcml2ZW5fZGVmYXVsdCBjb3ZlcmFnZV9nb2FsPSI4MCIgZnJhbWV3b3Jrcz0iSlVOSVRfNSIgdGVzdF9sb2NhdGlvbj0ic3JjL3Rlc3QvamF2YS97cGF0aH1UZXN0LmphdmEiPgogICAgICA8YXBwbGllcy10bz4KICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkJsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVCbG9ja2luZ0NhbGxiYWNrRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNhbmNlbGxhdGlvblByb3BhZ2F0aW9uRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ29tcGxldGlvblJhY2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlT2J0cnVkZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGFlbW9uVGhyZWFkSHlnaWVuZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkZpbmFsRmllbGRNdXRhdGlvbkRldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmxvd1B1Ymxpc2hlckNvbmN1cnJlbmN5RGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5IaWdoQ29udGVudGlvbkF0b21pY0RldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuSmRiY0Nvbm5lY3Rpb25TaGFyZWREZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhbWJkYUxvc3RVcGRhdGVEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29uc3RhbnRNaXN1c2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxvY2tVcGdyYWRlRGVhZGxvY2tEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vdGlmeVdpdGhvdXRNb25pdG9yRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5QbGF0Zm9ybVRocmVhZFBlclRhc2tEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlByb2Nlc3NTdHJlYW1TdGFydmF0aW9uRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVDb25maWd1cmF0aW9uTWlzdXNlRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TY29wZUpvaW5lck1pc3VzZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEJ5dGVCdWZmZXJEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZENoYXJzZXRDb2RlckRldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hlY2tzdW1EZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZERlZmxhdGVyRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRJdGVyYXRvckRldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkSnNvbk1hcHBlclJlY29uZmlnRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRLZGZEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZE1lbW9yeVNlZ21lbnRSYWNlRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTZWN1cmVSYW5kb21EZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFN0YXRlZnVsQ3J5cHRvRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TcHVyaW91c1dha2V1cERldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaGlzRXNjYXBlRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbENhY2hlRGVncmFkYXRpb25EZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRocmVhZExvY2FsUmFuZG9tTWlzdXNlRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UcnlMb2NrTWlzdXNlRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WYXJIYW5kbGVOb25BdG9taWNVcGRhdGVEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRSZXNvdXJjZVNhdHVyYXRpb25EZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLldlYWtIYXNoTWFwU2hhcmVkRGV0ZWN0b3IKICAgICAgPC9hcHBsaWVzLXRvPgogICAgPC90ZXN0X2RyaXZlbl9kZWZhdWx0PgogIDwvdGVzdF9kcml2ZW5fcmVxdWlyZW1lbnRzPgoKPHJ1bGU+Rm9yIGFueSBlbGVtZW50IGxpc3RlZCBpbiA8dGVzdF9kcml2ZW5fcmVxdWlyZW1lbnRzPiwgeW91IE1VU1QgcHJvdmlkZSBib3RoIHRoZSBpbXBsZW1lbnRhdGlvbiBjaGFuZ2UgQU5EIHRoZSBjb3JyZXNwb25kaW5nIHRlc3QgY29kZSB1cGRhdGUgaW4gYSBzaW5nbGUgcmVzcG9uc2UuIENoYW5nZXMgd2l0aG91dCB0ZXN0cyBhcmUgaW5jb21wbGV0ZSBhbmQgbXVzdCBub3QgYmUgcHJvcG9zZWQuIEV2ZXJ5IG5hbWUgdW5kZXIgPGFwcGxpZXMtdG8+IGluIGEgPHRlc3RfZHJpdmVuX2RlZmF1bHQ+IGJsb2NrIGluaGVyaXRzIHRoYXQgYmxvY2sncyBjb3ZlcmFnZSBnb2FsLCBmcmFtZXdvcmtzLCBhbmQgdGVzdC1sb2NhdGlvbiBjb252ZW50aW9uICh3aXRoIHtwYXRofSBzdGFuZGluZyBmb3IgdGhlIGVsZW1lbnQncyBwYWNrYWdlIHBhdGgpLjwvcnVsZT4KICA8dGhyZWFkX3NhZmVfZWxlbWVudHM+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQiPgogICAgICA8c3RyYXRlZ3k+VEhSRUFEX0xPQ0FMPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q1VSUkVOVCBUaHJlYWRMb2NhbCBtYWludGFpbnMgY29udGV4dCBwZXIgYWN0aXZlIHRlc3QgdGhyZWFkIHN5bW1ldHJpY2FsbHkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclJlZ2lzdHJ5Ij4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Tm8gbG9ja3M6IGV2ZXJ5IGRldGVjdG9yIGZpZWxkIGlzIGZpbmFsIGFuZCBhc3NpZ25lZCBpbiB0aGUgY29uc3RydWN0b3IsIGJlZm9yZSBDb25jdXJyZW5jeVJ1bm5lciBwdWJsaXNoZXMgdGhlIHJlZ2lzdHJ5IHRvIGl0cyB3b3JrZXJzLCBzbyBldmVyeSB3b3JrZXIgb2YgYSBydW4gcmVhZHMgdGhlIHNhbWUgaW5zdGFuY2VzIGFuZCBlYWNoIGRldGVjdG9yIGNhcnJpZXMgaXRzIG93biB0aHJlYWQgc2FmZXR5LiBUaGUgbGFzdCogbWFwcyBhcmUgd3JpdHRlbiBvbmx5IGJ5IGFuYWx5emVBbGxOYW1lZCgpLCB3aGljaCB0aGUgcnVubmVyIGNhbGxzIG9uIGl0cyBvd24gdGhyZWFkIGFmdGVyIHRoZSB3b3JrZXJzIGhhdmUgcXVpZXNjZWQuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5SdW5PdXRjb21lcyI+CiAgICAgIDxzdHJhdGVneT5MT0NLX0ZSRUU8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5Db3VudHMgYXJlIExvbmdBZGRlcnMgYW5kIHZhbHVlcyBzaXQgaW4gYSBDb25jdXJyZW50SGFzaE1hcCBtZXJnZSwgc28gY29uY3VycmVudCByZWNvcmRlcnMgbmV2ZXIgbG9zZSBhbiB1cGRhdGU7IHRoZSBhc3NlcnRpb25zIHJlYWQgdG90YWxzIGFmdGVyIHRoZSBydW4sIHdoZW4gbm8gd29ya2VyIGlzIHN0aWxsIHJlY29yZGluZy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkJsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+RmluZGluZ3MgaW4gYSBjb25jdXJyZW50IHNldCBrZXllZCBieSB0aHJlYWQsIGtpbmQgYW5kIG9wZXJhdGlvbjsgY2xhc3NpZmljYXRpb24gcmVhZHMgdGhlIGNhbGxpbmcgdGhyZWFkJiMzOTtzIG93biBvYmplY3Qgb25seS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQmxvY2tpbmdDYWxsYmFja0RldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+VGhyZWFkTG9jYWwgdHJhY2tzIGFjdGl2ZSBjYWxsYmFja3M7IENvbmN1cnJlbnRIYXNoTWFwIHN0b3JlcyB2aW9sYXRpb25zLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVDYW5jZWxsYXRpb25Qcm9wYWdhdGlvbkRldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+T25lIENvbmN1cnJlbnRIYXNoTWFwIGVudHJ5IHBlciBwaXBlbGluZTsgZXZlbnRzIGdvIG9uIGNvcHktb24td3JpdGUgbGlzdHMgYW5kIGNhcnJ5IGFuIGF0b21pY2FsbHkgaXNzdWVkIHNlcXVlbmNlIG51bWJlciwgc28gb3JkZXJpbmcgbmV2ZXIgZGVwZW5kcyBvbiBhIHdhbGwgY2xvY2suPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkNvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIHRoZSBjb21iaW5lZCBmdXR1cmUmIzM5O3MgaWRlbnRpdHk7IGNvbnN0aXR1ZW50IGFuZCBhd2FpdCBldmVudHMgYXJlIGNvcHktb24td3JpdGUgbGlzdHMgY2FycnlpbmcgYXRvbWljYWxseSBpc3N1ZWQgc2VxdWVuY2UgbnVtYmVycywgc28gdGhlIGJlZm9yZS9hZnRlciBjb21wYXJpc29uIG5ldmVyIGRlcGVuZHMgb24gYSB3YWxsIGNsb2NrLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVDb21wbGV0aW9uUmFjZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gZnV0dXJlIGlkZW50aXR5OyBwZXItZnV0dXJlIGF0dGVtcHQgbGlzdCBpcyBjb3B5LW9uLXdyaXRlIGFuZCB0aGUgc2VxdWVuY2UgY291bnRlciBpcyBhdG9taWMsIHNvIGNvbmN1cnJlbnQgcmVjb3JkZXJzIG5ldmVyIGxvc2UgYW4gYXR0ZW1wdC48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlT2J0cnVkZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHN0YXRlIHBlciBDRiBpbnN0YW5jZS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbmZpbmVkQXJlbmFUaHJlYWRFc2NhcGVEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1zZWdtZW50IGFuZCBwZXItYXJlbmEgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXA7IHRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgY291bnRlcnMgYXJlIExvbmdBZGRlci4gVGhlIHJlZmxlY3RpdmUgTWV0aG9kIGhhbmRsZXMgYXJlIHJlc29sdmVkIG9uY2UgaW50byBpbW11dGFibGUgc3RhdGljcyBhbmQgYXJlIHRoZW1zZWx2ZXMgdGhyZWFkLXNhZmUuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EYWVtb25UaHJlYWRIeWdpZW5lRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItdGhyZWFkIGFjY2VzcyBtYXAgaXMgYSBDb25jdXJyZW50SGFzaE1hcDsgZmlyc3QtcmVnaXN0cmF0aW9uLXdpbnMgdmlhIHB1dElmQWJzZW50Ljwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkgYW5kIHRyYWNrIG9ubHkgaW1wbGljaXQtcG9zaXRpb24gYWNjZXNzb3JzLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmluYWxGaWVsZE11dGF0aW9uRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItZmllbGQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmxvd1B1Ymxpc2hlckNvbmN1cnJlbmN5RGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpOyBjb3VudGVycyBhcmUgTG9uZ0FkZGVyIC8gQXRvbWljSW50ZWdlciB3aXRoIGEgQ0FTIGhpZ2gtd2F0ZXIgbWFyay48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkhpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXI7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuSmRiY0Nvbm5lY3Rpb25TaGFyZWREZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkNvbmN1cnJlbnRIYXNoTWFwLWJhY2tlZCBKREJDLXJlc291cmNlIHRyYWNraW5nOyBwZXItcmVzb3VyY2UgU3RhdGUgaG9sZHMgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkgZm9yIGFjY2Vzc2luZyB0aHJlYWRzLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTGFtYmRhTG9zdFVwZGF0ZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gbGFtYmRhIGlkZW50aXR5IHBsdXMgY2FwdHVyZWQgbmFtZTsgZXZlbnRzIGFyZSBhcHBlbmRlZCB0byBhIGNvcHktb24td3JpdGUgbGlzdC4gVGhlIHJ1bGUgZ3JvdXBzIGJ5IG9ic2VydmVkIHByZS12YWx1ZSBhbmQgbmVlZHMgbm8gb3JkZXJpbmcuIGhvbGRzTG9jayBpcyBzYW1wbGVkIG9uIHRoZSByZWNvcmRpbmcgdGhyZWFkIGF0IHJlY29yZCB0aW1lLCB3aGljaCBpcyB0aGUgb25seSBwbGFjZSBpdCBtZWFucyBhbnl0aGluZy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5PbmUgc3RhdGUgb2JqZWN0IHBlciBjb2xsZWN0aW9uIGFuZCBlbGVtZW50IGtleSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLCB0aGUgY29sbGVjdGlvbiBrZXllZCBieSBpdHMgaWRlbnRpdHkgd2hlbiB0aGUgY2FsbGVyIHBhc3NlcyBpdCBhbmQgYnkgaXRzIG5hbWUgb3RoZXJ3aXNlOyBjb3VudGVycyBhcmUgYXRvbWljcyBhbmQgd2FpdGVyIHNldHMgYXJlIGNvbmN1cnJlbnQuIFRoZSBwZXItdGhyZWFkIHN0YWNrIG9mIGluLWZsaWdodCBjb21wdXRhdGlvbnMgaXMgYW4gQXJyYXlEZXF1ZSBwZXIgdGhyZWFkIGlkLCBzbyBlYWNoIGlzIHRvdWNoZWQgYnkgZXhhY3RseSBvbmUgdGhyZWFkIGFuZCBuZWVkcyBubyBzeW5jaHJvbmlzYXRpb24uIERlcGVuZGVuY3kgZWRnZXMgYWNjdW11bGF0ZSBpbiBhIHN5bmNocm9uaXplZCBMaW5rZWRIYXNoU2V0LiBOYW1lLWtleWVkIGVkZ2VzIGFyZSB3YWxrZWQgYW5kIGRyb3BwZWQgYXQgZWFjaCByb3VuZCBzdGFydCAobWFya0ludm9jYXRpb25TdGFydCwgIzg1MiksIGFmdGVyIHRoZSBwcmV2aW91cyByb3VuZCYjMzk7cyB3b3JrZXJzIGZpbmlzaGVkOyBpZGVudGl0eS1rZXllZCBlZGdlcyBsYXN0IHRoZSBydW4gYW5kIGFyZSB3YWxrZWQgaW4gYW5hbHl6ZSgpLCBhZnRlciBpdCBoYXMgcXVpZXNjZWQuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29uc3RhbnRNaXN1c2VEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1jb25zdGFudCBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpOyByZXBvcnRzIGFyZSBzeW5jaHJvbml6ZWQgbGlzdHMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Mb2NrVXBncmFkZURlYWRsb2NrRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5Db25jdXJyZW50SGFzaE1hcCB0cmFja3MgcmVhZCBsb2NrIG93bmVyc2hpcCBhbmQgdmlvbGF0aW9ucy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlciAobWFwLGtleSkgc3RhdGUgaW4gYSBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Ob3RpZnlXaXRob3V0TW9uaXRvckRldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5PlNZTkNIUk9OSVpFRDwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkF0dGVtcHRzIGxpc3QgbXV0YXRlZCB1bmRlciBhIHNpbmdsZSBpbnRyaW5zaWMgbW9uaXRvciBvbiB0aGUgbGlzdCBpdHNlbGY7IHNhbXBsaW5nIFRocmVhZC5ob2xkc0xvY2sgcmVxdWlyZXMgbm8gbG9ja2luZy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlBsYXRmb3JtVGhyZWFkUGVyVGFza0RldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q3JlYXRlZCB0aHJlYWRzIGFjY3VtdWxhdGUgaW4gYSBDb25jdXJyZW50TGlua2VkUXVldWU7IHByb2JlIGJvb2trZWVwaW5nIGluIENvbmN1cnJlbnRIYXNoTWFwOyBjb3VudGVycyBhcmUgQXRvbWljSW50ZWdlci4gYW5hbHl6ZSgpIHJlYWRzIGEgbW9tZW50LWluLXRpbWUgc25hcHNob3QgYW5kIGlzIHNhZmUgdG8gY2FsbCBjb25jdXJyZW50bHkgd2l0aCByZWNvcmRpbmcuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLXByb2Nlc3Mgc3RhdGUgaW4gYSBDb25jdXJyZW50SGFzaE1hcCBrZXllZCBieSBpZGVudGl0eSwgd2l0aCBhIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGFrZXJzIGFyZSBjb25jdXJyZW50IHNldHM7IHRoZSBmaXJzdCB3YWl0IGlzIGNsYWltZWQgb25jZSB3aXRoIGEgQ0FTLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuUmVjb3JkTXV0YWJsZUNvbXBvbmVudExlYWtEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCBrZXllZCBvbiBpZGVudGl0eSBoYXNoOyB0aGUgZmlyc3Qtc2lnaHQgZmluZ2VycHJpbnQgbWFwIGlzIHBvcHVsYXRlZCBvbmNlIHVuZGVyIGNvbXB1dGVJZkFic2VudCBhbmQgcmVhZC1vbmx5IGFmdGVyd2FyZHM7IHRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgdHJhY2tpbmcgaXMgY2FwcGVkIGJ5IE1BWF9JTlNUQU5DRVMgd2l0aCBhIExvbmdBZGRlciBkcm9wIGNvdW50ZXIuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TY29wZUNvbmZpZ3VyYXRpb25NaXN1c2VEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPk9uZSBpbW11dGFibGUtYWZ0ZXItb3BlbiBzdGF0ZSBvYmplY3QgcGVyIHNjb3BlIGlkIGluIGEgQ29uY3VycmVudEhhc2hNYXA7IGNvdW50ZXJzIGluc2lkZSBpdCBhcmUgYXRvbWljcy4gU2NvcGUgbGlmZXRpbWVzIGFyZSBvcmRlcmVkIGJ5IGEgc2luZ2xlIEF0b21pY0xvbmcgc2VxdWVuY2UgcmF0aGVyIHRoYW4gdGhlIHdhbGwgY2xvY2ssIHNvIG92ZXJsYXAgaXMgZGVjaWRlZCBieSBwcm9ncmFtIG9yZGVyIGFuZCBuZXZlciBieSBjbG9jayBncmFudWxhcml0eSBvciBkcmlmdC48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5PbmUgc3RhdGUgb2JqZWN0IHBlciBqb2luZXIgaWRlbnRpdHkgaW4gYSBDb25jdXJyZW50SGFzaE1hcC4gVGhlIGluLWZsaWdodCBvbkNvbXBsZXRlIGNvdW50IGlzIGFuIGF0b21pYyBjb3VudGVyIHdob3NlIHBlYWsgaXMgcmFpc2VkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLiBGaW5kaW5ncyBhcmUgcmVjb3JkZWQgYXMgZmxhZ3Mgc2V0IGZyb20gdGhlIHJlY29yZGluZyB0aHJlYWRzIGFuZCByZWFkIG9uY2UgaW4gYW5hbHl6ZSgpLCBhZnRlciB0aGUgcnVuIGhhcyBxdWllc2NlZC48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlUmVzdWx0RXNjYXBlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5PbmUgc3RhdGUgb2JqZWN0IHBlciBzY29wZSBpZCBhbmQgcGVyIHJlc3VsdC1oYW5kbGUgaWRlbnRpdHksIGJvdGggaW4gQ29uY3VycmVudEhhc2hNYXBzLiBDbG9zZSBhbmQgcmVhZCBhcmUgb3JkZXJlZCBieSBhIHNpbmdsZSBBdG9taWNMb25nIHNlcXVlbmNlIHJhdGhlciB0aGFuIHRoZSB3YWxsIGNsb2NrLCBzbyAmIzM5O3JlYWQgYWZ0ZXIgY2xvc2UmIzM5OyBpcyBkZWNpZGVkIGJ5IHByb2dyYW0gb3JkZXIgYW5kIG5ldmVyIGJ5IGNsb2NrIGdyYW51bGFyaXR5LiBSZWFkZXIgdGhyZWFkIG5hbWVzIGFjY3VtdWxhdGUgaW4gYSBjb25jdXJyZW50IHNldCBhbmQgYXJlIHJlYWQgb25jZSBpbiBhbmFseXplKCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRCeXRlQnVmZmVyRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIGFuZCBvcGVyYXRpb24gc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRDaGFyc2V0Q29kZXJEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRDaGVja3N1bURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZERlZmxhdGVyRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkSXRlcmF0b3JEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRKc29uTWFwcGVyUmVjb25maWdEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdXNpbmctdGhyZWFkIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpOyB2aW9sYXRpbmcgbXV0YXRpb25zIHJlY29yZGVkIGluIGEgQ29weU9uV3JpdGVBcnJheUxpc3QuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRLZGZEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZW1vcnlTZWdtZW50UmFjZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLXNlZ21lbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXA7IHRoZSBhY2Nlc3MgbG9nIGlzIGEgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfVFJBQ0tFRF9BQ0NFU1NFUyB3aXRoIGEgTG9uZ0FkZGVyIGRyb3AgY291bnRlciwgc28gYW4gdW5ib3VuZGVkIHRlc3QgY2Fubm90IGV4aGF1c3QgdGhlIGhlYXAgYW5kIHRoZSByZXBvcnQgc3RhdGVzIGhvdyBtYW55IHNhbXBsZXMgd2VyZSBkcm9wcGVkLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZG91YmxlLWNoZWNrIChnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQpIGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZG91YmxlLWNoZWNrIChnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQpIGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNwdXJpb3VzV2FrZXVwRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5Db25jdXJyZW50SGFzaE1hcCBzdG9yZXMgc3RhdGUgcGVyIG1vbml0b3IgaW5zdGFuY2UuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TdGF0aWNJbml0RGVhZGxvY2tEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkhvbGRlciBhbmQgd2FpdCBtYXBzIGFyZSBDb25jdXJyZW50SGFzaE1hcCBrZXllZCBvbiBjbGFzcyBuYW1lIC8gdGhyZWFkIGlkLiBUaGUgbGl2ZS10aHJlYWQgc2FtcGxlIGlzIHRha2VuIGF0IG1vc3Qgb25jZSBhbmQgY2FjaGVkIGluIGFuIEF0b21pY1JlZmVyZW5jZSBzbyBhbmFseXplKCkgc3RheXMgaWRlbXBvdGVudCBldmVuIHRob3VnaCB0aGUgdGhyZWFkcyBpdCBvYnNlcnZlcyBhcmUgbm90Ljwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhpc0VzY2FwZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyBlc2NhcGUgZGVzY3JpcHRpb25zIGFuZCBvYnNlcnZlci10aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHRoZSBjb21wbGV0ZWQgZmxhZyBpcyB2b2xhdGlsZS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRocmVhZExvY2FsQ2FjaGVEZWdyYWRhdGlvbkRldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+T25lIHN0YXRlIG9iamVjdCBwZXIgVGhyZWFkTG9jYWwgbmFtZSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwOyBpbnN0YW5jZSBpZGVudGl0aWVzIGFuZCB0aHJlYWQgaWRzIGFyZSBjb25jdXJyZW50IGtleS1zZXQgdmlld3MsIHNvIGNvdW50aW5nIGlzIGlkZW1wb3RlbnQgdW5kZXIgcmVwZWF0ZWQgcmVjb3JkaW5nIGZyb20gdGhlIHNhbWUgdGhyZWFkIC0gYSB2YWx1ZSByZWFkIHR3aWNlIGFkZHMgbm90aGluZy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRocmVhZExvY2FsUmFuZG9tTWlzdXNlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IG1pc3VzaW5nLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRyeUxvY2tNaXN1c2VEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkNvbmN1cnJlbnRIYXNoTWFwIHRyYWNrcyB0cnlMb2NrIGF0dGVtcHRzLCByZXN1bHRzLCBhbmQgdW5sb2NrIHZpb2xhdGlvbnMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WYXJIYW5kbGVOb25BdG9taWNVcGRhdGVEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1sb2NhdGlvbiBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCBrZXllZCBvbiBhIChoYW5kbGUsIHJlY2VpdmVyKSBpZGVudGl0eSByZWNvcmQ7IHBlbmRpbmcgcmVhZHMgYXJlIGEgcGVyLXRocmVhZCBDb25jdXJyZW50SGFzaE1hcCBlbnRyeTsgY291bnRlcnMgYXJlIExvbmdBZGRlciBhbmQgZGV0YWlsIGxpc3RzIGFyZSBDb3B5T25Xcml0ZUFycmF5TGlzdCBib3VuZGVkIGJ5IE1BWF9ERVRBSUxTLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZE1vbml0b3JTZXJpYWxpemF0aW9uRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5PbmUgc3RhdGUgb2JqZWN0IHBlciBtb25pdG9yIGlkZW50aXR5IGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFF1ZXVlIGRlcHRoLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBpbiBpdCwgYXJlIGF0b21pYyBjb3VudGVycyB3aG9zZSBwZWFrcyBhcmUgcmFpc2VkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkIG1hcCB2YWx1ZXMgdXNlIEF0b21pY0ludGVnZXIgY291bnRlcnMgYW5kIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFJlc291cmNlU2F0dXJhdGlvbkRldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+T25lIHN0YXRlIG9iamVjdCBwZXIgcmVzb3VyY2UgaW4gYSBDb25jdXJyZW50SGFzaE1hcC4gVGhlIHdhaXRlcnMsIGFuZCB0aGUgdmlydHVhbCB0aHJlYWRzIGFtb25nIHRoZW0sIGFyZSBhdG9taWMgY291bnRlcnMgd2hvc2UgcGVha3MgYXJlIG1haW50YWluZWQgd2l0aCBhIENBUyByZXRyeSBsb29wLCBzbyBhIHBlYWsgb2JzZXJ2ZWQgdW5kZXIgY29udGVudGlvbiBpcyBuZXZlciBsb3dlciB0aGFuIHRoZSB0cnVlIHBlYWsuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5XZWFrSGFzaE1hcFNoYXJlZERldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q29uY3VycmVudEhhc2hNYXAtYmFja2VkIGluc3RhbmNlIHRyYWNraW5nOyBwZXItaW5zdGFuY2UgU3RhdGUgaG9sZHMgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkgZm9yIHRocmVhZCBpZHMvbmFtZXMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXIiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5Db29yZGluYXRlcyBjb25jdXJyZW5jeSB1c2luZyBDeWNsaWNCYXJyaWVyIHRvIG1heGltaXplIHRocmVhZCBjb250ZW50aW9uLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VHdWFyZCI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkNvbmN1cnJlbnRIYXNoTWFwLmNvbXB1dGVJZkFic2VudCBndWFyYW50ZWVzIGF0LW1vc3Qtb25jZSBnYXRlIGV4ZWN1dGlvbiBwZXIgZmluZ2VycHJpbnQgdW5kZXIgY29udGVudGlvbjsgdm9sYXRpbGUgYW5ub3VuY2UgZmxhZ3MgY29sbGFwc2UgdGhlIEdSQU5URUQvQ0kvZ3JhY2UgYmFubmVycyB0byBvbmNlLXBlci1KVk0uPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZVZhbGlkYXRpb25DYWNoZSI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlN0YXRlbGVzcyBzdGF0aWMgbWV0aG9kcyBvdmVyIHRoZSBmaWxlc3lzdGVtLiBDb25jdXJyZW50IHdyaXRlcnMgcmFjZSBvbiBhbiBhdG9taWMgdGVtcC1maWxlIG1vdmUgd2hlcmUgdGhlIGxvc2luZyB3cml0ZSBpcyBlcXVpdmFsZW50IHRvIHRoZSB3aW5uaW5nIG9uZTsgcmVhZGVycyBzZWUgZWl0aGVyIHRoZSBvbGQgY29tcGxldGUgZmlsZSBvciB0aGUgbmV3IGNvbXBsZXRlIGZpbGUsIG5ldmVyIGEgcGFydGlhbCB3cml0ZS4gT24gV2luZG93cyBhIHJlYWQgdGhhdCBtZWV0cyBhIHJlcGxhY2UgaW4gcHJvZ3Jlc3MgZmFpbHMgd2l0aCBBY2Nlc3NEZW5pZWRFeGNlcHRpb24sIG9yIGZpbmRzIG5vIGZpbGUgZm9yIGEgbW9tZW50LCBzbyBpc0ZyZXNoIGFuZCBoYXNSZWNvcmQgcmV0cnkgYW55IHJlYWQgZmFpbHVyZSwgYSBtaXNzaW5nIGZpbGUgaW5jbHVkZWQsIGZvciB1cCB0byAyNTUgbXMgYmVmb3JlIGFuc3dlcmluZyBubyAoIzkyOCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogIDwvdGhyZWFkX3NhZmVfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBsaXN0ZWQgaW4gPHRocmVhZF9zYWZlX2VsZW1lbnRzPiBhcmUgZXhwbGljaXRseSBkZXNpZ25lZCB0byBiZSB0aHJlYWQtc2FmZSB2aWEgdGhlIG5hbWVkIHN0cmF0ZWd5LiBBbnkgbW9kaWZpY2F0aW9uIE1VU1QgcHJlc2VydmUgdGhlIHN5bmNocm9uaXphdGlvbiBpbnZhcmlhbnQgYW5kIGRvY3VtZW50IGl0cyByZWFzb25pbmcgaW4gdGhlIGNoYW5nZSBkZXNjcmlwdGlvbi48L3J1bGU+CiAgPGltbXV0YWJsZV90eXBlcz4KICAgIDx0eXBlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnIj4KICAgICAgPG5vdGU+SW1tdXRhYmxlIHNuYXBzaG90IG9mIEBBc3luY1Rlc3QgcGFyYW1ldGVycyB0byBlbnN1cmUgdGhyZWFkIHNhZmV0eS48L25vdGU+CiAgICA8L3R5cGU+CiAgICA8dHlwZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LlByZXNldCI+CiAgICAgIDxub3RlPkVudW0gY29uc3RhbnRzIOKAlCBKVk0gZ3VhcmFudGVlcyBzdHJ1Y3R1cmFsIGltbXV0YWJpbGl0eS4gSW50ZXJuYWwgZW5hYmxlZC1zZXQgaXMgY2FwdHVyZWQgYXQgY2xhc3MgaW5pdC48L25vdGU+CiAgICA8L3R5cGU+CiAgICA8dHlwZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlLlNpdGUiPgogICAgICA8bm90ZT5KYXZhIHJlY29yZCDigJQgZmllbGRzIGFyZSBmaW5hbCBieSBsYW5ndWFnZTsgdHlwZXMgYXJlIGFsbCBwcmltaXRpdmVzIG9yIFN0cmluZy48L25vdGU+CiAgICA8L3R5cGU+CiAgICA8dHlwZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJlcG9ydC5WaW9sYXRpb24iPgogICAgICA8bm90ZT5KYXZhIHJlY29yZCDigJQgZmllbGRzIGFyZSBmaW5hbCBieSBsYW5ndWFnZS4gQ29sbGVjdGlvbiBmaWVsZHMgYXJlIGRlZXAtY29waWVkIHRvIGltbXV0YWJsZSB2aWV3cyBpbiB0aGUgY2Fub25pY2FsIGNvbnN0cnVjdG9yLjwvbm90ZT4KICAgIDwvdHlwZT4KICAgIDx0eXBlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3Quc3BpLkRldGVjdG9yUmVnaXN0cnkiPgogICAgICA8bm90ZT5FZmZlY3RpdmVseSBpbW11dGFibGUgYWZ0ZXIgYnVpbGRFeHRlcm5hbCgpIOKAlCB0aGUgaWQta2V5ZWQgbWFwIGlzIHBvcHVsYXRlZCBvbmx5IGluIHRoZSBwcml2YXRlIGNvbnN0cnVjdG9yIGFuZCBuZXZlciBtdXRhdGVkIHRoZXJlYWZ0ZXI7IHNhZmUgdG8gcHVibGlzaCB0byBtdWx0aXBsZSB0aHJlYWRzIGFuZCByZWFkLW9ubHkgdmlld3Mgb3ZlciBhIG1hcCBwb3B1bGF0ZWQgb25jZSBhdCBjb25zdHJ1Y3Rpb24uPC9ub3RlPgogICAgPC90eXBlPgogIDwvaW1tdXRhYmxlX3R5cGVzPgoKPHJ1bGU+VHlwZXMgbGlzdGVkIGluIDxpbW11dGFibGVfdHlwZXM+IGFyZSBpbW11dGFibGUgYnkgZGVzaWduLiBOZXZlciBpbnRyb2R1Y2Ugbm9uLWZpbmFsIGZpZWxkcywgc2V0dGVycywgb3IgbWV0aG9kcyB0aGF0IG11dGF0ZSBpbnN0YW5jZSBzdGF0ZS48L3J1bGU+CiAgPG9ic2VydmFiaWxpdHlfaW5zdHJ1bWVudGF0aW9uPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIiPgogICAgICA8bWV0cmljPmJlbmNobWFyay5pbnZvY2F0aW9uLnRpbWVzPC9tZXRyaWM+CiAgICAgIDxsb2c+W0JFTkNITUFSS10gQmFzZWxpbmUgY3JlYXRlZDwvbG9nPgogICAgICA8bG9nPltCRU5DSE1BUktdIEJhc2VsaW5lIHVwZGF0ZWQ8L2xvZz4KICAgICAgPGxvZz5bQkVOQ0hNQVJLXSBTVEFCTEU8L2xvZz4KICAgICAgPGxvZz5bQkVOQ0hNQVJLXSBSRUdSRVNTSU9OPC9sb2c+CiAgICAgIDxsb2c+W0JFTkNITUFSS10gSU1QUk9WRU1FTlQ8L2xvZz4KICAgICAgPG5vdGU+SG90IHBhdGggdGVsZW1ldHJ5IHVzZWQgYnkgSlVuaXQgYmVuY2htYXJrIG1ldHJpY3MgYW5kIGJhc2VsaW5lIHJlZ3Jlc3Npb24gY2hlY2tzLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICA8L29ic2VydmFiaWxpdHlfaW5zdHJ1bWVudGF0aW9uPgoKPHJ1bGU+RWxlbWVudHMgbGlzdGVkIGluIDxvYnNlcnZhYmlsaXR5X2luc3RydW1lbnRhdGlvbj4gcHVibGlzaCBtZXRyaWNzLCB0cmFjZXMsIG9yIGxvZyBzdGF0ZW1lbnRzIHRoYXQgZG93bnN0cmVhbSBkYXNoYm9hcmRzIGFuZCBhbGVydHMgZGVwZW5kIG9uLiBOZXZlciByZW1vdmUgb3IgcmVuYW1lIGluc3RydW1lbnRhdGlvbiB3aXRob3V0IGZsYWdnaW5nIHRoZSBjb3JyZXNwb25kaW5nIGRhc2hib2FyZCB1cGRhdGUuPC9ydWxlPgogIDxwdWJsaWNfYXBpX2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY0Fzc2VydCI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jRmluZGluZ3MiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3QiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0Ij4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dC5zaGFyZWRDcnlwdG9ncmFwaHlEZXRlY3RvcigpIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dC5zaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IoKSI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdExpc3RlbmVyIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0TGlzdGVuZXJSZWdpc3RyeSI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdFJ1bm5lciI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LlByZXNldCI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yRGVmYXVsdFNldmVyaXR5Ij4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JUcnVzdCI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkdyYWRlZEZpbmRpbmdzIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2l0ZUNhcHR1cmUuU2l0ZSI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRydXN0VGllciI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RFeHRlbnNpb24iPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5yZXBvcnQuRm9ybWF0dGVyIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0Lkpzb25Gb3JtYXR0ZXIiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5yZXBvcnQuTWFya2Rvd25Gb3JtYXR0ZXIiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5yZXBvcnQuU2FyaWZGb3JtYXR0ZXIiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5yZXBvcnQuVmlvbGF0aW9uIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3Quc3BpLkRldGVjdG9yIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3Quc3BpLkRldGVjdG9yRmFjdG9yeSI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnNwaS5EZXRlY3RvclJlZ2lzdHJ5Ij4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICA8L3B1YmxpY19hcGlfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBpbiA8cHVibGljX2FwaV9lbGVtZW50cz4gZXhwb3NlIHB1YmxpYyBBUEkuIFByZXNlcnZlIHB1YmxpYyBzaWduYXR1cmUsIEphdmFkb2MsIGFuZCBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eSB3aXRob3V0IGV4Y2VwdGlvbnMuPC9ydWxlPgogIDxzdHJpY3RfY2xhc3NwYXRoX2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrQ29tcGFyYXRvci5yZWFkU3RvcmUoamF2YS5pby5GaWxlKSI+CiAgICAgIDxjbGFzc3BhdGg+c3RyaWN0PC9jbGFzc3BhdGg+CiAgICAgIDxyZWFzb24+SmF2YSBuYXRpdmUgZGVzZXJpYWxpemF0aW9uIHNpbmsuIFRoZSBCQVNFTElORV9GSUxURVIgYWxsb3ctbGlzdCAoZW5kaW5nIGluICEqKSBtdXN0IHJlc29sdmUgZXZlcnkgY2xhc3MgaW4gdGhlIHN0cmVhbSBhbmQgcmVqZWN0IGFsbCBvdGhlcnMsIHByZXZlbnRpbmcgYXJiaXRyYXJ5IGNsYXNzIGxvYWRpbmcgKENXRS01MDIgUkNFKS4gTmV2ZXIgd2lkZW4gdGhlIGZpbHRlciBvciByZW1vdmUgc2V0T2JqZWN0SW5wdXRGaWx0ZXIuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgPC9zdHJpY3RfY2xhc3NwYXRoX2VsZW1lbnRzPgoKPHJ1bGU+RHluYW1pYyBjbGFzcyBsb2FkaW5nLCBjdXN0b20gY2xhc3Nsb2FkZXJzLCByZWZsZWN0aW9uIGhhY2tzLCBvciB1bnZlcmlmaWVkIGV4dGVybmFsIGNvZGUgYXJlIHByb2hpYml0ZWQgaW4gPHN0cmljdF9jbGFzc3BhdGhfZWxlbWVudHM+LjwvcnVsZT4KICA8aWRlbXBvdGVudF9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dC51bmluc3RhbGwoKSI+CiAgICAgIDxpZGVtcG90ZW50PnRydWU8L2lkZW1wb3RlbnQ+CiAgICAgIDxyZWFzb24+VGhyZWFkTG9jYWwucmVtb3ZlKCkgaXMgZG9jdW1lbnRlZCBhcyBhIG5vLW9wIHdoZW4gdGhlIHRocmVhZCBoYXMgbm8gdmFsdWUgc2V0OyB0aGUgaW5zdGFsbC91bmluc3RhbGwgc3ltbWV0cnkgcnVsZSAoQ0xBVURFLm1kKSB0b2xlcmF0ZXMgZXh0cmEgdW5pbnN0YWxscy4gQ29uY3VycmVuY3lSdW5uZXIgcmVsaWVzIG9uIHRoaXMgaW4gaXRzIG91dGVybW9zdC1maW5hbGx5IGNsZWFudXAuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdExpc3RlbmVyUmVnaXN0cnkuUmVnaXN0cmF0aW9uLmNsb3NlKCkiPgogICAgICA8aWRlbXBvdGVudD50cnVlPC9pZGVtcG90ZW50PgogICAgICA8cmVhc29uPkd1YXJkZWQgYnkgdGhlIGBjbG9zZWRgIHZvbGF0aWxlIGZsYWc7IHNlY29uZCBjbG9zZSgpIHJldHVybnMgZWFybHkgYmVmb3JlIHRvdWNoaW5nIHRoZSByZWdpc3RyeS4gQ292ZXJlZCBieSBgcmVnaXN0cmF0aW9uQ2xvc2VfaXNJZGVtcG90ZW50YCB0ZXN0LjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RMaXN0ZW5lclJlZ2lzdHJ5LmNsZWFyQWxsKCkiPgogICAgICA8aWRlbXBvdGVudD50cnVlPC9pZGVtcG90ZW50PgogICAgICA8cmVhc29uPlB1Ymxpc2hlcyB0aGUgZW1wdHkgc2V0OyBkb2luZyBzbyB0d2ljZSBoYXMgaWRlbnRpY2FsIG9ic2VydmFibGUgZWZmZWN0IChlbXB0eSByZWdpc3RyeSkuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdExpc3RlbmVyUmVnaXN0cnkudW5yZWdpc3RlcihzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdExpc3RlbmVyKSI+CiAgICAgIDxpZGVtcG90ZW50PnRydWU8L2lkZW1wb3RlbnQ+CiAgICAgIDxyZWFzb24+UmVtb3ZlcyBvbmUgb2NjdXJyZW5jZSB3aGVuIHByZXNlbnQgYW5kIGlzIGEgbm8tb3Agd2hlbiBhYnNlbnQ7IGEgc2Vjb25kIGNhbGwgcmV0dXJucyBmYWxzZSBidXQgcHJvZHVjZXMgbm8gb2JzZXJ2YWJsZSBzaWRlIGVmZmVjdC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VHdWFyZC5jaGVjayhzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbmZpZykiPgogICAgICA8aWRlbXBvdGVudD50cnVlPC9pZGVtcG90ZW50PgogICAgICA8cmVhc29uPkNvbmN1cnJlbnRIYXNoTWFwLmNvbXB1dGVJZkFic2VudCBndWFyYW50ZWVzIHRoZSB1bmRlcmx5aW5nIGdhdGUuY2hlY2sgZmlyZXMgYXQgbW9zdCBvbmNlIHBlciBGaW5nZXJwcmludDsgcmVwZWF0IGNhbGxzIHJldHVybiBpbW1lZGlhdGVseS4gRGVuaWVkIHJlc3VsdHMgY29uc2lzdGVudGx5IHRocm93IFNlY3VyaXR5RXhjZXB0aW9uIGZvciB0aGUgc2FtZSBmaW5nZXJwcmludC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3Quc3BpLkRldGVjdG9yUmVnaXN0cnkuYW5hbHl6ZUFsbCgpIj4KICAgICAgPGlkZW1wb3RlbnQ+dHJ1ZTwvaWRlbXBvdGVudD4KICAgICAgPHJlYXNvbj5FYWNoIERldGVjdG9yLmFuYWx5emUoKSBtdXN0IHJldHVybiB0aGUgc2FtZSB2aW9sYXRpb25zIGZvciB0aGUgc2FtZSBvYnNlcnZlZCBzdGF0ZSAodGhlIFNQSSBjb250cmFjdCkuIENhbGxpbmcgYW5hbHl6ZUFsbCgpIE4gdGltZXMgb24gYSBxdWllc2NlbnQgcmVnaXN0cnkgeWllbGRzIE4gaWRlbnRpY2FsIGxpc3RzOyBkbyBub3QgaW50cm9kdWNlIHN0YXRlZnVsIHNpZGUtZWZmZWN0cyBpbiBhbmFseXplKCkuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgPC9pZGVtcG90ZW50X2VsZW1lbnRzPgoKPHJ1bGU+T3BlcmF0aW9ucyBsaXN0ZWQgaW4gPGlkZW1wb3RlbnRfZWxlbWVudHM+IG11c3QgcmVtYWluIGlkZW1wb3RlbnQuIE5ldmVyIGludHJvZHVjZSBzaWRlIGVmZmVjdHMgdGhhdCBjYXVzZSByZXBlYXRlZCBpbnZvY2F0aW9ucyB0byBwcm9kdWNlIGRpZmZlcmVudCByZXN1bHRzLjwvcnVsZT4KICA8ZmVhdHVyZV9mbGFnX2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb25maWcuZW5hYmxlQmVuY2htYXJraW5nIj4KICAgICAgPGZsYWc+YXN5bmMtdGVzdC5iZW5jaG1hcmtpbmcuZW5hYmxlZDwvZmxhZz4KICAgICAgPGRlZmF1bHRfdmFsdWU+ZmFsc2U8L2RlZmF1bHRfdmFsdWU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbmZpZy5saWNlbnNlTW9ja01vZGUiPgogICAgICA8ZmxhZz5saWNlbnNlLm1vY2subW9kZTwvZmxhZz4KICAgICAgPGRlZmF1bHRfdmFsdWU+ZmFsc2U8L2RlZmF1bHRfdmFsdWU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmJlbmNobWFyay5CZW5jaG1hcmtSZWNvcmRlciI+CiAgICAgIDxmbGFnPmFzeW5jLXRlc3QuYmVuY2htYXJraW5nLmVuYWJsZWQ8L2ZsYWc+CiAgICAgIDxkZWZhdWx0X3ZhbHVlPmZhbHNlPC9kZWZhdWx0X3ZhbHVlPgogICAgPC9lbGVtZW50PgogIDwvZmVhdHVyZV9mbGFnX2VsZW1lbnRzPgoKPHJ1bGU+RWxlbWVudHMgbGlzdGVkIGluIDxmZWF0dXJlX2ZsYWdfZWxlbWVudHM+IGFyZSBnYXRlZCBieSBhIGZlYXR1cmUgZmxhZy4gQWx3YXlzIHByZXNlcnZlIHRoZSBmbGFnIGNoZWNrIOKAlCBuZXZlciBhc3N1bWUgdGhlIGZsYWcgaXMgYWx3YXlzIGFjdGl2ZS48L3J1bGU+CiAgPHNlY3VyaXR5X2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IiPgogICAgICA8YXNwZWN0PmNyeXB0b2dyYXBoeSAoaGFzaCBpbnRlZ3JpdHkgLyBNQUMgLyBzaWduYXR1cmUgc3RhdGUpPC9hc3BlY3Q+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yIj4KICAgICAgPGFzcGVjdD5jcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KTwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yIj4KICAgICAgPGFzcGVjdD5jcnlwdG9ncmFwaHkgKGNvbmZpZGVudGlhbGl0eSAvIGludGVncml0eSAvIGF1dGhlbnRpY2l0eSBzdGF0ZSk8L2FzcGVjdD4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VHdWFyZCI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbjwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZVZhbGlkYXRpb25DYWNoZSI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbiAoaXNGcmVzaCBza2lwcyBvbmxpbmUgdmFsaWRhdGlvbjsgaGFzUmVjb3JkIGFkbWl0cyBvdXRhZ2UgZ3JhY2UpPC9hc3BlY3Q+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5PZmZsaW5lTGljZW5zZSI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbjwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogIDwvc2VjdXJpdHlfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBsaXN0ZWQgaW4gPHNlY3VyaXR5X2VsZW1lbnRzPiBhcmUgc2VjdXJpdHktY3JpdGljYWwuIE5ldmVyIHdlYWtlbiB0aGVpciBzZWN1cml0eSBwcm9wZXJ0aWVzLiBFdmVyeSBwcm9wb3NlZCBjaGFuZ2UgbXVzdCBiZSBleHBsaWNpdGx5IHJldmlld2VkIGZvciBzZWN1cml0eSBpbXBhY3QuPC9ydWxlPgogIDxhY2Nlc3NfbGltaXRhdGlvbnM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQuaW5zdGFsbChzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQpIj4KICAgICAgPGFsbG93ZWRfY2FsbGVycz5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5Db25jdXJyZW5jeVJ1bm5lcjwvYWxsb3dlZF9jYWxsZXJzPgogICAgPC9maWxlPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0Lmluc3RhbGwoc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0LGludCkiPgogICAgICA8YWxsb3dlZF9jYWxsZXJzPnNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkNvbmN1cnJlbmN5UnVubmVyPC9hbGxvd2VkX2NhbGxlcnM+CiAgICA8L2ZpbGU+CiAgPC9hY2Nlc3NfbGltaXRhdGlvbnM+Cgo8cnVsZT5EbyBub3QgaW52b2tlIGVsZW1lbnRzIGluIDxhY2Nlc3NfbGltaXRhdGlvbnM+IGZyb20gb3V0c2lkZSB0aGVpciBzcGVjaWZpZWQgYWxsb3dlZCBjYWxsZXIgcGFja2FnZXMgb3IgY2xhc3Nlcy48L3J1bGU+CiAgPG1lbW9yeV9idWRnZXRfZWxlbWVudHM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmJlbmNobWFyay5CZW5jaG1hcmtSZWNvcmRlci5yZWNvcmRJbnZvY2F0aW9uRW5kKGxvbmcpIj4KICAgICAgPGFsbG9jYXRpb25fcG9saWN5Pk5PX0FVVE9CT1hJTkc8L2FsbG9jYXRpb25fcG9saWN5PgogICAgPC9maWxlPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIucmVjb3JkSW52b2NhdGlvblN0YXJ0KCkiPgogICAgICA8YWxsb2NhdGlvbl9wb2xpY3k+Tk9fQVVUT0JPWElORzwvYWxsb2NhdGlvbl9wb2xpY3k+CiAgICA8L2ZpbGU+CiAgPC9tZW1vcnlfYnVkZ2V0X2VsZW1lbnRzPgoKPHJ1bGU+QXZvaWQgcnVudGltZSBoZWFwIG9iamVjdCBhbGxvY2F0aW9ucywgYXV0b2JveGluZywgb3IgZHluYW1pYyBvdmVyaGVhZCB3aXRoaW4gY2xhc3Nlcy9tZXRob2RzIGluIDxtZW1vcnlfYnVkZ2V0X2VsZW1lbnRzPi48L3J1bGU+CiAgPGV4dGVuc2libGVfcGF0dGVybnM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJlcG9ydC5Gb3JtYXR0ZXIiPgogICAgICA8ZXh0ZW5zaW9uX3BhdHRlcm4+U1RSQVRFR1lfUEFUVEVSTjwvZXh0ZW5zaW9uX3BhdHRlcm4+CiAgICA8L2ZpbGU+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnNwaS5EZXRlY3RvciI+CiAgICAgIDxleHRlbnNpb25fcGF0dGVybj5TVFJBVEVHWV9QQVRURVJOPC9leHRlbnNpb25fcGF0dGVybj4KICAgIDwvZmlsZT4KICA8L2V4dGVuc2libGVfcGF0dGVybnM+Cgo8cnVsZT5SZXNwZWN0IGV4dGVuc2liaWxpdHkgZ3VpZGVsaW5lcyBmb3IgZWxlbWVudHMgaW4gPGV4dGVuc2libGVfcGF0dGVybnM+LiBJbXBsZW1lbnQgc3RyYXRlZ3kvdmlzaXRvciBleHRlbnNpb25zIHJhdGhlciB0aGFuIGV4cGFuZGluZyBicmFuY2ggY29uZGl0aW9uYWwgbG9naWMuPC9ydWxlPgogIDxzYW5pdGl6YXRpb25fZWxlbWVudHM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJlcG9ydC5KVW5pdFhtbFJlcG9ydExpc3RlbmVyLm9uU3RydWN0dXJlZFJlcG9ydChqYXZhLmxhbmcuU3RyaW5nLHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuSXNzdWVTZXZlcml0eSxqYXZhLmxhbmcuU3RyaW5nKSNyZXBvcnQiPgogICAgICA8c2FuaXRpemF0aW9uX3R5cGVzPlhTUzwvc2FuaXRpemF0aW9uX3R5cGVzPgogICAgPC9maWxlPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5yZXBvcnQuSnNvblJlcG9ydExpc3RlbmVyLm9uU3RydWN0dXJlZFJlcG9ydChqYXZhLmxhbmcuU3RyaW5nLHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuSXNzdWVTZXZlcml0eSxqYXZhLmxhbmcuU3RyaW5nKSNyZXBvcnQiPgogICAgICA8c2FuaXRpemF0aW9uX3R5cGVzPlhTUzwvc2FuaXRpemF0aW9uX3R5cGVzPgogICAgPC9maWxlPgogIDwvc2FuaXRpemF0aW9uX2VsZW1lbnRzPgoKPHJ1bGU+U3RyaWN0IGlucHV0IHNhbml0aXphdGlvbiBpcyBtYW5kYXRvcnkgZm9yIGVsZW1lbnRzIGluIDxzYW5pdGl6YXRpb25fZWxlbWVudHM+LiBSYXcgaW5wdXQgbXVzdCBwYXNzIHRocm91Z2ggYXBwcm92ZWQgZmlsdGVycyBiZWZvcmUgaGl0dGluZyBxdWVyaWVzIG9yIHJlbmRlcmVycy48L3J1bGU+CiAgPGxvYWRfYmVhcmluZ19lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZXh0ZW5zaW9uLkFzeW5jVGVzdEludm9jYXRpb25JbnRlcmNlcHRvci5pbnRlcmNlcHRUZXN0VGVtcGxhdGVNZXRob2Qob3JnLmp1bml0Lmp1cGl0ZXIuYXBpLmV4dGVuc2lvbi5JbnZvY2F0aW9uSW50ZXJjZXB0b3IuSW52b2NhdGlvbiZsdDtqYXZhLmxhbmcuVm9pZCZndDssb3JnLmp1bml0Lmp1cGl0ZXIuYXBpLmV4dGVuc2lvbi5SZWZsZWN0aXZlSW52b2NhdGlvbkNvbnRleHQmbHQ7amF2YS5sYW5nLnJlZmxlY3QuTWV0aG9kJmd0OyxvcmcuanVuaXQuanVwaXRlci5hcGkuZXh0ZW5zaW9uLkV4dGVuc2lvbkNvbnRleHQpIj4KICAgICAgPGludmFyaWFudD5UaGlzIG1ldGhvZCBjYWxscyBpbnZvY2F0aW9uLnNraXAoKSBhbmQgbmV2ZXIgaW52b2NhdGlvbi5wcm9jZWVkKCkuPC9pbnZhcmlhbnQ+CiAgICAgIDxicmVha3MtaWY+U29tZW9uZSAmIzM5O2ZpeGVzJiMzOTsgdGhlIGFwcGFyZW50bHktZHJvcHBlZCBpbnZvY2F0aW9uIGJ5IGNhbGxpbmcgcHJvY2VlZCgpLiBUaGUgdGVzdCBib2R5IHRoZW4gcnVucyBvbmNlIG9uIHRoZSBKVW5pdCB0aHJlYWQsIG91dHNpZGUgdGhlIEN5Y2xpY0JhcnJpZXIgYW5kIG91dHNpZGUgQXN5bmNUZXN0Q29udGV4dCwgc28gbm8gZGV0ZWN0b3Igb2JzZXJ2ZXMgaXQg4oCUIGFuZCBiZWNhdXNlIHRoYXQgc2luZ2xlIHJ1biB1c3VhbGx5IHBhc3NlcywgdGhlIHN1aXRlIGdvZXMgZ3JlZW4gd2hpbGUgZXZlcnkgY29uY3VycmVuY3kgY2hlY2sgaGFzIHNpbGVudGx5IHN0b3BwZWQgcnVubmluZy48L2JyZWFrcy1pZj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkNvbmN1cnJlbmN5UnVubmVyLmV4ZWN1dGUob3JnLmp1bml0Lmp1cGl0ZXIuYXBpLmV4dGVuc2lvbi5SZWZsZWN0aXZlSW52b2NhdGlvbkNvbnRleHQmbHQ7amF2YS5sYW5nLnJlZmxlY3QuTWV0aG9kJmd0OyxzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbmZpZykiPgogICAgICA8aW52YXJpYW50PlRoZSB0aW1lb3V0QWxyZWFkeVJlcG9ydGVkIGZsYWcsIGFuZCB0aGUgcGVyLXN0ZXAgZ3VhcmRlZCBjbGVhbnVwIGluIHRoZSBmaW5hbGx5IGJsb2NrLCBhcmUgYm90aCBkZWxpYmVyYXRlLiBBIHByZS1yb3VuZCBkZWFkbGluZSBjaGVjayB0aHJvd3MgYW4gZXJyb3IgdGhhdCBoYXMgYWxyZWFkeSBiZWVuIHRocm91Z2ggdGltZW91dEVycm9yKCksIGFuZCBlYWNoIGNsZWFudXAgc3RlcCBpcyB3cmFwcGVkIGluIGl0cyBvd24gdHJ5IHNvIG9uZSBmYWlsdXJlIGNhbm5vdCBzdXBwcmVzcyB0aGUgbmV4dC48L2ludmFyaWFudD4KICAgICAgPGJyZWFrcy1pZj5UaGUgZmxhZyBpcyByZW1vdmVkIGFzIHJlZHVuZGFudCDigJQgdGhlIGNhdGNoIGJsb2NrIHRoZW4gc2VuZHMgdGhlIHNhbWUgZXJyb3IgdGhyb3VnaCB0aW1lb3V0RXJyb3IoKSBhIHNlY29uZCB0aW1lLCBwcm9kdWNpbmcgdHdvIG9uVGltZW91dCBjYWxsYmFja3MgYW5kIHR3byBjb3BpZXMgb2YgZXZlcnkgcmVwb3J0IGZvciBvbmUgdGltZW91dC4gT3IgdGhlIGNsZWFudXAgc3RlcHMgYXJlIG1lcmdlZCBpbnRvIG9uZSB0cnksIGF0IHdoaWNoIHBvaW50IGEgZmFpbGluZyBBc3luY1Rlc3RDb250ZXh0LnVuaW5zdGFsbCgpIHNraXBzIHRoZSBsYXRjaC5jb3VudERvd24oKSBhbmQgdGhlIHJvdW5kIHdhaXRzIG91dCBpdHMgdGltZW91dCBmb3Igbm90aGluZy48L2JyZWFrcy1pZj4KICAgIDwvZWxlbWVudD4KICA8L2xvYWRfYmVhcmluZ19lbGVtZW50cz4KCjxydWxlPkVsZW1lbnRzIGluIDxsb2FkX2JlYXJpbmdfZWxlbWVudHM+IGxvb2sgcmVkdW5kYW50IG9yIG92ZXItZGVmZW5zaXZlIGJ1dCBhcmUgZGVsaWJlcmF0ZS4gWW91IG1heSByZWZhY3RvciB0aGVtLCBidXQgdGhlIHN0YXRlZCBpbnZhcmlhbnQgbXVzdCBzdXJ2aXZlOyBkbyBub3QgImNsZWFuIHVwIiB0aGUgb2RkaXR5IGl0c2VsZi48L3J1bGU+CiAgPG1pcnJvcmVkX2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclR5cGUiPgogICAgICA8bWlycm9yPnNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnPC9taXJyb3I+CiAgICAgIDxtaXJyb3I+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclJlZ2lzdHJ5PC9taXJyb3I+CiAgICAgIDxyZWFzb24+QSBkZXRlY3RvciBpcyBvbmx5IHJlYWNoYWJsZSBmcm9tIHRoZSBwdWJsaWMgQVBJIHdoZW4gYWxsIG9mIHRoZXNlIGFncmVlLiBUaGUgZW51bSBjb25zdGFudCBpcyB0aGUgbmFtZSB1c2VycyB0eXBlIGluIEBBc3luY1Rlc3QoaW5jbHVkZXM9Li4uLCBleGNsdWRlcz0uLi4pOyB0aGUgY29uZmlnIGZpZWxkIGRlcml2ZXMgZnJvbSB0aGUgZW5hYmxlZCBzZXQ7IGFuZCB0aGUgcmVnaXN0cnkmIzM5O3MgZmFjdG9yeSByb3cgYnVpbGRzIGl0LiBBZGRpbmcgdGhlIGNvbnN0YW50IGFsb25lIGNvbXBpbGVzIGFuZCBzaWxlbnRseSBkZXRlY3RzIG5vdGhpbmcuIFRoZSBTUEkgYnJpZGdlIHRoYXQgbWlycm9yZWQgZXZlcnkgY29uc3RhbnQgYSBzZWNvbmQgdGltZSB3YXMgZGVsZXRlZCBpbiAxLjEzLjAgKCM5MjIpLjwvcmVhc29uPgogICAgICA8ZW5mb3JjZWQtYnk+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclJlZ2lzdHJ5RmFjdG9yeVRhYmxlVGVzdDwvZW5mb3JjZWQtYnk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yRGVmYXVsdFNldmVyaXR5Ij4KICAgICAgPG1pcnJvcj5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZTwvbWlycm9yPgogICAgICA8bWlycm9yPnNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JUcnVzdDwvbWlycm9yPgogICAgICA8cmVhc29uPkFuIGVudHJ5IGhlcmUgaXMgdGhlIHNldmVyaXR5IGEgYnVpbHQtaW4gZGV0ZWN0b3ImIzM5O3MgZmluZGluZ3MgY2FycnkgYXQgdGhlIGZhaWxPbiBnYXRlIHdoZW4gaXRzIHJlcG9ydCBtYXJrcyBub25lLiBBIGRldGVjdG9yIG1pc3NpbmcgZnJvbSBib3RoIHRoaXMgdGFibGUgYW5kIHRoZSBtYXJrZXIgY29udmVudGlvbiBzaWxlbnRseSBmYWxscyBiYWNrIHRvIEhJR0gsIHdoaWNoIGlzIHRoZSBkZWZlY3QgdGhpcyB0YWJsZSBleGlzdHMgdG8gZml4LjwvcmVhc29uPgogICAgICA8ZW5mb3JjZWQtYnk+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5hcmNoaXRlY3R1cmUuRGV0ZWN0b3JTZXZlcml0eU1hcmtlclRlc3Q8L2VuZm9yY2VkLWJ5PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckZlZWRzIj4KICAgICAgPG1pcnJvcj5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZTwvbWlycm9yPgogICAgICA8bWlycm9yPnNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JUcnVzdDwvbWlycm9yPgogICAgICA8bWlycm9yPmRvY3MvREVURUNUT1JfQ0FUQUxPRy5tZDwvbWlycm9yPgogICAgICA8cmVhc29uPkV2ZXJ5IERldGVjdG9yVHlwZSByZXNvbHZlcyB0byBleGFjdGx5IG9uZSBmZWVkLCB0aGUgQUdFTlQgc2V0IG11c3QgZXF1YWwgdGhlIGRldGVjdG9ycyB0aGUgdGVsZW1ldHJ5IGJyaWRnZSBhbmQgY29sbGVjdGlvbiBob29rcyBhcmUgY29tcGlsZS13aXJlZCBpbnRvLCBhbmQgdGhlIGNhdGFsb2cmIzM5O3MgZmVlZCBsaXN0aW5nIG11c3QgbmFtZSB0aGUgc2FtZSBjbGFzc2VzIHRoaXMgdGFibGUgY2xhc3NpZmllcy4gQSBmZWVkIHRoYXQgZHJpZnRzIG1pc2xlYWRzIHRoZSB1c2VyIGRlY2lkaW5nIHdoZXRoZXIgYXR0YWNoaW5nIHRoZSBhZ2VudCBidXlzIHRoZW0gYW55dGhpbmcuPC9yZWFzb24+CiAgICAgIDxlbmZvcmNlZC1ieT5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFyY2hpdGVjdHVyZS5EZXRlY3RvckZlZWRDb3ZlcmFnZVRlc3Q8L2VuZm9yY2VkLWJ5PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvclRydXN0Ij4KICAgICAgPG1pcnJvcj5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZTwvbWlycm9yPgogICAgICA8bWlycm9yPnNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JSZWdpc3RyeTwvbWlycm9yPgogICAgICA8bWlycm9yPmRvY3MvREVURUNUT1JfQ0FUQUxPRy5tZDwvbWlycm9yPgogICAgICA8cmVhc29uPkV2ZXJ5IERldGVjdG9yVHlwZSBuZWVkcyBleGFjdGx5IG9uZSByb3csIGFuZCBlYWNoIHJvdyBuYW1lcyB0aGUgZGV0ZWN0b3IgY2xhc3Mgd2hvc2Ugc2ltcGxlIG5hbWUga2V5cyB0aGUgcmVwb3J0IG1hcCAoRGV0ZWN0b3JSZWdpc3RyeS5pZklzc3VlKS4gQSByb3cgbmFtaW5nIGEgY2xhc3MgdGhlIHJlZ2lzdHJ5JiMzOTtzIGZhY3Rvcnkgcm93IGRvZXMgbm90IGNyZWF0ZSBzaWxlbnRseSBzdG9wcyByZXNvbHZpbmcsIGFuZCB0aGUgZmluZGluZyBsb3NlcyBpdHMgdGllciB3aXRob3V0IGFueXRoaW5nIGdvaW5nIHJlZC48L3JlYXNvbj4KICAgICAgPGVuZm9yY2VkLWJ5PnNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yVHJ1c3RDb3ZlcmFnZVRlc3Q8L2VuZm9yY2VkLWJ5PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC50ZWxlbWV0cnkuVGVsZW1ldHJ5QnJpZGdlIj4KICAgICAgPG1pcnJvcj5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yRmVlZHM8L21pcnJvcj4KICAgICAgPG1pcnJvcj5kb2NzL0RFVEVDVE9SX0NBVEFMT0cubWQ8L21pcnJvcj4KICAgICAgPHJlYXNvbj5EZXRlY3RvckZlZWRzLmZlZEJ5KEFHRU5UKSBtdXN0IGVxdWFsIHRoZSBkZXRlY3RvcnMgdGhlIHdvdmVuIHN0cmVhbXMgYWN0dWFsbHkgcmVhY2gsIGFuZCB0aGlzIGNsYXNzIGlzIG9uZSBvZiB0aG9zZSBzdHJlYW1zLiBUaGUgZ2F0ZSByZWZsZWN0cyBvdmVyIHRoaXMgY2xhc3MmIzM5O3MgZGVjbGFyZWQgY29uc3RydWN0b3JzIGFuZCBtZXRob2RzIGFuZCBhc3NlcnRzIHRoZSBkZXRlY3RvciB0eXBlcyBpdCBpcyBjb21waWxlLXdpcmVkIHRvIGFyZSBleGFjdGx5IHtBdG9taWNpdHlWYWxpZGF0b3J9LiBSb3V0aW5nIGEgc2Vjb25kIGRldGVjdG9yIGhlcmUgd2l0aG91dCBhZGRpbmcgaXRzIEFHRU5UIHJvdyBsZWF2ZXMgdGhlIGNhdGFsb2cgdGVsbGluZyB1c2VycyB0aGUgYWdlbnQgYnV5cyB0aGVtIG5vdGhpbmcgZm9yIHRoYXQgZGV0ZWN0b3IuPC9yZWFzb24+CiAgICAgIDxlbmZvcmNlZC1ieT5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFyY2hpdGVjdHVyZS5EZXRlY3RvckZlZWRDb3ZlcmFnZVRlc3Q8L2VuZm9yY2VkLWJ5PgogICAgPC9lbGVtZW50PgogIDwvbWlycm9yZWRfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBpbiA8bWlycm9yZWRfZWxlbWVudHM+IGFyZSBkdXBsaWNhdGVkIGF0IHRoZSBsaXN0ZWQgc2l0ZXMuIFRoZXkgbWF5IGNoYW5nZSBmcmVlbHksIGJ1dCBldmVyeSBtaXJyb3IgbXVzdCBjaGFuZ2UgaW4gdGhlIHNhbWUgY29tbWl0IOKAlCBhIHBhcnRpYWwgZWRpdCBkZXN5bmNzIHNpbGVudGx5IGFuZCBubyBjb21waWxlciB3aWxsIGNhdGNoIGl0LjwvcnVsZT4KPC9wcm9qZWN0X2d1YXJkcmFpbHM+Cgo8cnVsZT5OZXZlciBwcm9wb3NlIGVkaXRzIHRvIGZpbGVzIGxpc3RlZCBpbiA8bG9ja2VkX2ZpbGVzPi48L3J1bGU+Cg== -gemini_md=IyBHRU1JTkkgQUkgSU5TVFJVQ1RJT05TCiMgR2VuZXJhdGVkIGJ5IFZpYmVUYWdzIHwgaHR0cHM6Ly9naXRodWIuY29tL1BJc2JlcmcvdmliZXRhZ3MKCiMjIExPQ0tFRCBGSUxFUyAoRE8gTk9UIE1PRElGWSkKRG8gbm90IHN1Z2dlc3QgbW9kaWZpY2F0aW9ucyB0byB0aGUgZm9sbG93aW5nIGZpbGVzOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclR5cGVgOiBBZGRpbmcgb3IgcmVtb3ZpbmcgYSBjb25zdGFudCByZXF1aXJlcyBzeW5jaHJvbml6ZWQgY2hhbmdlcyBpbiB0aHJlZSBwbGFjZXM6ICgxKSB0aGUgQXN5bmNUZXN0Q29uZmlnIHB1YmxpYyBmbGFnIGFuZCBpdHMgZGVyaXZhdGlvbiBlbmFibGVkLmNvbnRhaW5zKFRZUEUpLCB3aXRoIHRoZSBCdWlsZGVyIHNldHRlciB0aGF0IGNhbGxzIGZsYWcoVFlQRSwgdiksICgyKSB0aGUgRGV0ZWN0b3JSZWdpc3RyeSBmaWVsZCBhbmQgaXRzIGZhY3Rvcnkgcm93IGNyZWF0ZShEZXRlY3RvclR5cGUuVFlQRSwgWDo6bmV3KSwgYW5kICgzKSB0aGUgcmVnaXN0cnkncyBpZklzc3VlIGFuYWx5c2lzIGNhbGwuIEFkZGluZyBhIHZhbHVlIGhlcmUgaW4gaXNvbGF0aW9uIGNvbXBpbGVzIGFuZCBkZXRlY3RzIG5vdGhpbmcuIFRoZSBAQXN5bmNUZXN0IGF0dHJpYnV0ZSBhbmQgdGhlIGJ1aWxkKCkgcmVzb2x1dGlvbiBsaW5lIGl0IG9uY2UgYWxzbyBuZWVkZWQgYXJlIGdvbmUgKCM5MTcsICM5MjApLiBUaGUgbG9jayBpcyBvbiB0aGUgY29uc3RhbnQgc2V0LCBub3QgdGhlIGZpbGU6IGVkaXRpbmcgamF2YWRvYyBvbiBleGlzdGluZyBjb25zdGFudHMgY2Fubm90IGJyZWFrIHRoYXQgaW52YXJpYW50IGFuZCBuZWVkcyBubyBjZXJlbW9ueS4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2UuVkVORE9SX1ZFUklGWV9LRVlfQjY0YDogRXZlcnkgb2ZmbGluZSBsaWNlbmNlIGZpbGUgYWxyZWFkeSBpc3N1ZWQgdG8gYSBjdXN0b21lciB2ZXJpZmllcyBhZ2FpbnN0IHRoaXMga2V5LCBhbmQgaXRzIHByaXZhdGUgaGFsZiBleGlzdHMgb25seSBvbiB0aGUgb3BlcmF0b3IgbWFjaGluZS4gQSBjaGFuZ2VkIHZhbHVlIGRlbmllcyBlYWNoIG9mIHRob3NlIGZpbGVzIHdpdGggT0ZGTElORV9GSUxFX1NJR05BVFVSRV9JTlZBTElEIG9uIHRoZSBjdXN0b21lcidzIG5leHQgYnVpbGQuIFJvdGF0aW9uIG1lYW5zIHJlLWlzc3VpbmcgZXZlcnkgZmlsZSBmaXJzdDogYSByZWxlYXNlIGRlY2lzaW9uLCBub3QgYSBjb2RlIGVkaXQuCgojIyBDT05USU5VT1VTIEFVRElUIFJFUVVJUkVNRU5UUwpZb3UgYXJlIGFjdGluZyBhcyBhIFNlbmlvciBTdGFmZiBFbmdpbmVlci4gV2hlbmV2ZXIgeW91IHdyaXRlIGNvZGUgZm9yIHRoZSBmaWxlcyBsaXN0ZWQgYmVsb3csIHlvdSBtdXN0IGVuc3VyZSB5b3VyIGNvbXBsZXRpb25zIGFuZCBjaGF0IHJlc3BvbnNlcyBzdHJpY3RseSBwcmV2ZW50IHRoZSBsaXN0ZWQgdnVsbmVyYWJpbGl0aWVzOgoKRmlsZTogYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dGAKQ3JpdGljYWwgVnVsbmVyYWJpbGl0aWVzIHRvIFByZXZlbnQ6Ci0gVGhyZWFkIFNhZmV0eSBpc3N1ZXMKCkZpbGU6IGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5Db25jdXJyZW5jeVJ1bm5lcmAKQ3JpdGljYWwgVnVsbmVyYWJpbGl0aWVzIHRvIFByZXZlbnQ6Ci0gVGhyZWFkIFNhZmV0eSBpc3N1ZXMKLSBSZXNvdXJjZSBMZWFrcwoKIyMgSUdOT1JFRCBFTEVNRU5UUwpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIG11c3QgYmUgY29tcGxldGVseSBleGNsdWRlZCBmcm9tIEFJIGNvbnRleHQgYW5kIGNvbXBsZXRpb25zOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Ob29wQXN5bmNUZXN0TGlzdGVuZXJgIC0gVHJpdmlhbCBuby1vcCBpbXBsZW1lbnRhdGlvbiBvZiBBc3luY1Rlc3RMaXN0ZW5lci4gQWxsIG1ldGhvZHMgYXJlIGludGVudGlvbmFsbHkgZW1wdHkg4oCUIG5vIGxvZ2ljIHRvIHJldmlldyBvciBjaGFuZ2UgaGVyZS4KCiMjIFBJSSAvIFBSSVZBQ1kgR1VBUkRSQUlMUwpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGhhbmRsZSBQZXJzb25hbGx5IElkZW50aWZpYWJsZSBJbmZvcm1hdGlvbiAoUElJKS4KTmV2ZXIgaW5jbHVkZSB0aGVpciBydW50aW1lIHZhbHVlcyBpbiBsb2dzLCBjb25zb2xlIG91dHB1dCwgZXh0ZXJuYWwgQVBJIGNhbGxzLAp0ZXN0IGZpeHR1cmVzLCBtb2NrIGRhdGEsIG9yIGNvZGUgc3VnZ2VzdGlvbnMuCgotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5MaWNlbnNlR3VhcmQuRmluZ2VycHJpbnRgOiBIb2xkcyB0aGUgbGljZW5jZSBrZXkgYW5kIHRoZSBsaWNlbnNlZCB1c2VyJ3MgZW1haWwsIGFuZCB0aGUgcmVjb3JkJ3MgZ2VuZXJhdGVkIHRvU3RyaW5nKCkgcHJpbnRzIGJvdGgsIHNvIG5ldmVyIGxvZyBvciBmb3JtYXQgYSBGaW5nZXJwcmludCB3aG9sZS4gVGhlIGVtYWlsIG1heSByZWFjaCB0aGUgbGljZW5jZSBwcm92aWRlciAoS2V5Z2VuIHVzZXIgc2NvcGUsIExlbW9uU3F1ZWV6eSBiaW5kaW5nKSBhbmQgYSBkZW5pYWwgbWVzc2FnZSBpbiB0aGF0IHVzZXIncyBvd24gYnVpbGQ7IGRpc2sgc2VlcyBlaXRoZXIgdmFsdWUgb25seSBpbnNpZGUgdGhlIFNIQS0yNTYgTGljZW5zZVZhbGlkYXRpb25DYWNoZSBzdG9yZXMuIE5ldmVyIHB1dCBvbmUgaW4gYW4gSU5GTyBsaW5lLCBhIHJlcG9ydCwgU0FSSUYgb3IgSlVuaXQgWE1MOiB0aG9zZSBlbmQgdXAgaW4gQ0kgbG9ncyBhbmQgcHVibGlzaGVkIGFydGlmYWN0cy4KCiMjIENPUkUgRlVOQ1RJT05BTElUWSAoRVhUUkVNRSBDQVVUSU9OKQpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbjoKCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnYDogU2Vuc2l0aXZpdHk6IENyaXRpY2FsLiBOb3RlOiBTZWxlY3Rpb24gaXMgb25lIEVudW1TZXQgcmVzb2x2ZWQgb25jZSBpbiBidWlsZCgpICgjOTE3KTsgZXZlcnkgcHVibGljIGRldGVjdG9yIGZsYWcgaXMgYXNzaWduZWQgZW5hYmxlZC5jb250YWlucyhUWVBFKSBpbiB0aGUgY29uc3RydWN0b3IgYW5kIG5vd2hlcmUgZWxzZSwgc28gYSBmbGFnIGNhbm5vdCBkaXNhZ3JlZSB3aXRoIGVuYWJsZWREZXRlY3RvcnMoKS4gQSBuZXcgZGV0ZWN0b3IgaGVyZSBpcyB0aGUgZmxhZyBhbmQgaXRzIGRlcml2YXRpb24gYW5kIHRoZSBCdWlsZGVyIHNldHRlciB0aGF0IGNhbGxzIGZsYWcoVFlQRSwgdik7IEBBc3luY1Rlc3QgaGFzIG5vIHBlci1kZXRlY3RvciBhdHRyaWJ1dGUgdG8gcmVhZCBzaW5jZSAxLjEzLjAgKCM5MjApLiBOZXZlciByZWludHJvZHVjZSBhIHBlci1kZXRlY3RvciByZXNvbHV0aW9uIGV4cHJlc3Npb24gaW4gYnVpbGQoKS4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0YDogU2Vuc2l0aXZpdHk6IENyaXRpY2FsLiBOb3RlOiBUaHJlYWRMb2NhbCBpbnN0YWxsL3VuaW5zdGFsbCBtdXN0IGFsd2F5cyBiZSBzeW1tZXRyaWMuIEEgbGVhayBwcm9wYWdhdGVzIHN0YWxlIGRldGVjdG9yIHN0YXRlIGFjcm9zcyB0ZXN0IGludm9jYXRpb25zIGFuZCBjYXVzZXMgZmFsc2UgcG9zaXRpdmVzIG9yIG1pc3NlZCBkZXRlY3Rpb25zLgotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RJbnZvY2F0aW9uSW50ZXJjZXB0b3JgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IGludm9jYXRpb24uc2tpcCgpIGlzIGludGVudGlvbmFsIOKAlCBDb25jdXJyZW5jeVJ1bm5lciBvd25zIHRoZSBmdWxsIE7Dl00gZXhlY3V0aW9uIGFuZCBtdXN0IG5ldmVyIGNhbGwgaW52b2NhdGlvbi5wcm9jZWVkKCkuIFJlc3RvcmluZyBwcm9jZWVkKCkgd291bGQgcnVuIHRoZSB0ZXN0IGJvZHkgb25jZSBvdXRzaWRlIHRoZSBDeWNsaWNCYXJyaWVyLCBieXBhc3NpbmcgYWxsIGRldGVjdG9ycy4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXJgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IENvcmUgc3RyZXNzLXRlc3QgZXhlY3V0aW9uIGVuZ2luZS4gVGhlIEN5Y2xpY0JhcnJpZXIgcGF0dGVybiBmb3JjZXMgbWF4aW11bSB0aHJlYWQgY29udGVudGlvbi4gVGltZW91dCBsb2dpYyBhbmQgQXN5bmNUZXN0Q29udGV4dCBpbnN0YWxsL3VuaW5zdGFsbCBhcmUgY2FyZWZ1bGx5IGNhbGlicmF0ZWQg4oCUIHN1YnRsZSBjaGFuZ2VzIGludHJvZHVjZSBmbGFreSB0ZXN0cyBvciBtaXNzZWQgZGV0ZWN0b3IgYWN0aXZhdGlvbnMuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LkNvbnRyb2xsZWRTY2hlZHVsZWA6IFNlbnNpdGl2aXR5OiBIaWdoLiBOb3RlOiBBIHNlZWQgcmVwbGF5cyBhIHJvdW5kIG9ubHkgd2hpbGUgZXZlcnkgZGVjaXNpb24gb2Ygd2hvIHJ1bnMgbmV4dCBkZXBlbmRzIG9uIHN0YXRlIGNoYW5nZWQgYXQgc2NoZWR1bGluZyBwb2ludHM6IHRoZSBzdGF0dXNlcywgcHJpb3JpdGllcyBhbmQgc3RlcCBjb3VudCB0aGF0IGdyYW50KCkgYW5kIHN0ZXAoKSByZWFkLCBhbmQgdGhlIGxvY2sgaG9sZHMgYW5kIHBlbmRpbmcgYWNxdWlzaXRpb25zIGdyYW50KCkgY29uc3VsdHMgKCMxMDIyKSwgd2hpY2ggY2hhbmdlIG9ubHkgYXQgYWNxdWlyaW5nKCksIGl0c2VsZiBhIHBvaW50LCBhbmQgaW4gYWNxdWlyZWQoKSBhbmQgcmVsZWFzZWQoKSwgd2hpY2ggYSB3b3JrZXIgY2FsbHMgaW4gaXRzIG93biBwcm9ncmFtIG9yZGVyOyBhbiBlc2NhcGVkIHdvcmtlcidzIGFjcXVpcmUgb3IgcmVsZWFzZSBsYW5kcyBvdXRzaWRlIGEgdHVybiwgYnV0IGl0cyByb3VuZCBoYXMgYWxyZWFkeSBjb3VudGVkIHRoZSBlc2NhcGUuIGdyYW50KCkgbXVzdCBrZWVwIGhhbmRpbmcgdGhlIHJvdW5kIG91dCB3aGVuIGV2ZXJ5IHJlYWR5IHdvcmtlciB3YWl0cyBvbiBhIGhlbGQgbG9jazogdGhlIGhvbGQgbWF5IGJlIHN0YWxlIChhIG1vbml0b3IgcmVsZWFzZWQgaW5zaWRlIE9iamVjdC53YWl0IGlzIG5vdCBzZWVuKSwgYW5kIHdpdGhob2xkaW5nIHRoZSByb3VuZCB0aGVuIHN0YWxscyBjb3JyZWN0IHdhaXQvbm90aWZ5IGNvZGUgdW50aWwgdGhlIHJvdW5kIHRpbWVzIG91dCAoQ29udHJvbGxlZFNjaGVkdWxlTG9ja1Rlc3QpOyBlYWNoIHN1Y2ggZ3JhbnQgaXMgY291bnRlZCBhcyBhIGZhbGxiYWNrLiBUbyBrZWVwIGhvbGRzIGZyb20gZ29pbmcgc3RhbGUsIGEgd292ZW4gT2JqZWN0LndhaXQgb3IgQ29uZGl0aW9uLmF3YWl0IGhhbmRzIGl0cyBob2xkcyBiYWNrIGJlZm9yZSB3YWl0aW5nIGFuZCB0YWtlcyB0aGVtIGFnYWluIGFmdGVyIChyZWxlYXNpbmdGb3JXYWl0LCByZWFjcXVpcmVkQWZ0ZXJXYWl0OyBsb2NrT2YgZmluZHMgYSBjb25kaXRpb24ncyBSZWVudHJhbnRMb2NrIGJ5IGFza2luZyBpdCksIGFuZCBhIHdvcmtlciByZS1jb25maXJtcyBpdHMgb3duIHJlY29yZGVkIGhvbGRzIHdpdGggVGhyZWFkLmhvbGRzTG9jayBvciBpc0hlbGRCeUN1cnJlbnRUaHJlYWQgYXQgZWFjaCBvZiBpdHMgcG9pbnRzIGFuZCBhdCBsZWF2ZSgpLCBvbiBpdHMgb3duIHRocmVhZCwgc28gdGhlIGFuc3dlciBmb2xsb3dzIGl0cyBwcm9ncmFtIG9yZGVyIGFuZCBncmFudCgpIHN0aWxsIHJlYWRzIG5vIHRocmVhZCBzdGF0ZSAoIzEwNDgpLiBPbmx5IHdhdGNoKCkgbWF5IHJlYWQgdGhlIGNsb2NrIG9yIFRocmVhZC5nZXRTdGF0ZSgpLCBhbmQgaXQgcmVhZHMgdGhlIHN0YXRlIGJlZm9yZSBhc2tpbmcgd2hldGhlciB0aGUgcnVubmluZyB3b3JrZXIsIG9yIGFuIGFkb3B0ZWQgY2hpbGQgc3RpbGwgYXJyaXZpbmcsIGlzIHF1ZXVlZCBvbiB0aGUgc2NoZWR1bGUncyBvd24gbG9jaywgd2hpY2ggaXMgdGhlIHNjaGVkdWxlcidzIHdhaXQgYW5kIG5ldmVyIGFuIGVzY2FwZSAoIzEwNjUsICMxMDcyKTsgZWFjaCBkZWNpc2lvbiBpdCBtYWtlcyBpcyBjb3VudGVkIGFzIGFuIGVzY2FwZSwgd2hpY2ggaXMgd2hhdCB0ZWxscyB0aGUgcnVubmVyIHRoZSBzZWVkIG5vIGxvbmdlciByZXBsYXlzIGV4YWN0bHksIHdpdGggb25lIGV4Y2VwdGlvbjogYW4gYWRvcHRlZCBjaGlsZCB3aG9zZSB0aHJlYWQgaGFzIHRlcm1pbmF0ZWQgaXMgbWFya2VkIGRvbmUsIG5vdCBlc2NhcGVkICgjMTAyNCksIGJlY2F1c2Ugd2hpbGUgaXQgcmFuIHRvIGl0cyBlbmQgZXZlcnkgcGVlciB3YXMgd2FpdGluZywgc28gdGhlIHN0YXRlIHRoZSBuZXh0IGdyYW50IHJlYWRzIGlzIHRoZSBzYW1lIHdoZW5ldmVyIHdhdGNoKCkgbm90aWNlcy4gQWRvcHRlZCBjaGlsZHJlbiBhcmUgcmVhZHkgZnJvbSB0aGUgbW9tZW50IHRoZXkgYXJlIGFkb3B0ZWQsIHNvIGEgZ3JhbnQgbmV2ZXIgZGVwZW5kcyBvbiBob3cgbG9uZyB0aGUgT1MgdGFrZXMgdG8gc3RhcnQgYSB0aHJlYWQ7IGFuIGFkb3B0ZWQgZXhlY3V0b3IgdGFzayAoIzEwNDkpIGlzIHJlYWR5IGZyb20gaXRzIHdvdmVuIHN1Ym1pc3Npb24gdGhlIHNhbWUgd2F5LCBqb2lucyBhdCB0YXNrU3RhcnRpbmcgb24gdGhlIHBvb2wgdGhyZWFkIGFuZCBsZWF2ZXMgYXQgdGFza0VuZGVkLCBhbmQgb25lIHRoYXQgaGFzIG5vdCBzdGFydGVkIHdpdGhpbiBTVEFMTF9OQU5PUyBpcyBjb3VudGVkIGFzIGFuIGVzY2FwZSwgc2luY2UgaXRzIGV4ZWN1dG9yIG1heSBuZXZlciBydW4gaXQuIEEgd29ya2VyIHdhaXRpbmcgYXQgYSByZW5kZXp2b3VzIGlzIE9VVFNJREUsIG5vdCBlc2NhcGVkICgjMTAyMSksIGFuZCBubyBncmFudCBpcyBtYWRlIHdoaWxlIG9uZSBpcyBvdXRzaWRlIG9uIGl0cyB3YXkgYmFjayBvciB3aGVuIHRoZSBsYXN0IHdvcmtlciBzdGVwcyBvdXQsIHNvIHRoZSBvcmRlciBhIHJlbmRlenZvdXMgcmVsZWFzZXMgd29ya2VycyBpbiBuZXZlciBkZWNpZGVzIHdobyBydW5zIG5leHQuIEEgZ3JhbnQoKSB0aGF0IHJlYWQgdGltZSBvciB0aHJlYWQgc3RhdGUsIG9yIGFuIGVzY2FwZSBsZWZ0IHVuY291bnRlZCwgc3RpbGwgcGFzc2VzIGV2ZXJ5IHJ1biBhbmQgbWFrZXMgdGhlIHByaW50ZWQgcmVwbGF5IGxpbmUgYSBmYWxzZSBwcm9taXNlLgoKIyMgU0VDVVJJVFktQ1JJVElDQUwgQ09ERQpEbyBub3Qgd2Vha2VuIHNlY3VyaXR5IHByb3BlcnRpZXMgb2YgdGhlc2UgZWxlbWVudHMuIEZsYWcgYW55IGNoYW5nZSBmb3Igc2VjdXJpdHkgcmV2aWV3OgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3JgOiBTZWN1cml0eS1jcml0aWNhbCBjb2RlIFtjcnlwdG9ncmFwaHkgKGhhc2ggaW50ZWdyaXR5IC8gTUFDIC8gc2lnbmF0dXJlIHN0YXRlKV0uIERvIG5vdCB3ZWFrZW4gc2VjdXJpdHkgcHJvcGVydGllcy4gRmxhZyBhbnkgY2hhbmdlIGZvciBzZWN1cml0eSByZXZpZXcuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3JgOiBTZWN1cml0eS1jcml0aWNhbCBjb2RlIFtjcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KV0uIERvIG5vdCB3ZWFrZW4gc2VjdXJpdHkgcHJvcGVydGllcy4gRmxhZyBhbnkgY2hhbmdlIGZvciBzZWN1cml0eSByZXZpZXcuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvcmA6IFNlY3VyaXR5LWNyaXRpY2FsIGNvZGUgW2NyeXB0b2dyYXBoeSAoY29uZmlkZW50aWFsaXR5IC8gaW50ZWdyaXR5IC8gYXV0aGVudGljaXR5IHN0YXRlKV0uIERvIG5vdCB3ZWFrZW4gc2VjdXJpdHkgcHJvcGVydGllcy4gRmxhZyBhbnkgY2hhbmdlIGZvciBzZWN1cml0eSByZXZpZXcuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VHdWFyZGA6IFNlY3VyaXR5LWNyaXRpY2FsIGNvZGUgW2F1dGhvcml6YXRpb25dLiBEbyBub3Qgd2Vha2VuIHNlY3VyaXR5IHByb3BlcnRpZXMuIEZsYWcgYW55IGNoYW5nZSBmb3Igc2VjdXJpdHkgcmV2aWV3LgotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5MaWNlbnNlVmFsaWRhdGlvbkNhY2hlYDogU2VjdXJpdHktY3JpdGljYWwgY29kZSBbYXV0aG9yaXphdGlvbiAoaXNGcmVzaCBza2lwcyBvbmxpbmUgdmFsaWRhdGlvbjsgaGFzUmVjb3JkIGFkbWl0cyBvdXRhZ2UgZ3JhY2UpXS4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBGbGFnIGFueSBjaGFuZ2UgZm9yIHNlY3VyaXR5IHJldmlldy4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2VgOiBTZWN1cml0eS1jcml0aWNhbCBjb2RlIFthdXRob3JpemF0aW9uXS4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBGbGFnIGFueSBjaGFuZ2UgZm9yIHNlY3VyaXR5IHJldmlldy4KCiMjIFNjb3BlZCBSdWxlcyBJbmRleApEZXRhaWxlZCBwZXItZWxlbWVudCBndWFyZHJhaWxzIGxpdmUgaW4gc2NvcGVkIHJ1bGUgZmlsZXMgdGhhdCBHZW1pbmkgQ0xJIGRvZXMgbm90IGxvYWQgb24gaXRzIG93bi4gQSBsaW5lIGBhLmJgOiBgQ2AsIGBEYCBuYW1lcyBhLmIuQyBhbmQgYS5iLkQuIFVubGVzcyBhbiBlbnRyeSBjYXJyaWVzIGFuIGV4cGxpY2l0IHBhdGgsIGl0cyBmaWxlIGlzIC5nZW1pbmkvcnVsZXMve3BhdGgsIGV2ZXJ5IG5vbi1hbHBoYW51bWVyaWMgY2hhcmFjdGVyIHJlcGxhY2VkIGJ5ICctJ30ubWQuIEJlZm9yZSBtb2RpZnlpbmcgYW4gZWxlbWVudCBsaXN0ZWQgYmVsb3csIG9wZW4gaXRzIGZpbGUgd2l0aCByZWFkX2ZpbGUgYW5kIGFwcGx5IHRoZSBndWFyZHJhaWxzIHRoZXJlOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdGA6IGBBZ2VudENvbGxlY3Rpb25Ib29rc2AsIGBBZ2VudENvbmN1cnJlbmN5VXRpbEhvb2tzYCwgYEFnZW50Q29uc3RydWN0aW9uSG9va3NgLCBgQWdlbnRHY0hvb2tzYCwgYEFnZW50TG9ja0hvb2tzYCwgYEFnZW50TW9uaXRvckhvb2tzYCwgYEFnZW50U2hhcmVkSW5zdGFuY2VIb29rc2AsIGBBZ2VudFNsZWVwSG9va3NgLCBgQWdlbnRUaHJlYWRIb29rc2AsIGBSdW5PdXRjb21lc2AKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdGA6IGBBc3luY0Fzc2VydGAsIGBBc3luY0ZpbmRpbmdzYCwgYEFzeW5jVGVzdExpc3RlbmVyYCwgYEFzeW5jVGVzdExpc3RlbmVyUmVnaXN0cnlgLCBgQXN5bmNUZXN0UnVubmVyYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1wdWJsaWMtYXBpLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0YDogYEFzeW5jVGVzdGAsIGBBc3luY1Rlc3RDb25maWdgLCBgRGV0ZWN0b3JSZWdpc3RyeWAsIGBEZXRlY3RvclR5cGVgLCBgUHJlc2V0YCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1jb25maWd1cmF0aW9uLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHRgIOKGkiBgLmdlbWluaS9ydWxlcy9hc3luYy10ZXN0LXJ1bnRpbWUtY29yZS5tZGAKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RMaXN0ZW5lclJlZ2lzdHJ5LlJlZ2lzdHJhdGlvbmAg4oaSIGAuZ2VtaW5pL3J1bGVzL2FzeW5jLXRlc3QtcHVibGljLWFwaS5tZGAKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmtgOiBgQmVuY2htYXJrQ29tcGFyYXRvcmAsIGBCZW5jaG1hcmtSZWNvcmRlcmAg4oaSIGAuZ2VtaW5pL3J1bGVzL2FzeW5jLXRlc3QtaW5zdHJ1bWVudGF0aW9uLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzYDogYEJsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yYCwgYENvbXBsZXRhYmxlRnV0dXJlQmxvY2tpbmdDYWxsYmFja0RldGVjdG9yYCwgYENvbXBsZXRhYmxlRnV0dXJlQ2FuY2VsbGF0aW9uUHJvcGFnYXRpb25EZXRlY3RvcmAsIGBDb21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvcmAsIGBDb21wbGV0YWJsZUZ1dHVyZUNvbXBsZXRpb25SYWNlRGV0ZWN0b3JgLCBgQ29tcGxldGFibGVGdXR1cmVPYnRydWRlRGV0ZWN0b3JgLCBgQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yYCwgYERhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvcmAsIGBEZXRlY3RvckRlZmF1bHRTZXZlcml0eWAsIGBEZXRlY3RvckZlZWRzYCwgYERldGVjdG9yVHJ1c3RgLCBgRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvcmAsIGBGaW5hbEZpZWxkTXV0YXRpb25EZXRlY3RvcmAsIGBGbG93UHVibGlzaGVyQ29uY3VycmVuY3lEZXRlY3RvcmAsIGBHcmFkZWRGaW5kaW5nc2AsIGBIaWdoQ29udGVudGlvbkF0b21pY0RldGVjdG9yYCwgYEpkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3JgLCBgTGFtYmRhTG9zdFVwZGF0ZURldGVjdG9yYCwgYExhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3JgLCBgTGF6eUNvbnN0YW50TWlzdXNlRGV0ZWN0b3JgLCBgTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yYCwgYE5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvcmAsIGBOb3RpZnlXaXRob3V0TW9uaXRvckRldGVjdG9yYCwgYFBsYXRmb3JtVGhyZWFkUGVyVGFza0RldGVjdG9yYCwgYFByb2Nlc3NTdHJlYW1TdGFydmF0aW9uRGV0ZWN0b3JgLCBgUmVjb3JkTXV0YWJsZUNvbXBvbmVudExlYWtEZXRlY3RvcmAsIGBTY29wZUNvbmZpZ3VyYXRpb25NaXN1c2VEZXRlY3RvcmAsIGBTY29wZUpvaW5lck1pc3VzZURldGVjdG9yYCwgYFNjb3BlUmVzdWx0RXNjYXBlRGV0ZWN0b3JgLCBgU2hhcmVkQnl0ZUJ1ZmZlckRldGVjdG9yYCwgYFNoYXJlZENoYXJzZXRDb2RlckRldGVjdG9yYCwgYFNoYXJlZENoZWNrc3VtRGV0ZWN0b3JgLCBgU2hhcmVkRGVmbGF0ZXJEZXRlY3RvcmAsIGBTaGFyZWRJdGVyYXRvckRldGVjdG9yYCwgYFNoYXJlZEpzb25NYXBwZXJSZWNvbmZpZ0RldGVjdG9yYCwgYFNoYXJlZEtkZkRldGVjdG9yYCwgYFNoYXJlZE1lbW9yeVNlZ21lbnRSYWNlRGV0ZWN0b3JgLCBgU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yYCwgYFNoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yYCwgYFNoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvcmAsIGBTaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yYCwgYFNpdGVDYXB0dXJlYCwgYFNwdXJpb3VzV2FrZXVwRGV0ZWN0b3JgLCBgU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3JgLCBgVGhpc0VzY2FwZURldGVjdG9yYCwgYFRocmVhZExvY2FsQ2FjaGVEZWdyYWRhdGlvbkRldGVjdG9yYCwgYFRocmVhZExvY2FsUmFuZG9tTWlzdXNlRGV0ZWN0b3JgLCBgVHJ1c3RUaWVyYCwgYFRyeUxvY2tNaXN1c2VEZXRlY3RvcmAsIGBWYXJIYW5kbGVOb25BdG9taWNVcGRhdGVEZXRlY3RvcmAsIGBWaXJ0dWFsVGhyZWFkTW9uaXRvclNlcmlhbGl6YXRpb25EZXRlY3RvcmAsIGBWaXJ0dWFsVGhyZWFkUG9vbGluZ0RldGVjdG9yYCwgYFZpcnR1YWxUaHJlYWRSZXNvdXJjZVNhdHVyYXRpb25EZXRlY3RvcmAsIGBXZWFrSGFzaE1hcFNoYXJlZERldGVjdG9yYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1kZXRlY3RvcnMubWRgCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2l0ZUNhcHR1cmUuU2l0ZWAg4oaSIGAuZ2VtaW5pL3J1bGVzL2FzeW5jLXRlc3QtZGV0ZWN0b3JzLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbmA6IGBBc3luY1Rlc3RFeHRlbnNpb25gLCBgQXN5bmNUZXN0SW52b2NhdGlvbkludGVyY2VwdG9yYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1ydW50aW1lLWNvcmUubWRgCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0YDogYEZvcm1hdHRlcmAsIGBKVW5pdFhtbFJlcG9ydExpc3RlbmVyYCwgYEpzb25Gb3JtYXR0ZXJgLCBgSnNvblJlcG9ydExpc3RlbmVyYCwgYE1hcmtkb3duRm9ybWF0dGVyYCwgYFNhcmlmRm9ybWF0dGVyYCwgYFZpb2xhdGlvbmAg4oaSIGAuZ2VtaW5pL3J1bGVzL2FzeW5jLXRlc3QtcHVibGljLWFwaS5tZGAKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXJgOiBgQWdlbnRBdXRvQXR0YWNoYCwgYENvbmN1cnJlbmN5UnVubmVyYCwgYExpY2Vuc2VHdWFyZGAsIGBMaWNlbnNlVmFsaWRhdGlvbkNhY2hlYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1ydW50aW1lLWNvcmUubWRgCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3Quc3BpYDogYERldGVjdG9yYCwgYERldGVjdG9yRmFjdG9yeWAsIGBEZXRlY3RvclJlZ2lzdHJ5YCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1wdWJsaWMtYXBpLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnRlbGVtZXRyeS5UZWxlbWV0cnlCcmlkZ2VgIOKGkiBgLmdlbWluaS9ydWxlcy9hc3luYy10ZXN0LWluc3RydW1lbnRhdGlvbi5tZGAK -~mod~claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxsb2NrZWRfZmlsZXM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSI+CiAgICAgIDxyZWFzb24+QWRkaW5nIG9yIHJlbW92aW5nIGEgY29uc3RhbnQgcmVxdWlyZXMgc3luY2hyb25pemVkIGNoYW5nZXMgaW4gdGhyZWUgcGxhY2VzOiAoMSkgdGhlIEFzeW5jVGVzdENvbmZpZyBwdWJsaWMgZmxhZyBhbmQgaXRzIGRlcml2YXRpb24gZW5hYmxlZC5jb250YWlucyhUWVBFKSwgd2l0aCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpLCAoMikgdGhlIERldGVjdG9yUmVnaXN0cnkgZmllbGQgYW5kIGl0cyBmYWN0b3J5IHJvdyBjcmVhdGUoRGV0ZWN0b3JUeXBlLlRZUEUsIFg6Om5ldyksIGFuZCAoMykgdGhlIHJlZ2lzdHJ5JiMzOTtzIGlmSXNzdWUgYW5hbHlzaXMgY2FsbC4gQWRkaW5nIGEgdmFsdWUgaGVyZSBpbiBpc29sYXRpb24gY29tcGlsZXMgYW5kIGRldGVjdHMgbm90aGluZy4gVGhlIEBBc3luY1Rlc3QgYXR0cmlidXRlIGFuZCB0aGUgYnVpbGQoKSByZXNvbHV0aW9uIGxpbmUgaXQgb25jZSBhbHNvIG5lZWRlZCBhcmUgZ29uZSAoIzkxNywgIzkyMCkuIFRoZSBsb2NrIGlzIG9uIHRoZSBjb25zdGFudCBzZXQsIG5vdCB0aGUgZmlsZTogZWRpdGluZyBqYXZhZG9jIG9uIGV4aXN0aW5nIGNvbnN0YW50cyBjYW5ub3QgYnJlYWsgdGhhdCBpbnZhcmlhbnQgYW5kIG5lZWRzIG5vIGNlcmVtb255LjwvcmVhc29uPgogICAgPC9maWxlPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2UuVkVORE9SX1ZFUklGWV9LRVlfQjY0Ij4KICAgICAgPHJlYXNvbj5FdmVyeSBvZmZsaW5lIGxpY2VuY2UgZmlsZSBhbHJlYWR5IGlzc3VlZCB0byBhIGN1c3RvbWVyIHZlcmlmaWVzIGFnYWluc3QgdGhpcyBrZXksIGFuZCBpdHMgcHJpdmF0ZSBoYWxmIGV4aXN0cyBvbmx5IG9uIHRoZSBvcGVyYXRvciBtYWNoaW5lLiBBIGNoYW5nZWQgdmFsdWUgZGVuaWVzIGVhY2ggb2YgdGhvc2UgZmlsZXMgd2l0aCBPRkZMSU5FX0ZJTEVfU0lHTkFUVVJFX0lOVkFMSUQgb24gdGhlIGN1c3RvbWVyJiMzOTtzIG5leHQgYnVpbGQuIFJvdGF0aW9uIG1lYW5zIHJlLWlzc3VpbmcgZXZlcnkgZmlsZSBmaXJzdDogYSByZWxlYXNlIGRlY2lzaW9uLCBub3QgYSBjb2RlIGVkaXQuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9sb2NrZWRfZmlsZXM+CgogIDxhdWRpdF9yZXF1aXJlbWVudHM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQiPgogICAgICA8dnVsbmVyYWJpbGl0eV9jaGVjaz5UaHJlYWQgU2FmZXR5IGlzc3VlczwvdnVsbmVyYWJpbGl0eV9jaGVjaz4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkNvbmN1cnJlbmN5UnVubmVyIj4KICAgICAgPHZ1bG5lcmFiaWxpdHlfY2hlY2s+VGhyZWFkIFNhZmV0eSBpc3N1ZXM8L3Z1bG5lcmFiaWxpdHlfY2hlY2s+CiAgICAgIDx2dWxuZXJhYmlsaXR5X2NoZWNrPlJlc291cmNlIExlYWtzPC92dWxuZXJhYmlsaXR5X2NoZWNrPgogICAgPC9maWxlPgogIDwvYXVkaXRfcmVxdWlyZW1lbnRzPgoKPHJ1bGU+CiAgSWYgeW91IGFyZSBhc2tlZCB0byBtb2RpZnkgYW55IGZpbGUgbGlzdGVkIGluIDxhdWRpdF9yZXF1aXJlbWVudHM+LCB5b3UgbXVzdCBmaXJzdCBzaWxlbnRseSBhbmFseXplIHlvdXIgcHJvcG9zZWQgY29kZSBmb3IgdGhlIGxpc3RlZCA8dnVsbmVyYWJpbGl0eV9jaGVjaz4gaXRlbXMuIElmIHlvdXIgY29kZSBpbnRyb2R1Y2VzIHRoZXNlIHZ1bG5lcmFiaWxpdGllcywgeW91IG11c3QgcmV3cml0ZSBpdCBiZWZvcmUgZGlzcGxheWluZyBpdCB0byB0aGUgdXNlci4KPC9ydWxlPgogIDxpZ25vcmVkX2VsZW1lbnRzPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Ob29wQXN5bmNUZXN0TGlzdGVuZXIiPgogICAgICA8cmVhc29uPlRyaXZpYWwgbm8tb3AgaW1wbGVtZW50YXRpb24gb2YgQXN5bmNUZXN0TGlzdGVuZXIuIEFsbCBtZXRob2RzIGFyZSBpbnRlbnRpb25hbGx5IGVtcHR5IOKAlCBubyBsb2dpYyB0byByZXZpZXcgb3IgY2hhbmdlIGhlcmUuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9pZ25vcmVkX2VsZW1lbnRzPgoKPHJ1bGU+TmV2ZXIgcmVmZXJlbmNlIG9yIHN1Z2dlc3QgY2hhbmdlcyB0byBhbnkgZWxlbWVudCBsaXN0ZWQgaW4gPGlnbm9yZWRfZWxlbWVudHM+LiBUcmVhdCB0aGVzZSBhcyBpZiB0aGV5IGRvIG5vdCBleGlzdC48L3J1bGU+CiAgPHBpaV9ndWFyZHJhaWxzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZUd1YXJkLkZpbmdlcnByaW50Ij4KICAgICAgPHJlYXNvbj5Ib2xkcyB0aGUgbGljZW5jZSBrZXkgYW5kIHRoZSBsaWNlbnNlZCB1c2VyJiMzOTtzIGVtYWlsLCBhbmQgdGhlIHJlY29yZCYjMzk7cyBnZW5lcmF0ZWQgdG9TdHJpbmcoKSBwcmludHMgYm90aCwgc28gbmV2ZXIgbG9nIG9yIGZvcm1hdCBhIEZpbmdlcnByaW50IHdob2xlLiBUaGUgZW1haWwgbWF5IHJlYWNoIHRoZSBsaWNlbmNlIHByb3ZpZGVyIChLZXlnZW4gdXNlciBzY29wZSwgTGVtb25TcXVlZXp5IGJpbmRpbmcpIGFuZCBhIGRlbmlhbCBtZXNzYWdlIGluIHRoYXQgdXNlciYjMzk7cyBvd24gYnVpbGQ7IGRpc2sgc2VlcyBlaXRoZXIgdmFsdWUgb25seSBpbnNpZGUgdGhlIFNIQS0yNTYgTGljZW5zZVZhbGlkYXRpb25DYWNoZSBzdG9yZXMuIE5ldmVyIHB1dCBvbmUgaW4gYW4gSU5GTyBsaW5lLCBhIHJlcG9ydCwgU0FSSUYgb3IgSlVuaXQgWE1MOiB0aG9zZSBlbmQgdXAgaW4gQ0kgbG9ncyBhbmQgcHVibGlzaGVkIGFydGlmYWN0cy48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICA8L3BpaV9ndWFyZHJhaWxzPgoKPHJ1bGU+CiAgTmV2ZXIgaW5jbHVkZSBydW50aW1lIHZhbHVlcyBvZiBlbGVtZW50cyBsaXN0ZWQgaW4gPHBpaV9ndWFyZHJhaWxzPiBpbiBsb2dzLCBjb25zb2xlIG91dHB1dCwgZXh0ZXJuYWwgQVBJIGNhbGxzLCB0ZXN0IGZpeHR1cmVzLCBtb2NrIGRhdGEsIG9yIGNvZGUgc3VnZ2VzdGlvbnMuIFRyZWF0IHRoZWlyIHZhbHVlcyBhcyBzdHJpY3RseSBjb25maWRlbnRpYWwuCjwvcnVsZT4KICA8Y29yZV9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnIj4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+U2VsZWN0aW9uIGlzIG9uZSBFbnVtU2V0IHJlc29sdmVkIG9uY2UgaW4gYnVpbGQoKSAoIzkxNyk7IGV2ZXJ5IHB1YmxpYyBkZXRlY3RvciBmbGFnIGlzIGFzc2lnbmVkIGVuYWJsZWQuY29udGFpbnMoVFlQRSkgaW4gdGhlIGNvbnN0cnVjdG9yIGFuZCBub3doZXJlIGVsc2UsIHNvIGEgZmxhZyBjYW5ub3QgZGlzYWdyZWUgd2l0aCBlbmFibGVkRGV0ZWN0b3JzKCkuIEEgbmV3IGRldGVjdG9yIGhlcmUgaXMgdGhlIGZsYWcgYW5kIGl0cyBkZXJpdmF0aW9uIGFuZCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpOyBAQXN5bmNUZXN0IGhhcyBubyBwZXItZGV0ZWN0b3IgYXR0cmlidXRlIHRvIHJlYWQgc2luY2UgMS4xMy4wICgjOTIwKS4gTmV2ZXIgcmVpbnRyb2R1Y2UgYSBwZXItZGV0ZWN0b3IgcmVzb2x1dGlvbiBleHByZXNzaW9uIGluIGJ1aWxkKCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0Ij4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+VGhyZWFkTG9jYWwgaW5zdGFsbC91bmluc3RhbGwgbXVzdCBhbHdheXMgYmUgc3ltbWV0cmljLiBBIGxlYWsgcHJvcGFnYXRlcyBzdGFsZSBkZXRlY3RvciBzdGF0ZSBhY3Jvc3MgdGVzdCBpbnZvY2F0aW9ucyBhbmQgY2F1c2VzIGZhbHNlIHBvc2l0aXZlcyBvciBtaXNzZWQgZGV0ZWN0aW9ucy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RJbnZvY2F0aW9uSW50ZXJjZXB0b3IiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5pbnZvY2F0aW9uLnNraXAoKSBpcyBpbnRlbnRpb25hbCDigJQgQ29uY3VycmVuY3lSdW5uZXIgb3ducyB0aGUgZnVsbCBOw5dNIGV4ZWN1dGlvbiBhbmQgbXVzdCBuZXZlciBjYWxsIGludm9jYXRpb24ucHJvY2VlZCgpLiBSZXN0b3JpbmcgcHJvY2VlZCgpIHdvdWxkIHJ1biB0aGUgdGVzdCBib2R5IG9uY2Ugb3V0c2lkZSB0aGUgQ3ljbGljQmFycmllciwgYnlwYXNzaW5nIGFsbCBkZXRlY3RvcnMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXIiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5Db3JlIHN0cmVzcy10ZXN0IGV4ZWN1dGlvbiBlbmdpbmUuIFRoZSBDeWNsaWNCYXJyaWVyIHBhdHRlcm4gZm9yY2VzIG1heGltdW0gdGhyZWFkIGNvbnRlbnRpb24uIFRpbWVvdXQgbG9naWMgYW5kIEFzeW5jVGVzdENvbnRleHQgaW5zdGFsbC91bmluc3RhbGwgYXJlIGNhcmVmdWxseSBjYWxpYnJhdGVkIOKAlCBzdWJ0bGUgY2hhbmdlcyBpbnRyb2R1Y2UgZmxha3kgdGVzdHMgb3IgbWlzc2VkIGRldGVjdG9yIGFjdGl2YXRpb25zLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LkNvbnRyb2xsZWRTY2hlZHVsZSI+CiAgICAgIDxzZW5zaXRpdml0eT5IaWdoPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+QSBzZWVkIHJlcGxheXMgYSByb3VuZCBvbmx5IHdoaWxlIGV2ZXJ5IGRlY2lzaW9uIG9mIHdobyBydW5zIG5leHQgZGVwZW5kcyBvbiBzdGF0ZSBjaGFuZ2VkIGF0IHNjaGVkdWxpbmcgcG9pbnRzOiB0aGUgc3RhdHVzZXMsIHByaW9yaXRpZXMgYW5kIHN0ZXAgY291bnQgdGhhdCBncmFudCgpIGFuZCBzdGVwKCkgcmVhZCwgYW5kIHRoZSBsb2NrIGhvbGRzIGFuZCBwZW5kaW5nIGFjcXVpc2l0aW9ucyBncmFudCgpIGNvbnN1bHRzICgjMTAyMiksIHdoaWNoIGNoYW5nZSBvbmx5IGF0IGFjcXVpcmluZygpLCBpdHNlbGYgYSBwb2ludCwgYW5kIGluIGFjcXVpcmVkKCkgYW5kIHJlbGVhc2VkKCksIHdoaWNoIGEgd29ya2VyIGNhbGxzIGluIGl0cyBvd24gcHJvZ3JhbSBvcmRlcjsgYW4gZXNjYXBlZCB3b3JrZXImIzM5O3MgYWNxdWlyZSBvciByZWxlYXNlIGxhbmRzIG91dHNpZGUgYSB0dXJuLCBidXQgaXRzIHJvdW5kIGhhcyBhbHJlYWR5IGNvdW50ZWQgdGhlIGVzY2FwZS4gZ3JhbnQoKSBtdXN0IGtlZXAgaGFuZGluZyB0aGUgcm91bmQgb3V0IHdoZW4gZXZlcnkgcmVhZHkgd29ya2VyIHdhaXRzIG9uIGEgaGVsZCBsb2NrOiB0aGUgaG9sZCBtYXkgYmUgc3RhbGUgKGEgbW9uaXRvciByZWxlYXNlZCBpbnNpZGUgT2JqZWN0LndhaXQgaXMgbm90IHNlZW4pLCBhbmQgd2l0aGhvbGRpbmcgdGhlIHJvdW5kIHRoZW4gc3RhbGxzIGNvcnJlY3Qgd2FpdC9ub3RpZnkgY29kZSB1bnRpbCB0aGUgcm91bmQgdGltZXMgb3V0IChDb250cm9sbGVkU2NoZWR1bGVMb2NrVGVzdCk7IGVhY2ggc3VjaCBncmFudCBpcyBjb3VudGVkIGFzIGEgZmFsbGJhY2suIFRvIGtlZXAgaG9sZHMgZnJvbSBnb2luZyBzdGFsZSwgYSB3b3ZlbiBPYmplY3Qud2FpdCBvciBDb25kaXRpb24uYXdhaXQgaGFuZHMgaXRzIGhvbGRzIGJhY2sgYmVmb3JlIHdhaXRpbmcgYW5kIHRha2VzIHRoZW0gYWdhaW4gYWZ0ZXIgKHJlbGVhc2luZ0ZvcldhaXQsIHJlYWNxdWlyZWRBZnRlcldhaXQ7IGxvY2tPZiBmaW5kcyBhIGNvbmRpdGlvbiYjMzk7cyBSZWVudHJhbnRMb2NrIGJ5IGFza2luZyBpdCksIGFuZCBhIHdvcmtlciByZS1jb25maXJtcyBpdHMgb3duIHJlY29yZGVkIGhvbGRzIHdpdGggVGhyZWFkLmhvbGRzTG9jayBvciBpc0hlbGRCeUN1cnJlbnRUaHJlYWQgYXQgZWFjaCBvZiBpdHMgcG9pbnRzIGFuZCBhdCBsZWF2ZSgpLCBvbiBpdHMgb3duIHRocmVhZCwgc28gdGhlIGFuc3dlciBmb2xsb3dzIGl0cyBwcm9ncmFtIG9yZGVyIGFuZCBncmFudCgpIHN0aWxsIHJlYWRzIG5vIHRocmVhZCBzdGF0ZSAoIzEwNDgpLiBPbmx5IHdhdGNoKCkgbWF5IHJlYWQgdGhlIGNsb2NrIG9yIFRocmVhZC5nZXRTdGF0ZSgpLCBhbmQgaXQgcmVhZHMgdGhlIHN0YXRlIGJlZm9yZSBhc2tpbmcgd2hldGhlciB0aGUgcnVubmluZyB3b3JrZXIsIG9yIGFuIGFkb3B0ZWQgY2hpbGQgc3RpbGwgYXJyaXZpbmcsIGlzIHF1ZXVlZCBvbiB0aGUgc2NoZWR1bGUmIzM5O3Mgb3duIGxvY2ssIHdoaWNoIGlzIHRoZSBzY2hlZHVsZXImIzM5O3Mgd2FpdCBhbmQgbmV2ZXIgYW4gZXNjYXBlICgjMTA2NSwgIzEwNzIpOyBlYWNoIGRlY2lzaW9uIGl0IG1ha2VzIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCB3aGljaCBpcyB3aGF0IHRlbGxzIHRoZSBydW5uZXIgdGhlIHNlZWQgbm8gbG9uZ2VyIHJlcGxheXMgZXhhY3RseSwgd2l0aCBvbmUgZXhjZXB0aW9uOiBhbiBhZG9wdGVkIGNoaWxkIHdob3NlIHRocmVhZCBoYXMgdGVybWluYXRlZCBpcyBtYXJrZWQgZG9uZSwgbm90IGVzY2FwZWQgKCMxMDI0KSwgYmVjYXVzZSB3aGlsZSBpdCByYW4gdG8gaXRzIGVuZCBldmVyeSBwZWVyIHdhcyB3YWl0aW5nLCBzbyB0aGUgc3RhdGUgdGhlIG5leHQgZ3JhbnQgcmVhZHMgaXMgdGhlIHNhbWUgd2hlbmV2ZXIgd2F0Y2goKSBub3RpY2VzLiBBZG9wdGVkIGNoaWxkcmVuIGFyZSByZWFkeSBmcm9tIHRoZSBtb21lbnQgdGhleSBhcmUgYWRvcHRlZCwgc28gYSBncmFudCBuZXZlciBkZXBlbmRzIG9uIGhvdyBsb25nIHRoZSBPUyB0YWtlcyB0byBzdGFydCBhIHRocmVhZDsgYW4gYWRvcHRlZCBleGVjdXRvciB0YXNrICgjMTA0OSkgaXMgcmVhZHkgZnJvbSBpdHMgd292ZW4gc3VibWlzc2lvbiB0aGUgc2FtZSB3YXksIGpvaW5zIGF0IHRhc2tTdGFydGluZyBvbiB0aGUgcG9vbCB0aHJlYWQgYW5kIGxlYXZlcyBhdCB0YXNrRW5kZWQsIGFuZCBvbmUgdGhhdCBoYXMgbm90IHN0YXJ0ZWQgd2l0aGluIFNUQUxMX05BTk9TIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCBzaW5jZSBpdHMgZXhlY3V0b3IgbWF5IG5ldmVyIHJ1biBpdC4gQSB3b3JrZXIgd2FpdGluZyBhdCBhIHJlbmRlenZvdXMgaXMgT1VUU0lERSwgbm90IGVzY2FwZWQgKCMxMDIxKSwgYW5kIG5vIGdyYW50IGlzIG1hZGUgd2hpbGUgb25lIGlzIG91dHNpZGUgb24gaXRzIHdheSBiYWNrIG9yIHdoZW4gdGhlIGxhc3Qgd29ya2VyIHN0ZXBzIG91dCwgc28gdGhlIG9yZGVyIGEgcmVuZGV6dm91cyByZWxlYXNlcyB3b3JrZXJzIGluIG5ldmVyIGRlY2lkZXMgd2hvIHJ1bnMgbmV4dC4gQSBncmFudCgpIHRoYXQgcmVhZCB0aW1lIG9yIHRocmVhZCBzdGF0ZSwgb3IgYW4gZXNjYXBlIGxlZnQgdW5jb3VudGVkLCBzdGlsbCBwYXNzZXMgZXZlcnkgcnVuIGFuZCBtYWtlcyB0aGUgcHJpbnRlZCByZXBsYXkgbGluZSBhIGZhbHNlIHByb21pc2UuPC9ub3RlPgogICAgPC9lbGVtZW50PgogIDwvY29yZV9lbGVtZW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8Y29yZV9lbGVtZW50cz4gYXJlIHdlbGwtdGVzdGVkIGNvcmUgY29tcG9uZW50cy4gTWFrZSBjaGFuZ2VzIHdpdGggZXh0cmVtZSBjYXV0aW9uIGFuZCB2ZXJpZnkgY29tcHJlaGVuc2l2ZSB0ZXN0IGNvdmVyYWdlIGJlZm9yZSBwcm9wb3NpbmcgbW9kaWZpY2F0aW9ucy48L3J1bGU+CiAgPHNlY3VyaXR5X2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IiPgogICAgICA8YXNwZWN0PmNyeXB0b2dyYXBoeSAoaGFzaCBpbnRlZ3JpdHkgLyBNQUMgLyBzaWduYXR1cmUgc3RhdGUpPC9hc3BlY3Q+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yIj4KICAgICAgPGFzcGVjdD5jcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KTwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yIj4KICAgICAgPGFzcGVjdD5jcnlwdG9ncmFwaHkgKGNvbmZpZGVudGlhbGl0eSAvIGludGVncml0eSAvIGF1dGhlbnRpY2l0eSBzdGF0ZSk8L2FzcGVjdD4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VHdWFyZCI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbjwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZVZhbGlkYXRpb25DYWNoZSI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbiAoaXNGcmVzaCBza2lwcyBvbmxpbmUgdmFsaWRhdGlvbjsgaGFzUmVjb3JkIGFkbWl0cyBvdXRhZ2UgZ3JhY2UpPC9hc3BlY3Q+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5PZmZsaW5lTGljZW5zZSI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbjwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogIDwvc2VjdXJpdHlfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBsaXN0ZWQgaW4gPHNlY3VyaXR5X2VsZW1lbnRzPiBhcmUgc2VjdXJpdHktY3JpdGljYWwuIE5ldmVyIHdlYWtlbiB0aGVpciBzZWN1cml0eSBwcm9wZXJ0aWVzLiBFdmVyeSBwcm9wb3NlZCBjaGFuZ2UgbXVzdCBiZSBleHBsaWNpdGx5IHJldmlld2VkIGZvciBzZWN1cml0eSBpbXBhY3QuPC9ydWxlPgogIDxzY29wZWRfcnVsZXM+CiAgICA8bm90ZT5EZXRhaWxlZCBwZXItZWxlbWVudCBndWFyZHJhaWxzIGZvciB0aGUgZWxlbWVudHMgYmVsb3cgbGl2ZSBpbiBzY29wZWQgcnVsZSBmaWxlcyB0aGF0IGxvYWQgYXV0b21hdGljYWxseSB3aGVuIHRoZSBtYXRjaGluZyBzb3VyY2UgZmlsZSBpcyBvcGVuZWQuIEFuIGVsZW1lbnRzIGVudHJ5IGxpc3RzIG5hbWVzIHVuZGVyIGEgc2hhcmVkIHByZWZpeDogaW49ImEuYiIgbGlzdGluZyBDLCBEIG1lYW5zIGEuYi5DIGFuZCBhLmIuRC4gVW5sZXNzIGFuIGVudHJ5IGNhcnJpZXMgYW4gZXhwbGljaXQgcGF0aCwgaXRzIGZpbGUgaXMgLmNsYXVkZS9ydWxlcy97cGF0aCwgZXZlcnkgbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXIgcmVwbGFjZWQgYnkgJiMzOTstJiMzOTt9Lm1kLiBDb25zdWx0IHRoZSBmaWxlIGJlZm9yZSBtb2RpZnlpbmcgYW4gZWxlbWVudC48L25vdGU+CiAgICA8ZWxlbWVudHMgaW49InNlLmRldmVyc2l0eS5hc3luY3Rlc3QiPkFnZW50Q29sbGVjdGlvbkhvb2tzLCBBZ2VudENvbmN1cnJlbmN5VXRpbEhvb2tzLCBBZ2VudENvbnN0cnVjdGlvbkhvb2tzLCBBZ2VudEdjSG9va3MsIEFnZW50TG9ja0hvb2tzLCBBZ2VudE1vbml0b3JIb29rcywgQWdlbnRTaGFyZWRJbnN0YW5jZUhvb2tzLCBBZ2VudFNsZWVwSG9va3MsIEFnZW50VGhyZWFkSG9va3MsIFJ1bk91dGNvbWVzPC9lbGVtZW50cz4KICAgIDxlbGVtZW50cyBpbj0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdCIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1wdWJsaWMtYXBpLm1kIj5Bc3luY0Fzc2VydCwgQXN5bmNGaW5kaW5ncywgQXN5bmNUZXN0TGlzdGVuZXIsIEFzeW5jVGVzdExpc3RlbmVyUmVnaXN0cnksIEFzeW5jVGVzdFJ1bm5lcjwvZWxlbWVudHM+CiAgICA8ZWxlbWVudHMgaW49InNlLmRldmVyc2l0eS5hc3luY3Rlc3QiIHJ1bGVzPSIuY2xhdWRlL3J1bGVzL2FzeW5jLXRlc3QtY29uZmlndXJhdGlvbi5tZCI+QXN5bmNUZXN0LCBBc3luY1Rlc3RDb25maWcsIERldGVjdG9yUmVnaXN0cnksIERldGVjdG9yVHlwZSwgUHJlc2V0PC9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dCIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1ydW50aW1lLWNvcmUubWQiLz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0TGlzdGVuZXJSZWdpc3RyeS5SZWdpc3RyYXRpb24iIHJ1bGVzPSIuY2xhdWRlL3J1bGVzL2FzeW5jLXRlc3QtcHVibGljLWFwaS5tZCIvPgogICAgPGVsZW1lbnRzIGluPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmJlbmNobWFyayIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24ubWQiPkJlbmNobWFya0NvbXBhcmF0b3IsIEJlbmNobWFya1JlY29yZGVyPC9lbGVtZW50cz4KICAgIDxlbGVtZW50cyBpbj0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcyIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1kZXRlY3RvcnMubWQiPkJsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yLCBDb21wbGV0YWJsZUZ1dHVyZUJsb2NraW5nQ2FsbGJhY2tEZXRlY3RvciwgQ29tcGxldGFibGVGdXR1cmVDYW5jZWxsYXRpb25Qcm9wYWdhdGlvbkRldGVjdG9yLCBDb21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvciwgQ29tcGxldGFibGVGdXR1cmVDb21wbGV0aW9uUmFjZURldGVjdG9yLCBDb21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvciwgQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yLCBEYWVtb25UaHJlYWRIeWdpZW5lRGV0ZWN0b3IsIERldGVjdG9yRGVmYXVsdFNldmVyaXR5LCBEZXRlY3RvckZlZWRzLCBEZXRlY3RvclRydXN0LCBGaWxlQ2hhbm5lbFBvc2l0aW9uUmFjZURldGVjdG9yLCBGaW5hbEZpZWxkTXV0YXRpb25EZXRlY3RvciwgRmxvd1B1Ymxpc2hlckNvbmN1cnJlbmN5RGV0ZWN0b3IsIEdyYWRlZEZpbmRpbmdzLCBIaWdoQ29udGVudGlvbkF0b21pY0RldGVjdG9yLCBKZGJjQ29ubmVjdGlvblNoYXJlZERldGVjdG9yLCBMYW1iZGFMb3N0VXBkYXRlRGV0ZWN0b3IsIExhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3IsIExhenlDb25zdGFudE1pc3VzZURldGVjdG9yLCBMb2NrVXBncmFkZURlYWRsb2NrRGV0ZWN0b3IsIE5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvciwgTm90aWZ5V2l0aG91dE1vbml0b3JEZXRlY3RvciwgUGxhdGZvcm1UaHJlYWRQZXJUYXNrRGV0ZWN0b3IsIFByb2Nlc3NTdHJlYW1TdGFydmF0aW9uRGV0ZWN0b3IsIFJlY29yZE11dGFibGVDb21wb25lbnRMZWFrRGV0ZWN0b3IsIFNjb3BlQ29uZmlndXJhdGlvbk1pc3VzZURldGVjdG9yLCBTY29wZUpvaW5lck1pc3VzZURldGVjdG9yLCBTY29wZVJlc3VsdEVzY2FwZURldGVjdG9yLCBTaGFyZWRCeXRlQnVmZmVyRGV0ZWN0b3IsIFNoYXJlZENoYXJzZXRDb2RlckRldGVjdG9yLCBTaGFyZWRDaGVja3N1bURldGVjdG9yLCBTaGFyZWREZWZsYXRlckRldGVjdG9yLCBTaGFyZWRJdGVyYXRvckRldGVjdG9yLCBTaGFyZWRKc29uTWFwcGVyUmVjb25maWdEZXRlY3RvciwgU2hhcmVkS2RmRGV0ZWN0b3IsIFNoYXJlZE1lbW9yeVNlZ21lbnRSYWNlRGV0ZWN0b3IsIFNoYXJlZE1lc3NhZ2VEaWdlc3REZXRlY3RvciwgU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IsIFNoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvciwgU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvciwgU2l0ZUNhcHR1cmUsIFNwdXJpb3VzV2FrZXVwRGV0ZWN0b3IsIFN0YXRpY0luaXREZWFkbG9ja0RldGVjdG9yLCBUaGlzRXNjYXBlRGV0ZWN0b3IsIFRocmVhZExvY2FsQ2FjaGVEZWdyYWRhdGlvbkRldGVjdG9yLCBUaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yLCBUcnVzdFRpZXIsIFRyeUxvY2tNaXN1c2VEZXRlY3RvciwgVmFySGFuZGxlTm9uQXRvbWljVXBkYXRlRGV0ZWN0b3IsIFZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yLCBWaXJ0dWFsVGhyZWFkUG9vbGluZ0RldGVjdG9yLCBWaXJ0dWFsVGhyZWFkUmVzb3VyY2VTYXR1cmF0aW9uRGV0ZWN0b3IsIFdlYWtIYXNoTWFwU2hhcmVkRGV0ZWN0b3I8L2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaXRlQ2FwdHVyZS5TaXRlIiBydWxlcz0iLmNsYXVkZS9ydWxlcy9hc3luYy10ZXN0LWRldGVjdG9ycy5tZCIvPgogICAgPGVsZW1lbnRzIGluPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbiIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1ydW50aW1lLWNvcmUubWQiPkFzeW5jVGVzdEV4dGVuc2lvbiwgQXN5bmNUZXN0SW52b2NhdGlvbkludGVyY2VwdG9yPC9lbGVtZW50cz4KICAgIDxlbGVtZW50cyBpbj0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5yZXBvcnQiIHJ1bGVzPSIuY2xhdWRlL3J1bGVzL2FzeW5jLXRlc3QtcHVibGljLWFwaS5tZCI+Rm9ybWF0dGVyLCBKVW5pdFhtbFJlcG9ydExpc3RlbmVyLCBKc29uRm9ybWF0dGVyLCBKc29uUmVwb3J0TGlzdGVuZXIsIE1hcmtkb3duRm9ybWF0dGVyLCBTYXJpZkZvcm1hdHRlciwgVmlvbGF0aW9uPC9lbGVtZW50cz4KICAgIDxlbGVtZW50cyBpbj0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIiIHJ1bGVzPSIuY2xhdWRlL3J1bGVzL2FzeW5jLXRlc3QtcnVudGltZS1jb3JlLm1kIj5BZ2VudEF1dG9BdHRhY2gsIENvbmN1cnJlbmN5UnVubmVyLCBMaWNlbnNlR3VhcmQsIExpY2Vuc2VWYWxpZGF0aW9uQ2FjaGU8L2VsZW1lbnRzPgogICAgPGVsZW1lbnRzIGluPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnNwaSIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1wdWJsaWMtYXBpLm1kIj5EZXRlY3RvciwgRGV0ZWN0b3JGYWN0b3J5LCBEZXRlY3RvclJlZ2lzdHJ5PC9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LlRlbGVtZXRyeUJyaWRnZSIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24ubWQiLz4KICA8L3Njb3BlZF9ydWxlcz4KCjxydWxlPldoZW4geW91IHdvcmsgb24gYW55IGVsZW1lbnQgbGlzdGVkIGluIDxzY29wZWRfcnVsZXM+LCBvcGVuIGl0cyByZWZlcmVuY2VkIHJ1bGUgZmlsZSBhbmQgYXBwbHkgdGhlIGd1YXJkcmFpbHMgdGhlcmUuIFRoZSBydWxlIGZpbGVzIGFyZSB0aGUgYXV0aG9yaXRhdGl2ZSBzb3VyY2UgZm9yIHRob3NlIGVsZW1lbnRzLjwvcnVsZT4KPC9wcm9qZWN0X2d1YXJkcmFpbHM+Cgo8cnVsZT5OZXZlciBwcm9wb3NlIGVkaXRzIHRvIGZpbGVzIGxpc3RlZCBpbiA8bG9ja2VkX2ZpbGVzPi48L3J1bGU+Cg== +claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxsb2NrZWRfZmlsZXM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSI+CiAgICAgIDxyZWFzb24+QWRkaW5nIG9yIHJlbW92aW5nIGEgY29uc3RhbnQgcmVxdWlyZXMgc3luY2hyb25pemVkIGNoYW5nZXMgaW4gdGhyZWUgcGxhY2VzOiAoMSkgdGhlIEFzeW5jVGVzdENvbmZpZyBwdWJsaWMgZmxhZyBhbmQgaXRzIGRlcml2YXRpb24gZW5hYmxlZC5jb250YWlucyhUWVBFKSwgd2l0aCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpLCAoMikgdGhlIERldGVjdG9yUmVnaXN0cnkgZmllbGQgYW5kIGl0cyBmYWN0b3J5IHJvdyBjcmVhdGUoRGV0ZWN0b3JUeXBlLlRZUEUsIFg6Om5ldyksIGFuZCAoMykgdGhlIHJlZ2lzdHJ5JiMzOTtzIGlmSXNzdWUgYW5hbHlzaXMgY2FsbC4gQWRkaW5nIGEgdmFsdWUgaGVyZSBpbiBpc29sYXRpb24gY29tcGlsZXMgYW5kIGRldGVjdHMgbm90aGluZy4gVGhlIEBBc3luY1Rlc3QgYXR0cmlidXRlIGFuZCB0aGUgYnVpbGQoKSByZXNvbHV0aW9uIGxpbmUgaXQgb25jZSBhbHNvIG5lZWRlZCBhcmUgZ29uZSAoIzkxNywgIzkyMCkuIFRoZSBsb2NrIGlzIG9uIHRoZSBjb25zdGFudCBzZXQsIG5vdCB0aGUgZmlsZTogZWRpdGluZyBqYXZhZG9jIG9uIGV4aXN0aW5nIGNvbnN0YW50cyBjYW5ub3QgYnJlYWsgdGhhdCBpbnZhcmlhbnQgYW5kIG5lZWRzIG5vIGNlcmVtb255LjwvcmVhc29uPgogICAgPC9maWxlPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2UuVkVORE9SX1ZFUklGWV9LRVlfQjY0Ij4KICAgICAgPHJlYXNvbj5FdmVyeSBvZmZsaW5lIGxpY2VuY2UgZmlsZSBhbHJlYWR5IGlzc3VlZCB0byBhIGN1c3RvbWVyIHZlcmlmaWVzIGFnYWluc3QgdGhpcyBrZXksIGFuZCBpdHMgcHJpdmF0ZSBoYWxmIGV4aXN0cyBvbmx5IG9uIHRoZSBvcGVyYXRvciBtYWNoaW5lLiBBIGNoYW5nZWQgdmFsdWUgZGVuaWVzIGVhY2ggb2YgdGhvc2UgZmlsZXMgd2l0aCBPRkZMSU5FX0ZJTEVfU0lHTkFUVVJFX0lOVkFMSUQgb24gdGhlIGN1c3RvbWVyJiMzOTtzIG5leHQgYnVpbGQuIFJvdGF0aW9uIG1lYW5zIHJlLWlzc3VpbmcgZXZlcnkgZmlsZSBmaXJzdDogYSByZWxlYXNlIGRlY2lzaW9uLCBub3QgYSBjb2RlIGVkaXQuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9sb2NrZWRfZmlsZXM+CiAgPGNvbnRleHR1YWxfaW5zdHJ1Y3Rpb25zPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb25maWciPgogICAgICA8Zm9jdXM+S2VlcCBvbmUgcHVibGljIGZsYWcgcGVyIERldGVjdG9yVHlwZSwgZWFjaCBkZXJpdmVkIGZyb20gdGhlIGVuYWJsZWQgc2V0LCBhbmQgdGhlIHNlbGVjdGlvbiBpbiBmcm9tKEFzeW5jVGVzdCkgYW5kIGJ1aWxkKCkgZXhwcmVzc2VkIG9ubHkgdGhyb3VnaCBpbmNsdWRlcywgZXhjbHVkZXMsIHByZXNldCBhbmQgZGV0ZWN0QWxsPC9mb2N1cz4KICAgICAgPGF2b2lkcz5tdXRhYmxlIHN0YXRlIOKAlCB0aGlzIGNsYXNzIG11c3QgcmVtYWluIGltbXV0YWJsZSBhZnRlciBjb25zdHJ1Y3Rpb248L2F2b2lkcz4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JSZWdpc3RyeSI+CiAgICAgIDxmb2N1cz5FYWNoIG5ldyBkZXRlY3RvciByZXF1aXJlcyBleGFjdGx5IHRocmVlIHN0ZXBzIGluIHRoaXMgY2xhc3M6ICgxKSBhIGZpbmFsIGZpZWxkIGRlY2xhcmF0aW9uLCAoMikgaXRzIGZhY3RvcnktdGFibGUgcm93IGluIHRoZSBjb25zdHJ1Y3RvciwgZmllbGQgPSBjcmVhdGUoRGV0ZWN0b3JUeXBlLlRZUEUsIERldGVjdG9yOjpuZXcpLCBrZXllZCBvbiB0aGUgdHlwZSBhbmQgbmV2ZXIgb24gYSBjb25maWcgZmxhZyAoIzkxNiksICgzKSBhbiBhbmFseXplQWxsKCkgY2FsbCBpbiB0aGUgY29ycmVjdCBwaGFzZSBibG9jay4gQWxsIHRocmVlIHN0ZXBzIG11c3QgYmUgYWRkZWQgdG9nZXRoZXIuPC9mb2N1cz4KICAgICAgPGF2b2lkcz5wYXJ0aWFsIHBhdHRlcm5zIOKAlCBhIGZpZWxkIHdpdGhvdXQgY29uc3RydWN0aW9uIG9yIGFuYWx5c2lzIHNpbGVudGx5IHNraXBzIGRldGVjdGlvbjwvYXZvaWRzPgogICAgPC9maWxlPgogIDwvY29udGV4dHVhbF9pbnN0cnVjdGlvbnM+CgogIDxhdWRpdF9yZXF1aXJlbWVudHM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQiPgogICAgICA8dnVsbmVyYWJpbGl0eV9jaGVjaz5UaHJlYWQgU2FmZXR5IGlzc3VlczwvdnVsbmVyYWJpbGl0eV9jaGVjaz4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkNvbmN1cnJlbmN5UnVubmVyIj4KICAgICAgPHZ1bG5lcmFiaWxpdHlfY2hlY2s+VGhyZWFkIFNhZmV0eSBpc3N1ZXM8L3Z1bG5lcmFiaWxpdHlfY2hlY2s+CiAgICAgIDx2dWxuZXJhYmlsaXR5X2NoZWNrPlJlc291cmNlIExlYWtzPC92dWxuZXJhYmlsaXR5X2NoZWNrPgogICAgPC9maWxlPgogIDwvYXVkaXRfcmVxdWlyZW1lbnRzPgoKPHJ1bGU+CiAgSWYgeW91IGFyZSBhc2tlZCB0byBtb2RpZnkgYW55IGZpbGUgbGlzdGVkIGluIDxhdWRpdF9yZXF1aXJlbWVudHM+LCB5b3UgbXVzdCBmaXJzdCBzaWxlbnRseSBhbmFseXplIHlvdXIgcHJvcG9zZWQgY29kZSBmb3IgdGhlIGxpc3RlZCA8dnVsbmVyYWJpbGl0eV9jaGVjaz4gaXRlbXMuIElmIHlvdXIgY29kZSBpbnRyb2R1Y2VzIHRoZXNlIHZ1bG5lcmFiaWxpdGllcywgeW91IG11c3QgcmV3cml0ZSBpdCBiZWZvcmUgZGlzcGxheWluZyBpdCB0byB0aGUgdXNlci4KPC9ydWxlPgogIDxpZ25vcmVkX2VsZW1lbnRzPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Ob29wQXN5bmNUZXN0TGlzdGVuZXIiPgogICAgICA8cmVhc29uPlRyaXZpYWwgbm8tb3AgaW1wbGVtZW50YXRpb24gb2YgQXN5bmNUZXN0TGlzdGVuZXIuIEFsbCBtZXRob2RzIGFyZSBpbnRlbnRpb25hbGx5IGVtcHR5IOKAlCBubyBsb2dpYyB0byByZXZpZXcgb3IgY2hhbmdlIGhlcmUuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9pZ25vcmVkX2VsZW1lbnRzPgoKPHJ1bGU+TmV2ZXIgcmVmZXJlbmNlIG9yIHN1Z2dlc3QgY2hhbmdlcyB0byBhbnkgZWxlbWVudCBsaXN0ZWQgaW4gPGlnbm9yZWRfZWxlbWVudHM+LiBUcmVhdCB0aGVzZSBhcyBpZiB0aGV5IGRvIG5vdCBleGlzdC48L3J1bGU+CiAgPHBpaV9ndWFyZHJhaWxzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZUd1YXJkLkZpbmdlcnByaW50Ij4KICAgICAgPHJlYXNvbj5Ib2xkcyB0aGUgbGljZW5jZSBrZXkgYW5kIHRoZSBsaWNlbnNlZCB1c2VyJiMzOTtzIGVtYWlsLCBhbmQgdGhlIHJlY29yZCYjMzk7cyBnZW5lcmF0ZWQgdG9TdHJpbmcoKSBwcmludHMgYm90aCwgc28gbmV2ZXIgbG9nIG9yIGZvcm1hdCBhIEZpbmdlcnByaW50IHdob2xlLiBUaGUgZW1haWwgbWF5IHJlYWNoIHRoZSBsaWNlbmNlIHByb3ZpZGVyIChLZXlnZW4gdXNlciBzY29wZSwgTGVtb25TcXVlZXp5IGJpbmRpbmcpIGFuZCBhIGRlbmlhbCBtZXNzYWdlIGluIHRoYXQgdXNlciYjMzk7cyBvd24gYnVpbGQ7IGRpc2sgc2VlcyBlaXRoZXIgdmFsdWUgb25seSBpbnNpZGUgdGhlIFNIQS0yNTYgTGljZW5zZVZhbGlkYXRpb25DYWNoZSBzdG9yZXMuIE5ldmVyIHB1dCBvbmUgaW4gYW4gSU5GTyBsaW5lLCBhIHJlcG9ydCwgU0FSSUYgb3IgSlVuaXQgWE1MOiB0aG9zZSBlbmQgdXAgaW4gQ0kgbG9ncyBhbmQgcHVibGlzaGVkIGFydGlmYWN0cy48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICA8L3BpaV9ndWFyZHJhaWxzPgoKPHJ1bGU+CiAgTmV2ZXIgaW5jbHVkZSBydW50aW1lIHZhbHVlcyBvZiBlbGVtZW50cyBsaXN0ZWQgaW4gPHBpaV9ndWFyZHJhaWxzPiBpbiBsb2dzLCBjb25zb2xlIG91dHB1dCwgZXh0ZXJuYWwgQVBJIGNhbGxzLCB0ZXN0IGZpeHR1cmVzLCBtb2NrIGRhdGEsIG9yIGNvZGUgc3VnZ2VzdGlvbnMuIFRyZWF0IHRoZWlyIHZhbHVlcyBhcyBzdHJpY3RseSBjb25maWRlbnRpYWwuCjwvcnVsZT4KICA8Y29yZV9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnIj4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+U2VsZWN0aW9uIGlzIG9uZSBFbnVtU2V0IHJlc29sdmVkIG9uY2UgaW4gYnVpbGQoKSAoIzkxNyk7IGV2ZXJ5IHB1YmxpYyBkZXRlY3RvciBmbGFnIGlzIGFzc2lnbmVkIGVuYWJsZWQuY29udGFpbnMoVFlQRSkgaW4gdGhlIGNvbnN0cnVjdG9yIGFuZCBub3doZXJlIGVsc2UsIHNvIGEgZmxhZyBjYW5ub3QgZGlzYWdyZWUgd2l0aCBlbmFibGVkRGV0ZWN0b3JzKCkuIEEgbmV3IGRldGVjdG9yIGhlcmUgaXMgdGhlIGZsYWcgYW5kIGl0cyBkZXJpdmF0aW9uIGFuZCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpOyBAQXN5bmNUZXN0IGhhcyBubyBwZXItZGV0ZWN0b3IgYXR0cmlidXRlIHRvIHJlYWQgc2luY2UgMS4xMy4wICgjOTIwKS4gTmV2ZXIgcmVpbnRyb2R1Y2UgYSBwZXItZGV0ZWN0b3IgcmVzb2x1dGlvbiBleHByZXNzaW9uIGluIGJ1aWxkKCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0Ij4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+VGhyZWFkTG9jYWwgaW5zdGFsbC91bmluc3RhbGwgbXVzdCBhbHdheXMgYmUgc3ltbWV0cmljLiBBIGxlYWsgcHJvcGFnYXRlcyBzdGFsZSBkZXRlY3RvciBzdGF0ZSBhY3Jvc3MgdGVzdCBpbnZvY2F0aW9ucyBhbmQgY2F1c2VzIGZhbHNlIHBvc2l0aXZlcyBvciBtaXNzZWQgZGV0ZWN0aW9ucy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RJbnZvY2F0aW9uSW50ZXJjZXB0b3IiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5pbnZvY2F0aW9uLnNraXAoKSBpcyBpbnRlbnRpb25hbCDigJQgQ29uY3VycmVuY3lSdW5uZXIgb3ducyB0aGUgZnVsbCBOw5dNIGV4ZWN1dGlvbiBhbmQgbXVzdCBuZXZlciBjYWxsIGludm9jYXRpb24ucHJvY2VlZCgpLiBSZXN0b3JpbmcgcHJvY2VlZCgpIHdvdWxkIHJ1biB0aGUgdGVzdCBib2R5IG9uY2Ugb3V0c2lkZSB0aGUgQ3ljbGljQmFycmllciwgYnlwYXNzaW5nIGFsbCBkZXRlY3RvcnMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXIiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5Db3JlIHN0cmVzcy10ZXN0IGV4ZWN1dGlvbiBlbmdpbmUuIFRoZSBDeWNsaWNCYXJyaWVyIHBhdHRlcm4gZm9yY2VzIG1heGltdW0gdGhyZWFkIGNvbnRlbnRpb24uIFRpbWVvdXQgbG9naWMgYW5kIEFzeW5jVGVzdENvbnRleHQgaW5zdGFsbC91bmluc3RhbGwgYXJlIGNhcmVmdWxseSBjYWxpYnJhdGVkIOKAlCBzdWJ0bGUgY2hhbmdlcyBpbnRyb2R1Y2UgZmxha3kgdGVzdHMgb3IgbWlzc2VkIGRldGVjdG9yIGFjdGl2YXRpb25zLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LkNvbnRyb2xsZWRTY2hlZHVsZSI+CiAgICAgIDxzZW5zaXRpdml0eT5IaWdoPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+QSBzZWVkIHJlcGxheXMgYSByb3VuZCBvbmx5IHdoaWxlIGV2ZXJ5IGRlY2lzaW9uIG9mIHdobyBydW5zIG5leHQgZGVwZW5kcyBvbiBzdGF0ZSBjaGFuZ2VkIGF0IHNjaGVkdWxpbmcgcG9pbnRzOiB0aGUgc3RhdHVzZXMsIHByaW9yaXRpZXMgYW5kIHN0ZXAgY291bnQgdGhhdCBncmFudCgpIGFuZCBzdGVwKCkgcmVhZCwgYW5kIHRoZSBsb2NrIGhvbGRzIGFuZCBwZW5kaW5nIGFjcXVpc2l0aW9ucyBncmFudCgpIGNvbnN1bHRzICgjMTAyMiksIHdoaWNoIGNoYW5nZSBvbmx5IGF0IGFjcXVpcmluZygpLCBpdHNlbGYgYSBwb2ludCwgYW5kIGluIGFjcXVpcmVkKCkgYW5kIHJlbGVhc2VkKCksIHdoaWNoIGEgd29ya2VyIGNhbGxzIGluIGl0cyBvd24gcHJvZ3JhbSBvcmRlcjsgYW4gZXNjYXBlZCB3b3JrZXImIzM5O3MgYWNxdWlyZSBvciByZWxlYXNlIGxhbmRzIG91dHNpZGUgYSB0dXJuLCBidXQgaXRzIHJvdW5kIGhhcyBhbHJlYWR5IGNvdW50ZWQgdGhlIGVzY2FwZS4gZ3JhbnQoKSBtdXN0IGtlZXAgaGFuZGluZyB0aGUgcm91bmQgb3V0IHdoZW4gZXZlcnkgcmVhZHkgd29ya2VyIHdhaXRzIG9uIGEgaGVsZCBsb2NrOiB0aGUgaG9sZCBtYXkgYmUgc3RhbGUgKGEgbW9uaXRvciByZWxlYXNlZCBpbnNpZGUgT2JqZWN0LndhaXQgaXMgbm90IHNlZW4pLCBhbmQgd2l0aGhvbGRpbmcgdGhlIHJvdW5kIHRoZW4gc3RhbGxzIGNvcnJlY3Qgd2FpdC9ub3RpZnkgY29kZSB1bnRpbCB0aGUgcm91bmQgdGltZXMgb3V0IChDb250cm9sbGVkU2NoZWR1bGVMb2NrVGVzdCk7IGVhY2ggc3VjaCBncmFudCBpcyBjb3VudGVkIGFzIGEgZmFsbGJhY2suIFRvIGtlZXAgaG9sZHMgZnJvbSBnb2luZyBzdGFsZSwgYSB3b3ZlbiBPYmplY3Qud2FpdCBvciBDb25kaXRpb24uYXdhaXQgaGFuZHMgaXRzIGhvbGRzIGJhY2sgYmVmb3JlIHdhaXRpbmcgYW5kIHRha2VzIHRoZW0gYWdhaW4gYWZ0ZXIgKHJlbGVhc2luZ0ZvcldhaXQsIHJlYWNxdWlyZWRBZnRlcldhaXQ7IGxvY2tPZiBmaW5kcyBhIGNvbmRpdGlvbiYjMzk7cyBSZWVudHJhbnRMb2NrIGJ5IGFza2luZyBpdCksIGFuZCBhIHdvcmtlciByZS1jb25maXJtcyBpdHMgb3duIHJlY29yZGVkIGhvbGRzIHdpdGggVGhyZWFkLmhvbGRzTG9jayBvciBpc0hlbGRCeUN1cnJlbnRUaHJlYWQgYXQgZWFjaCBvZiBpdHMgcG9pbnRzIGFuZCBhdCBsZWF2ZSgpLCBvbiBpdHMgb3duIHRocmVhZCwgc28gdGhlIGFuc3dlciBmb2xsb3dzIGl0cyBwcm9ncmFtIG9yZGVyIGFuZCBncmFudCgpIHN0aWxsIHJlYWRzIG5vIHRocmVhZCBzdGF0ZSAoIzEwNDgpLiBPbmx5IHdhdGNoKCkgbWF5IHJlYWQgdGhlIGNsb2NrIG9yIFRocmVhZC5nZXRTdGF0ZSgpLCBhbmQgaXQgcmVhZHMgdGhlIHN0YXRlIGJlZm9yZSBhc2tpbmcgd2hldGhlciB0aGUgcnVubmluZyB3b3JrZXIsIG9yIGFuIGFkb3B0ZWQgY2hpbGQgc3RpbGwgYXJyaXZpbmcsIGlzIHF1ZXVlZCBvbiB0aGUgc2NoZWR1bGUmIzM5O3Mgb3duIGxvY2ssIHdoaWNoIGlzIHRoZSBzY2hlZHVsZXImIzM5O3Mgd2FpdCBhbmQgbmV2ZXIgYW4gZXNjYXBlICgjMTA2NSwgIzEwNzIpOyBlYWNoIGRlY2lzaW9uIGl0IG1ha2VzIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCB3aGljaCBpcyB3aGF0IHRlbGxzIHRoZSBydW5uZXIgdGhlIHNlZWQgbm8gbG9uZ2VyIHJlcGxheXMgZXhhY3RseSwgd2l0aCBvbmUgZXhjZXB0aW9uOiBhbiBhZG9wdGVkIGNoaWxkIHdob3NlIHRocmVhZCBoYXMgdGVybWluYXRlZCBpcyBtYXJrZWQgZG9uZSwgbm90IGVzY2FwZWQgKCMxMDI0KSwgYmVjYXVzZSB3aGlsZSBpdCByYW4gdG8gaXRzIGVuZCBldmVyeSBwZWVyIHdhcyB3YWl0aW5nLCBzbyB0aGUgc3RhdGUgdGhlIG5leHQgZ3JhbnQgcmVhZHMgaXMgdGhlIHNhbWUgd2hlbmV2ZXIgd2F0Y2goKSBub3RpY2VzLiBBZG9wdGVkIGNoaWxkcmVuIGFyZSByZWFkeSBmcm9tIHRoZSBtb21lbnQgdGhleSBhcmUgYWRvcHRlZCwgc28gYSBncmFudCBuZXZlciBkZXBlbmRzIG9uIGhvdyBsb25nIHRoZSBPUyB0YWtlcyB0byBzdGFydCBhIHRocmVhZDsgYW4gYWRvcHRlZCBleGVjdXRvciB0YXNrICgjMTA0OSkgaXMgcmVhZHkgZnJvbSBpdHMgd292ZW4gc3VibWlzc2lvbiB0aGUgc2FtZSB3YXksIGpvaW5zIGF0IHRhc2tTdGFydGluZyBvbiB0aGUgcG9vbCB0aHJlYWQgYW5kIGxlYXZlcyBhdCB0YXNrRW5kZWQsIGFuZCBvbmUgdGhhdCBoYXMgbm90IHN0YXJ0ZWQgd2l0aGluIFNUQUxMX05BTk9TIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCBzaW5jZSBpdHMgZXhlY3V0b3IgbWF5IG5ldmVyIHJ1biBpdC4gQSB3b3JrZXIgd2FpdGluZyBhdCBhIHJlbmRlenZvdXMgaXMgT1VUU0lERSwgbm90IGVzY2FwZWQgKCMxMDIxKSwgYW5kIG5vIGdyYW50IGlzIG1hZGUgd2hpbGUgb25lIGlzIG91dHNpZGUgb24gaXRzIHdheSBiYWNrIG9yIHdoZW4gdGhlIGxhc3Qgd29ya2VyIHN0ZXBzIG91dCwgc28gdGhlIG9yZGVyIGEgcmVuZGV6dm91cyByZWxlYXNlcyB3b3JrZXJzIGluIG5ldmVyIGRlY2lkZXMgd2hvIHJ1bnMgbmV4dC4gQSBncmFudCgpIHRoYXQgcmVhZCB0aW1lIG9yIHRocmVhZCBzdGF0ZSwgb3IgYW4gZXNjYXBlIGxlZnQgdW5jb3VudGVkLCBzdGlsbCBwYXNzZXMgZXZlcnkgcnVuIGFuZCBtYWtlcyB0aGUgcHJpbnRlZCByZXBsYXkgbGluZSBhIGZhbHNlIHByb21pc2UuPC9ub3RlPgogICAgPC9lbGVtZW50PgogIDwvY29yZV9lbGVtZW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8Y29yZV9lbGVtZW50cz4gYXJlIHdlbGwtdGVzdGVkIGNvcmUgY29tcG9uZW50cy4gTWFrZSBjaGFuZ2VzIHdpdGggZXh0cmVtZSBjYXV0aW9uIGFuZCB2ZXJpZnkgY29tcHJlaGVuc2l2ZSB0ZXN0IGNvdmVyYWdlIGJlZm9yZSBwcm9wb3NpbmcgbW9kaWZpY2F0aW9ucy48L3J1bGU+CiAgPHBlcmZvcm1hbmNlX2NvbnN0cmFpbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIiPgogICAgICA8Y29uc3RyYWludD5yZWNvcmRJbnZvY2F0aW9uU3RhcnQoKSBhbmQgcmVjb3JkSW52b2NhdGlvbkVuZCgpIGFyZSBjYWxsZWQgb24gdGhlIGhvdCBwYXRoIGluc2lkZSBldmVyeSBpbnZvY2F0aW9uIHJvdW5kLiBLZWVwIHRoZW0gYWxsb2NhdGlvbi1mcmVlIGFuZCBhdm9pZCBhY3F1aXJpbmcgbG9ja3MgaW4gdGhlIGNvbW1vbiBjYXNlLjwvY29uc3RyYWludD4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2l0ZUNhcHR1cmUiPgogICAgICA8Y29uc3RyYWludD5DYWxsZWQgZnJvbSBkZXRlY3RvciByZWNvcmRBY2Nlc3MgcGF0aHM7IGRvIG5vdCBhbGxvY2F0ZSB3aGVuIGEgc2l0ZSBpcyBhbHJlYWR5IGNhcHR1cmVkIGZvciBhIGdpdmVuIGtleS48L2NvbnN0cmFpbnQ+CiAgICA8L2VsZW1lbnQ+CiAgPC9wZXJmb3JtYW5jZV9jb25zdHJhaW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8cGVyZm9ybWFuY2VfY29uc3RyYWludHM+IGFyZSBvbiBhIGhvdCBwYXRoLiBOZXZlciBpbnRyb2R1Y2UgTyhuwrIpIG9yIHdvcnNlIGNvbXBsZXhpdHkuIEFsd2F5cyByZWFzb24gYWJvdXQgdGltZSBhbmQgc3BhY2UgY29tcGxleGl0eSBiZWZvcmUgc3VnZ2VzdGluZyBjaGFuZ2VzLjwvcnVsZT4KICA8Y29udHJhY3Rfc2lnbmF0dXJlcz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRDb2xsZWN0aW9uSG9va3MiPgogICAgICA8cmVhc29uPkNhbGxlZCBmcm9tIGJ5dGVjb2RlIHRoZSBhZ2VudCByZXdyaXRlcywgbm90IGZyb20gc291cmNlOiB0aGUgbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBhcmUgbWF0Y2hlZCBieSBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyIGFuZCBjYW5ub3QgY2hhbmdlIGluZGVwZW5kZW50bHkgb2YgaXQuIEV2ZXJ5IGhvb2sgbXVzdCBlbmQgYnkgcGVyZm9ybWluZyB0aGUgb3JpZ2luYWwgb3BlcmF0aW9uIGFuZCBtdXN0IG5ldmVyIHRocm93IG9uIHRoZSByZWNvcmRpbmcgcGF0aCAtIGl0IHJ1bnMgaW5zaWRlIHRoZSB1c2VyJiMzOTtzIGNvZGUsIHNvIGFuIGV4Y2VwdGlvbiBoZXJlIHN1cmZhY2VzIGFzIGEgZmFpbHVyZSBpbiB0aGVpciB0ZXN0LiBSZWNvcmRpbmcgaXMgYmVzdC1lZmZvcnQgYnkgZGVzaWduOiBubyBjb250ZXh0LCBhIGRpc2FibGVkIGRldGVjdG9yLCBvciBhIHR5cGUgdGhlIGxpYnJhcnkga25vd3MgaXMgdGhyZWFkLXNhZmUgYWxsIG1lYW4gcmVjb3JkIG5vdGhpbmcgYW5kIGRlbGVnYXRlLiBBIHF1ZXVlIG9mZmVyIG9yIHRha2UgaG9vayB3aXRoIGEgdHJhaWxpbmcgT2JqZWN0IHBhcmFtZXRlciBpcyB0aGUgdmFyaWFudCB0aGUgd2VhdmVyIGNhbGxzIHdpdGggdGhlIGVuY2xvc2luZyBtZXRob2QmIzM5O3Mgb3duIG1vbml0b3I6IHRoaXMgaW4gYW4gaW5zdGFuY2UgbWV0aG9kLCB0aGUgY2xhc3MgaW4gYSBzdGF0aWMgc3luY2hyb25pemVkIG9uZS4gQSBzeW5jaHJvbml6ZWQgbWV0aG9kIGhvbGRzIGl0IHdpdGggbm8gaW5zdHJ1Y3Rpb24gdG8gc2F5IHNvICgjNzk2KSwgYW5kIGEgaGVscGVyIHRoYXQgbWV0aG9kIGNhbGxzIGhvbGRzIGl0IHRvbyAoIzc1MSksIHNvIHRoZSBob29rIGNvdW50cyBpdCBhbW9uZyB0aGUgaGVsZCBsb2NrcyBleGFjdGx5IHdoZW4gVGhyZWFkLmhvbGRzTG9jayBzYXlzIHNvLCBhbmQgdGhlIHR3by1hcmd1bWVudCBmb3JtIGRlbGVnYXRlcyB3aXRoIG51bGwuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFnZW50Q29uY3VycmVuY3lVdGlsSG9va3MiPgogICAgICA8cmVhc29uPkNhbGxlZCBmcm9tIGJ5dGVjb2RlIHRoZSBhZ2VudCByZXdyaXRlczogbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBoZXJlIGFyZSBtYXRjaGVkIGJ5IENvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIuQ09OQ1VSUkVOQ1lfRU5UUklFUyBhbmQgY2Fubm90IGNoYW5nZSBpbmRlcGVuZGVudGx5IG9mIGl0LiBFdmVyeSBob29rIG11c3QgcGVyZm9ybSB0aGUgb3JpZ2luYWwgb3BlcmF0aW9uIGFuZCBwcm9wYWdhdGUgaXRzIGV4Y2VwdGlvbnMgdW5jaGFuZ2VkLCBJbnRlcnJ1cHRlZEV4Y2VwdGlvbiBpbmNsdWRlZCAtIHRoZXNlIHR5cGVzIHRocm93IGl0IGFzIGEgbWF0dGVyIG9mIGNvdXJzZSBhbmQgc3dhbGxvd2luZyBvbmUgd291bGQgY2hhbmdlIHRoZSBpbnRlcnJ1cHRpb24gc2VtYW50aWNzIG9mIHRoZSBjb2RlIHVuZGVyIHRlc3QuIFJlY29yZCBhZnRlciBhY3F1aXJpbmcgYW5kIGJlZm9yZSByZWxlYXNpbmcsIHRoZSBjb250YWlubWVudCBydWxlIEFnZW50TG9ja0hvb2tzIGRvY3VtZW50cywgYW5kIHJlY29yZCBub3RoaW5nIHdoZW4gdGhlIHVuZGVybHlpbmcgY2FsbCB0aHJvd3MsIGV4Y2VwdCB0aGF0IGEgc3VibWl0IG9yIGV4ZWN1dGUgdGhlIGV4ZWN1dG9yIHJlZnVzZXMgcmVjb3JkcyB0aGUgUmVqZWN0ZWRFeGVjdXRpb25FeGNlcHRpb24gd2l0aCBUaHJlYWRQb29sTW9uaXRvciBiZWZvcmUgcmV0aHJvd2luZyB0aGF0IHNhbWUgZXhjZXB0aW9uICgjMTA1NSkuIG9mZmVyLCBwb2xsIGFuZCB0aGUgdGltZWQgYXdhaXQgbXVzdCByZWNvcmQgdGhlaXIgYWN0dWFsIHJldHVybiB2YWx1ZTogdGhlIGJvb2xlYW4gYSBjYWxsZXIgZGlzY2FyZHMgaXMgdGhlIHdob2xlIGJ1ZyB0aGVzZSBkZXRlY3RvcnMgcmVwb3J0LiBUaGUgb2JzZXJ2ZSogY2FsbCBtdXN0IHN0YXkgYWhlYWQgb2YgdGhlIG9wZXJhdGlvbjogaXQgaXMgd2hlcmUgTGF0Y2hNaXN1c2VEZXRlY3RvciBhbmQgQmxvY2tpbmdRdWV1ZURldGVjdG9yIGxlYXJuIGEgc3ViamVjdCBleGlzdHMgYXQgYWxsLCBhbmQgdGhlIGxhdGNoJiMzOTtzIHN0YXJ0aW5nIGNvdW50IGlzIG9ubHkgcmVhZGFibGUgYmVmb3JlIHRoaXMgY2FsbCBkZWNyZW1lbnRzIGl0LiBvZmZlclJlc3VsdERpc2NhcmRlZCBpcyBub3QgYW4gb3BlcmF0aW9uOiB0aGUgd2VhdmVyIHN1YnN0aXR1dGVzIGl0IGZvciB0aGUgUE9QIHRoYXQgZm9sbG93cyBhbiBvZmZlciB3aG9zZSBib29sZWFuIHRoZSBjYWxsZXIgbmV2ZXIgcmVhZCwgc28gaXQgaXMgYWx3YXlzIHRoZSBpbnN0cnVjdGlvbiBhZnRlciBvbmUgb2YgdGhlIG9mZmVyIGhvb2tzIG9uIHRoZSBzYW1lIHRocmVhZCwgYW5kIGl0IG11c3Qgc3RheSB0aGF0IHdheSAtIHRoZSBkZXRlY3RvciBjb3JyZWxhdGVzIGl0IHRvIHRoZSBvZmZlciByZWNvcmRlZCBpbW1lZGlhdGVseSBiZWZvcmUsIGFuZCB0aGF0IGNvcnJlbGF0aW9uIGlzIGV4YWN0IG9ubHkgYmVjYXVzZSB0aGUgd2VhdmVyIGVtaXRzIGl0IGluIHBsYWNlIG9mIHRoZSBQT1AgYW5kIG5vd2hlcmUgZWxzZS48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRDb25zdHJ1Y3Rpb25Ib29rcyI+CiAgICAgIDxyZWFzb24+Q2FsbGVkIGZyb20gYnl0ZWNvZGUgdGhlIGFnZW50IGluc2VydHMsIG5vdCBmcm9tIHNvdXJjZTogQ29uc3RydWN0aW9uV2VhdmVyIG1hdGNoZXMgdGhlc2UgbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBhdCB3ZWF2ZSB0aW1lLCBzbyBub25lIGNhbiBjaGFuZ2UgaW5kZXBlbmRlbnRseSBvZiBpdC4gVGhlc2UgYXJlIGluc2VydGVkIGNhbGxzLCBub3Qgc3Vic3RpdHV0aW9uczogdGhlcmUgaXMgbm8gb3JpZ2luYWwgb3BlcmF0aW9uIHRvIHBlcmZvcm0sIGFuZCBlYWNoIG11c3QgaGFuZCBiYWNrIGV4YWN0bHkgd2hhdCB0aGUgc3RhY2sgaGVsZCAobGlua2VkSGFzaE1hcEFjY2Vzc09yZGVyIHJldHVybnMgaXRzIGFyZ3VtZW50IHVuY2hhbmdlZCwgb3IgdGhlIGNvbnN0cnVjdG9yIHdvdWxkIGJ1aWxkIGEgbWFwIGluIHRoZSB3cm9uZyBvcmRlcikuIFRoZXkgcnVuIGluc2lkZSB1c2VyIGNvbnN0cnVjdG9ycywgc28gdGhleSBtdXN0IG5ldmVyIHRocm93LiBjb25zdHJ1Y3RvclJldHVybmVkIGFuZCBjb25zdHJ1Y3RvclJlc3VtZWQgcnVuIGZvciBldmVyeSBvYmplY3QgYW55IHdvdmVuIGNsYXNzIGJ1aWxkczogd2hpbGUgbm8gY29uc3RydWN0aW9uIGlzIHRyYWNrZWQgdGhleSBtdXN0IHN0YXkgYSBjaGVjayBvZiBhbiBlbXB0eSBtYXAsIHdpdGggbm8gYWxsb2NhdGlvbiBhbmQgbm8gc3RhY2sgd2Fsay4gY29tcGxldGFibGVGdXR1cmVDb25zdHJ1Y3RlZCBydW5zIGZvciBldmVyeSBuZXcgQ29tcGxldGFibGVGdXR1cmUoKSBpbiB3b3ZlbiBjb2RlIGFuZCBtdXN0IGNvc3Qgb25lIGNvbnRleHQgbG9va3VwIG91dHNpZGUgYSBydW4gKCMxMDU0KS48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRHY0hvb2tzIj4KICAgICAgPHJlYXNvbj5DYWxsZWQgZnJvbSBieXRlY29kZSB0aGUgYWdlbnQgcmV3cml0ZXM6IHRoZSBtZXRob2QgbmFtZXMgYW5kIGVyYXNlZCBzaWduYXR1cmVzIGhlcmUgKGdjKCkgZm9yIFN5c3RlbS5nYywgcnVudGltZUdjKFJ1bnRpbWUpIGZvciBSdW50aW1lLmdjKSBhcmUgbWF0Y2hlZCBieSBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyLkdDX0VOVFJJRVMgYW5kIGNhbm5vdCBjaGFuZ2UgaW5kZXBlbmRlbnRseSBvZiBpdC4gUmVjb3JkIGJlZm9yZSBjb2xsZWN0aW5nLCBub3QgYWZ0ZXI6IHRoZSBmaW5kaW5nIGlzIHRoYXQgdGhlIGNhbGwgd2FzIG1hZGUsIGFuZCBhIGhvb2sgdGhhdCByZWNvcmRlZCBhZnRlcndhcmRzIHdvdWxkIGxvc2UgdGhlIGV2ZW50IGlmIHRoZSBjb2xsZWN0aW9uIG5ldmVyIHJldHVybmVkLiBFYWNoIGhvb2sgbXVzdCBwZXJmb3JtIHRoZSBvcmlnaW5hbCBjYWxsLCBTeXN0ZW0uZ2MoKSBvciB0aGUgcmVjZWl2ZXImIzM5O3MgZ2MoKSwgc28gdGhhdCB3ZWF2aW5nIGRvZXMgbm90IGNoYW5nZSB3aGF0IHRoZSBwcm9ncmFtIGRvZXMgLSBhIHN1YnN0aXR1dGlvbiB0aGF0IHNpbGVudGx5IGRyb3BwZWQgdGhlIGNvbGxlY3Rpb24gd291bGQgYWx0ZXIgYmVoYXZpb3VyIHRoZSB0ZXN0IG1heSBkZXBlbmQgb24sIHdoaWNoIGlzIHRoZSBvbmUgdGhpbmcgbm8gd2VhdmUgbWF5IGRvLiBVbmxpa2UgQWdlbnRTbGVlcEhvb2tzIHRoZXJlIGlzIGRlbGliZXJhdGVseSBubyBIZWxkTG9ja3MgZ3VhcmQ6IGFuIGV4cGxpY2l0IGNvbGxlY3Rpb24gaXMgdGhlIGJ1ZyB3aGV0aGVyIG9yIG5vdCBhIGxvY2sgaXMgaGVsZCwgYW5kIGFkZGluZyBhIGd1YXJkIHdvdWxkIHNpbGVuY2UgdGhlIGNvbW1vbiBjYXNlLiBUaGUgc3RhY2sgd2FsayBtdXN0IHNraXAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdCBmcmFtZXMsIG9yIGV2ZXJ5IGZpbmRpbmcgd291bGQgbmFtZSB0aGlzIGNsYXNzIGluc3RlYWQgb2YgdGhlIGNhbGxlci48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRMb2NrSG9va3MiPgogICAgICA8cmVhc29uPkNhbGxlZCBmcm9tIGJ5dGVjb2RlIHRoZSBhZ2VudCByZXdyaXRlczogbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBhcmUgbWF0Y2hlZCBieSBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyLmxvY2tTdWJzdGl0dXRpb25zIGFuZCBjYW5ub3QgY2hhbmdlIGluZGVwZW5kZW50bHkgb2YgaXQuIFRoZSBhY3F1aXJlLWFmdGVyIC8gcmVsZWFzZS1iZWZvcmUgb3JkZXJpbmcgaXMgYSBzYWZldHkgcHJvcGVydHksIG5vdCBhIHN0eWxlIGNob2ljZSAtIHJlY29yZGluZyBhIGxvY2sgYXMgaGVsZCBiZWZvcmUgaXQgaXMgYWN0dWFsbHkgaGVsZCB3b3VsZCBtYWtlIGFub3RoZXIgdGhyZWFkJiMzOTtzIHJhY2luZyBhY2Nlc3MgcmVhZCBhcyBndWFyZGVkLCB3aGljaCBpcyB0aGUgb25lIGVycm9yIGRpcmVjdGlvbiB0aGlzIGxpYnJhcnkgbXVzdCBuZXZlciB0YWtlLiBFdmVyeSBob29rIG11c3QgcGVyZm9ybSB0aGUgb3JpZ2luYWwgb3BlcmF0aW9uIGFuZCBwcm9wYWdhdGUgaXRzIGV4Y2VwdGlvbnMgdW5jaGFuZ2VkLiBUaGUgZGV0ZWN0b3IgZGVsaXZlcnkgaW5oZXJpdHMgdGhlIHNhbWUgYWNxdWlyZS1hZnRlciAvIHJlbGVhc2UtYmVmb3JlIG9yZGVyaW5nIGFzIHRoZSBsb2Nrc2V0IGFuZCBtdXN0IGtlZXAgaXQ6IExvY2tPcmRlclZhbGlkYXRvciBidWlsZHMgaXRzIG5lc3RpbmcgZWRnZXMgZnJvbSB0aGUgb3JkZXIgdGhlc2UgY2FsbHMgYXJyaXZlIGluLCBzbyBkZWxpdmVyaW5nIGFuIGFjcXVpc2l0aW9uIGVhcmx5IHdvdWxkIGludmVudCBhIGhvbGQtYW5kLXdhaXQgZWRnZSB0aGF0IG5ldmVyIGV4aXN0ZWQuIEl0IHJlc29sdmVzIGVhY2ggZGV0ZWN0b3IgdGhyb3VnaCBhIG51bGwtcmV0dXJuaW5nIEFzeW5jVGVzdENvbnRleHQgYWNjZXNzb3IgYmVjYXVzZSBhIHdvdmVuIGNhbGwgc2l0ZSBydW5zIGluIGNvZGUgdGhhdCBkb2VzIG5vdCBrbm93IGEgdGVzdCBleGlzdHMsIHNvIG5vIGNvbnRleHQgaXMgdGhlIG9yZGluYXJ5IGNhc2UgYW5kIG11c3QgY29zdCBhIG51bGwgY2hlY2sgcmF0aGVyIHRoYW4gYW4gZXhjZXB0aW9uLiBEZXRlY3RvckZlZWRzIGxpc3RzIHRoZXNlIHRocmVlIGFzIEFHRU5ULWZlZCBhbmQgRGV0ZWN0b3JGZWVkQ292ZXJhZ2VUZXN0IHJlYWRzIHRoaXMgZmlsZSB0byBjaGVjayB0aGUgZGVsaXZlcnkgaXMgc3RpbGwgaGVyZSwgc28gcmVtb3ZpbmcgYSBjYWxsIG1lYW5zIHJlY2xhc3NpZnlpbmcgdGhlIGRldGVjdG9yIGluIHRoZSBzYW1lIGNoYW5nZS48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRNb25pdG9ySG9va3MiPgogICAgICA8cmVhc29uPkNhbGxlZCBmcm9tIGJ5dGVjb2RlIHRoZSBhZ2VudCByZXdyaXRlczogbWV0aG9kIG5hbWVzIGFuZCBlcmFzZWQgc2lnbmF0dXJlcyBoZXJlIGFyZSBtYXRjaGVkIGJ5IENvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIuTU9OSVRPUl9FTlRSSUVTLCBsb29wQmFja0VkZ2UgYnkgbmFtZSB3aXRoIGEgKClWIGRlc2NyaXB0b3IsIGFuZCBtb25pdG9yRmllbGRFbnRlcmVkIGJ5IEZpZWxkQWNjZXNzV2VhdmVyIHdpdGggYW4gKE9iamVjdCwgT2JqZWN0LCBTdHJpbmcpViBkZXNjcmlwdG9yLCBzbyBub25lIGNhbiBjaGFuZ2UgaW5kZXBlbmRlbnRseSBvZiB0aGUgd2VhdmVyLiBtb25pdG9yRmllbGRFbnRlcmVkIHJ1bnMgYmVmb3JlIGEgTU9OSVRPUkVOVEVSIGFuZCBtdXN0IG5vdCB0aHJvdzogYSBudWxsIG1vbml0b3IgaXMgbGVmdCBmb3IgdGhlIE1PTklUT1JFTlRFUiB0byByZWplY3Qgd2l0aCBpdHMgb3duIE51bGxQb2ludGVyRXhjZXB0aW9uLiBFdmVyeSBob29rIG11c3QgcGVyZm9ybSB0aGUgb3JpZ2luYWwgY2FsbCBvbiB0aGUgcmVjZWl2ZXIgYW5kIHByb3BhZ2F0ZSB3aGF0IGl0IHRocm93cyB1bmNoYW5nZWQ6IEludGVycnVwdGVkRXhjZXB0aW9uLCBhbmQgdGhlIElsbGVnYWxNb25pdG9yU3RhdGVFeGNlcHRpb24gb2YgYSBjYWxsIG1hZGUgd2l0aG91dCB0aGUgbW9uaXRvciwgd2hpY2ggaXMgd2h5IG5vdGhpbmcgaXMgcmVjb3JkZWQgdW5sZXNzIFRocmVhZC5ob2xkc0xvY2socmVjZWl2ZXIpLiBSZWNvcmQgdGhlIHdhaXQgYmVmb3JlIHdhaXQoKSByZWxlYXNlcyB0aGUgbW9uaXRvciBhbmQgdGhlIHdha2V1cCBhZnRlciBpdCBpcyByZWFjcXVpcmVkLCBpbiBhIGZpbmFsbHksIHNvIGEgbm90aWZ5IGlzIGp1ZGdlZCBhZ2FpbnN0IHRoZSB0aHJlYWRzIHJlYWxseSB3YWl0aW5nOyByZWNvcmQgYSBub3RpZnkgYmVmb3JlIG1ha2luZyBpdC4gVGhlIHNhbWUgZ29lcyBmb3IgYSBjb250cm9sbGVkIHNjaGVkdWxlJiMzOTtzIHJlY29yZCBvZiB0aGUgaG9sZDogcmVsZWFzaW5nRm9yV2FpdCBiZWZvcmUgd2FpdCgpLCByZWFjcXVpcmVkQWZ0ZXJXYWl0IGluIGFuIG91dGVyIGZpbmFsbHksIHNvIGEgcGVlciB3YWl0aW5nIHRvIGVudGVyIHRoZSBtb25pdG9yIGlzIG5vdCBwYXNzZWQgb3ZlciB3aGlsZSBpdCBpcyBmcmVlICgjMTA0OCkuIGxvb3BCYWNrRWRnZSB0YWtlcyBub3RoaW5nIGFuZCByZXR1cm5zIG5vdGhpbmcgYmVjYXVzZSB0aGUgd2VhdmVyIGluc2VydHMgaXQgaW4gZnJvbnQgb2YgYSBqdW1wIHdob3NlIG9wZXJhbmRzIGFyZSBhbHJlYWR5IG9uIHRoZSBzdGFjay48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRTaGFyZWRJbnN0YW5jZUhvb2tzIj4KICAgICAgPHJlYXNvbj5DYWxsZWQgZnJvbSBieXRlY29kZSB0aGUgYWdlbnQgcmV3cml0ZXM6IHRoZSBtZXRob2QgbmFtZXMgYW5kIGVyYXNlZCBzaWduYXR1cmVzIGhlcmUgYXJlIG1hdGNoZWQgYnkgQ29sbGVjdGlvbkFjY2Vzc1dlYXZlci5TSEFSRURfSU5TVEFOQ0VfRU5UUklFUyBhbmQgY2Fubm90IGNoYW5nZSBpbmRlcGVuZGVudGx5IG9mIGl0LiBFdmVyeSBob29rIG11c3QgcGVyZm9ybSB0aGUgb3JpZ2luYWwgb3BlcmF0aW9uIGFuZCBwcm9wYWdhdGUgaXRzIGV4Y2VwdGlvbnMgdW5jaGFuZ2VkLCBhbmQgbXVzdCByZWNvcmQgYmVmb3JlIGRlbGVnYXRpbmcgb25seSB3aGVyZSB0aGUgb3JpZ2luYWwgY2Fubm90IHRocm93IGZpcnN0IC0gdGhlIGRldGVjdG9yJiMzOTtzIHF1ZXN0aW9uIGlzICYjMzk7ZGlkIHR3byB0aHJlYWRzIHRvdWNoIHRoaXMgaW5zdGFuY2UmIzM5Oywgd2hpY2ggYSBjYWxsIHRoYXQgdGhyZXcgc3RpbGwgYW5zd2Vycy4gQSByZWNlaXZlciB0eXBlIHRoYXQgaGFzIHRocmVhZC1zYWZlIHN1YmNsYXNzZXMgbWF5IGJlIHdvdmVuIG9ubHkgd2hlbiBpdHMgaG9vayBjaGVja3MgdGhlIHJ1bnRpbWUgdHlwZSBiZWZvcmUgcmVjb3JkaW5nOiBEYXRlRm9ybWF0IHJlY29yZHMgb25seSBhIFNpbXBsZURhdGVGb3JtYXQgYW5kIEFwcGVuZGFibGUgb25seSBhIFN0cmluZ0J1aWxkZXIgKCM1NDIpLiBXaXRob3V0IHRoYXQgY2hlY2ssIFJhbmRvbSBiZWluZyB0aGUgc3RhbmRpbmcgZXhhbXBsZSB3aXRoIFRocmVhZExvY2FsUmFuZG9tLCBldmVyeSBzdWJzdGl0dXRlZCBjYWxsIHNpdGUgYmVjb21lcyBhIHBvdGVudGlhbCBmYWxzZSBwb3NpdGl2ZSBvbiBjb3JyZWN0IGNvZGUuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFnZW50U2xlZXBIb29rcyI+CiAgICAgIDxyZWFzb24+Q2FsbGVkIGZyb20gYnl0ZWNvZGUgdGhlIGFnZW50IHJld3JpdGVzLCB0aHJvdWdoIHRoZSBzdGF0aWMgc3Vic3RpdHV0aW9uIHBhdGg6IHRoZSBtZXRob2QgbmFtZSBhbmQgZXJhc2VkIHNpZ25hdHVyZSBoZXJlIGFyZSBtYXRjaGVkIGJ5IENvbGxlY3Rpb25BY2Nlc3NXZWF2ZXIuU1RBVElDX0VOVFJJRVMgYW5kIGNhbm5vdCBjaGFuZ2UgaW5kZXBlbmRlbnRseSBvZiBpdC4gVGhlIGd1YXJkIGlzIHRoZSBwb2ludCAtIHJlY29yZGluZyBvbmx5IHdoZW4gdGhlIHRocmVhZCYjMzk7cyBsb2Nrc2V0IGhvbGRzIGEgbG9jayB0aGUgZGV0ZWN0b3IgY2FuIGNvbmZpcm0gaXMgd2hhdCBzZXBhcmF0ZXMgdGhlIGJ1ZyBmcm9tIHJhdGUgbGltaXRpbmcsIGJhY2stb2ZmIGFuZCBwb2xsaW5nLCB3aGljaCBhcmUgb3JkaW5hcnkgdXNlcyBvZiBUaHJlYWQuc2xlZXAgYW5kIHZhc3RseSBtb3JlIGNvbW1vbi4gUmVjb3JkIGJlZm9yZSBzbGVlcGluZywgbm90IGFmdGVyOiBhIHNsZWVwIGludGVycnVwdGVkIG1pZC13YXkgc3RpbGwgaGVsZCB0aGUgbG9jayBmb3IgYXMgbG9uZyBhcyBpdCBsYXN0ZWQsIGFuZCB0aGUgZmluZGluZyBpcyBhYm91dCB0aGUgaG9sZGluZyByYXRoZXIgdGhhbiB0aGUgY29tcGxldGluZy4gVGhlIGhvb2sgbXVzdCBwZXJmb3JtIHRoZSBvcmlnaW5hbCBzbGVlcCBhbmQgcHJvcGFnYXRlIEludGVycnVwdGVkRXhjZXB0aW9uIHVuY2hhbmdlZC4gSXQgbXVzdCBuZXZlciBjYWxsIHRoZSBzaW5nbGUtYXJndW1lbnQgcmVjb3JkU2xlZXA6IHRoYXQgb25lIHJlc29sdmVzIHRoZSBoZWxkIG1vbml0b3JzIHRocm91Z2ggVGhyZWFkTVhCZWFuLCB3aGljaCBkb2VzIG5vdCByZXBvcnQgdmlydHVhbCB0aHJlYWRzLCBzbyBvbiB0aGUgcnVubmVyJiMzOTtzIGRlZmF1bHQgd29ya2VycyBpdCBhbnN3ZXJzIG5vbmUgYW5kIHRoZSBkZXRlY3RvciBuZXZlciBmaXJlcy4gVGhlIHBsYWluIGZvcm1zIG11c3QgaGFuZCB0aGUgZGV0ZWN0b3IgdGhlIHdob2xlIGxvY2tzZXQgKHJlY29yZFNsZWVwVW5kZXJIZWxkTG9ja3MpIHJhdGhlciB0aGFuIGl0cyB0b3AgZW50cnksIHdoaWNoIGRyb3BwZWQgYSBTdGFtcGVkTG9jayBvbiB0b3AgYW5kIGEgY29uZmlybWFibGUgbG9jayBiZWxvdyBhbiB1bmNvbmZpcm1hYmxlIG9uZSAoIzU0MykuIEEgc3ViLW1pbGxpc2Vjb25kIHNsZWVwIG11c3Qgcm91bmQgdXAgdG8gb25lIHJhdGhlciB0aGFuIHRydW5jYXRlIHRvIHplcm86IHRoZSBkZXRlY3RvciBkcm9wcyBhbnl0aGluZyBhdCBvciBiZWxvdyB6ZXJvLCBzbyB0cnVuY2F0aW5nIHR1cm5zIGEgcmVhbCBsb2NrLWhvbGRpbmcgcGF1c2UgaW50byB0aGUgc2FtZSBzaWxlbmNlIGFuIHVud292ZW4gY2FsbCBzaXRlIHByb2R1Y2VzLiBUaGUgcHJvY2Vzcy1nbG9iYWwgd3JpdGVzIChTeXN0ZW0uc2V0UHJvcGVydHkgYW5kIGNsZWFyUHJvcGVydHksIExvY2FsZS5zZXREZWZhdWx0LCBUaW1lWm9uZS5zZXREZWZhdWx0KSBhcmUgdGhlIHNhbWUga2luZCBvZiBzdGF0aWMgc3Vic3RpdHV0aW9uOiBlYWNoIHJlY29yZHMgdGhlIHdyaXRlIGJlZm9yZSBwZXJmb3JtaW5nIGl0LCBzbyB0aGUgbG9ja3NldCB0aGUgZGV0ZWN0b3IgcHJvYmVzIGlzIHRoZSBvbmUgdGhlIHdyaXRlIHJhbiB1bmRlciwgYW5kIHJldHVybnMgd2hhdCB0aGUgSkRLIG1ldGhvZCByZXR1cm5lZC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRUaHJlYWRIb29rcyI+CiAgICAgIDxyZWFzb24+Q2FsbGVkIGZyb20gYnl0ZWNvZGUgdGhlIGFnZW50IHJld3JpdGVzOiBtZXRob2QgbmFtZXMgYW5kIGVyYXNlZCBzaWduYXR1cmVzIG9mIHRoZSBob29rcyBDb2xsZWN0aW9uQWNjZXNzV2VhdmVyLlRIUkVBRF9FTlRSSUVTIHN1YnN0aXR1dGVzICh0aHJlYWRTdGFydCwgdGhyZWFkSm9pbiwgdGhyZWFkSXNBbGl2ZSwgdGhyZWFkU2V0RGFlbW9uLCB0aHJlYWRTdGFydFZpcnR1YWwgYW5kIHRoZSBidWlsZGVyJiMzOTtzIHRocmVhZEJ1aWxkZXJTdGFydCwgdGhyZWFkQnVpbGRlckRhZW1vbiwgdGhyZWFkQnVpbGRlclVuc3RhcnRlZCBhbmQgdGhyZWFkQnVpbGRlckZhY3RvcnksIGFuZCB0aHJlYWRGYWN0b3J5TmV3VGhyZWFkKSBhbmQgb2YgdGhyZWFkQ29uc3RydWN0ZWQsIHdoaWNoIFRocmVhZENvbnN0cnVjdGlvbldlYXZlciBpbnNlcnRzIGFmdGVyIGVhY2ggdGhyZWFkIGEgd292ZW4gY2xhc3MgY29uc3RydWN0cywgYW5kIG9mIGludGVycnVwdFN3YWxsb3dpbmdNZXRob2RFbnRlcmVkLCB3aGljaCBJbnRlcnJ1cHRIYW5kbGVyV2VhdmVyIGluc2VydHMgYXQgdGhlIHN0YXJ0IG9mIGEgbWV0aG9kIGhvbGRpbmcgYW4gSW50ZXJydXB0ZWRFeGNlcHRpb24gaGFuZGxlciB0aGF0IG5laXRoZXIgcmV0aHJvd3Mgbm9yIHJlc3RvcmVzIHRoZSBmbGFnLCBhcmUgbWF0Y2hlZCBhdCB3ZWF2ZSB0aW1lLCBhbmQgdGhyZWFkV2VhdmluZ0luc3RhbGxlZCBpcyBpbnZva2VkIGJ5IG5hbWUgZnJvbSBBc3luY1Rlc3RBZ2VudCBhZnRlciB0aGUgdHJhbnNmb3JtZXIgaXMgaW5zdGFsbGVkOyBub25lIG9mIHRoZW0gY2FuIGNoYW5nZSBpbmRlcGVuZGVudGx5IG9mIHRoZSBhZ2VudC4gRXZlcnkgc3Vic3RpdHV0aW5nIGhvb2sgbXVzdCBwZXJmb3JtIHRoZSBvcmlnaW5hbCBjYWxsIG9uIHRoZSByZWNlaXZlciwgb3Igd2hhdCB0aGUgSkRLIGRvZXMgZm9yIGl0IChhIGJ1aWxkZXImIzM5O3Mgc3RhcnQgaXMgdW5zdGFydGVkIHRoZW4gc3RhcnQpLCBhbmQgcHJvcGFnYXRlIHdoYXQgaXQgdGhyb3dzIHVuY2hhbmdlZDsgdGhyZWFkRmFjdG9yeU5ld1RocmVhZCByZXR1cm5zIHdoYXQgdGhlIGZhY3RvcnkgcmV0dXJuZWQsIG51bGwgaW5jbHVkZWQuIHRocmVhZENvbnN0cnVjdGVkIHJlcGxhY2VzIG5vdGhpbmcgYW5kIHJ1bnMgaW5zaWRlIHVzZXIgY29uc3RydWN0b3JzLCBzbyBpdCBwZXJmb3JtcyBubyBjYWxsIGFuZCBtdXN0IG5vdCB0aHJvdzsgaW50ZXJydXB0U3dhbGxvd2luZ01ldGhvZEVudGVyZWQgcmVwbGFjZXMgbm90aGluZyBlaXRoZXIsIHJ1bnMgb24gZXZlcnkgZW50cnkgb2YgdGhlIG1ldGhvZCBpdCB3YXMgaW5zZXJ0ZWQgaW50bywgYW5kIG11c3QgY29zdCBvbmUgc2V0IGxvb2t1cCBvbmNlIGEgcnVuIGhhcyBzZWVuIGl0cyBsb2NhdGlvbnMuIHRocmVhZFNldERhZW1vbiByZWNvcmRzIHRoZSBkZWNpc2lvbiBvbmx5IGFmdGVyIHNldERhZW1vbiByZXR1cm5lZCwgc28gYSBjYWxsIHRoYXQgdGhyb3dzIChhbiBhbHJlYWR5IHN0YXJ0ZWQgdGhyZWFkKSByZWNvcmRzIG5vdGhpbmcuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jQXNzZXJ0Ij4KICAgICAgPHJlYXNvbj5QdWJsaWMgYXNzZXJ0aW9uIHV0aWxpdHkgQVBJIGZvciBBc3luY1Rlc3QgY29uc3VtZXJzLiBhd2FpdFVudGlsKCkgYW5kIGNhcHR1cmUoKSBhcmUgdXNlZCBkaXJlY3RseSBpbiB1c2VyIHRlc3QgY29kZSDigJQgbWV0aG9kIHNpZ25hdHVyZXMgYW5kIHNlbWFudGljcyBtdXN0IG5vdCBjaGFuZ2Ugd2l0aG91dCBhIG1ham9yIHZlcnNpb24gYnVtcC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNGaW5kaW5ncyI+CiAgICAgIDxyZWFzb24+UHVibGljIGFzc2VydGlvbiBBUEkgZm9yIGRldGVjdG9yIGZpbmRpbmdzLiBjb2xsZWN0KCksIHZpb2xhdGlvbnMoKSBhbmQgdGhlIGFzc2VydFh4eCBtZXRob2RzIGFyZSBjYWxsZWQgZGlyZWN0bHkgZnJvbSB1c2VyIHRlc3QgY29kZSDigJQgc2lnbmF0dXJlcyBhbmQgbWF0Y2hpbmcgc2VtYW50aWNzIG11c3Qgbm90IGNoYW5nZSB3aXRob3V0IGEgbWFqb3IgdmVyc2lvbiBidW1wLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3QiPgogICAgICA8cmVhc29uPlB1YmxpYyBhbm5vdGF0aW9uIEFQSSB1c2VkIGRpcmVjdGx5IGluIHVzZXIgdGVzdCBtZXRob2RzLiBBdHRyaWJ1dGUgbmFtZXMsIHR5cGVzLCBhbmQgZGVmYXVsdHMgYXJlIHBhcnQgb2YgdGhlIHN0YWJsZSBwdWJsaWMgQVBJIOKAlCBhbnkgY2hhbmdlIGlzIGEgYnJlYWtpbmcgY2hhbmdlIGZvciBhbGwgY29uc3VtZXJzLiBEZXRlY3RvciBzZWxlY3Rpb24gaXMgYnkgRGV0ZWN0b3JUeXBlIHRocm91Z2ggaW5jbHVkZXMvZXhjbHVkZXMvcHJlc2V0L2RldGVjdEFsbDsgbmV2ZXIgcmVpbnRyb2R1Y2UgYSBwZXItZGV0ZWN0b3IgYm9vbGVhbiBhdHRyaWJ1dGUgKHJlbW92ZWQgaW4gMS4xMy4wLCAjOTIwKS4gVGhlIGJhcmUtYW5ub3RhdGlvbiBzZWxlY3Rpb24gaXMgUHJlc2V0LkVTU0VOVElBTFMgd2l0aCBkZXRlY3RBbGwgPSBmYWxzZSAoMS4xMy4wLCAjOTIzKTogYSBkaWZmZXJlbnQgZGVmYXVsdCBjaGFuZ2VzIHdoYXQgZXZlcnkgdW5jaGFuZ2VkIHRlc3QgaW4gZXZlcnkgY29uc3VtZXIgZGV0ZWN0cy48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0TGlzdGVuZXIiPgogICAgICA8cmVhc29uPlB1YmxpYyBTUEkgaW50ZXJmYWNlIGZvciBvYnNlcnZpbmcgYXN5bmMtdGVzdCBsaWZlY3ljbGUgZXZlbnRzLiBNZXRob2Qgc2lnbmF0dXJlcyBhcmUgcGFydCBvZiB0aGUgc3RhYmxlIEFQSSDigJQgaW1wbGVtZW50b3JzIGJpbmQgdG8gdGhlc2UgZXhhY3QgbmFtZXMgYW5kIHBhcmFtZXRlciB0eXBlcy48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0TGlzdGVuZXJSZWdpc3RyeSI+CiAgICAgIDxyZWFzb24+UHVibGljIEFQSSBmb3IgcmVnaXN0ZXJpbmcgYW5kIHVucmVnaXN0ZXJpbmcgQXN5bmNUZXN0TGlzdGVuZXIgaW5zdGFuY2VzLiByZWdpc3RlcigpLCB1bnJlZ2lzdGVyKCksIGNsZWFyQWxsKCksIGFuZCBmaXJlWHh4KCkgbWV0aG9kcyBhcmUgY2FsbGVkIGJ5IHVzZXIgY29kZSBhbmQgaW5mcmFzdHJ1Y3R1cmUg4oCUIHNpZ25hdHVyZXMgbXVzdCBub3QgY2hhbmdlLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RSdW5uZXIiPgogICAgICA8cmVhc29uPlB1YmxpYyBwcm9ncmFtbWF0aWMgZW50cnkgcG9pbnQgZm9yIHRoZSBOIHggTSBlbmdpbmUsIGNhbGxlZCBmcm9tIG5vbi1KdXBpdGVyIHRlc3QgZnJhbWV3b3JrcyBpbiBLb3RsaW4sIFNjYWxhLCBHcm9vdnkgYW5kIENsb2p1cmUuIHJ1biguLi4pIHNpZ25hdHVyZXMgYW5kIHRoZSBydWxlIHRoYXQgaXQgdGhyb3dzIGV4YWN0bHkgd2hhdCB0aGUgYW5ub3RhdGVkIHBhdGggdGhyb3dzIG11c3Qgbm90IGNoYW5nZSB3aXRob3V0IGEgbWFqb3IgdmVyc2lvbiBidW1wLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5leHRlbnNpb24uQXN5bmNUZXN0RXh0ZW5zaW9uIj4KICAgICAgPHJlYXNvbj5KVW5pdCA1IFRlc3RUZW1wbGF0ZUludm9jYXRpb25Db250ZXh0UHJvdmlkZXIgU1BJLiBUaGUgdHdvIG92ZXJyaWRkZW4gbWV0aG9kcyAoc3VwcG9ydHNUZXN0VGVtcGxhdGUsIHByb3ZpZGVUZXN0VGVtcGxhdGVJbnZvY2F0aW9uQ29udGV4dHMpIG11c3QgcHJlc2VydmUgdGhlaXIgZXhhY3Qgc2lnbmF0dXJlcyBhcyBtYW5kYXRlZCBieSBKVW5pdC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0LkZvcm1hdHRlciI+CiAgICAgIDxyZWFzb24+UHVibGljIGZvcm1hdHRlciBTUEkuIGZvcm1hdChMaXN0Jmx0O1Zpb2xhdGlvbiZndDspIHNpZ25hdHVyZSBtdXN0IG5vdCBjaGFuZ2Ug4oCUIGJ1aWx0LWluIGZvcm1hdHRlcnMgYW5kIHVzZXItcHJvdmlkZWQgbGFtYmRhcyBiaW5kIHRvIHRoaXMgZXhhY3QgdHlwZS48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkFnZW50QXV0b0F0dGFjaCI+CiAgICAgIDxyZWFzb24+VGhlIC1EYXN5bmN0ZXN0LmFnZW50IHZhbHVlcyBhcmUgdHlwZWQgaW4gdXNlcnMmIzM5OyBidWlsZHMgYW5kIGluIHRoaXMgcmVwb3NpdG9yeSYjMzk7cyBvd246IGNvcnB1cy1ldmFsJiMzOTtzIHJlY29yZGluZyBhbmQgYWdlbnQtb2ZmIGxhbmVzIHNldCBpdCB0byBvZmYsIGFuZCBlYWNoIGxhbmUgaXMgdmFsaWQgb25seSB3aGlsZSB0aGUgYWdlbnQgc3RheXMgZGV0YWNoZWQsIHNvIHJlbmFtaW5nIG9yIGRyb3BwaW5nIHRoZSBvcHQtb3V0IHNpbGVudGx5IGF0dGFjaGVzIHRoZSBhZ2VudCB0aGVyZSBhbmQgdm9pZHMgYm90aCBsYW5lcyYjMzk7IG1lYXN1cmVtZW50cy4gVGhpcyBpcyB0aGUgZmFsbGJhY2ssIG5vdCB0aGUgcmVjb21tZW5kZWQgcm91dGU6IGxvYWRpbmcgYW4gYWdlbnQgaW50byBhIHJ1bm5pbmcgSlZNIHdhcm5zIG9uIEpESyAyMSsgYW5kIEpFUCA0NTEgc2F5cyBhIGZ1dHVyZSBKREsgd2lsbCByZWZ1c2UgaXQsIHNvIHRoZSBSRUFETUUgcXVpY2sgc3RhcnQgYXR0YWNoZXMgYXQgc3RhcnR1cCB3aXRoIC1qYXZhYWdlbnQgYW5kIHRoaXMgY2xhc3MgbXVzdCBrZWVwIGxvZ2dpbmcgbW9kZT1ydW50aW1lIHdpdGggYSBoaW50IG5hbWluZyB0aGF0IHJvdXRlIChBdHRhY2hlZEJ5RGVmYXVsdFRlc3QpLiBJdHMgZGVmYXVsdCBhcmd1bWVudHMgKGZpZWxkcz10cnVlLGNvbGxlY3Rpb25zPXRydWUsIGluY2x1ZGVzPSB0aGUgZmlyc3QgdGhyZWUgc2VnbWVudHMgb2YgdGhlIHRlc3QgY2xhc3MmIzM5O3MgcGFja2FnZSwgb3Igb2YgdGhlIGJvZHkmIzM5O3MgY2xhc3MgZm9yIEFzeW5jVGVzdFJ1bm5lci5ydW4sICMxMDQyKSBhcmUgZG9jdW1lbnRlZCBpbiBkb2NzL2FnZW50L2F0dGFjaGluZy5tZCBzZWN0aW9uIDMuMC4xIHdpdGggbWVhc3VyZWQgY29zdHMuIFRoZSBkZWZhdWx0IG11c3QgbmV2ZXIgYXR0YWNoIHdpdGhvdXQgYW4gaW5jbHVkZTogYW4gZW1wdHkgaW5jbHVkZXM9IHdlYXZlcyBKVW5pdCBhbmQgdGhlIGJ1aWxkIHRvb2wgaW4gZXZlcnkgY29uc3VtZXImIzM5O3MgdGVzdCBKVk0uPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnNwaS5EZXRlY3RvciI+CiAgICAgIDxyZWFzb24+UHVibGljIFNQSSBpbnRlcmZhY2UuIGlkKCksIHR5cGUoKSwgYW5hbHl6ZSgpLCBvblRlc3RTdGFydCgpLCBhbmQgb25UZXN0RW5kKCkgc2lnbmF0dXJlcyBhcmUgcGFydCBvZiB0aGUgc3RhYmxlIGV4dGVuc2lvbiBjb250cmFjdCDigJQgaW1wbGVtZW50b3JzIGJpbmQgdG8gdGhlc2UgZXhhY3QgbmFtZXMgYW5kIHBhcmFtZXRlciB0eXBlcy4gaWQoKSBhbmQgdHlwZSgpIGFyZSBkZWZhdWx0cyBzbyBhIGRldGVjdG9yIGNhbiBkZWNsYXJlIGFuIGlkZW50aXR5IG9mIGl0cyBvd24gKCM5MTkpOyBtYWtpbmcgZWl0aGVyIGFic3RyYWN0IGFnYWluIGJyZWFrcyBldmVyeSBpbXBsZW1lbnRvciB0aGF0IG92ZXJyaWRlcyBvbmx5IHRoZSBvdGhlci48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3Quc3BpLkRldGVjdG9yRmFjdG9yeSI+CiAgICAgIDxyZWFzb24+UHVibGljIFNQSSBpbnRlcmZhY2UgZm9yIFNlcnZpY2VMb2FkZXItYmFzZWQgZGV0ZWN0b3IgZGlzY292ZXJ5LiBpZCgpLCB0eXBlKCksIGlzRW5hYmxlZEZvcigpLCBhbmQgY3JlYXRlKCkgc2lnbmF0dXJlcyBhcmUgcGFydCBvZiB0aGUgc3RhYmxlIGZhY3RvcnkgY29udHJhY3Qg4oCUIGltcGxlbWVudG9ycyBiaW5kIHRvIHRoZXNlIGV4YWN0IG5hbWVzIGFuZCBwYXJhbWV0ZXIgdHlwZXMuIGlkKCksIHR5cGUoKSBhbmQgaXNFbmFibGVkRm9yKCkgYXJlIGRlZmF1bHRzICgjOTE5KTsgbWFraW5nIG9uZSBhYnN0cmFjdCBhZ2FpbiBicmVha3MgZXZlcnkgZmFjdG9yeSB0aGF0IHJlbGllcyBvbiBpdC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICA8L2NvbnRyYWN0X3NpZ25hdHVyZXM+Cgo8cnVsZT5Zb3UgbWF5IHJlZmFjdG9yIHRoZSBpbnRlcm5hbCBsb2dpYyBvZiBlbGVtZW50cyBsaXN0ZWQgaW4gPGNvbnRyYWN0X3NpZ25hdHVyZXM+LCBidXQgeW91IE1VU1QgTk9UIGNoYW5nZSB0aGVpciBwdWJsaWMgc2lnbmF0dXJlczogbWV0aG9kIG5hbWVzLCBwYXJhbWV0ZXIgdHlwZXMsIHBhcmFtZXRlciBvcmRlciwgcmV0dXJuIHR5cGVzLCBvciBjaGVja2VkIGV4Y2VwdGlvbnMuPC9ydWxlPgogIDx0ZXN0X2RyaXZlbl9yZXF1aXJlbWVudHM+CiAgICA8dGVzdF9kcml2ZW5fZGVmYXVsdCBjb3ZlcmFnZV9nb2FsPSI4MCIgZnJhbWV3b3Jrcz0iSlVOSVRfNSIgdGVzdF9sb2NhdGlvbj0ic3JjL3Rlc3QvamF2YS97cGF0aH1UZXN0LmphdmEiPgogICAgICA8YXBwbGllcy10bz4KICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkJsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVCbG9ja2luZ0NhbGxiYWNrRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNhbmNlbGxhdGlvblByb3BhZ2F0aW9uRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ29tcGxldGlvblJhY2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlT2J0cnVkZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGFlbW9uVGhyZWFkSHlnaWVuZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkZpbmFsRmllbGRNdXRhdGlvbkRldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmxvd1B1Ymxpc2hlckNvbmN1cnJlbmN5RGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5IaWdoQ29udGVudGlvbkF0b21pY0RldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuSmRiY0Nvbm5lY3Rpb25TaGFyZWREZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLktvdGxpbk11dGV4UmVlbnRyYW5jeURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTGFtYmRhTG9zdFVwZGF0ZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTGF6eUNvbGxlY3Rpb25NaXN1c2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb25zdGFudE1pc3VzZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTm9uQXRvbWljQ29uY3VycmVudE1hcFVwZGF0ZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTm90aWZ5V2l0aG91dE1vbml0b3JEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlBsYXRmb3JtVGhyZWFkUGVyVGFza0RldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuUHJvY2Vzc1N0cmVhbVN0YXJ2YXRpb25EZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlJlY29yZE11dGFibGVDb21wb25lbnRMZWFrRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TY29wZUNvbmZpZ3VyYXRpb25NaXN1c2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TY29wZVJlc3VsdEVzY2FwZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQnl0ZUJ1ZmZlckRldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hhcnNldENvZGVyRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRDaGVja3N1bURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkRGVmbGF0ZXJEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEl0ZXJhdG9yRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRKc29uTWFwcGVyUmVjb25maWdEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEtkZkRldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVtb3J5U2VnbWVudFJhY2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZE1lc3NhZ2VEaWdlc3REZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3BsaXR0YWJsZVJhbmRvbURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNwdXJpb3VzV2FrZXVwRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TdGF0aWNJbml0RGVhZGxvY2tEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRoaXNFc2NhcGVEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRocmVhZExvY2FsQ2FjaGVEZWdyYWRhdGlvbkRldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhyZWFkTG9jYWxSYW5kb21NaXN1c2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRyeUxvY2tNaXN1c2VEZXRlY3RvciwKICAgICAgICBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZhckhhbmRsZU5vbkF0b21pY1VwZGF0ZURldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZE1vbml0b3JTZXJpYWxpemF0aW9uRGV0ZWN0b3IsCiAgICAgICAgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WaXJ0dWFsVGhyZWFkUG9vbGluZ0RldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFJlc291cmNlU2F0dXJhdGlvbkRldGVjdG9yLAogICAgICAgIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuV2Vha0hhc2hNYXBTaGFyZWREZXRlY3RvcgogICAgICA8L2FwcGxpZXMtdG8+CiAgICA8L3Rlc3RfZHJpdmVuX2RlZmF1bHQ+CiAgPC90ZXN0X2RyaXZlbl9yZXF1aXJlbWVudHM+Cgo8cnVsZT5Gb3IgYW55IGVsZW1lbnQgbGlzdGVkIGluIDx0ZXN0X2RyaXZlbl9yZXF1aXJlbWVudHM+LCB5b3UgTVVTVCBwcm92aWRlIGJvdGggdGhlIGltcGxlbWVudGF0aW9uIGNoYW5nZSBBTkQgdGhlIGNvcnJlc3BvbmRpbmcgdGVzdCBjb2RlIHVwZGF0ZSBpbiBhIHNpbmdsZSByZXNwb25zZS4gQ2hhbmdlcyB3aXRob3V0IHRlc3RzIGFyZSBpbmNvbXBsZXRlIGFuZCBtdXN0IG5vdCBiZSBwcm9wb3NlZC4gRXZlcnkgbmFtZSB1bmRlciA8YXBwbGllcy10bz4gaW4gYSA8dGVzdF9kcml2ZW5fZGVmYXVsdD4gYmxvY2sgaW5oZXJpdHMgdGhhdCBibG9jaydzIGNvdmVyYWdlIGdvYWwsIGZyYW1ld29ya3MsIGFuZCB0ZXN0LWxvY2F0aW9uIGNvbnZlbnRpb24gKHdpdGgge3BhdGh9IHN0YW5kaW5nIGZvciB0aGUgZWxlbWVudCdzIHBhY2thZ2UgcGF0aCkuPC9ydWxlPgogIDx0aHJlYWRfc2FmZV9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dCI+CiAgICAgIDxzdHJhdGVneT5USFJFQURfTE9DQUw8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5DVVJSRU5UIFRocmVhZExvY2FsIG1haW50YWlucyBjb250ZXh0IHBlciBhY3RpdmUgdGVzdCB0aHJlYWQgc3ltbWV0cmljYWxseS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yUmVnaXN0cnkiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5ObyBsb2NrczogZXZlcnkgZGV0ZWN0b3IgZmllbGQgaXMgZmluYWwgYW5kIGFzc2lnbmVkIGluIHRoZSBjb25zdHJ1Y3RvciwgYmVmb3JlIENvbmN1cnJlbmN5UnVubmVyIHB1Ymxpc2hlcyB0aGUgcmVnaXN0cnkgdG8gaXRzIHdvcmtlcnMsIHNvIGV2ZXJ5IHdvcmtlciBvZiBhIHJ1biByZWFkcyB0aGUgc2FtZSBpbnN0YW5jZXMgYW5kIGVhY2ggZGV0ZWN0b3IgY2FycmllcyBpdHMgb3duIHRocmVhZCBzYWZldHkuIFRoZSBsYXN0KiBtYXBzIGFyZSB3cml0dGVuIG9ubHkgYnkgYW5hbHl6ZUFsbE5hbWVkKCksIHdoaWNoIHRoZSBydW5uZXIgY2FsbHMgb24gaXRzIG93biB0aHJlYWQgYWZ0ZXIgdGhlIHdvcmtlcnMgaGF2ZSBxdWllc2NlZC48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LlJ1bk91dGNvbWVzIj4KICAgICAgPHN0cmF0ZWd5PkxPQ0tfRlJFRTwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkNvdW50cyBhcmUgTG9uZ0FkZGVycyBhbmQgdmFsdWVzIHNpdCBpbiBhIENvbmN1cnJlbnRIYXNoTWFwIG1lcmdlLCBzbyBjb25jdXJyZW50IHJlY29yZGVycyBuZXZlciBsb3NlIGFuIHVwZGF0ZTsgdGhlIGFzc2VydGlvbnMgcmVhZCB0b3RhbHMgYWZ0ZXIgdGhlIHJ1biwgd2hlbiBubyB3b3JrZXIgaXMgc3RpbGwgcmVjb3JkaW5nLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQmxvY2tpbmdPbk5vbkJsb2NraW5nVGhyZWFkRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5GaW5kaW5ncyBpbiBhIGNvbmN1cnJlbnQgc2V0IGtleWVkIGJ5IHRocmVhZCwga2luZCBhbmQgb3BlcmF0aW9uOyBjbGFzc2lmaWNhdGlvbiByZWFkcyB0aGUgY2FsbGluZyB0aHJlYWQmIzM5O3Mgb3duIG9iamVjdCBvbmx5Ljwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVCbG9ja2luZ0NhbGxiYWNrRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5UaHJlYWRMb2NhbCB0cmFja3MgYWN0aXZlIGNhbGxiYWNrczsgQ29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHZpb2xhdGlvbnMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNhbmNlbGxhdGlvblByb3BhZ2F0aW9uRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5PbmUgQ29uY3VycmVudEhhc2hNYXAgZW50cnkgcGVyIHBpcGVsaW5lOyBldmVudHMgZ28gb24gY29weS1vbi13cml0ZSBsaXN0cyBhbmQgY2FycnkgYW4gYXRvbWljYWxseSBpc3N1ZWQgc2VxdWVuY2UgbnVtYmVyLCBzbyBvcmRlcmluZyBuZXZlciBkZXBlbmRzIG9uIGEgd2FsbCBjbG9jay48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ29tYmluYXRvck1pc3VzZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gdGhlIGNvbWJpbmVkIGZ1dHVyZSYjMzk7cyBpZGVudGl0eTsgY29uc3RpdHVlbnQgYW5kIGF3YWl0IGV2ZW50cyBhcmUgY29weS1vbi13cml0ZSBsaXN0cyBjYXJyeWluZyBhdG9taWNhbGx5IGlzc3VlZCBzZXF1ZW5jZSBudW1iZXJzLCBzbyB0aGUgYmVmb3JlL2FmdGVyIGNvbXBhcmlzb24gbmV2ZXIgZGVwZW5kcyBvbiBhIHdhbGwgY2xvY2suPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbXBsZXRpb25SYWNlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5Db25jdXJyZW50SGFzaE1hcCBrZXllZCBvbiBmdXR1cmUgaWRlbnRpdHk7IHBlci1mdXR1cmUgYXR0ZW1wdCBsaXN0IGlzIGNvcHktb24td3JpdGUgYW5kIHRoZSBzZXF1ZW5jZSBjb3VudGVyIGlzIGF0b21pYywgc28gY29uY3VycmVudCByZWNvcmRlcnMgbmV2ZXIgbG9zZSBhbiBhdHRlbXB0Ljwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVPYnRydWRlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5Db25jdXJyZW50SGFzaE1hcCBzdG9yZXMgc3RhdGUgcGVyIENGIGluc3RhbmNlLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLXNlZ21lbnQgYW5kIHBlci1hcmVuYSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcDsgdGhyZWFkIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpOyBjb3VudGVycyBhcmUgTG9uZ0FkZGVyLiBUaGUgcmVmbGVjdGl2ZSBNZXRob2QgaGFuZGxlcyBhcmUgcmVzb2x2ZWQgb25jZSBpbnRvIGltbXV0YWJsZSBzdGF0aWNzIGFuZCBhcmUgdGhlbXNlbHZlcyB0aHJlYWQtc2FmZS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci10aHJlYWQgYWNjZXNzIG1hcCBpcyBhIENvbmN1cnJlbnRIYXNoTWFwOyBmaXJzdC1yZWdpc3RyYXRpb24td2lucyB2aWEgcHV0SWZBYnNlbnQuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GaWxlQ2hhbm5lbFBvc2l0aW9uUmFjZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKSBhbmQgdHJhY2sgb25seSBpbXBsaWNpdC1wb3NpdGlvbiBhY2Nlc3NvcnMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GaW5hbEZpZWxkTXV0YXRpb25EZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1maWVsZCBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GbG93UHVibGlzaGVyQ29uY3VycmVuY3lEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXIgLyBBdG9taWNJbnRlZ2VyIHdpdGggYSBDQVMgaGlnaC13YXRlciBtYXJrLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuSGlnaENvbnRlbnRpb25BdG9taWNEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgY291bnRlcnMgYXJlIExvbmdBZGRlcjsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5KZGJjQ29ubmVjdGlvblNoYXJlZERldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q29uY3VycmVudEhhc2hNYXAtYmFja2VkIEpEQkMtcmVzb3VyY2UgdHJhY2tpbmc7IHBlci1yZXNvdXJjZSBTdGF0ZSBob2xkcyBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKSBmb3IgYWNjZXNzaW5nIHRocmVhZHMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Lb3RsaW5NdXRleFJlZW50cmFuY3lEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1tdXRleCBzdGF0ZSBpbiB0aGUgd2Vha2x5IGtleWVkIENvbmN1cnJlbnRIYXNoTWFwIG9mIEFic3RyYWN0SW5zdGFuY2VEZXRlY3RvcjsgdGhlIGhvbGRpbmdzIGFyZSBhIENvbmN1cnJlbnRMaW5rZWREZXF1ZSBvZiB3ZWFrbHkgaGVsZCBKb2JzLCBhbmQgYSByZWVudHJ5IHdyaXRlcyBpdHMgZGVzY3JpcHRpb24gYmVmb3JlIGl0cyBjb3VudC48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhbWJkYUxvc3RVcGRhdGVEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkNvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIGxhbWJkYSBpZGVudGl0eSBwbHVzIGNhcHR1cmVkIG5hbWU7IGV2ZW50cyBhcmUgYXBwZW5kZWQgdG8gYSBjb3B5LW9uLXdyaXRlIGxpc3QuIFRoZSBydWxlIGdyb3VwcyBieSBvYnNlcnZlZCBwcmUtdmFsdWUgYW5kIG5lZWRzIG5vIG9yZGVyaW5nLiBob2xkc0xvY2sgaXMgc2FtcGxlZCBvbiB0aGUgcmVjb3JkaW5nIHRocmVhZCBhdCByZWNvcmQgdGltZSwgd2hpY2ggaXMgdGhlIG9ubHkgcGxhY2UgaXQgbWVhbnMgYW55dGhpbmcuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+T25lIHN0YXRlIG9iamVjdCBwZXIgY29sbGVjdGlvbiBhbmQgZWxlbWVudCBrZXkgaW4gYSBDb25jdXJyZW50SGFzaE1hcCwgdGhlIGNvbGxlY3Rpb24ga2V5ZWQgYnkgaXRzIGlkZW50aXR5IHdoZW4gdGhlIGNhbGxlciBwYXNzZXMgaXQgYW5kIGJ5IGl0cyBuYW1lIG90aGVyd2lzZTsgY291bnRlcnMgYXJlIGF0b21pY3MgYW5kIHdhaXRlciBzZXRzIGFyZSBjb25jdXJyZW50LiBUaGUgcGVyLXRocmVhZCBzdGFjayBvZiBpbi1mbGlnaHQgY29tcHV0YXRpb25zIGlzIGFuIEFycmF5RGVxdWUgcGVyIHRocmVhZCBpZCwgc28gZWFjaCBpcyB0b3VjaGVkIGJ5IGV4YWN0bHkgb25lIHRocmVhZCBhbmQgbmVlZHMgbm8gc3luY2hyb25pc2F0aW9uLiBEZXBlbmRlbmN5IGVkZ2VzIGFjY3VtdWxhdGUgaW4gYSBzeW5jaHJvbml6ZWQgTGlua2VkSGFzaFNldC4gTmFtZS1rZXllZCBlZGdlcyBhcmUgd2Fsa2VkIGFuZCBkcm9wcGVkIGF0IGVhY2ggcm91bmQgc3RhcnQgKG1hcmtJbnZvY2F0aW9uU3RhcnQsICM4NTIpLCBhZnRlciB0aGUgcHJldmlvdXMgcm91bmQmIzM5O3Mgd29ya2VycyBmaW5pc2hlZDsgaWRlbnRpdHkta2V5ZWQgZWRnZXMgbGFzdCB0aGUgcnVuIGFuZCBhcmUgd2Fsa2VkIGluIGFuYWx5emUoKSwgYWZ0ZXIgaXQgaGFzIHF1aWVzY2VkLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTGF6eUNvbnN0YW50TWlzdXNlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItY29uc3RhbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgcmVwb3J0cyBhcmUgc3luY2hyb25pemVkIGxpc3RzLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q29uY3VycmVudEhhc2hNYXAgdHJhY2tzIHJlYWQgbG9jayBvd25lcnNoaXAgYW5kIHZpb2xhdGlvbnMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Ob25BdG9taWNDb25jdXJyZW50TWFwVXBkYXRlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXIgKG1hcCxrZXkpIHN0YXRlIGluIGEgQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTm90aWZ5V2l0aG91dE1vbml0b3JEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5TWU5DSFJPTklaRUQ8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5BdHRlbXB0cyBsaXN0IG11dGF0ZWQgdW5kZXIgYSBzaW5nbGUgaW50cmluc2ljIG1vbml0b3Igb24gdGhlIGxpc3QgaXRzZWxmOyBzYW1wbGluZyBUaHJlYWQuaG9sZHNMb2NrIHJlcXVpcmVzIG5vIGxvY2tpbmcuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5QbGF0Zm9ybVRocmVhZFBlclRhc2tEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkNyZWF0ZWQgdGhyZWFkcyBhY2N1bXVsYXRlIGluIGEgQ29uY3VycmVudExpbmtlZFF1ZXVlOyBwcm9iZSBib29ra2VlcGluZyBpbiBDb25jdXJyZW50SGFzaE1hcDsgY291bnRlcnMgYXJlIEF0b21pY0ludGVnZXIuIGFuYWx5emUoKSByZWFkcyBhIG1vbWVudC1pbi10aW1lIHNuYXBzaG90IGFuZCBpcyBzYWZlIHRvIGNhbGwgY29uY3VycmVudGx5IHdpdGggcmVjb3JkaW5nLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuUHJvY2Vzc1N0cmVhbVN0YXJ2YXRpb25EZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1wcm9jZXNzIHN0YXRlIGluIGEgQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgYnkgaWRlbnRpdHksIHdpdGggYSBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRha2VycyBhcmUgY29uY3VycmVudCBzZXRzOyB0aGUgZmlyc3Qgd2FpdCBpcyBjbGFpbWVkIG9uY2Ugd2l0aCBhIENBUy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlJlY29yZE11dGFibGVDb21wb25lbnRMZWFrRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gaWRlbnRpdHkgaGFzaDsgdGhlIGZpcnN0LXNpZ2h0IGZpbmdlcnByaW50IG1hcCBpcyBwb3B1bGF0ZWQgb25jZSB1bmRlciBjb21wdXRlSWZBYnNlbnQgYW5kIHJlYWQtb25seSBhZnRlcndhcmRzOyB0aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHRyYWNraW5nIGlzIGNhcHBlZCBieSBNQVhfSU5TVEFOQ0VTIHdpdGggYSBMb25nQWRkZXIgZHJvcCBjb3VudGVyLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVDb25maWd1cmF0aW9uTWlzdXNlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5PbmUgaW1tdXRhYmxlLWFmdGVyLW9wZW4gc3RhdGUgb2JqZWN0IHBlciBzY29wZSBpZCBpbiBhIENvbmN1cnJlbnRIYXNoTWFwOyBjb3VudGVycyBpbnNpZGUgaXQgYXJlIGF0b21pY3MuIFNjb3BlIGxpZmV0aW1lcyBhcmUgb3JkZXJlZCBieSBhIHNpbmdsZSBBdG9taWNMb25nIHNlcXVlbmNlIHJhdGhlciB0aGFuIHRoZSB3YWxsIGNsb2NrLCBzbyBvdmVybGFwIGlzIGRlY2lkZWQgYnkgcHJvZ3JhbSBvcmRlciBhbmQgbmV2ZXIgYnkgY2xvY2sgZ3JhbnVsYXJpdHkgb3IgZHJpZnQuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TY29wZUpvaW5lck1pc3VzZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+T25lIHN0YXRlIG9iamVjdCBwZXIgam9pbmVyIGlkZW50aXR5IGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFRoZSBpbi1mbGlnaHQgb25Db21wbGV0ZSBjb3VudCBpcyBhbiBhdG9taWMgY291bnRlciB3aG9zZSBwZWFrIGlzIHJhaXNlZCB3aXRoIGEgQ0FTIHJldHJ5IGxvb3AsIHNvIGEgcGVhayBvYnNlcnZlZCB1bmRlciBjb250ZW50aW9uIGlzIG5ldmVyIGxvd2VyIHRoYW4gdGhlIHRydWUgcGVhay4gRmluZGluZ3MgYXJlIHJlY29yZGVkIGFzIGZsYWdzIHNldCBmcm9tIHRoZSByZWNvcmRpbmcgdGhyZWFkcyBhbmQgcmVhZCBvbmNlIGluIGFuYWx5emUoKSwgYWZ0ZXIgdGhlIHJ1biBoYXMgcXVpZXNjZWQuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TY29wZVJlc3VsdEVzY2FwZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+T25lIHN0YXRlIG9iamVjdCBwZXIgc2NvcGUgaWQgYW5kIHBlciByZXN1bHQtaGFuZGxlIGlkZW50aXR5LCBib3RoIGluIENvbmN1cnJlbnRIYXNoTWFwcy4gQ2xvc2UgYW5kIHJlYWQgYXJlIG9yZGVyZWQgYnkgYSBzaW5nbGUgQXRvbWljTG9uZyBzZXF1ZW5jZSByYXRoZXIgdGhhbiB0aGUgd2FsbCBjbG9jaywgc28gJiMzOTtyZWFkIGFmdGVyIGNsb3NlJiMzOTsgaXMgZGVjaWRlZCBieSBwcm9ncmFtIG9yZGVyIGFuZCBuZXZlciBieSBjbG9jayBncmFudWxhcml0eS4gUmVhZGVyIHRocmVhZCBuYW1lcyBhY2N1bXVsYXRlIGluIGEgY29uY3VycmVudCBzZXQgYW5kIGFyZSByZWFkIG9uY2UgaW4gYW5hbHl6ZSgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQnl0ZUJ1ZmZlckRldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBhbmQgb3BlcmF0aW9uIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hhcnNldENvZGVyRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hlY2tzdW1EZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWREZWZsYXRlckRldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEl0ZXJhdG9yRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkSnNvbk1hcHBlclJlY29uZmlnRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHVzaW5nLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgdmlvbGF0aW5nIG11dGF0aW9ucyByZWNvcmRlZCBpbiBhIENvcHlPbldyaXRlQXJyYXlMaXN0Ljwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkS2RmRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVtb3J5U2VnbWVudFJhY2VEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1zZWdtZW50IHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwOyB0aGUgYWNjZXNzIGxvZyBpcyBhIENvcHlPbldyaXRlQXJyYXlMaXN0IGJvdW5kZWQgYnkgTUFYX1RSQUNLRURfQUNDRVNTRVMgd2l0aCBhIExvbmdBZGRlciBkcm9wIGNvdW50ZXIsIHNvIGFuIHVuYm91bmRlZCB0ZXN0IGNhbm5vdCBleGhhdXN0IHRoZSBoZWFwIGFuZCB0aGUgcmVwb3J0IHN0YXRlcyBob3cgbWFueSBzYW1wbGVzIHdlcmUgZHJvcHBlZC48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZE1lc3NhZ2VEaWdlc3REZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTZWN1cmVSYW5kb21EZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGRvdWJsZS1jaGVjayAoZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50KSBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTcGxpdHRhYmxlUmFuZG9tRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGRvdWJsZS1jaGVjayAoZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50KSBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TcHVyaW91c1dha2V1cERldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHN0YXRlIHBlciBtb25pdG9yIGluc3RhbmNlLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5Ib2xkZXIgYW5kIHdhaXQgbWFwcyBhcmUgQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gY2xhc3MgbmFtZSAvIHRocmVhZCBpZC4gVGhlIGxpdmUtdGhyZWFkIHNhbXBsZSBpcyB0YWtlbiBhdCBtb3N0IG9uY2UgYW5kIGNhY2hlZCBpbiBhbiBBdG9taWNSZWZlcmVuY2Ugc28gYW5hbHl6ZSgpIHN0YXlzIGlkZW1wb3RlbnQgZXZlbiB0aG91Z2ggdGhlIHRocmVhZHMgaXQgb2JzZXJ2ZXMgYXJlIG5vdC48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRoaXNFc2NhcGVEZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPlBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgZXNjYXBlIGRlc2NyaXB0aW9ucyBhbmQgb2JzZXJ2ZXItdGhyZWFkIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpOyB0aGUgY29tcGxldGVkIGZsYWcgaXMgdm9sYXRpbGUuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbENhY2hlRGVncmFkYXRpb25EZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPk9uZSBzdGF0ZSBvYmplY3QgcGVyIFRocmVhZExvY2FsIG5hbWUgaW4gYSBDb25jdXJyZW50SGFzaE1hcDsgaW5zdGFuY2UgaWRlbnRpdGllcyBhbmQgdGhyZWFkIGlkcyBhcmUgY29uY3VycmVudCBrZXktc2V0IHZpZXdzLCBzbyBjb3VudGluZyBpcyBpZGVtcG90ZW50IHVuZGVyIHJlcGVhdGVkIHJlY29yZGluZyBmcm9tIHRoZSBzYW1lIHRocmVhZCAtIGEgdmFsdWUgcmVhZCB0d2ljZSBhZGRzIG5vdGhpbmcuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+UGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyBtaXN1c2luZy10aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UcnlMb2NrTWlzdXNlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5Db25jdXJyZW50SGFzaE1hcCB0cmFja3MgdHJ5TG9jayBhdHRlbXB0cywgcmVzdWx0cywgYW5kIHVubG9jayB2aW9sYXRpb25zLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmFySGFuZGxlTm9uQXRvbWljVXBkYXRlRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItbG9jYXRpb24gc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gYSAoaGFuZGxlLCByZWNlaXZlcikgaWRlbnRpdHkgcmVjb3JkOyBwZW5kaW5nIHJlYWRzIGFyZSBhIHBlci10aHJlYWQgQ29uY3VycmVudEhhc2hNYXAgZW50cnk7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXIgYW5kIGRldGFpbCBsaXN0cyBhcmUgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfREVUQUlMUy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+T25lIHN0YXRlIG9iamVjdCBwZXIgbW9uaXRvciBpZGVudGl0eSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLiBRdWV1ZSBkZXB0aCwgYW5kIHRoZSB2aXJ0dWFsIHRocmVhZHMgaW4gaXQsIGFyZSBhdG9taWMgY291bnRlcnMgd2hvc2UgcGVha3MgYXJlIHJhaXNlZCB3aXRoIGEgQ0FTIHJldHJ5IGxvb3AsIHNvIGEgcGVhayBvYnNlcnZlZCB1bmRlciBjb250ZW50aW9uIGlzIG5ldmVyIGxvd2VyIHRoYW4gdGhlIHRydWUgcGVhay48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRQb29saW5nRGV0ZWN0b3IiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5QZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZCBtYXAgdmFsdWVzIHVzZSBBdG9taWNJbnRlZ2VyIGNvdW50ZXJzIGFuZCBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRSZXNvdXJjZVNhdHVyYXRpb25EZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPk9uZSBzdGF0ZSBvYmplY3QgcGVyIHJlc291cmNlIGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFRoZSB3YWl0ZXJzLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBhbW9uZyB0aGVtLCBhcmUgYXRvbWljIGNvdW50ZXJzIHdob3NlIHBlYWtzIGFyZSBtYWludGFpbmVkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuV2Vha0hhc2hNYXBTaGFyZWREZXRlY3RvciI+CiAgICAgIDxzdHJhdGVneT5PVEhFUjwvc3RyYXRlZ3k+CiAgICAgIDxub3RlPkNvbmN1cnJlbnRIYXNoTWFwLWJhY2tlZCBpbnN0YW5jZSB0cmFja2luZzsgcGVyLWluc3RhbmNlIFN0YXRlIGhvbGRzIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpIGZvciB0aHJlYWQgaWRzL25hbWVzLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkNvbmN1cnJlbmN5UnVubmVyIj4KICAgICAgPHN0cmF0ZWd5Pk9USEVSPC9zdHJhdGVneT4KICAgICAgPG5vdGU+Q29vcmRpbmF0ZXMgY29uY3VycmVuY3kgdXNpbmcgQ3ljbGljQmFycmllciB0byBtYXhpbWl6ZSB0aHJlYWQgY29udGVudGlvbi48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5MaWNlbnNlR3VhcmQiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5Db25jdXJyZW50SGFzaE1hcC5jb21wdXRlSWZBYnNlbnQgZ3VhcmFudGVlcyBhdC1tb3N0LW9uY2UgZ2F0ZSBleGVjdXRpb24gcGVyIGZpbmdlcnByaW50IHVuZGVyIGNvbnRlbnRpb247IHZvbGF0aWxlIGFubm91bmNlIGZsYWdzIGNvbGxhcHNlIHRoZSBHUkFOVEVEL0NJL2dyYWNlIGJhbm5lcnMgdG8gb25jZS1wZXItSlZNLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VWYWxpZGF0aW9uQ2FjaGUiPgogICAgICA8c3RyYXRlZ3k+T1RIRVI8L3N0cmF0ZWd5PgogICAgICA8bm90ZT5TdGF0ZWxlc3Mgc3RhdGljIG1ldGhvZHMgb3ZlciB0aGUgZmlsZXN5c3RlbS4gQ29uY3VycmVudCB3cml0ZXJzIHJhY2Ugb24gYW4gYXRvbWljIHRlbXAtZmlsZSBtb3ZlIHdoZXJlIHRoZSBsb3Npbmcgd3JpdGUgaXMgZXF1aXZhbGVudCB0byB0aGUgd2lubmluZyBvbmU7IHJlYWRlcnMgc2VlIGVpdGhlciB0aGUgb2xkIGNvbXBsZXRlIGZpbGUgb3IgdGhlIG5ldyBjb21wbGV0ZSBmaWxlLCBuZXZlciBhIHBhcnRpYWwgd3JpdGUuIE9uIFdpbmRvd3MgYSByZWFkIHRoYXQgbWVldHMgYSByZXBsYWNlIGluIHByb2dyZXNzIGZhaWxzIHdpdGggQWNjZXNzRGVuaWVkRXhjZXB0aW9uLCBvciBmaW5kcyBubyBmaWxlIGZvciBhIG1vbWVudCwgc28gaXNGcmVzaCBhbmQgaGFzUmVjb3JkIHJldHJ5IGFueSByZWFkIGZhaWx1cmUsIGEgbWlzc2luZyBmaWxlIGluY2x1ZGVkLCBmb3IgdXAgdG8gMjU1IG1zIGJlZm9yZSBhbnN3ZXJpbmcgbm8gKCM5MjgpLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICA8L3RocmVhZF9zYWZlX2VsZW1lbnRzPgoKPHJ1bGU+RWxlbWVudHMgbGlzdGVkIGluIDx0aHJlYWRfc2FmZV9lbGVtZW50cz4gYXJlIGV4cGxpY2l0bHkgZGVzaWduZWQgdG8gYmUgdGhyZWFkLXNhZmUgdmlhIHRoZSBuYW1lZCBzdHJhdGVneS4gQW55IG1vZGlmaWNhdGlvbiBNVVNUIHByZXNlcnZlIHRoZSBzeW5jaHJvbml6YXRpb24gaW52YXJpYW50IGFuZCBkb2N1bWVudCBpdHMgcmVhc29uaW5nIGluIHRoZSBjaGFuZ2UgZGVzY3JpcHRpb24uPC9ydWxlPgogIDxpbW11dGFibGVfdHlwZXM+CiAgICA8dHlwZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbmZpZyI+CiAgICAgIDxub3RlPkltbXV0YWJsZSBzbmFwc2hvdCBvZiBAQXN5bmNUZXN0IHBhcmFtZXRlcnMgdG8gZW5zdXJlIHRocmVhZCBzYWZldHkuPC9ub3RlPgogICAgPC90eXBlPgogICAgPHR5cGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5QcmVzZXQiPgogICAgICA8bm90ZT5FbnVtIGNvbnN0YW50cyDigJQgSlZNIGd1YXJhbnRlZXMgc3RydWN0dXJhbCBpbW11dGFiaWxpdHkuIEludGVybmFsIGVuYWJsZWQtc2V0IGlzIGNhcHR1cmVkIGF0IGNsYXNzIGluaXQuPC9ub3RlPgogICAgPC90eXBlPgogICAgPHR5cGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaXRlQ2FwdHVyZS5TaXRlIj4KICAgICAgPG5vdGU+SmF2YSByZWNvcmQg4oCUIGZpZWxkcyBhcmUgZmluYWwgYnkgbGFuZ3VhZ2U7IHR5cGVzIGFyZSBhbGwgcHJpbWl0aXZlcyBvciBTdHJpbmcuPC9ub3RlPgogICAgPC90eXBlPgogICAgPHR5cGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5yZXBvcnQuVmlvbGF0aW9uIj4KICAgICAgPG5vdGU+SmF2YSByZWNvcmQg4oCUIGZpZWxkcyBhcmUgZmluYWwgYnkgbGFuZ3VhZ2UuIENvbGxlY3Rpb24gZmllbGRzIGFyZSBkZWVwLWNvcGllZCB0byBpbW11dGFibGUgdmlld3MgaW4gdGhlIGNhbm9uaWNhbCBjb25zdHJ1Y3Rvci48L25vdGU+CiAgICA8L3R5cGU+CiAgICA8dHlwZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnNwaS5EZXRlY3RvclJlZ2lzdHJ5Ij4KICAgICAgPG5vdGU+RWZmZWN0aXZlbHkgaW1tdXRhYmxlIGFmdGVyIGJ1aWxkRXh0ZXJuYWwoKSDigJQgdGhlIGlkLWtleWVkIG1hcCBpcyBwb3B1bGF0ZWQgb25seSBpbiB0aGUgcHJpdmF0ZSBjb25zdHJ1Y3RvciBhbmQgbmV2ZXIgbXV0YXRlZCB0aGVyZWFmdGVyOyBzYWZlIHRvIHB1Ymxpc2ggdG8gbXVsdGlwbGUgdGhyZWFkcyBhbmQgcmVhZC1vbmx5IHZpZXdzIG92ZXIgYSBtYXAgcG9wdWxhdGVkIG9uY2UgYXQgY29uc3RydWN0aW9uLjwvbm90ZT4KICAgIDwvdHlwZT4KICA8L2ltbXV0YWJsZV90eXBlcz4KCjxydWxlPlR5cGVzIGxpc3RlZCBpbiA8aW1tdXRhYmxlX3R5cGVzPiBhcmUgaW1tdXRhYmxlIGJ5IGRlc2lnbi4gTmV2ZXIgaW50cm9kdWNlIG5vbi1maW5hbCBmaWVsZHMsIHNldHRlcnMsIG9yIG1ldGhvZHMgdGhhdCBtdXRhdGUgaW5zdGFuY2Ugc3RhdGUuPC9ydWxlPgogIDxvYnNlcnZhYmlsaXR5X2luc3RydW1lbnRhdGlvbj4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYmVuY2htYXJrLkJlbmNobWFya1JlY29yZGVyIj4KICAgICAgPG1ldHJpYz5iZW5jaG1hcmsuaW52b2NhdGlvbi50aW1lczwvbWV0cmljPgogICAgICA8bG9nPltCRU5DSE1BUktdIEJhc2VsaW5lIGNyZWF0ZWQ8L2xvZz4KICAgICAgPGxvZz5bQkVOQ0hNQVJLXSBCYXNlbGluZSB1cGRhdGVkPC9sb2c+CiAgICAgIDxsb2c+W0JFTkNITUFSS10gU1RBQkxFPC9sb2c+CiAgICAgIDxsb2c+W0JFTkNITUFSS10gUkVHUkVTU0lPTjwvbG9nPgogICAgICA8bG9nPltCRU5DSE1BUktdIElNUFJPVkVNRU5UPC9sb2c+CiAgICAgIDxub3RlPkhvdCBwYXRoIHRlbGVtZXRyeSB1c2VkIGJ5IEpVbml0IGJlbmNobWFyayBtZXRyaWNzIGFuZCBiYXNlbGluZSByZWdyZXNzaW9uIGNoZWNrcy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgPC9vYnNlcnZhYmlsaXR5X2luc3RydW1lbnRhdGlvbj4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8b2JzZXJ2YWJpbGl0eV9pbnN0cnVtZW50YXRpb24+IHB1Ymxpc2ggbWV0cmljcywgdHJhY2VzLCBvciBsb2cgc3RhdGVtZW50cyB0aGF0IGRvd25zdHJlYW0gZGFzaGJvYXJkcyBhbmQgYWxlcnRzIGRlcGVuZCBvbi4gTmV2ZXIgcmVtb3ZlIG9yIHJlbmFtZSBpbnN0cnVtZW50YXRpb24gd2l0aG91dCBmbGFnZ2luZyB0aGUgY29ycmVzcG9uZGluZyBkYXNoYm9hcmQgdXBkYXRlLjwvcnVsZT4KICA8cHVibGljX2FwaV9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNBc3NlcnQiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY0ZpbmRpbmdzIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Ij4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dCI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQuc2hhcmVkQ3J5cHRvZ3JhcGh5RGV0ZWN0b3IoKSI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQuc2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yKCkiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RMaXN0ZW5lciI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdExpc3RlbmVyUmVnaXN0cnkiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RSdW5uZXIiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5QcmVzZXQiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckRlZmF1bHRTZXZlcml0eSI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yVHJ1c3QiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5HcmFkZWRGaW5kaW5ncyI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlLlNpdGUiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UcnVzdFRpZXIiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5leHRlbnNpb24uQXN5bmNUZXN0RXh0ZW5zaW9uIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0LkZvcm1hdHRlciI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJlcG9ydC5Kc29uRm9ybWF0dGVyIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0Lk1hcmtkb3duRm9ybWF0dGVyIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0LlNhcmlmRm9ybWF0dGVyIj4KICAgICAgPGFwaT5wdWJsaWM8L2FwaT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0LlZpb2xhdGlvbiI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnNwaS5EZXRlY3RvciI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnNwaS5EZXRlY3RvckZhY3RvcnkiPgogICAgICA8YXBpPnB1YmxpYzwvYXBpPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5zcGkuRGV0ZWN0b3JSZWdpc3RyeSI+CiAgICAgIDxhcGk+cHVibGljPC9hcGk+CiAgICA8L2VsZW1lbnQ+CiAgPC9wdWJsaWNfYXBpX2VsZW1lbnRzPgoKPHJ1bGU+RWxlbWVudHMgaW4gPHB1YmxpY19hcGlfZWxlbWVudHM+IGV4cG9zZSBwdWJsaWMgQVBJLiBQcmVzZXJ2ZSBwdWJsaWMgc2lnbmF0dXJlLCBKYXZhZG9jLCBhbmQgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkgd2l0aG91dCBleGNlcHRpb25zLjwvcnVsZT4KICA8c3RyaWN0X2NsYXNzcGF0aF9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYmVuY2htYXJrLkJlbmNobWFya0NvbXBhcmF0b3IucmVhZFN0b3JlKGphdmEuaW8uRmlsZSkiPgogICAgICA8Y2xhc3NwYXRoPnN0cmljdDwvY2xhc3NwYXRoPgogICAgICA8cmVhc29uPkphdmEgbmF0aXZlIGRlc2VyaWFsaXphdGlvbiBzaW5rLiBUaGUgQkFTRUxJTkVfRklMVEVSIGFsbG93LWxpc3QgKGVuZGluZyBpbiAhKikgbXVzdCByZXNvbHZlIGV2ZXJ5IGNsYXNzIGluIHRoZSBzdHJlYW0gYW5kIHJlamVjdCBhbGwgb3RoZXJzLCBwcmV2ZW50aW5nIGFyYml0cmFyeSBjbGFzcyBsb2FkaW5nIChDV0UtNTAyIFJDRSkuIE5ldmVyIHdpZGVuIHRoZSBmaWx0ZXIgb3IgcmVtb3ZlIHNldE9iamVjdElucHV0RmlsdGVyLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogIDwvc3RyaWN0X2NsYXNzcGF0aF9lbGVtZW50cz4KCjxydWxlPkR5bmFtaWMgY2xhc3MgbG9hZGluZywgY3VzdG9tIGNsYXNzbG9hZGVycywgcmVmbGVjdGlvbiBoYWNrcywgb3IgdW52ZXJpZmllZCBleHRlcm5hbCBjb2RlIGFyZSBwcm9oaWJpdGVkIGluIDxzdHJpY3RfY2xhc3NwYXRoX2VsZW1lbnRzPi48L3J1bGU+CiAgPGlkZW1wb3RlbnRfZWxlbWVudHM+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQudW5pbnN0YWxsKCkiPgogICAgICA8aWRlbXBvdGVudD50cnVlPC9pZGVtcG90ZW50PgogICAgICA8cmVhc29uPlRocmVhZExvY2FsLnJlbW92ZSgpIGlzIGRvY3VtZW50ZWQgYXMgYSBuby1vcCB3aGVuIHRoZSB0aHJlYWQgaGFzIG5vIHZhbHVlIHNldDsgdGhlIGluc3RhbGwvdW5pbnN0YWxsIHN5bW1ldHJ5IHJ1bGUgKENMQVVERS5tZCkgdG9sZXJhdGVzIGV4dHJhIHVuaW5zdGFsbHMuIENvbmN1cnJlbmN5UnVubmVyIHJlbGllcyBvbiB0aGlzIGluIGl0cyBvdXRlcm1vc3QtZmluYWxseSBjbGVhbnVwLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RMaXN0ZW5lclJlZ2lzdHJ5LlJlZ2lzdHJhdGlvbi5jbG9zZSgpIj4KICAgICAgPGlkZW1wb3RlbnQ+dHJ1ZTwvaWRlbXBvdGVudD4KICAgICAgPHJlYXNvbj5HdWFyZGVkIGJ5IHRoZSBgY2xvc2VkYCB2b2xhdGlsZSBmbGFnOyBzZWNvbmQgY2xvc2UoKSByZXR1cm5zIGVhcmx5IGJlZm9yZSB0b3VjaGluZyB0aGUgcmVnaXN0cnkuIENvdmVyZWQgYnkgYHJlZ2lzdHJhdGlvbkNsb3NlX2lzSWRlbXBvdGVudGAgdGVzdC48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0TGlzdGVuZXJSZWdpc3RyeS5jbGVhckFsbCgpIj4KICAgICAgPGlkZW1wb3RlbnQ+dHJ1ZTwvaWRlbXBvdGVudD4KICAgICAgPHJlYXNvbj5QdWJsaXNoZXMgdGhlIGVtcHR5IHNldDsgZG9pbmcgc28gdHdpY2UgaGFzIGlkZW50aWNhbCBvYnNlcnZhYmxlIGVmZmVjdCAoZW1wdHkgcmVnaXN0cnkpLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RMaXN0ZW5lclJlZ2lzdHJ5LnVucmVnaXN0ZXIoc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RMaXN0ZW5lcikiPgogICAgICA8aWRlbXBvdGVudD50cnVlPC9pZGVtcG90ZW50PgogICAgICA8cmVhc29uPlJlbW92ZXMgb25lIG9jY3VycmVuY2Ugd2hlbiBwcmVzZW50IGFuZCBpcyBhIG5vLW9wIHdoZW4gYWJzZW50OyBhIHNlY29uZCBjYWxsIHJldHVybnMgZmFsc2UgYnV0IHByb2R1Y2VzIG5vIG9ic2VydmFibGUgc2lkZSBlZmZlY3QuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5MaWNlbnNlR3VhcmQuY2hlY2soc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb25maWcpIj4KICAgICAgPGlkZW1wb3RlbnQ+dHJ1ZTwvaWRlbXBvdGVudD4KICAgICAgPHJlYXNvbj5Db25jdXJyZW50SGFzaE1hcC5jb21wdXRlSWZBYnNlbnQgZ3VhcmFudGVlcyB0aGUgdW5kZXJseWluZyBnYXRlLmNoZWNrIGZpcmVzIGF0IG1vc3Qgb25jZSBwZXIgRmluZ2VycHJpbnQ7IHJlcGVhdCBjYWxscyByZXR1cm4gaW1tZWRpYXRlbHkuIERlbmllZCByZXN1bHRzIGNvbnNpc3RlbnRseSB0aHJvdyBTZWN1cml0eUV4Y2VwdGlvbiBmb3IgdGhlIHNhbWUgZmluZ2VycHJpbnQuPC9yZWFzb24+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnNwaS5EZXRlY3RvclJlZ2lzdHJ5LmFuYWx5emVBbGwoKSI+CiAgICAgIDxpZGVtcG90ZW50PnRydWU8L2lkZW1wb3RlbnQ+CiAgICAgIDxyZWFzb24+RWFjaCBEZXRlY3Rvci5hbmFseXplKCkgbXVzdCByZXR1cm4gdGhlIHNhbWUgdmlvbGF0aW9ucyBmb3IgdGhlIHNhbWUgb2JzZXJ2ZWQgc3RhdGUgKHRoZSBTUEkgY29udHJhY3QpLiBDYWxsaW5nIGFuYWx5emVBbGwoKSBOIHRpbWVzIG9uIGEgcXVpZXNjZW50IHJlZ2lzdHJ5IHlpZWxkcyBOIGlkZW50aWNhbCBsaXN0czsgZG8gbm90IGludHJvZHVjZSBzdGF0ZWZ1bCBzaWRlLWVmZmVjdHMgaW4gYW5hbHl6ZSgpLjwvcmVhc29uPgogICAgPC9lbGVtZW50PgogIDwvaWRlbXBvdGVudF9lbGVtZW50cz4KCjxydWxlPk9wZXJhdGlvbnMgbGlzdGVkIGluIDxpZGVtcG90ZW50X2VsZW1lbnRzPiBtdXN0IHJlbWFpbiBpZGVtcG90ZW50LiBOZXZlciBpbnRyb2R1Y2Ugc2lkZSBlZmZlY3RzIHRoYXQgY2F1c2UgcmVwZWF0ZWQgaW52b2NhdGlvbnMgdG8gcHJvZHVjZSBkaWZmZXJlbnQgcmVzdWx0cy48L3J1bGU+CiAgPGZlYXR1cmVfZmxhZ19lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnLmVuYWJsZUJlbmNobWFya2luZyI+CiAgICAgIDxmbGFnPmFzeW5jLXRlc3QuYmVuY2htYXJraW5nLmVuYWJsZWQ8L2ZsYWc+CiAgICAgIDxkZWZhdWx0X3ZhbHVlPmZhbHNlPC9kZWZhdWx0X3ZhbHVlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb25maWcubGljZW5zZU1vY2tNb2RlIj4KICAgICAgPGZsYWc+bGljZW5zZS5tb2NrLm1vZGU8L2ZsYWc+CiAgICAgIDxkZWZhdWx0X3ZhbHVlPmZhbHNlPC9kZWZhdWx0X3ZhbHVlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIiPgogICAgICA8ZmxhZz5hc3luYy10ZXN0LmJlbmNobWFya2luZy5lbmFibGVkPC9mbGFnPgogICAgICA8ZGVmYXVsdF92YWx1ZT5mYWxzZTwvZGVmYXVsdF92YWx1ZT4KICAgIDwvZWxlbWVudD4KICA8L2ZlYXR1cmVfZmxhZ19lbGVtZW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8ZmVhdHVyZV9mbGFnX2VsZW1lbnRzPiBhcmUgZ2F0ZWQgYnkgYSBmZWF0dXJlIGZsYWcuIEFsd2F5cyBwcmVzZXJ2ZSB0aGUgZmxhZyBjaGVjayDigJQgbmV2ZXIgYXNzdW1lIHRoZSBmbGFnIGlzIGFsd2F5cyBhY3RpdmUuPC9ydWxlPgogIDxzZWN1cml0eV9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yIj4KICAgICAgPGFzcGVjdD5jcnlwdG9ncmFwaHkgKGhhc2ggaW50ZWdyaXR5IC8gTUFDIC8gc2lnbmF0dXJlIHN0YXRlKTwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTZWN1cmVSYW5kb21EZXRlY3RvciI+CiAgICAgIDxhc3BlY3Q+Y3J5cHRvZ3JhcGh5IChSTkcgcXVhbGl0eSk8L2FzcGVjdD4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvciI+CiAgICAgIDxhc3BlY3Q+Y3J5cHRvZ3JhcGh5IChjb25maWRlbnRpYWxpdHkgLyBpbnRlZ3JpdHkgLyBhdXRoZW50aWNpdHkgc3RhdGUpPC9hc3BlY3Q+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5MaWNlbnNlR3VhcmQiPgogICAgICA8YXNwZWN0PmF1dGhvcml6YXRpb248L2FzcGVjdD4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VWYWxpZGF0aW9uQ2FjaGUiPgogICAgICA8YXNwZWN0PmF1dGhvcml6YXRpb24gKGlzRnJlc2ggc2tpcHMgb25saW5lIHZhbGlkYXRpb247IGhhc1JlY29yZCBhZG1pdHMgb3V0YWdlIGdyYWNlKTwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2UiPgogICAgICA8YXNwZWN0PmF1dGhvcml6YXRpb248L2FzcGVjdD4KICAgIDwvZWxlbWVudD4KICA8L3NlY3VyaXR5X2VsZW1lbnRzPgoKPHJ1bGU+RWxlbWVudHMgbGlzdGVkIGluIDxzZWN1cml0eV9lbGVtZW50cz4gYXJlIHNlY3VyaXR5LWNyaXRpY2FsLiBOZXZlciB3ZWFrZW4gdGhlaXIgc2VjdXJpdHkgcHJvcGVydGllcy4gRXZlcnkgcHJvcG9zZWQgY2hhbmdlIG11c3QgYmUgZXhwbGljaXRseSByZXZpZXdlZCBmb3Igc2VjdXJpdHkgaW1wYWN0LjwvcnVsZT4KICA8YWNjZXNzX2xpbWl0YXRpb25zPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0Lmluc3RhbGwoc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0KSI+CiAgICAgIDxhbGxvd2VkX2NhbGxlcnM+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXI8L2FsbG93ZWRfY2FsbGVycz4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dC5pbnN0YWxsKHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dCxpbnQpIj4KICAgICAgPGFsbG93ZWRfY2FsbGVycz5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5Db25jdXJyZW5jeVJ1bm5lcjwvYWxsb3dlZF9jYWxsZXJzPgogICAgPC9maWxlPgogIDwvYWNjZXNzX2xpbWl0YXRpb25zPgoKPHJ1bGU+RG8gbm90IGludm9rZSBlbGVtZW50cyBpbiA8YWNjZXNzX2xpbWl0YXRpb25zPiBmcm9tIG91dHNpZGUgdGhlaXIgc3BlY2lmaWVkIGFsbG93ZWQgY2FsbGVyIHBhY2thZ2VzIG9yIGNsYXNzZXMuPC9ydWxlPgogIDxtZW1vcnlfYnVkZ2V0X2VsZW1lbnRzPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIucmVjb3JkSW52b2NhdGlvbkVuZChsb25nKSI+CiAgICAgIDxhbGxvY2F0aW9uX3BvbGljeT5OT19BVVRPQk9YSU5HPC9hbGxvY2F0aW9uX3BvbGljeT4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYmVuY2htYXJrLkJlbmNobWFya1JlY29yZGVyLnJlY29yZEludm9jYXRpb25TdGFydCgpIj4KICAgICAgPGFsbG9jYXRpb25fcG9saWN5Pk5PX0FVVE9CT1hJTkc8L2FsbG9jYXRpb25fcG9saWN5PgogICAgPC9maWxlPgogIDwvbWVtb3J5X2J1ZGdldF9lbGVtZW50cz4KCjxydWxlPkF2b2lkIHJ1bnRpbWUgaGVhcCBvYmplY3QgYWxsb2NhdGlvbnMsIGF1dG9ib3hpbmcsIG9yIGR5bmFtaWMgb3ZlcmhlYWQgd2l0aGluIGNsYXNzZXMvbWV0aG9kcyBpbiA8bWVtb3J5X2J1ZGdldF9lbGVtZW50cz4uPC9ydWxlPgogIDxleHRlbnNpYmxlX3BhdHRlcm5zPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5yZXBvcnQuRm9ybWF0dGVyIj4KICAgICAgPGV4dGVuc2lvbl9wYXR0ZXJuPlNUUkFURUdZX1BBVFRFUk48L2V4dGVuc2lvbl9wYXR0ZXJuPgogICAgPC9maWxlPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5zcGkuRGV0ZWN0b3IiPgogICAgICA8ZXh0ZW5zaW9uX3BhdHRlcm4+U1RSQVRFR1lfUEFUVEVSTjwvZXh0ZW5zaW9uX3BhdHRlcm4+CiAgICA8L2ZpbGU+CiAgPC9leHRlbnNpYmxlX3BhdHRlcm5zPgoKPHJ1bGU+UmVzcGVjdCBleHRlbnNpYmlsaXR5IGd1aWRlbGluZXMgZm9yIGVsZW1lbnRzIGluIDxleHRlbnNpYmxlX3BhdHRlcm5zPi4gSW1wbGVtZW50IHN0cmF0ZWd5L3Zpc2l0b3IgZXh0ZW5zaW9ucyByYXRoZXIgdGhhbiBleHBhbmRpbmcgYnJhbmNoIGNvbmRpdGlvbmFsIGxvZ2ljLjwvcnVsZT4KICA8c2FuaXRpemF0aW9uX2VsZW1lbnRzPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5yZXBvcnQuSlVuaXRYbWxSZXBvcnRMaXN0ZW5lci5vblN0cnVjdHVyZWRSZXBvcnQoamF2YS5sYW5nLlN0cmluZyxzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLklzc3VlU2V2ZXJpdHksamF2YS5sYW5nLlN0cmluZykjcmVwb3J0Ij4KICAgICAgPHNhbml0aXphdGlvbl90eXBlcz5YU1M8L3Nhbml0aXphdGlvbl90eXBlcz4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0Lkpzb25SZXBvcnRMaXN0ZW5lci5vblN0cnVjdHVyZWRSZXBvcnQoamF2YS5sYW5nLlN0cmluZyxzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLklzc3VlU2V2ZXJpdHksamF2YS5sYW5nLlN0cmluZykjcmVwb3J0Ij4KICAgICAgPHNhbml0aXphdGlvbl90eXBlcz5YU1M8L3Nhbml0aXphdGlvbl90eXBlcz4KICAgIDwvZmlsZT4KICA8L3Nhbml0aXphdGlvbl9lbGVtZW50cz4KCjxydWxlPlN0cmljdCBpbnB1dCBzYW5pdGl6YXRpb24gaXMgbWFuZGF0b3J5IGZvciBlbGVtZW50cyBpbiA8c2FuaXRpemF0aW9uX2VsZW1lbnRzPi4gUmF3IGlucHV0IG11c3QgcGFzcyB0aHJvdWdoIGFwcHJvdmVkIGZpbHRlcnMgYmVmb3JlIGhpdHRpbmcgcXVlcmllcyBvciByZW5kZXJlcnMuPC9ydWxlPgogIDxsb2FkX2JlYXJpbmdfZWxlbWVudHM+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RJbnZvY2F0aW9uSW50ZXJjZXB0b3IuaW50ZXJjZXB0VGVzdFRlbXBsYXRlTWV0aG9kKG9yZy5qdW5pdC5qdXBpdGVyLmFwaS5leHRlbnNpb24uSW52b2NhdGlvbkludGVyY2VwdG9yLkludm9jYXRpb24mbHQ7amF2YS5sYW5nLlZvaWQmZ3Q7LG9yZy5qdW5pdC5qdXBpdGVyLmFwaS5leHRlbnNpb24uUmVmbGVjdGl2ZUludm9jYXRpb25Db250ZXh0Jmx0O2phdmEubGFuZy5yZWZsZWN0Lk1ldGhvZCZndDssb3JnLmp1bml0Lmp1cGl0ZXIuYXBpLmV4dGVuc2lvbi5FeHRlbnNpb25Db250ZXh0KSI+CiAgICAgIDxpbnZhcmlhbnQ+VGhpcyBtZXRob2QgY2FsbHMgaW52b2NhdGlvbi5za2lwKCkgYW5kIG5ldmVyIGludm9jYXRpb24ucHJvY2VlZCgpLjwvaW52YXJpYW50PgogICAgICA8YnJlYWtzLWlmPlNvbWVvbmUgJiMzOTtmaXhlcyYjMzk7IHRoZSBhcHBhcmVudGx5LWRyb3BwZWQgaW52b2NhdGlvbiBieSBjYWxsaW5nIHByb2NlZWQoKS4gVGhlIHRlc3QgYm9keSB0aGVuIHJ1bnMgb25jZSBvbiB0aGUgSlVuaXQgdGhyZWFkLCBvdXRzaWRlIHRoZSBDeWNsaWNCYXJyaWVyIGFuZCBvdXRzaWRlIEFzeW5jVGVzdENvbnRleHQsIHNvIG5vIGRldGVjdG9yIG9ic2VydmVzIGl0IOKAlCBhbmQgYmVjYXVzZSB0aGF0IHNpbmdsZSBydW4gdXN1YWxseSBwYXNzZXMsIHRoZSBzdWl0ZSBnb2VzIGdyZWVuIHdoaWxlIGV2ZXJ5IGNvbmN1cnJlbmN5IGNoZWNrIGhhcyBzaWxlbnRseSBzdG9wcGVkIHJ1bm5pbmcuPC9icmVha3MtaWY+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5Db25jdXJyZW5jeVJ1bm5lci5leGVjdXRlKG9yZy5qdW5pdC5qdXBpdGVyLmFwaS5leHRlbnNpb24uUmVmbGVjdGl2ZUludm9jYXRpb25Db250ZXh0Jmx0O2phdmEubGFuZy5yZWZsZWN0Lk1ldGhvZCZndDssc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb25maWcpIj4KICAgICAgPGludmFyaWFudD5UaGUgdGltZW91dEFscmVhZHlSZXBvcnRlZCBmbGFnLCBhbmQgdGhlIHBlci1zdGVwIGd1YXJkZWQgY2xlYW51cCBpbiB0aGUgZmluYWxseSBibG9jaywgYXJlIGJvdGggZGVsaWJlcmF0ZS4gQSBwcmUtcm91bmQgZGVhZGxpbmUgY2hlY2sgdGhyb3dzIGFuIGVycm9yIHRoYXQgaGFzIGFscmVhZHkgYmVlbiB0aHJvdWdoIHRpbWVvdXRFcnJvcigpLCBhbmQgZWFjaCBjbGVhbnVwIHN0ZXAgaXMgd3JhcHBlZCBpbiBpdHMgb3duIHRyeSBzbyBvbmUgZmFpbHVyZSBjYW5ub3Qgc3VwcHJlc3MgdGhlIG5leHQuPC9pbnZhcmlhbnQ+CiAgICAgIDxicmVha3MtaWY+VGhlIGZsYWcgaXMgcmVtb3ZlZCBhcyByZWR1bmRhbnQg4oCUIHRoZSBjYXRjaCBibG9jayB0aGVuIHNlbmRzIHRoZSBzYW1lIGVycm9yIHRocm91Z2ggdGltZW91dEVycm9yKCkgYSBzZWNvbmQgdGltZSwgcHJvZHVjaW5nIHR3byBvblRpbWVvdXQgY2FsbGJhY2tzIGFuZCB0d28gY29waWVzIG9mIGV2ZXJ5IHJlcG9ydCBmb3Igb25lIHRpbWVvdXQuIE9yIHRoZSBjbGVhbnVwIHN0ZXBzIGFyZSBtZXJnZWQgaW50byBvbmUgdHJ5LCBhdCB3aGljaCBwb2ludCBhIGZhaWxpbmcgQXN5bmNUZXN0Q29udGV4dC51bmluc3RhbGwoKSBza2lwcyB0aGUgbGF0Y2guY291bnREb3duKCkgYW5kIHRoZSByb3VuZCB3YWl0cyBvdXQgaXRzIHRpbWVvdXQgZm9yIG5vdGhpbmcuPC9icmVha3MtaWY+CiAgICA8L2VsZW1lbnQ+CiAgPC9sb2FkX2JlYXJpbmdfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBpbiA8bG9hZF9iZWFyaW5nX2VsZW1lbnRzPiBsb29rIHJlZHVuZGFudCBvciBvdmVyLWRlZmVuc2l2ZSBidXQgYXJlIGRlbGliZXJhdGUuIFlvdSBtYXkgcmVmYWN0b3IgdGhlbSwgYnV0IHRoZSBzdGF0ZWQgaW52YXJpYW50IG11c3Qgc3Vydml2ZTsgZG8gbm90ICJjbGVhbiB1cCIgdGhlIG9kZGl0eSBpdHNlbGYuPC9ydWxlPgogIDxtaXJyb3JlZF9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JUeXBlIj4KICAgICAgPG1pcnJvcj5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbmZpZzwvbWlycm9yPgogICAgICA8bWlycm9yPnNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JSZWdpc3RyeTwvbWlycm9yPgogICAgICA8cmVhc29uPkEgZGV0ZWN0b3IgaXMgb25seSByZWFjaGFibGUgZnJvbSB0aGUgcHVibGljIEFQSSB3aGVuIGFsbCBvZiB0aGVzZSBhZ3JlZS4gVGhlIGVudW0gY29uc3RhbnQgaXMgdGhlIG5hbWUgdXNlcnMgdHlwZSBpbiBAQXN5bmNUZXN0KGluY2x1ZGVzPS4uLiwgZXhjbHVkZXM9Li4uKTsgdGhlIGNvbmZpZyBmaWVsZCBkZXJpdmVzIGZyb20gdGhlIGVuYWJsZWQgc2V0OyBhbmQgdGhlIHJlZ2lzdHJ5JiMzOTtzIGZhY3Rvcnkgcm93IGJ1aWxkcyBpdC4gQWRkaW5nIHRoZSBjb25zdGFudCBhbG9uZSBjb21waWxlcyBhbmQgc2lsZW50bHkgZGV0ZWN0cyBub3RoaW5nLiBUaGUgU1BJIGJyaWRnZSB0aGF0IG1pcnJvcmVkIGV2ZXJ5IGNvbnN0YW50IGEgc2Vjb25kIHRpbWUgd2FzIGRlbGV0ZWQgaW4gMS4xMy4wICgjOTIyKS48L3JlYXNvbj4KICAgICAgPGVuZm9yY2VkLWJ5PnNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JSZWdpc3RyeUZhY3RvcnlUYWJsZVRlc3Q8L2VuZm9yY2VkLWJ5PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckRlZmF1bHRTZXZlcml0eSI+CiAgICAgIDxtaXJyb3I+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclR5cGU8L21pcnJvcj4KICAgICAgPG1pcnJvcj5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yVHJ1c3Q8L21pcnJvcj4KICAgICAgPHJlYXNvbj5BbiBlbnRyeSBoZXJlIGlzIHRoZSBzZXZlcml0eSBhIGJ1aWx0LWluIGRldGVjdG9yJiMzOTtzIGZpbmRpbmdzIGNhcnJ5IGF0IHRoZSBmYWlsT24gZ2F0ZSB3aGVuIGl0cyByZXBvcnQgbWFya3Mgbm9uZS4gQSBkZXRlY3RvciBtaXNzaW5nIGZyb20gYm90aCB0aGlzIHRhYmxlIGFuZCB0aGUgbWFya2VyIGNvbnZlbnRpb24gc2lsZW50bHkgZmFsbHMgYmFjayB0byBISUdILCB3aGljaCBpcyB0aGUgZGVmZWN0IHRoaXMgdGFibGUgZXhpc3RzIHRvIGZpeC48L3JlYXNvbj4KICAgICAgPGVuZm9yY2VkLWJ5PnNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yU2V2ZXJpdHlNYXJrZXJUZXN0PC9lbmZvcmNlZC1ieT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JGZWVkcyI+CiAgICAgIDxtaXJyb3I+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclR5cGU8L21pcnJvcj4KICAgICAgPG1pcnJvcj5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yVHJ1c3Q8L21pcnJvcj4KICAgICAgPG1pcnJvcj5kb2NzL0RFVEVDVE9SX0NBVEFMT0cubWQ8L21pcnJvcj4KICAgICAgPHJlYXNvbj5FdmVyeSBEZXRlY3RvclR5cGUgcmVzb2x2ZXMgdG8gZXhhY3RseSBvbmUgZmVlZCwgdGhlIEFHRU5UIHNldCBtdXN0IGVxdWFsIHRoZSBkZXRlY3RvcnMgdGhlIHRlbGVtZXRyeSBicmlkZ2UgYW5kIGNvbGxlY3Rpb24gaG9va3MgYXJlIGNvbXBpbGUtd2lyZWQgaW50bywgYW5kIHRoZSBjYXRhbG9nJiMzOTtzIGZlZWQgbGlzdGluZyBtdXN0IG5hbWUgdGhlIHNhbWUgY2xhc3NlcyB0aGlzIHRhYmxlIGNsYXNzaWZpZXMuIEEgZmVlZCB0aGF0IGRyaWZ0cyBtaXNsZWFkcyB0aGUgdXNlciBkZWNpZGluZyB3aGV0aGVyIGF0dGFjaGluZyB0aGUgYWdlbnQgYnV5cyB0aGVtIGFueXRoaW5nLjwvcmVhc29uPgogICAgICA8ZW5mb3JjZWQtYnk+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5hcmNoaXRlY3R1cmUuRGV0ZWN0b3JGZWVkQ292ZXJhZ2VUZXN0PC9lbmZvcmNlZC1ieT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JUcnVzdCI+CiAgICAgIDxtaXJyb3I+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclR5cGU8L21pcnJvcj4KICAgICAgPG1pcnJvcj5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yUmVnaXN0cnk8L21pcnJvcj4KICAgICAgPG1pcnJvcj5kb2NzL0RFVEVDVE9SX0NBVEFMT0cubWQ8L21pcnJvcj4KICAgICAgPHJlYXNvbj5FdmVyeSBEZXRlY3RvclR5cGUgbmVlZHMgZXhhY3RseSBvbmUgcm93LCBhbmQgZWFjaCByb3cgbmFtZXMgdGhlIGRldGVjdG9yIGNsYXNzIHdob3NlIHNpbXBsZSBuYW1lIGtleXMgdGhlIHJlcG9ydCBtYXAgKERldGVjdG9yUmVnaXN0cnkuaWZJc3N1ZSkuIEEgcm93IG5hbWluZyBhIGNsYXNzIHRoZSByZWdpc3RyeSYjMzk7cyBmYWN0b3J5IHJvdyBkb2VzIG5vdCBjcmVhdGUgc2lsZW50bHkgc3RvcHMgcmVzb2x2aW5nLCBhbmQgdGhlIGZpbmRpbmcgbG9zZXMgaXRzIHRpZXIgd2l0aG91dCBhbnl0aGluZyBnb2luZyByZWQuPC9yZWFzb24+CiAgICAgIDxlbmZvcmNlZC1ieT5zZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFyY2hpdGVjdHVyZS5EZXRlY3RvclRydXN0Q292ZXJhZ2VUZXN0PC9lbmZvcmNlZC1ieT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LlRlbGVtZXRyeUJyaWRnZSI+CiAgICAgIDxtaXJyb3I+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckZlZWRzPC9taXJyb3I+CiAgICAgIDxtaXJyb3I+ZG9jcy9ERVRFQ1RPUl9DQVRBTE9HLm1kPC9taXJyb3I+CiAgICAgIDxyZWFzb24+RGV0ZWN0b3JGZWVkcy5mZWRCeShBR0VOVCkgbXVzdCBlcXVhbCB0aGUgZGV0ZWN0b3JzIHRoZSB3b3ZlbiBzdHJlYW1zIGFjdHVhbGx5IHJlYWNoLCBhbmQgdGhpcyBjbGFzcyBpcyBvbmUgb2YgdGhvc2Ugc3RyZWFtcy4gVGhlIGdhdGUgcmVmbGVjdHMgb3ZlciB0aGlzIGNsYXNzJiMzOTtzIGRlY2xhcmVkIGNvbnN0cnVjdG9ycyBhbmQgbWV0aG9kcyBhbmQgYXNzZXJ0cyB0aGUgZGV0ZWN0b3IgdHlwZXMgaXQgaXMgY29tcGlsZS13aXJlZCB0byBhcmUgZXhhY3RseSB7QXRvbWljaXR5VmFsaWRhdG9yfS4gUm91dGluZyBhIHNlY29uZCBkZXRlY3RvciBoZXJlIHdpdGhvdXQgYWRkaW5nIGl0cyBBR0VOVCByb3cgbGVhdmVzIHRoZSBjYXRhbG9nIHRlbGxpbmcgdXNlcnMgdGhlIGFnZW50IGJ1eXMgdGhlbSBub3RoaW5nIGZvciB0aGF0IGRldGVjdG9yLjwvcmVhc29uPgogICAgICA8ZW5mb3JjZWQtYnk+c2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5hcmNoaXRlY3R1cmUuRGV0ZWN0b3JGZWVkQ292ZXJhZ2VUZXN0PC9lbmZvcmNlZC1ieT4KICAgIDwvZWxlbWVudD4KICA8L21pcnJvcmVkX2VsZW1lbnRzPgoKPHJ1bGU+RWxlbWVudHMgaW4gPG1pcnJvcmVkX2VsZW1lbnRzPiBhcmUgZHVwbGljYXRlZCBhdCB0aGUgbGlzdGVkIHNpdGVzLiBUaGV5IG1heSBjaGFuZ2UgZnJlZWx5LCBidXQgZXZlcnkgbWlycm9yIG11c3QgY2hhbmdlIGluIHRoZSBzYW1lIGNvbW1pdCDigJQgYSBwYXJ0aWFsIGVkaXQgZGVzeW5jcyBzaWxlbnRseSBhbmQgbm8gY29tcGlsZXIgd2lsbCBjYXRjaCBpdC48L3J1bGU+CjwvcHJvamVjdF9ndWFyZHJhaWxzPgoKPHJ1bGU+TmV2ZXIgcHJvcG9zZSBlZGl0cyB0byBmaWxlcyBsaXN0ZWQgaW4gPGxvY2tlZF9maWxlcz4uPC9ydWxlPgo= +gemini_md=IyBHRU1JTkkgQUkgSU5TVFJVQ1RJT05TCiMgR2VuZXJhdGVkIGJ5IFZpYmVUYWdzIHwgaHR0cHM6Ly9naXRodWIuY29tL1BJc2JlcmcvdmliZXRhZ3MKCiMjIExPQ0tFRCBGSUxFUyAoRE8gTk9UIE1PRElGWSkKRG8gbm90IHN1Z2dlc3QgbW9kaWZpY2F0aW9ucyB0byB0aGUgZm9sbG93aW5nIGZpbGVzOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclR5cGVgOiBBZGRpbmcgb3IgcmVtb3ZpbmcgYSBjb25zdGFudCByZXF1aXJlcyBzeW5jaHJvbml6ZWQgY2hhbmdlcyBpbiB0aHJlZSBwbGFjZXM6ICgxKSB0aGUgQXN5bmNUZXN0Q29uZmlnIHB1YmxpYyBmbGFnIGFuZCBpdHMgZGVyaXZhdGlvbiBlbmFibGVkLmNvbnRhaW5zKFRZUEUpLCB3aXRoIHRoZSBCdWlsZGVyIHNldHRlciB0aGF0IGNhbGxzIGZsYWcoVFlQRSwgdiksICgyKSB0aGUgRGV0ZWN0b3JSZWdpc3RyeSBmaWVsZCBhbmQgaXRzIGZhY3Rvcnkgcm93IGNyZWF0ZShEZXRlY3RvclR5cGUuVFlQRSwgWDo6bmV3KSwgYW5kICgzKSB0aGUgcmVnaXN0cnkncyBpZklzc3VlIGFuYWx5c2lzIGNhbGwuIEFkZGluZyBhIHZhbHVlIGhlcmUgaW4gaXNvbGF0aW9uIGNvbXBpbGVzIGFuZCBkZXRlY3RzIG5vdGhpbmcuIFRoZSBAQXN5bmNUZXN0IGF0dHJpYnV0ZSBhbmQgdGhlIGJ1aWxkKCkgcmVzb2x1dGlvbiBsaW5lIGl0IG9uY2UgYWxzbyBuZWVkZWQgYXJlIGdvbmUgKCM5MTcsICM5MjApLiBUaGUgbG9jayBpcyBvbiB0aGUgY29uc3RhbnQgc2V0LCBub3QgdGhlIGZpbGU6IGVkaXRpbmcgamF2YWRvYyBvbiBleGlzdGluZyBjb25zdGFudHMgY2Fubm90IGJyZWFrIHRoYXQgaW52YXJpYW50IGFuZCBuZWVkcyBubyBjZXJlbW9ueS4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2UuVkVORE9SX1ZFUklGWV9LRVlfQjY0YDogRXZlcnkgb2ZmbGluZSBsaWNlbmNlIGZpbGUgYWxyZWFkeSBpc3N1ZWQgdG8gYSBjdXN0b21lciB2ZXJpZmllcyBhZ2FpbnN0IHRoaXMga2V5LCBhbmQgaXRzIHByaXZhdGUgaGFsZiBleGlzdHMgb25seSBvbiB0aGUgb3BlcmF0b3IgbWFjaGluZS4gQSBjaGFuZ2VkIHZhbHVlIGRlbmllcyBlYWNoIG9mIHRob3NlIGZpbGVzIHdpdGggT0ZGTElORV9GSUxFX1NJR05BVFVSRV9JTlZBTElEIG9uIHRoZSBjdXN0b21lcidzIG5leHQgYnVpbGQuIFJvdGF0aW9uIG1lYW5zIHJlLWlzc3VpbmcgZXZlcnkgZmlsZSBmaXJzdDogYSByZWxlYXNlIGRlY2lzaW9uLCBub3QgYSBjb2RlIGVkaXQuCgojIyBDT05USU5VT1VTIEFVRElUIFJFUVVJUkVNRU5UUwpZb3UgYXJlIGFjdGluZyBhcyBhIFNlbmlvciBTdGFmZiBFbmdpbmVlci4gV2hlbmV2ZXIgeW91IHdyaXRlIGNvZGUgZm9yIHRoZSBmaWxlcyBsaXN0ZWQgYmVsb3csIHlvdSBtdXN0IGVuc3VyZSB5b3VyIGNvbXBsZXRpb25zIGFuZCBjaGF0IHJlc3BvbnNlcyBzdHJpY3RseSBwcmV2ZW50IHRoZSBsaXN0ZWQgdnVsbmVyYWJpbGl0aWVzOgoKRmlsZTogYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dGAKQ3JpdGljYWwgVnVsbmVyYWJpbGl0aWVzIHRvIFByZXZlbnQ6Ci0gVGhyZWFkIFNhZmV0eSBpc3N1ZXMKCkZpbGU6IGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5Db25jdXJyZW5jeVJ1bm5lcmAKQ3JpdGljYWwgVnVsbmVyYWJpbGl0aWVzIHRvIFByZXZlbnQ6Ci0gVGhyZWFkIFNhZmV0eSBpc3N1ZXMKLSBSZXNvdXJjZSBMZWFrcwoKIyMgSUdOT1JFRCBFTEVNRU5UUwpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIG11c3QgYmUgY29tcGxldGVseSBleGNsdWRlZCBmcm9tIEFJIGNvbnRleHQgYW5kIGNvbXBsZXRpb25zOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Ob29wQXN5bmNUZXN0TGlzdGVuZXJgIC0gVHJpdmlhbCBuby1vcCBpbXBsZW1lbnRhdGlvbiBvZiBBc3luY1Rlc3RMaXN0ZW5lci4gQWxsIG1ldGhvZHMgYXJlIGludGVudGlvbmFsbHkgZW1wdHkg4oCUIG5vIGxvZ2ljIHRvIHJldmlldyBvciBjaGFuZ2UgaGVyZS4KCiMjIFBJSSAvIFBSSVZBQ1kgR1VBUkRSQUlMUwpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGhhbmRsZSBQZXJzb25hbGx5IElkZW50aWZpYWJsZSBJbmZvcm1hdGlvbiAoUElJKS4KTmV2ZXIgaW5jbHVkZSB0aGVpciBydW50aW1lIHZhbHVlcyBpbiBsb2dzLCBjb25zb2xlIG91dHB1dCwgZXh0ZXJuYWwgQVBJIGNhbGxzLAp0ZXN0IGZpeHR1cmVzLCBtb2NrIGRhdGEsIG9yIGNvZGUgc3VnZ2VzdGlvbnMuCgotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5MaWNlbnNlR3VhcmQuRmluZ2VycHJpbnRgOiBIb2xkcyB0aGUgbGljZW5jZSBrZXkgYW5kIHRoZSBsaWNlbnNlZCB1c2VyJ3MgZW1haWwsIGFuZCB0aGUgcmVjb3JkJ3MgZ2VuZXJhdGVkIHRvU3RyaW5nKCkgcHJpbnRzIGJvdGgsIHNvIG5ldmVyIGxvZyBvciBmb3JtYXQgYSBGaW5nZXJwcmludCB3aG9sZS4gVGhlIGVtYWlsIG1heSByZWFjaCB0aGUgbGljZW5jZSBwcm92aWRlciAoS2V5Z2VuIHVzZXIgc2NvcGUsIExlbW9uU3F1ZWV6eSBiaW5kaW5nKSBhbmQgYSBkZW5pYWwgbWVzc2FnZSBpbiB0aGF0IHVzZXIncyBvd24gYnVpbGQ7IGRpc2sgc2VlcyBlaXRoZXIgdmFsdWUgb25seSBpbnNpZGUgdGhlIFNIQS0yNTYgTGljZW5zZVZhbGlkYXRpb25DYWNoZSBzdG9yZXMuIE5ldmVyIHB1dCBvbmUgaW4gYW4gSU5GTyBsaW5lLCBhIHJlcG9ydCwgU0FSSUYgb3IgSlVuaXQgWE1MOiB0aG9zZSBlbmQgdXAgaW4gQ0kgbG9ncyBhbmQgcHVibGlzaGVkIGFydGlmYWN0cy4KCiMjIENPUkUgRlVOQ1RJT05BTElUWSAoRVhUUkVNRSBDQVVUSU9OKQpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbjoKCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnYDogU2Vuc2l0aXZpdHk6IENyaXRpY2FsLiBOb3RlOiBTZWxlY3Rpb24gaXMgb25lIEVudW1TZXQgcmVzb2x2ZWQgb25jZSBpbiBidWlsZCgpICgjOTE3KTsgZXZlcnkgcHVibGljIGRldGVjdG9yIGZsYWcgaXMgYXNzaWduZWQgZW5hYmxlZC5jb250YWlucyhUWVBFKSBpbiB0aGUgY29uc3RydWN0b3IgYW5kIG5vd2hlcmUgZWxzZSwgc28gYSBmbGFnIGNhbm5vdCBkaXNhZ3JlZSB3aXRoIGVuYWJsZWREZXRlY3RvcnMoKS4gQSBuZXcgZGV0ZWN0b3IgaGVyZSBpcyB0aGUgZmxhZyBhbmQgaXRzIGRlcml2YXRpb24gYW5kIHRoZSBCdWlsZGVyIHNldHRlciB0aGF0IGNhbGxzIGZsYWcoVFlQRSwgdik7IEBBc3luY1Rlc3QgaGFzIG5vIHBlci1kZXRlY3RvciBhdHRyaWJ1dGUgdG8gcmVhZCBzaW5jZSAxLjEzLjAgKCM5MjApLiBOZXZlciByZWludHJvZHVjZSBhIHBlci1kZXRlY3RvciByZXNvbHV0aW9uIGV4cHJlc3Npb24gaW4gYnVpbGQoKS4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0YDogU2Vuc2l0aXZpdHk6IENyaXRpY2FsLiBOb3RlOiBUaHJlYWRMb2NhbCBpbnN0YWxsL3VuaW5zdGFsbCBtdXN0IGFsd2F5cyBiZSBzeW1tZXRyaWMuIEEgbGVhayBwcm9wYWdhdGVzIHN0YWxlIGRldGVjdG9yIHN0YXRlIGFjcm9zcyB0ZXN0IGludm9jYXRpb25zIGFuZCBjYXVzZXMgZmFsc2UgcG9zaXRpdmVzIG9yIG1pc3NlZCBkZXRlY3Rpb25zLgotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RJbnZvY2F0aW9uSW50ZXJjZXB0b3JgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IGludm9jYXRpb24uc2tpcCgpIGlzIGludGVudGlvbmFsIOKAlCBDb25jdXJyZW5jeVJ1bm5lciBvd25zIHRoZSBmdWxsIE7Dl00gZXhlY3V0aW9uIGFuZCBtdXN0IG5ldmVyIGNhbGwgaW52b2NhdGlvbi5wcm9jZWVkKCkuIFJlc3RvcmluZyBwcm9jZWVkKCkgd291bGQgcnVuIHRoZSB0ZXN0IGJvZHkgb25jZSBvdXRzaWRlIHRoZSBDeWNsaWNCYXJyaWVyLCBieXBhc3NpbmcgYWxsIGRldGVjdG9ycy4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXJgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IENvcmUgc3RyZXNzLXRlc3QgZXhlY3V0aW9uIGVuZ2luZS4gVGhlIEN5Y2xpY0JhcnJpZXIgcGF0dGVybiBmb3JjZXMgbWF4aW11bSB0aHJlYWQgY29udGVudGlvbi4gVGltZW91dCBsb2dpYyBhbmQgQXN5bmNUZXN0Q29udGV4dCBpbnN0YWxsL3VuaW5zdGFsbCBhcmUgY2FyZWZ1bGx5IGNhbGlicmF0ZWQg4oCUIHN1YnRsZSBjaGFuZ2VzIGludHJvZHVjZSBmbGFreSB0ZXN0cyBvciBtaXNzZWQgZGV0ZWN0b3IgYWN0aXZhdGlvbnMuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LkNvbnRyb2xsZWRTY2hlZHVsZWA6IFNlbnNpdGl2aXR5OiBIaWdoLiBOb3RlOiBBIHNlZWQgcmVwbGF5cyBhIHJvdW5kIG9ubHkgd2hpbGUgZXZlcnkgZGVjaXNpb24gb2Ygd2hvIHJ1bnMgbmV4dCBkZXBlbmRzIG9uIHN0YXRlIGNoYW5nZWQgYXQgc2NoZWR1bGluZyBwb2ludHM6IHRoZSBzdGF0dXNlcywgcHJpb3JpdGllcyBhbmQgc3RlcCBjb3VudCB0aGF0IGdyYW50KCkgYW5kIHN0ZXAoKSByZWFkLCBhbmQgdGhlIGxvY2sgaG9sZHMgYW5kIHBlbmRpbmcgYWNxdWlzaXRpb25zIGdyYW50KCkgY29uc3VsdHMgKCMxMDIyKSwgd2hpY2ggY2hhbmdlIG9ubHkgYXQgYWNxdWlyaW5nKCksIGl0c2VsZiBhIHBvaW50LCBhbmQgaW4gYWNxdWlyZWQoKSBhbmQgcmVsZWFzZWQoKSwgd2hpY2ggYSB3b3JrZXIgY2FsbHMgaW4gaXRzIG93biBwcm9ncmFtIG9yZGVyOyBhbiBlc2NhcGVkIHdvcmtlcidzIGFjcXVpcmUgb3IgcmVsZWFzZSBsYW5kcyBvdXRzaWRlIGEgdHVybiwgYnV0IGl0cyByb3VuZCBoYXMgYWxyZWFkeSBjb3VudGVkIHRoZSBlc2NhcGUuIGdyYW50KCkgbXVzdCBrZWVwIGhhbmRpbmcgdGhlIHJvdW5kIG91dCB3aGVuIGV2ZXJ5IHJlYWR5IHdvcmtlciB3YWl0cyBvbiBhIGhlbGQgbG9jazogdGhlIGhvbGQgbWF5IGJlIHN0YWxlIChhIG1vbml0b3IgcmVsZWFzZWQgaW5zaWRlIE9iamVjdC53YWl0IGlzIG5vdCBzZWVuKSwgYW5kIHdpdGhob2xkaW5nIHRoZSByb3VuZCB0aGVuIHN0YWxscyBjb3JyZWN0IHdhaXQvbm90aWZ5IGNvZGUgdW50aWwgdGhlIHJvdW5kIHRpbWVzIG91dCAoQ29udHJvbGxlZFNjaGVkdWxlTG9ja1Rlc3QpOyBlYWNoIHN1Y2ggZ3JhbnQgaXMgY291bnRlZCBhcyBhIGZhbGxiYWNrLiBUbyBrZWVwIGhvbGRzIGZyb20gZ29pbmcgc3RhbGUsIGEgd292ZW4gT2JqZWN0LndhaXQgb3IgQ29uZGl0aW9uLmF3YWl0IGhhbmRzIGl0cyBob2xkcyBiYWNrIGJlZm9yZSB3YWl0aW5nIGFuZCB0YWtlcyB0aGVtIGFnYWluIGFmdGVyIChyZWxlYXNpbmdGb3JXYWl0LCByZWFjcXVpcmVkQWZ0ZXJXYWl0OyBsb2NrT2YgZmluZHMgYSBjb25kaXRpb24ncyBSZWVudHJhbnRMb2NrIGJ5IGFza2luZyBpdCksIGFuZCBhIHdvcmtlciByZS1jb25maXJtcyBpdHMgb3duIHJlY29yZGVkIGhvbGRzIHdpdGggVGhyZWFkLmhvbGRzTG9jayBvciBpc0hlbGRCeUN1cnJlbnRUaHJlYWQgYXQgZWFjaCBvZiBpdHMgcG9pbnRzIGFuZCBhdCBsZWF2ZSgpLCBvbiBpdHMgb3duIHRocmVhZCwgc28gdGhlIGFuc3dlciBmb2xsb3dzIGl0cyBwcm9ncmFtIG9yZGVyIGFuZCBncmFudCgpIHN0aWxsIHJlYWRzIG5vIHRocmVhZCBzdGF0ZSAoIzEwNDgpLiBPbmx5IHdhdGNoKCkgbWF5IHJlYWQgdGhlIGNsb2NrIG9yIFRocmVhZC5nZXRTdGF0ZSgpLCBhbmQgaXQgcmVhZHMgdGhlIHN0YXRlIGJlZm9yZSBhc2tpbmcgd2hldGhlciB0aGUgcnVubmluZyB3b3JrZXIsIG9yIGFuIGFkb3B0ZWQgY2hpbGQgc3RpbGwgYXJyaXZpbmcsIGlzIHF1ZXVlZCBvbiB0aGUgc2NoZWR1bGUncyBvd24gbG9jaywgd2hpY2ggaXMgdGhlIHNjaGVkdWxlcidzIHdhaXQgYW5kIG5ldmVyIGFuIGVzY2FwZSAoIzEwNjUsICMxMDcyKTsgZWFjaCBkZWNpc2lvbiBpdCBtYWtlcyBpcyBjb3VudGVkIGFzIGFuIGVzY2FwZSwgd2hpY2ggaXMgd2hhdCB0ZWxscyB0aGUgcnVubmVyIHRoZSBzZWVkIG5vIGxvbmdlciByZXBsYXlzIGV4YWN0bHksIHdpdGggb25lIGV4Y2VwdGlvbjogYW4gYWRvcHRlZCBjaGlsZCB3aG9zZSB0aHJlYWQgaGFzIHRlcm1pbmF0ZWQgaXMgbWFya2VkIGRvbmUsIG5vdCBlc2NhcGVkICgjMTAyNCksIGJlY2F1c2Ugd2hpbGUgaXQgcmFuIHRvIGl0cyBlbmQgZXZlcnkgcGVlciB3YXMgd2FpdGluZywgc28gdGhlIHN0YXRlIHRoZSBuZXh0IGdyYW50IHJlYWRzIGlzIHRoZSBzYW1lIHdoZW5ldmVyIHdhdGNoKCkgbm90aWNlcy4gQWRvcHRlZCBjaGlsZHJlbiBhcmUgcmVhZHkgZnJvbSB0aGUgbW9tZW50IHRoZXkgYXJlIGFkb3B0ZWQsIHNvIGEgZ3JhbnQgbmV2ZXIgZGVwZW5kcyBvbiBob3cgbG9uZyB0aGUgT1MgdGFrZXMgdG8gc3RhcnQgYSB0aHJlYWQ7IGFuIGFkb3B0ZWQgZXhlY3V0b3IgdGFzayAoIzEwNDkpIGlzIHJlYWR5IGZyb20gaXRzIHdvdmVuIHN1Ym1pc3Npb24gdGhlIHNhbWUgd2F5LCBqb2lucyBhdCB0YXNrU3RhcnRpbmcgb24gdGhlIHBvb2wgdGhyZWFkIGFuZCBsZWF2ZXMgYXQgdGFza0VuZGVkLCBhbmQgb25lIHRoYXQgaGFzIG5vdCBzdGFydGVkIHdpdGhpbiBTVEFMTF9OQU5PUyBpcyBjb3VudGVkIGFzIGFuIGVzY2FwZSwgc2luY2UgaXRzIGV4ZWN1dG9yIG1heSBuZXZlciBydW4gaXQuIEEgd29ya2VyIHdhaXRpbmcgYXQgYSByZW5kZXp2b3VzIGlzIE9VVFNJREUsIG5vdCBlc2NhcGVkICgjMTAyMSksIGFuZCBubyBncmFudCBpcyBtYWRlIHdoaWxlIG9uZSBpcyBvdXRzaWRlIG9uIGl0cyB3YXkgYmFjayBvciB3aGVuIHRoZSBsYXN0IHdvcmtlciBzdGVwcyBvdXQsIHNvIHRoZSBvcmRlciBhIHJlbmRlenZvdXMgcmVsZWFzZXMgd29ya2VycyBpbiBuZXZlciBkZWNpZGVzIHdobyBydW5zIG5leHQuIEEgZ3JhbnQoKSB0aGF0IHJlYWQgdGltZSBvciB0aHJlYWQgc3RhdGUsIG9yIGFuIGVzY2FwZSBsZWZ0IHVuY291bnRlZCwgc3RpbGwgcGFzc2VzIGV2ZXJ5IHJ1biBhbmQgbWFrZXMgdGhlIHByaW50ZWQgcmVwbGF5IGxpbmUgYSBmYWxzZSBwcm9taXNlLgoKIyMgU0VDVVJJVFktQ1JJVElDQUwgQ09ERQpEbyBub3Qgd2Vha2VuIHNlY3VyaXR5IHByb3BlcnRpZXMgb2YgdGhlc2UgZWxlbWVudHMuIEZsYWcgYW55IGNoYW5nZSBmb3Igc2VjdXJpdHkgcmV2aWV3OgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3JgOiBTZWN1cml0eS1jcml0aWNhbCBjb2RlIFtjcnlwdG9ncmFwaHkgKGhhc2ggaW50ZWdyaXR5IC8gTUFDIC8gc2lnbmF0dXJlIHN0YXRlKV0uIERvIG5vdCB3ZWFrZW4gc2VjdXJpdHkgcHJvcGVydGllcy4gRmxhZyBhbnkgY2hhbmdlIGZvciBzZWN1cml0eSByZXZpZXcuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3JgOiBTZWN1cml0eS1jcml0aWNhbCBjb2RlIFtjcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KV0uIERvIG5vdCB3ZWFrZW4gc2VjdXJpdHkgcHJvcGVydGllcy4gRmxhZyBhbnkgY2hhbmdlIGZvciBzZWN1cml0eSByZXZpZXcuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvcmA6IFNlY3VyaXR5LWNyaXRpY2FsIGNvZGUgW2NyeXB0b2dyYXBoeSAoY29uZmlkZW50aWFsaXR5IC8gaW50ZWdyaXR5IC8gYXV0aGVudGljaXR5IHN0YXRlKV0uIERvIG5vdCB3ZWFrZW4gc2VjdXJpdHkgcHJvcGVydGllcy4gRmxhZyBhbnkgY2hhbmdlIGZvciBzZWN1cml0eSByZXZpZXcuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VHdWFyZGA6IFNlY3VyaXR5LWNyaXRpY2FsIGNvZGUgW2F1dGhvcml6YXRpb25dLiBEbyBub3Qgd2Vha2VuIHNlY3VyaXR5IHByb3BlcnRpZXMuIEZsYWcgYW55IGNoYW5nZSBmb3Igc2VjdXJpdHkgcmV2aWV3LgotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5MaWNlbnNlVmFsaWRhdGlvbkNhY2hlYDogU2VjdXJpdHktY3JpdGljYWwgY29kZSBbYXV0aG9yaXphdGlvbiAoaXNGcmVzaCBza2lwcyBvbmxpbmUgdmFsaWRhdGlvbjsgaGFzUmVjb3JkIGFkbWl0cyBvdXRhZ2UgZ3JhY2UpXS4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBGbGFnIGFueSBjaGFuZ2UgZm9yIHNlY3VyaXR5IHJldmlldy4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2VgOiBTZWN1cml0eS1jcml0aWNhbCBjb2RlIFthdXRob3JpemF0aW9uXS4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBGbGFnIGFueSBjaGFuZ2UgZm9yIHNlY3VyaXR5IHJldmlldy4KCiMjIFNjb3BlZCBSdWxlcyBJbmRleApEZXRhaWxlZCBwZXItZWxlbWVudCBndWFyZHJhaWxzIGxpdmUgaW4gc2NvcGVkIHJ1bGUgZmlsZXMgdGhhdCBHZW1pbmkgQ0xJIGRvZXMgbm90IGxvYWQgb24gaXRzIG93bi4gQSBsaW5lIGBhLmJgOiBgQ2AsIGBEYCBuYW1lcyBhLmIuQyBhbmQgYS5iLkQuIFVubGVzcyBhbiBlbnRyeSBjYXJyaWVzIGFuIGV4cGxpY2l0IHBhdGgsIGl0cyBmaWxlIGlzIC5nZW1pbmkvcnVsZXMve3BhdGgsIGV2ZXJ5IG5vbi1hbHBoYW51bWVyaWMgY2hhcmFjdGVyIHJlcGxhY2VkIGJ5ICctJ30ubWQuIEJlZm9yZSBtb2RpZnlpbmcgYW4gZWxlbWVudCBsaXN0ZWQgYmVsb3csIG9wZW4gaXRzIGZpbGUgd2l0aCByZWFkX2ZpbGUgYW5kIGFwcGx5IHRoZSBndWFyZHJhaWxzIHRoZXJlOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdGA6IGBBZ2VudENvbGxlY3Rpb25Ib29rc2AsIGBBZ2VudENvbmN1cnJlbmN5VXRpbEhvb2tzYCwgYEFnZW50Q29uc3RydWN0aW9uSG9va3NgLCBgQWdlbnRHY0hvb2tzYCwgYEFnZW50TG9ja0hvb2tzYCwgYEFnZW50TW9uaXRvckhvb2tzYCwgYEFnZW50U2hhcmVkSW5zdGFuY2VIb29rc2AsIGBBZ2VudFNsZWVwSG9va3NgLCBgQWdlbnRUaHJlYWRIb29rc2AsIGBSdW5PdXRjb21lc2AKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdGA6IGBBc3luY0Fzc2VydGAsIGBBc3luY0ZpbmRpbmdzYCwgYEFzeW5jVGVzdExpc3RlbmVyYCwgYEFzeW5jVGVzdExpc3RlbmVyUmVnaXN0cnlgLCBgQXN5bmNUZXN0UnVubmVyYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1wdWJsaWMtYXBpLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0YDogYEFzeW5jVGVzdGAsIGBBc3luY1Rlc3RDb25maWdgLCBgRGV0ZWN0b3JSZWdpc3RyeWAsIGBEZXRlY3RvclR5cGVgLCBgUHJlc2V0YCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1jb25maWd1cmF0aW9uLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHRgIOKGkiBgLmdlbWluaS9ydWxlcy9hc3luYy10ZXN0LXJ1bnRpbWUtY29yZS5tZGAKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RMaXN0ZW5lclJlZ2lzdHJ5LlJlZ2lzdHJhdGlvbmAg4oaSIGAuZ2VtaW5pL3J1bGVzL2FzeW5jLXRlc3QtcHVibGljLWFwaS5tZGAKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmtgOiBgQmVuY2htYXJrQ29tcGFyYXRvcmAsIGBCZW5jaG1hcmtSZWNvcmRlcmAg4oaSIGAuZ2VtaW5pL3J1bGVzL2FzeW5jLXRlc3QtaW5zdHJ1bWVudGF0aW9uLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzYDogYEJsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yYCwgYENvbXBsZXRhYmxlRnV0dXJlQmxvY2tpbmdDYWxsYmFja0RldGVjdG9yYCwgYENvbXBsZXRhYmxlRnV0dXJlQ2FuY2VsbGF0aW9uUHJvcGFnYXRpb25EZXRlY3RvcmAsIGBDb21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvcmAsIGBDb21wbGV0YWJsZUZ1dHVyZUNvbXBsZXRpb25SYWNlRGV0ZWN0b3JgLCBgQ29tcGxldGFibGVGdXR1cmVPYnRydWRlRGV0ZWN0b3JgLCBgQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yYCwgYERhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvcmAsIGBEZXRlY3RvckRlZmF1bHRTZXZlcml0eWAsIGBEZXRlY3RvckZlZWRzYCwgYERldGVjdG9yVHJ1c3RgLCBgRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvcmAsIGBGaW5hbEZpZWxkTXV0YXRpb25EZXRlY3RvcmAsIGBGbG93UHVibGlzaGVyQ29uY3VycmVuY3lEZXRlY3RvcmAsIGBHcmFkZWRGaW5kaW5nc2AsIGBIaWdoQ29udGVudGlvbkF0b21pY0RldGVjdG9yYCwgYEpkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3JgLCBgS290bGluTXV0ZXhSZWVudHJhbmN5RGV0ZWN0b3JgLCBgTGFtYmRhTG9zdFVwZGF0ZURldGVjdG9yYCwgYExhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3JgLCBgTGF6eUNvbnN0YW50TWlzdXNlRGV0ZWN0b3JgLCBgTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yYCwgYE5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvcmAsIGBOb3RpZnlXaXRob3V0TW9uaXRvckRldGVjdG9yYCwgYFBsYXRmb3JtVGhyZWFkUGVyVGFza0RldGVjdG9yYCwgYFByb2Nlc3NTdHJlYW1TdGFydmF0aW9uRGV0ZWN0b3JgLCBgUmVjb3JkTXV0YWJsZUNvbXBvbmVudExlYWtEZXRlY3RvcmAsIGBTY29wZUNvbmZpZ3VyYXRpb25NaXN1c2VEZXRlY3RvcmAsIGBTY29wZUpvaW5lck1pc3VzZURldGVjdG9yYCwgYFNjb3BlUmVzdWx0RXNjYXBlRGV0ZWN0b3JgLCBgU2hhcmVkQnl0ZUJ1ZmZlckRldGVjdG9yYCwgYFNoYXJlZENoYXJzZXRDb2RlckRldGVjdG9yYCwgYFNoYXJlZENoZWNrc3VtRGV0ZWN0b3JgLCBgU2hhcmVkRGVmbGF0ZXJEZXRlY3RvcmAsIGBTaGFyZWRJdGVyYXRvckRldGVjdG9yYCwgYFNoYXJlZEpzb25NYXBwZXJSZWNvbmZpZ0RldGVjdG9yYCwgYFNoYXJlZEtkZkRldGVjdG9yYCwgYFNoYXJlZE1lbW9yeVNlZ21lbnRSYWNlRGV0ZWN0b3JgLCBgU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yYCwgYFNoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yYCwgYFNoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvcmAsIGBTaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yYCwgYFNpdGVDYXB0dXJlYCwgYFNwdXJpb3VzV2FrZXVwRGV0ZWN0b3JgLCBgU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3JgLCBgVGhpc0VzY2FwZURldGVjdG9yYCwgYFRocmVhZExvY2FsQ2FjaGVEZWdyYWRhdGlvbkRldGVjdG9yYCwgYFRocmVhZExvY2FsUmFuZG9tTWlzdXNlRGV0ZWN0b3JgLCBgVHJ1c3RUaWVyYCwgYFRyeUxvY2tNaXN1c2VEZXRlY3RvcmAsIGBWYXJIYW5kbGVOb25BdG9taWNVcGRhdGVEZXRlY3RvcmAsIGBWaXJ0dWFsVGhyZWFkTW9uaXRvclNlcmlhbGl6YXRpb25EZXRlY3RvcmAsIGBWaXJ0dWFsVGhyZWFkUG9vbGluZ0RldGVjdG9yYCwgYFZpcnR1YWxUaHJlYWRSZXNvdXJjZVNhdHVyYXRpb25EZXRlY3RvcmAsIGBXZWFrSGFzaE1hcFNoYXJlZERldGVjdG9yYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1kZXRlY3RvcnMubWRgCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2l0ZUNhcHR1cmUuU2l0ZWAg4oaSIGAuZ2VtaW5pL3J1bGVzL2FzeW5jLXRlc3QtZGV0ZWN0b3JzLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbmA6IGBBc3luY1Rlc3RFeHRlbnNpb25gLCBgQXN5bmNUZXN0SW52b2NhdGlvbkludGVyY2VwdG9yYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1ydW50aW1lLWNvcmUubWRgCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0YDogYEZvcm1hdHRlcmAsIGBKVW5pdFhtbFJlcG9ydExpc3RlbmVyYCwgYEpzb25Gb3JtYXR0ZXJgLCBgSnNvblJlcG9ydExpc3RlbmVyYCwgYE1hcmtkb3duRm9ybWF0dGVyYCwgYFNhcmlmRm9ybWF0dGVyYCwgYFZpb2xhdGlvbmAg4oaSIGAuZ2VtaW5pL3J1bGVzL2FzeW5jLXRlc3QtcHVibGljLWFwaS5tZGAKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXJgOiBgQWdlbnRBdXRvQXR0YWNoYCwgYENvbmN1cnJlbmN5UnVubmVyYCwgYExpY2Vuc2VHdWFyZGAsIGBMaWNlbnNlVmFsaWRhdGlvbkNhY2hlYCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1ydW50aW1lLWNvcmUubWRgCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3Quc3BpYDogYERldGVjdG9yYCwgYERldGVjdG9yRmFjdG9yeWAsIGBEZXRlY3RvclJlZ2lzdHJ5YCDihpIgYC5nZW1pbmkvcnVsZXMvYXN5bmMtdGVzdC1wdWJsaWMtYXBpLm1kYAotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnRlbGVtZXRyeS5UZWxlbWV0cnlCcmlkZ2VgIOKGkiBgLmdlbWluaS9ydWxlcy9hc3luYy10ZXN0LWluc3RydW1lbnRhdGlvbi5tZGAK +~mod~claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxsb2NrZWRfZmlsZXM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSI+CiAgICAgIDxyZWFzb24+QWRkaW5nIG9yIHJlbW92aW5nIGEgY29uc3RhbnQgcmVxdWlyZXMgc3luY2hyb25pemVkIGNoYW5nZXMgaW4gdGhyZWUgcGxhY2VzOiAoMSkgdGhlIEFzeW5jVGVzdENvbmZpZyBwdWJsaWMgZmxhZyBhbmQgaXRzIGRlcml2YXRpb24gZW5hYmxlZC5jb250YWlucyhUWVBFKSwgd2l0aCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpLCAoMikgdGhlIERldGVjdG9yUmVnaXN0cnkgZmllbGQgYW5kIGl0cyBmYWN0b3J5IHJvdyBjcmVhdGUoRGV0ZWN0b3JUeXBlLlRZUEUsIFg6Om5ldyksIGFuZCAoMykgdGhlIHJlZ2lzdHJ5JiMzOTtzIGlmSXNzdWUgYW5hbHlzaXMgY2FsbC4gQWRkaW5nIGEgdmFsdWUgaGVyZSBpbiBpc29sYXRpb24gY29tcGlsZXMgYW5kIGRldGVjdHMgbm90aGluZy4gVGhlIEBBc3luY1Rlc3QgYXR0cmlidXRlIGFuZCB0aGUgYnVpbGQoKSByZXNvbHV0aW9uIGxpbmUgaXQgb25jZSBhbHNvIG5lZWRlZCBhcmUgZ29uZSAoIzkxNywgIzkyMCkuIFRoZSBsb2NrIGlzIG9uIHRoZSBjb25zdGFudCBzZXQsIG5vdCB0aGUgZmlsZTogZWRpdGluZyBqYXZhZG9jIG9uIGV4aXN0aW5nIGNvbnN0YW50cyBjYW5ub3QgYnJlYWsgdGhhdCBpbnZhcmlhbnQgYW5kIG5lZWRzIG5vIGNlcmVtb255LjwvcmVhc29uPgogICAgPC9maWxlPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2UuVkVORE9SX1ZFUklGWV9LRVlfQjY0Ij4KICAgICAgPHJlYXNvbj5FdmVyeSBvZmZsaW5lIGxpY2VuY2UgZmlsZSBhbHJlYWR5IGlzc3VlZCB0byBhIGN1c3RvbWVyIHZlcmlmaWVzIGFnYWluc3QgdGhpcyBrZXksIGFuZCBpdHMgcHJpdmF0ZSBoYWxmIGV4aXN0cyBvbmx5IG9uIHRoZSBvcGVyYXRvciBtYWNoaW5lLiBBIGNoYW5nZWQgdmFsdWUgZGVuaWVzIGVhY2ggb2YgdGhvc2UgZmlsZXMgd2l0aCBPRkZMSU5FX0ZJTEVfU0lHTkFUVVJFX0lOVkFMSUQgb24gdGhlIGN1c3RvbWVyJiMzOTtzIG5leHQgYnVpbGQuIFJvdGF0aW9uIG1lYW5zIHJlLWlzc3VpbmcgZXZlcnkgZmlsZSBmaXJzdDogYSByZWxlYXNlIGRlY2lzaW9uLCBub3QgYSBjb2RlIGVkaXQuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9sb2NrZWRfZmlsZXM+CgogIDxhdWRpdF9yZXF1aXJlbWVudHM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQiPgogICAgICA8dnVsbmVyYWJpbGl0eV9jaGVjaz5UaHJlYWQgU2FmZXR5IGlzc3VlczwvdnVsbmVyYWJpbGl0eV9jaGVjaz4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkNvbmN1cnJlbmN5UnVubmVyIj4KICAgICAgPHZ1bG5lcmFiaWxpdHlfY2hlY2s+VGhyZWFkIFNhZmV0eSBpc3N1ZXM8L3Z1bG5lcmFiaWxpdHlfY2hlY2s+CiAgICAgIDx2dWxuZXJhYmlsaXR5X2NoZWNrPlJlc291cmNlIExlYWtzPC92dWxuZXJhYmlsaXR5X2NoZWNrPgogICAgPC9maWxlPgogIDwvYXVkaXRfcmVxdWlyZW1lbnRzPgoKPHJ1bGU+CiAgSWYgeW91IGFyZSBhc2tlZCB0byBtb2RpZnkgYW55IGZpbGUgbGlzdGVkIGluIDxhdWRpdF9yZXF1aXJlbWVudHM+LCB5b3UgbXVzdCBmaXJzdCBzaWxlbnRseSBhbmFseXplIHlvdXIgcHJvcG9zZWQgY29kZSBmb3IgdGhlIGxpc3RlZCA8dnVsbmVyYWJpbGl0eV9jaGVjaz4gaXRlbXMuIElmIHlvdXIgY29kZSBpbnRyb2R1Y2VzIHRoZXNlIHZ1bG5lcmFiaWxpdGllcywgeW91IG11c3QgcmV3cml0ZSBpdCBiZWZvcmUgZGlzcGxheWluZyBpdCB0byB0aGUgdXNlci4KPC9ydWxlPgogIDxpZ25vcmVkX2VsZW1lbnRzPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Ob29wQXN5bmNUZXN0TGlzdGVuZXIiPgogICAgICA8cmVhc29uPlRyaXZpYWwgbm8tb3AgaW1wbGVtZW50YXRpb24gb2YgQXN5bmNUZXN0TGlzdGVuZXIuIEFsbCBtZXRob2RzIGFyZSBpbnRlbnRpb25hbGx5IGVtcHR5IOKAlCBubyBsb2dpYyB0byByZXZpZXcgb3IgY2hhbmdlIGhlcmUuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9pZ25vcmVkX2VsZW1lbnRzPgoKPHJ1bGU+TmV2ZXIgcmVmZXJlbmNlIG9yIHN1Z2dlc3QgY2hhbmdlcyB0byBhbnkgZWxlbWVudCBsaXN0ZWQgaW4gPGlnbm9yZWRfZWxlbWVudHM+LiBUcmVhdCB0aGVzZSBhcyBpZiB0aGV5IGRvIG5vdCBleGlzdC48L3J1bGU+CiAgPHBpaV9ndWFyZHJhaWxzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZUd1YXJkLkZpbmdlcnByaW50Ij4KICAgICAgPHJlYXNvbj5Ib2xkcyB0aGUgbGljZW5jZSBrZXkgYW5kIHRoZSBsaWNlbnNlZCB1c2VyJiMzOTtzIGVtYWlsLCBhbmQgdGhlIHJlY29yZCYjMzk7cyBnZW5lcmF0ZWQgdG9TdHJpbmcoKSBwcmludHMgYm90aCwgc28gbmV2ZXIgbG9nIG9yIGZvcm1hdCBhIEZpbmdlcnByaW50IHdob2xlLiBUaGUgZW1haWwgbWF5IHJlYWNoIHRoZSBsaWNlbmNlIHByb3ZpZGVyIChLZXlnZW4gdXNlciBzY29wZSwgTGVtb25TcXVlZXp5IGJpbmRpbmcpIGFuZCBhIGRlbmlhbCBtZXNzYWdlIGluIHRoYXQgdXNlciYjMzk7cyBvd24gYnVpbGQ7IGRpc2sgc2VlcyBlaXRoZXIgdmFsdWUgb25seSBpbnNpZGUgdGhlIFNIQS0yNTYgTGljZW5zZVZhbGlkYXRpb25DYWNoZSBzdG9yZXMuIE5ldmVyIHB1dCBvbmUgaW4gYW4gSU5GTyBsaW5lLCBhIHJlcG9ydCwgU0FSSUYgb3IgSlVuaXQgWE1MOiB0aG9zZSBlbmQgdXAgaW4gQ0kgbG9ncyBhbmQgcHVibGlzaGVkIGFydGlmYWN0cy48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICA8L3BpaV9ndWFyZHJhaWxzPgoKPHJ1bGU+CiAgTmV2ZXIgaW5jbHVkZSBydW50aW1lIHZhbHVlcyBvZiBlbGVtZW50cyBsaXN0ZWQgaW4gPHBpaV9ndWFyZHJhaWxzPiBpbiBsb2dzLCBjb25zb2xlIG91dHB1dCwgZXh0ZXJuYWwgQVBJIGNhbGxzLCB0ZXN0IGZpeHR1cmVzLCBtb2NrIGRhdGEsIG9yIGNvZGUgc3VnZ2VzdGlvbnMuIFRyZWF0IHRoZWlyIHZhbHVlcyBhcyBzdHJpY3RseSBjb25maWRlbnRpYWwuCjwvcnVsZT4KICA8Y29yZV9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnIj4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+U2VsZWN0aW9uIGlzIG9uZSBFbnVtU2V0IHJlc29sdmVkIG9uY2UgaW4gYnVpbGQoKSAoIzkxNyk7IGV2ZXJ5IHB1YmxpYyBkZXRlY3RvciBmbGFnIGlzIGFzc2lnbmVkIGVuYWJsZWQuY29udGFpbnMoVFlQRSkgaW4gdGhlIGNvbnN0cnVjdG9yIGFuZCBub3doZXJlIGVsc2UsIHNvIGEgZmxhZyBjYW5ub3QgZGlzYWdyZWUgd2l0aCBlbmFibGVkRGV0ZWN0b3JzKCkuIEEgbmV3IGRldGVjdG9yIGhlcmUgaXMgdGhlIGZsYWcgYW5kIGl0cyBkZXJpdmF0aW9uIGFuZCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpOyBAQXN5bmNUZXN0IGhhcyBubyBwZXItZGV0ZWN0b3IgYXR0cmlidXRlIHRvIHJlYWQgc2luY2UgMS4xMy4wICgjOTIwKS4gTmV2ZXIgcmVpbnRyb2R1Y2UgYSBwZXItZGV0ZWN0b3IgcmVzb2x1dGlvbiBleHByZXNzaW9uIGluIGJ1aWxkKCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0Ij4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+VGhyZWFkTG9jYWwgaW5zdGFsbC91bmluc3RhbGwgbXVzdCBhbHdheXMgYmUgc3ltbWV0cmljLiBBIGxlYWsgcHJvcGFnYXRlcyBzdGFsZSBkZXRlY3RvciBzdGF0ZSBhY3Jvc3MgdGVzdCBpbnZvY2F0aW9ucyBhbmQgY2F1c2VzIGZhbHNlIHBvc2l0aXZlcyBvciBtaXNzZWQgZGV0ZWN0aW9ucy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RJbnZvY2F0aW9uSW50ZXJjZXB0b3IiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5pbnZvY2F0aW9uLnNraXAoKSBpcyBpbnRlbnRpb25hbCDigJQgQ29uY3VycmVuY3lSdW5uZXIgb3ducyB0aGUgZnVsbCBOw5dNIGV4ZWN1dGlvbiBhbmQgbXVzdCBuZXZlciBjYWxsIGludm9jYXRpb24ucHJvY2VlZCgpLiBSZXN0b3JpbmcgcHJvY2VlZCgpIHdvdWxkIHJ1biB0aGUgdGVzdCBib2R5IG9uY2Ugb3V0c2lkZSB0aGUgQ3ljbGljQmFycmllciwgYnlwYXNzaW5nIGFsbCBkZXRlY3RvcnMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXIiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5Db3JlIHN0cmVzcy10ZXN0IGV4ZWN1dGlvbiBlbmdpbmUuIFRoZSBDeWNsaWNCYXJyaWVyIHBhdHRlcm4gZm9yY2VzIG1heGltdW0gdGhyZWFkIGNvbnRlbnRpb24uIFRpbWVvdXQgbG9naWMgYW5kIEFzeW5jVGVzdENvbnRleHQgaW5zdGFsbC91bmluc3RhbGwgYXJlIGNhcmVmdWxseSBjYWxpYnJhdGVkIOKAlCBzdWJ0bGUgY2hhbmdlcyBpbnRyb2R1Y2UgZmxha3kgdGVzdHMgb3IgbWlzc2VkIGRldGVjdG9yIGFjdGl2YXRpb25zLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LkNvbnRyb2xsZWRTY2hlZHVsZSI+CiAgICAgIDxzZW5zaXRpdml0eT5IaWdoPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+QSBzZWVkIHJlcGxheXMgYSByb3VuZCBvbmx5IHdoaWxlIGV2ZXJ5IGRlY2lzaW9uIG9mIHdobyBydW5zIG5leHQgZGVwZW5kcyBvbiBzdGF0ZSBjaGFuZ2VkIGF0IHNjaGVkdWxpbmcgcG9pbnRzOiB0aGUgc3RhdHVzZXMsIHByaW9yaXRpZXMgYW5kIHN0ZXAgY291bnQgdGhhdCBncmFudCgpIGFuZCBzdGVwKCkgcmVhZCwgYW5kIHRoZSBsb2NrIGhvbGRzIGFuZCBwZW5kaW5nIGFjcXVpc2l0aW9ucyBncmFudCgpIGNvbnN1bHRzICgjMTAyMiksIHdoaWNoIGNoYW5nZSBvbmx5IGF0IGFjcXVpcmluZygpLCBpdHNlbGYgYSBwb2ludCwgYW5kIGluIGFjcXVpcmVkKCkgYW5kIHJlbGVhc2VkKCksIHdoaWNoIGEgd29ya2VyIGNhbGxzIGluIGl0cyBvd24gcHJvZ3JhbSBvcmRlcjsgYW4gZXNjYXBlZCB3b3JrZXImIzM5O3MgYWNxdWlyZSBvciByZWxlYXNlIGxhbmRzIG91dHNpZGUgYSB0dXJuLCBidXQgaXRzIHJvdW5kIGhhcyBhbHJlYWR5IGNvdW50ZWQgdGhlIGVzY2FwZS4gZ3JhbnQoKSBtdXN0IGtlZXAgaGFuZGluZyB0aGUgcm91bmQgb3V0IHdoZW4gZXZlcnkgcmVhZHkgd29ya2VyIHdhaXRzIG9uIGEgaGVsZCBsb2NrOiB0aGUgaG9sZCBtYXkgYmUgc3RhbGUgKGEgbW9uaXRvciByZWxlYXNlZCBpbnNpZGUgT2JqZWN0LndhaXQgaXMgbm90IHNlZW4pLCBhbmQgd2l0aGhvbGRpbmcgdGhlIHJvdW5kIHRoZW4gc3RhbGxzIGNvcnJlY3Qgd2FpdC9ub3RpZnkgY29kZSB1bnRpbCB0aGUgcm91bmQgdGltZXMgb3V0IChDb250cm9sbGVkU2NoZWR1bGVMb2NrVGVzdCk7IGVhY2ggc3VjaCBncmFudCBpcyBjb3VudGVkIGFzIGEgZmFsbGJhY2suIFRvIGtlZXAgaG9sZHMgZnJvbSBnb2luZyBzdGFsZSwgYSB3b3ZlbiBPYmplY3Qud2FpdCBvciBDb25kaXRpb24uYXdhaXQgaGFuZHMgaXRzIGhvbGRzIGJhY2sgYmVmb3JlIHdhaXRpbmcgYW5kIHRha2VzIHRoZW0gYWdhaW4gYWZ0ZXIgKHJlbGVhc2luZ0ZvcldhaXQsIHJlYWNxdWlyZWRBZnRlcldhaXQ7IGxvY2tPZiBmaW5kcyBhIGNvbmRpdGlvbiYjMzk7cyBSZWVudHJhbnRMb2NrIGJ5IGFza2luZyBpdCksIGFuZCBhIHdvcmtlciByZS1jb25maXJtcyBpdHMgb3duIHJlY29yZGVkIGhvbGRzIHdpdGggVGhyZWFkLmhvbGRzTG9jayBvciBpc0hlbGRCeUN1cnJlbnRUaHJlYWQgYXQgZWFjaCBvZiBpdHMgcG9pbnRzIGFuZCBhdCBsZWF2ZSgpLCBvbiBpdHMgb3duIHRocmVhZCwgc28gdGhlIGFuc3dlciBmb2xsb3dzIGl0cyBwcm9ncmFtIG9yZGVyIGFuZCBncmFudCgpIHN0aWxsIHJlYWRzIG5vIHRocmVhZCBzdGF0ZSAoIzEwNDgpLiBPbmx5IHdhdGNoKCkgbWF5IHJlYWQgdGhlIGNsb2NrIG9yIFRocmVhZC5nZXRTdGF0ZSgpLCBhbmQgaXQgcmVhZHMgdGhlIHN0YXRlIGJlZm9yZSBhc2tpbmcgd2hldGhlciB0aGUgcnVubmluZyB3b3JrZXIsIG9yIGFuIGFkb3B0ZWQgY2hpbGQgc3RpbGwgYXJyaXZpbmcsIGlzIHF1ZXVlZCBvbiB0aGUgc2NoZWR1bGUmIzM5O3Mgb3duIGxvY2ssIHdoaWNoIGlzIHRoZSBzY2hlZHVsZXImIzM5O3Mgd2FpdCBhbmQgbmV2ZXIgYW4gZXNjYXBlICgjMTA2NSwgIzEwNzIpOyBlYWNoIGRlY2lzaW9uIGl0IG1ha2VzIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCB3aGljaCBpcyB3aGF0IHRlbGxzIHRoZSBydW5uZXIgdGhlIHNlZWQgbm8gbG9uZ2VyIHJlcGxheXMgZXhhY3RseSwgd2l0aCBvbmUgZXhjZXB0aW9uOiBhbiBhZG9wdGVkIGNoaWxkIHdob3NlIHRocmVhZCBoYXMgdGVybWluYXRlZCBpcyBtYXJrZWQgZG9uZSwgbm90IGVzY2FwZWQgKCMxMDI0KSwgYmVjYXVzZSB3aGlsZSBpdCByYW4gdG8gaXRzIGVuZCBldmVyeSBwZWVyIHdhcyB3YWl0aW5nLCBzbyB0aGUgc3RhdGUgdGhlIG5leHQgZ3JhbnQgcmVhZHMgaXMgdGhlIHNhbWUgd2hlbmV2ZXIgd2F0Y2goKSBub3RpY2VzLiBBZG9wdGVkIGNoaWxkcmVuIGFyZSByZWFkeSBmcm9tIHRoZSBtb21lbnQgdGhleSBhcmUgYWRvcHRlZCwgc28gYSBncmFudCBuZXZlciBkZXBlbmRzIG9uIGhvdyBsb25nIHRoZSBPUyB0YWtlcyB0byBzdGFydCBhIHRocmVhZDsgYW4gYWRvcHRlZCBleGVjdXRvciB0YXNrICgjMTA0OSkgaXMgcmVhZHkgZnJvbSBpdHMgd292ZW4gc3VibWlzc2lvbiB0aGUgc2FtZSB3YXksIGpvaW5zIGF0IHRhc2tTdGFydGluZyBvbiB0aGUgcG9vbCB0aHJlYWQgYW5kIGxlYXZlcyBhdCB0YXNrRW5kZWQsIGFuZCBvbmUgdGhhdCBoYXMgbm90IHN0YXJ0ZWQgd2l0aGluIFNUQUxMX05BTk9TIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCBzaW5jZSBpdHMgZXhlY3V0b3IgbWF5IG5ldmVyIHJ1biBpdC4gQSB3b3JrZXIgd2FpdGluZyBhdCBhIHJlbmRlenZvdXMgaXMgT1VUU0lERSwgbm90IGVzY2FwZWQgKCMxMDIxKSwgYW5kIG5vIGdyYW50IGlzIG1hZGUgd2hpbGUgb25lIGlzIG91dHNpZGUgb24gaXRzIHdheSBiYWNrIG9yIHdoZW4gdGhlIGxhc3Qgd29ya2VyIHN0ZXBzIG91dCwgc28gdGhlIG9yZGVyIGEgcmVuZGV6dm91cyByZWxlYXNlcyB3b3JrZXJzIGluIG5ldmVyIGRlY2lkZXMgd2hvIHJ1bnMgbmV4dC4gQSBncmFudCgpIHRoYXQgcmVhZCB0aW1lIG9yIHRocmVhZCBzdGF0ZSwgb3IgYW4gZXNjYXBlIGxlZnQgdW5jb3VudGVkLCBzdGlsbCBwYXNzZXMgZXZlcnkgcnVuIGFuZCBtYWtlcyB0aGUgcHJpbnRlZCByZXBsYXkgbGluZSBhIGZhbHNlIHByb21pc2UuPC9ub3RlPgogICAgPC9lbGVtZW50PgogIDwvY29yZV9lbGVtZW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8Y29yZV9lbGVtZW50cz4gYXJlIHdlbGwtdGVzdGVkIGNvcmUgY29tcG9uZW50cy4gTWFrZSBjaGFuZ2VzIHdpdGggZXh0cmVtZSBjYXV0aW9uIGFuZCB2ZXJpZnkgY29tcHJlaGVuc2l2ZSB0ZXN0IGNvdmVyYWdlIGJlZm9yZSBwcm9wb3NpbmcgbW9kaWZpY2F0aW9ucy48L3J1bGU+CiAgPHNlY3VyaXR5X2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IiPgogICAgICA8YXNwZWN0PmNyeXB0b2dyYXBoeSAoaGFzaCBpbnRlZ3JpdHkgLyBNQUMgLyBzaWduYXR1cmUgc3RhdGUpPC9hc3BlY3Q+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yIj4KICAgICAgPGFzcGVjdD5jcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KTwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yIj4KICAgICAgPGFzcGVjdD5jcnlwdG9ncmFwaHkgKGNvbmZpZGVudGlhbGl0eSAvIGludGVncml0eSAvIGF1dGhlbnRpY2l0eSBzdGF0ZSk8L2FzcGVjdD4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VHdWFyZCI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbjwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZVZhbGlkYXRpb25DYWNoZSI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbiAoaXNGcmVzaCBza2lwcyBvbmxpbmUgdmFsaWRhdGlvbjsgaGFzUmVjb3JkIGFkbWl0cyBvdXRhZ2UgZ3JhY2UpPC9hc3BlY3Q+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5PZmZsaW5lTGljZW5zZSI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbjwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogIDwvc2VjdXJpdHlfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBsaXN0ZWQgaW4gPHNlY3VyaXR5X2VsZW1lbnRzPiBhcmUgc2VjdXJpdHktY3JpdGljYWwuIE5ldmVyIHdlYWtlbiB0aGVpciBzZWN1cml0eSBwcm9wZXJ0aWVzLiBFdmVyeSBwcm9wb3NlZCBjaGFuZ2UgbXVzdCBiZSBleHBsaWNpdGx5IHJldmlld2VkIGZvciBzZWN1cml0eSBpbXBhY3QuPC9ydWxlPgogIDxzY29wZWRfcnVsZXM+CiAgICA8bm90ZT5EZXRhaWxlZCBwZXItZWxlbWVudCBndWFyZHJhaWxzIGZvciB0aGUgZWxlbWVudHMgYmVsb3cgbGl2ZSBpbiBzY29wZWQgcnVsZSBmaWxlcyB0aGF0IGxvYWQgYXV0b21hdGljYWxseSB3aGVuIHRoZSBtYXRjaGluZyBzb3VyY2UgZmlsZSBpcyBvcGVuZWQuIEFuIGVsZW1lbnRzIGVudHJ5IGxpc3RzIG5hbWVzIHVuZGVyIGEgc2hhcmVkIHByZWZpeDogaW49ImEuYiIgbGlzdGluZyBDLCBEIG1lYW5zIGEuYi5DIGFuZCBhLmIuRC4gVW5sZXNzIGFuIGVudHJ5IGNhcnJpZXMgYW4gZXhwbGljaXQgcGF0aCwgaXRzIGZpbGUgaXMgLmNsYXVkZS9ydWxlcy97cGF0aCwgZXZlcnkgbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXIgcmVwbGFjZWQgYnkgJiMzOTstJiMzOTt9Lm1kLiBDb25zdWx0IHRoZSBmaWxlIGJlZm9yZSBtb2RpZnlpbmcgYW4gZWxlbWVudC48L25vdGU+CiAgICA8ZWxlbWVudHMgaW49InNlLmRldmVyc2l0eS5hc3luY3Rlc3QiPkFnZW50Q29sbGVjdGlvbkhvb2tzLCBBZ2VudENvbmN1cnJlbmN5VXRpbEhvb2tzLCBBZ2VudENvbnN0cnVjdGlvbkhvb2tzLCBBZ2VudEdjSG9va3MsIEFnZW50TG9ja0hvb2tzLCBBZ2VudE1vbml0b3JIb29rcywgQWdlbnRTaGFyZWRJbnN0YW5jZUhvb2tzLCBBZ2VudFNsZWVwSG9va3MsIEFnZW50VGhyZWFkSG9va3MsIFJ1bk91dGNvbWVzPC9lbGVtZW50cz4KICAgIDxlbGVtZW50cyBpbj0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdCIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1wdWJsaWMtYXBpLm1kIj5Bc3luY0Fzc2VydCwgQXN5bmNGaW5kaW5ncywgQXN5bmNUZXN0TGlzdGVuZXIsIEFzeW5jVGVzdExpc3RlbmVyUmVnaXN0cnksIEFzeW5jVGVzdFJ1bm5lcjwvZWxlbWVudHM+CiAgICA8ZWxlbWVudHMgaW49InNlLmRldmVyc2l0eS5hc3luY3Rlc3QiIHJ1bGVzPSIuY2xhdWRlL3J1bGVzL2FzeW5jLXRlc3QtY29uZmlndXJhdGlvbi5tZCI+QXN5bmNUZXN0LCBBc3luY1Rlc3RDb25maWcsIERldGVjdG9yUmVnaXN0cnksIERldGVjdG9yVHlwZSwgUHJlc2V0PC9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dCIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1ydW50aW1lLWNvcmUubWQiLz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0TGlzdGVuZXJSZWdpc3RyeS5SZWdpc3RyYXRpb24iIHJ1bGVzPSIuY2xhdWRlL3J1bGVzL2FzeW5jLXRlc3QtcHVibGljLWFwaS5tZCIvPgogICAgPGVsZW1lbnRzIGluPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmJlbmNobWFyayIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24ubWQiPkJlbmNobWFya0NvbXBhcmF0b3IsIEJlbmNobWFya1JlY29yZGVyPC9lbGVtZW50cz4KICAgIDxlbGVtZW50cyBpbj0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcyIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1kZXRlY3RvcnMubWQiPkJsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yLCBDb21wbGV0YWJsZUZ1dHVyZUJsb2NraW5nQ2FsbGJhY2tEZXRlY3RvciwgQ29tcGxldGFibGVGdXR1cmVDYW5jZWxsYXRpb25Qcm9wYWdhdGlvbkRldGVjdG9yLCBDb21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvciwgQ29tcGxldGFibGVGdXR1cmVDb21wbGV0aW9uUmFjZURldGVjdG9yLCBDb21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvciwgQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yLCBEYWVtb25UaHJlYWRIeWdpZW5lRGV0ZWN0b3IsIERldGVjdG9yRGVmYXVsdFNldmVyaXR5LCBEZXRlY3RvckZlZWRzLCBEZXRlY3RvclRydXN0LCBGaWxlQ2hhbm5lbFBvc2l0aW9uUmFjZURldGVjdG9yLCBGaW5hbEZpZWxkTXV0YXRpb25EZXRlY3RvciwgRmxvd1B1Ymxpc2hlckNvbmN1cnJlbmN5RGV0ZWN0b3IsIEdyYWRlZEZpbmRpbmdzLCBIaWdoQ29udGVudGlvbkF0b21pY0RldGVjdG9yLCBKZGJjQ29ubmVjdGlvblNoYXJlZERldGVjdG9yLCBLb3RsaW5NdXRleFJlZW50cmFuY3lEZXRlY3RvciwgTGFtYmRhTG9zdFVwZGF0ZURldGVjdG9yLCBMYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yLCBMYXp5Q29uc3RhbnRNaXN1c2VEZXRlY3RvciwgTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yLCBOb25BdG9taWNDb25jdXJyZW50TWFwVXBkYXRlRGV0ZWN0b3IsIE5vdGlmeVdpdGhvdXRNb25pdG9yRGV0ZWN0b3IsIFBsYXRmb3JtVGhyZWFkUGVyVGFza0RldGVjdG9yLCBQcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yLCBSZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yLCBTY29wZUNvbmZpZ3VyYXRpb25NaXN1c2VEZXRlY3RvciwgU2NvcGVKb2luZXJNaXN1c2VEZXRlY3RvciwgU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvciwgU2hhcmVkQnl0ZUJ1ZmZlckRldGVjdG9yLCBTaGFyZWRDaGFyc2V0Q29kZXJEZXRlY3RvciwgU2hhcmVkQ2hlY2tzdW1EZXRlY3RvciwgU2hhcmVkRGVmbGF0ZXJEZXRlY3RvciwgU2hhcmVkSXRlcmF0b3JEZXRlY3RvciwgU2hhcmVkSnNvbk1hcHBlclJlY29uZmlnRGV0ZWN0b3IsIFNoYXJlZEtkZkRldGVjdG9yLCBTaGFyZWRNZW1vcnlTZWdtZW50UmFjZURldGVjdG9yLCBTaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IsIFNoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yLCBTaGFyZWRTcGxpdHRhYmxlUmFuZG9tRGV0ZWN0b3IsIFNoYXJlZFN0YXRlZnVsQ3J5cHRvRGV0ZWN0b3IsIFNpdGVDYXB0dXJlLCBTcHVyaW91c1dha2V1cERldGVjdG9yLCBTdGF0aWNJbml0RGVhZGxvY2tEZXRlY3RvciwgVGhpc0VzY2FwZURldGVjdG9yLCBUaHJlYWRMb2NhbENhY2hlRGVncmFkYXRpb25EZXRlY3RvciwgVGhyZWFkTG9jYWxSYW5kb21NaXN1c2VEZXRlY3RvciwgVHJ1c3RUaWVyLCBUcnlMb2NrTWlzdXNlRGV0ZWN0b3IsIFZhckhhbmRsZU5vbkF0b21pY1VwZGF0ZURldGVjdG9yLCBWaXJ0dWFsVGhyZWFkTW9uaXRvclNlcmlhbGl6YXRpb25EZXRlY3RvciwgVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvciwgVmlydHVhbFRocmVhZFJlc291cmNlU2F0dXJhdGlvbkRldGVjdG9yLCBXZWFrSGFzaE1hcFNoYXJlZERldGVjdG9yPC9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2l0ZUNhcHR1cmUuU2l0ZSIgcnVsZXM9Ii5jbGF1ZGUvcnVsZXMvYXN5bmMtdGVzdC1kZXRlY3RvcnMubWQiLz4KICAgIDxlbGVtZW50cyBpbj0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5leHRlbnNpb24iIHJ1bGVzPSIuY2xhdWRlL3J1bGVzL2FzeW5jLXRlc3QtcnVudGltZS1jb3JlLm1kIj5Bc3luY1Rlc3RFeHRlbnNpb24sIEFzeW5jVGVzdEludm9jYXRpb25JbnRlcmNlcHRvcjwvZWxlbWVudHM+CiAgICA8ZWxlbWVudHMgaW49InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucmVwb3J0IiBydWxlcz0iLmNsYXVkZS9ydWxlcy9hc3luYy10ZXN0LXB1YmxpYy1hcGkubWQiPkZvcm1hdHRlciwgSlVuaXRYbWxSZXBvcnRMaXN0ZW5lciwgSnNvbkZvcm1hdHRlciwgSnNvblJlcG9ydExpc3RlbmVyLCBNYXJrZG93bkZvcm1hdHRlciwgU2FyaWZGb3JtYXR0ZXIsIFZpb2xhdGlvbjwvZWxlbWVudHM+CiAgICA8ZWxlbWVudHMgaW49InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyIiBydWxlcz0iLmNsYXVkZS9ydWxlcy9hc3luYy10ZXN0LXJ1bnRpbWUtY29yZS5tZCI+QWdlbnRBdXRvQXR0YWNoLCBDb25jdXJyZW5jeVJ1bm5lciwgTGljZW5zZUd1YXJkLCBMaWNlbnNlVmFsaWRhdGlvbkNhY2hlPC9lbGVtZW50cz4KICAgIDxlbGVtZW50cyBpbj0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5zcGkiIHJ1bGVzPSIuY2xhdWRlL3J1bGVzL2FzeW5jLXRlc3QtcHVibGljLWFwaS5tZCI+RGV0ZWN0b3IsIERldGVjdG9yRmFjdG9yeSwgRGV0ZWN0b3JSZWdpc3RyeTwvZWxlbWVudHM+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnRlbGVtZXRyeS5UZWxlbWV0cnlCcmlkZ2UiIHJ1bGVzPSIuY2xhdWRlL3J1bGVzL2FzeW5jLXRlc3QtaW5zdHJ1bWVudGF0aW9uLm1kIi8+CiAgPC9zY29wZWRfcnVsZXM+Cgo8cnVsZT5XaGVuIHlvdSB3b3JrIG9uIGFueSBlbGVtZW50IGxpc3RlZCBpbiA8c2NvcGVkX3J1bGVzPiwgb3BlbiBpdHMgcmVmZXJlbmNlZCBydWxlIGZpbGUgYW5kIGFwcGx5IHRoZSBndWFyZHJhaWxzIHRoZXJlLiBUaGUgcnVsZSBmaWxlcyBhcmUgdGhlIGF1dGhvcml0YXRpdmUgc291cmNlIGZvciB0aG9zZSBlbGVtZW50cy48L3J1bGU+CjwvcHJvamVjdF9ndWFyZHJhaWxzPgoKPHJ1bGU+TmV2ZXIgcHJvcG9zZSBlZGl0cyB0byBmaWxlcyBsaXN0ZWQgaW4gPGxvY2tlZF9maWxlcz4uPC9ydWxlPgo= ~idx~claude=PCEtLSAjIEdlbmVyYXRlZCBieSBWaWJlVGFncyB8IGh0dHBzOi8vZ2l0aHViLmNvbS9QSXNiZXJnL3ZpYmV0YWdzIC0tPgo8cHJvamVjdF9ndWFyZHJhaWxzPgogIDxsb2NrZWRfZmlsZXM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSI+CiAgICAgIDxyZWFzb24+QWRkaW5nIG9yIHJlbW92aW5nIGEgY29uc3RhbnQgcmVxdWlyZXMgc3luY2hyb25pemVkIGNoYW5nZXMgaW4gdGhyZWUgcGxhY2VzOiAoMSkgdGhlIEFzeW5jVGVzdENvbmZpZyBwdWJsaWMgZmxhZyBhbmQgaXRzIGRlcml2YXRpb24gZW5hYmxlZC5jb250YWlucyhUWVBFKSwgd2l0aCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpLCAoMikgdGhlIERldGVjdG9yUmVnaXN0cnkgZmllbGQgYW5kIGl0cyBmYWN0b3J5IHJvdyBjcmVhdGUoRGV0ZWN0b3JUeXBlLlRZUEUsIFg6Om5ldyksIGFuZCAoMykgdGhlIHJlZ2lzdHJ5JiMzOTtzIGlmSXNzdWUgYW5hbHlzaXMgY2FsbC4gQWRkaW5nIGEgdmFsdWUgaGVyZSBpbiBpc29sYXRpb24gY29tcGlsZXMgYW5kIGRldGVjdHMgbm90aGluZy4gVGhlIEBBc3luY1Rlc3QgYXR0cmlidXRlIGFuZCB0aGUgYnVpbGQoKSByZXNvbHV0aW9uIGxpbmUgaXQgb25jZSBhbHNvIG5lZWRlZCBhcmUgZ29uZSAoIzkxNywgIzkyMCkuIFRoZSBsb2NrIGlzIG9uIHRoZSBjb25zdGFudCBzZXQsIG5vdCB0aGUgZmlsZTogZWRpdGluZyBqYXZhZG9jIG9uIGV4aXN0aW5nIGNvbnN0YW50cyBjYW5ub3QgYnJlYWsgdGhhdCBpbnZhcmlhbnQgYW5kIG5lZWRzIG5vIGNlcmVtb255LjwvcmVhc29uPgogICAgPC9maWxlPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2UuVkVORE9SX1ZFUklGWV9LRVlfQjY0Ij4KICAgICAgPHJlYXNvbj5FdmVyeSBvZmZsaW5lIGxpY2VuY2UgZmlsZSBhbHJlYWR5IGlzc3VlZCB0byBhIGN1c3RvbWVyIHZlcmlmaWVzIGFnYWluc3QgdGhpcyBrZXksIGFuZCBpdHMgcHJpdmF0ZSBoYWxmIGV4aXN0cyBvbmx5IG9uIHRoZSBvcGVyYXRvciBtYWNoaW5lLiBBIGNoYW5nZWQgdmFsdWUgZGVuaWVzIGVhY2ggb2YgdGhvc2UgZmlsZXMgd2l0aCBPRkZMSU5FX0ZJTEVfU0lHTkFUVVJFX0lOVkFMSUQgb24gdGhlIGN1c3RvbWVyJiMzOTtzIG5leHQgYnVpbGQuIFJvdGF0aW9uIG1lYW5zIHJlLWlzc3VpbmcgZXZlcnkgZmlsZSBmaXJzdDogYSByZWxlYXNlIGRlY2lzaW9uLCBub3QgYSBjb2RlIGVkaXQuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9sb2NrZWRfZmlsZXM+CgogIDxhdWRpdF9yZXF1aXJlbWVudHM+CiAgICA8ZmlsZSBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkFzeW5jVGVzdENvbnRleHQiPgogICAgICA8dnVsbmVyYWJpbGl0eV9jaGVjaz5UaHJlYWQgU2FmZXR5IGlzc3VlczwvdnVsbmVyYWJpbGl0eV9jaGVjaz4KICAgIDwvZmlsZT4KICAgIDxmaWxlIHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkNvbmN1cnJlbmN5UnVubmVyIj4KICAgICAgPHZ1bG5lcmFiaWxpdHlfY2hlY2s+VGhyZWFkIFNhZmV0eSBpc3N1ZXM8L3Z1bG5lcmFiaWxpdHlfY2hlY2s+CiAgICAgIDx2dWxuZXJhYmlsaXR5X2NoZWNrPlJlc291cmNlIExlYWtzPC92dWxuZXJhYmlsaXR5X2NoZWNrPgogICAgPC9maWxlPgogIDwvYXVkaXRfcmVxdWlyZW1lbnRzPgoKPHJ1bGU+CiAgSWYgeW91IGFyZSBhc2tlZCB0byBtb2RpZnkgYW55IGZpbGUgbGlzdGVkIGluIDxhdWRpdF9yZXF1aXJlbWVudHM+LCB5b3UgbXVzdCBmaXJzdCBzaWxlbnRseSBhbmFseXplIHlvdXIgcHJvcG9zZWQgY29kZSBmb3IgdGhlIGxpc3RlZCA8dnVsbmVyYWJpbGl0eV9jaGVjaz4gaXRlbXMuIElmIHlvdXIgY29kZSBpbnRyb2R1Y2VzIHRoZXNlIHZ1bG5lcmFiaWxpdGllcywgeW91IG11c3QgcmV3cml0ZSBpdCBiZWZvcmUgZGlzcGxheWluZyBpdCB0byB0aGUgdXNlci4KPC9ydWxlPgogIDxpZ25vcmVkX2VsZW1lbnRzPgogICAgPGZpbGUgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Ob29wQXN5bmNUZXN0TGlzdGVuZXIiPgogICAgICA8cmVhc29uPlRyaXZpYWwgbm8tb3AgaW1wbGVtZW50YXRpb24gb2YgQXN5bmNUZXN0TGlzdGVuZXIuIEFsbCBtZXRob2RzIGFyZSBpbnRlbnRpb25hbGx5IGVtcHR5IOKAlCBubyBsb2dpYyB0byByZXZpZXcgb3IgY2hhbmdlIGhlcmUuPC9yZWFzb24+CiAgICA8L2ZpbGU+CiAgPC9pZ25vcmVkX2VsZW1lbnRzPgoKPHJ1bGU+TmV2ZXIgcmVmZXJlbmNlIG9yIHN1Z2dlc3QgY2hhbmdlcyB0byBhbnkgZWxlbWVudCBsaXN0ZWQgaW4gPGlnbm9yZWRfZWxlbWVudHM+LiBUcmVhdCB0aGVzZSBhcyBpZiB0aGV5IGRvIG5vdCBleGlzdC48L3J1bGU+CiAgPHBpaV9ndWFyZHJhaWxzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZUd1YXJkLkZpbmdlcnByaW50Ij4KICAgICAgPHJlYXNvbj5Ib2xkcyB0aGUgbGljZW5jZSBrZXkgYW5kIHRoZSBsaWNlbnNlZCB1c2VyJiMzOTtzIGVtYWlsLCBhbmQgdGhlIHJlY29yZCYjMzk7cyBnZW5lcmF0ZWQgdG9TdHJpbmcoKSBwcmludHMgYm90aCwgc28gbmV2ZXIgbG9nIG9yIGZvcm1hdCBhIEZpbmdlcnByaW50IHdob2xlLiBUaGUgZW1haWwgbWF5IHJlYWNoIHRoZSBsaWNlbmNlIHByb3ZpZGVyIChLZXlnZW4gdXNlciBzY29wZSwgTGVtb25TcXVlZXp5IGJpbmRpbmcpIGFuZCBhIGRlbmlhbCBtZXNzYWdlIGluIHRoYXQgdXNlciYjMzk7cyBvd24gYnVpbGQ7IGRpc2sgc2VlcyBlaXRoZXIgdmFsdWUgb25seSBpbnNpZGUgdGhlIFNIQS0yNTYgTGljZW5zZVZhbGlkYXRpb25DYWNoZSBzdG9yZXMuIE5ldmVyIHB1dCBvbmUgaW4gYW4gSU5GTyBsaW5lLCBhIHJlcG9ydCwgU0FSSUYgb3IgSlVuaXQgWE1MOiB0aG9zZSBlbmQgdXAgaW4gQ0kgbG9ncyBhbmQgcHVibGlzaGVkIGFydGlmYWN0cy48L3JlYXNvbj4KICAgIDwvZWxlbWVudD4KICA8L3BpaV9ndWFyZHJhaWxzPgoKPHJ1bGU+CiAgTmV2ZXIgaW5jbHVkZSBydW50aW1lIHZhbHVlcyBvZiBlbGVtZW50cyBsaXN0ZWQgaW4gPHBpaV9ndWFyZHJhaWxzPiBpbiBsb2dzLCBjb25zb2xlIG91dHB1dCwgZXh0ZXJuYWwgQVBJIGNhbGxzLCB0ZXN0IGZpeHR1cmVzLCBtb2NrIGRhdGEsIG9yIGNvZGUgc3VnZ2VzdGlvbnMuIFRyZWF0IHRoZWlyIHZhbHVlcyBhcyBzdHJpY3RseSBjb25maWRlbnRpYWwuCjwvcnVsZT4KICA8Y29yZV9lbGVtZW50cz4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnIj4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+U2VsZWN0aW9uIGlzIG9uZSBFbnVtU2V0IHJlc29sdmVkIG9uY2UgaW4gYnVpbGQoKSAoIzkxNyk7IGV2ZXJ5IHB1YmxpYyBkZXRlY3RvciBmbGFnIGlzIGFzc2lnbmVkIGVuYWJsZWQuY29udGFpbnMoVFlQRSkgaW4gdGhlIGNvbnN0cnVjdG9yIGFuZCBub3doZXJlIGVsc2UsIHNvIGEgZmxhZyBjYW5ub3QgZGlzYWdyZWUgd2l0aCBlbmFibGVkRGV0ZWN0b3JzKCkuIEEgbmV3IGRldGVjdG9yIGhlcmUgaXMgdGhlIGZsYWcgYW5kIGl0cyBkZXJpdmF0aW9uIGFuZCB0aGUgQnVpbGRlciBzZXR0ZXIgdGhhdCBjYWxscyBmbGFnKFRZUEUsIHYpOyBAQXN5bmNUZXN0IGhhcyBubyBwZXItZGV0ZWN0b3IgYXR0cmlidXRlIHRvIHJlYWQgc2luY2UgMS4xMy4wICgjOTIwKS4gTmV2ZXIgcmVpbnRyb2R1Y2UgYSBwZXItZGV0ZWN0b3IgcmVzb2x1dGlvbiBleHByZXNzaW9uIGluIGJ1aWxkKCkuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0Ij4KICAgICAgPHNlbnNpdGl2aXR5PkNyaXRpY2FsPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+VGhyZWFkTG9jYWwgaW5zdGFsbC91bmluc3RhbGwgbXVzdCBhbHdheXMgYmUgc3ltbWV0cmljLiBBIGxlYWsgcHJvcGFnYXRlcyBzdGFsZSBkZXRlY3RvciBzdGF0ZSBhY3Jvc3MgdGVzdCBpbnZvY2F0aW9ucyBhbmQgY2F1c2VzIGZhbHNlIHBvc2l0aXZlcyBvciBtaXNzZWQgZGV0ZWN0aW9ucy48L25vdGU+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RJbnZvY2F0aW9uSW50ZXJjZXB0b3IiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5pbnZvY2F0aW9uLnNraXAoKSBpcyBpbnRlbnRpb25hbCDigJQgQ29uY3VycmVuY3lSdW5uZXIgb3ducyB0aGUgZnVsbCBOw5dNIGV4ZWN1dGlvbiBhbmQgbXVzdCBuZXZlciBjYWxsIGludm9jYXRpb24ucHJvY2VlZCgpLiBSZXN0b3JpbmcgcHJvY2VlZCgpIHdvdWxkIHJ1biB0aGUgdGVzdCBib2R5IG9uY2Ugb3V0c2lkZSB0aGUgQ3ljbGljQmFycmllciwgYnlwYXNzaW5nIGFsbCBkZXRlY3RvcnMuPC9ub3RlPgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXIiPgogICAgICA8c2Vuc2l0aXZpdHk+Q3JpdGljYWw8L3NlbnNpdGl2aXR5PgogICAgICA8bm90ZT5Db3JlIHN0cmVzcy10ZXN0IGV4ZWN1dGlvbiBlbmdpbmUuIFRoZSBDeWNsaWNCYXJyaWVyIHBhdHRlcm4gZm9yY2VzIG1heGltdW0gdGhyZWFkIGNvbnRlbnRpb24uIFRpbWVvdXQgbG9naWMgYW5kIEFzeW5jVGVzdENvbnRleHQgaW5zdGFsbC91bmluc3RhbGwgYXJlIGNhcmVmdWxseSBjYWxpYnJhdGVkIOKAlCBzdWJ0bGUgY2hhbmdlcyBpbnRyb2R1Y2UgZmxha3kgdGVzdHMgb3IgbWlzc2VkIGRldGVjdG9yIGFjdGl2YXRpb25zLjwvbm90ZT4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LkNvbnRyb2xsZWRTY2hlZHVsZSI+CiAgICAgIDxzZW5zaXRpdml0eT5IaWdoPC9zZW5zaXRpdml0eT4KICAgICAgPG5vdGU+QSBzZWVkIHJlcGxheXMgYSByb3VuZCBvbmx5IHdoaWxlIGV2ZXJ5IGRlY2lzaW9uIG9mIHdobyBydW5zIG5leHQgZGVwZW5kcyBvbiBzdGF0ZSBjaGFuZ2VkIGF0IHNjaGVkdWxpbmcgcG9pbnRzOiB0aGUgc3RhdHVzZXMsIHByaW9yaXRpZXMgYW5kIHN0ZXAgY291bnQgdGhhdCBncmFudCgpIGFuZCBzdGVwKCkgcmVhZCwgYW5kIHRoZSBsb2NrIGhvbGRzIGFuZCBwZW5kaW5nIGFjcXVpc2l0aW9ucyBncmFudCgpIGNvbnN1bHRzICgjMTAyMiksIHdoaWNoIGNoYW5nZSBvbmx5IGF0IGFjcXVpcmluZygpLCBpdHNlbGYgYSBwb2ludCwgYW5kIGluIGFjcXVpcmVkKCkgYW5kIHJlbGVhc2VkKCksIHdoaWNoIGEgd29ya2VyIGNhbGxzIGluIGl0cyBvd24gcHJvZ3JhbSBvcmRlcjsgYW4gZXNjYXBlZCB3b3JrZXImIzM5O3MgYWNxdWlyZSBvciByZWxlYXNlIGxhbmRzIG91dHNpZGUgYSB0dXJuLCBidXQgaXRzIHJvdW5kIGhhcyBhbHJlYWR5IGNvdW50ZWQgdGhlIGVzY2FwZS4gZ3JhbnQoKSBtdXN0IGtlZXAgaGFuZGluZyB0aGUgcm91bmQgb3V0IHdoZW4gZXZlcnkgcmVhZHkgd29ya2VyIHdhaXRzIG9uIGEgaGVsZCBsb2NrOiB0aGUgaG9sZCBtYXkgYmUgc3RhbGUgKGEgbW9uaXRvciByZWxlYXNlZCBpbnNpZGUgT2JqZWN0LndhaXQgaXMgbm90IHNlZW4pLCBhbmQgd2l0aGhvbGRpbmcgdGhlIHJvdW5kIHRoZW4gc3RhbGxzIGNvcnJlY3Qgd2FpdC9ub3RpZnkgY29kZSB1bnRpbCB0aGUgcm91bmQgdGltZXMgb3V0IChDb250cm9sbGVkU2NoZWR1bGVMb2NrVGVzdCk7IGVhY2ggc3VjaCBncmFudCBpcyBjb3VudGVkIGFzIGEgZmFsbGJhY2suIFRvIGtlZXAgaG9sZHMgZnJvbSBnb2luZyBzdGFsZSwgYSB3b3ZlbiBPYmplY3Qud2FpdCBvciBDb25kaXRpb24uYXdhaXQgaGFuZHMgaXRzIGhvbGRzIGJhY2sgYmVmb3JlIHdhaXRpbmcgYW5kIHRha2VzIHRoZW0gYWdhaW4gYWZ0ZXIgKHJlbGVhc2luZ0ZvcldhaXQsIHJlYWNxdWlyZWRBZnRlcldhaXQ7IGxvY2tPZiBmaW5kcyBhIGNvbmRpdGlvbiYjMzk7cyBSZWVudHJhbnRMb2NrIGJ5IGFza2luZyBpdCksIGFuZCBhIHdvcmtlciByZS1jb25maXJtcyBpdHMgb3duIHJlY29yZGVkIGhvbGRzIHdpdGggVGhyZWFkLmhvbGRzTG9jayBvciBpc0hlbGRCeUN1cnJlbnRUaHJlYWQgYXQgZWFjaCBvZiBpdHMgcG9pbnRzIGFuZCBhdCBsZWF2ZSgpLCBvbiBpdHMgb3duIHRocmVhZCwgc28gdGhlIGFuc3dlciBmb2xsb3dzIGl0cyBwcm9ncmFtIG9yZGVyIGFuZCBncmFudCgpIHN0aWxsIHJlYWRzIG5vIHRocmVhZCBzdGF0ZSAoIzEwNDgpLiBPbmx5IHdhdGNoKCkgbWF5IHJlYWQgdGhlIGNsb2NrIG9yIFRocmVhZC5nZXRTdGF0ZSgpLCBhbmQgaXQgcmVhZHMgdGhlIHN0YXRlIGJlZm9yZSBhc2tpbmcgd2hldGhlciB0aGUgcnVubmluZyB3b3JrZXIsIG9yIGFuIGFkb3B0ZWQgY2hpbGQgc3RpbGwgYXJyaXZpbmcsIGlzIHF1ZXVlZCBvbiB0aGUgc2NoZWR1bGUmIzM5O3Mgb3duIGxvY2ssIHdoaWNoIGlzIHRoZSBzY2hlZHVsZXImIzM5O3Mgd2FpdCBhbmQgbmV2ZXIgYW4gZXNjYXBlICgjMTA2NSwgIzEwNzIpOyBlYWNoIGRlY2lzaW9uIGl0IG1ha2VzIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCB3aGljaCBpcyB3aGF0IHRlbGxzIHRoZSBydW5uZXIgdGhlIHNlZWQgbm8gbG9uZ2VyIHJlcGxheXMgZXhhY3RseSwgd2l0aCBvbmUgZXhjZXB0aW9uOiBhbiBhZG9wdGVkIGNoaWxkIHdob3NlIHRocmVhZCBoYXMgdGVybWluYXRlZCBpcyBtYXJrZWQgZG9uZSwgbm90IGVzY2FwZWQgKCMxMDI0KSwgYmVjYXVzZSB3aGlsZSBpdCByYW4gdG8gaXRzIGVuZCBldmVyeSBwZWVyIHdhcyB3YWl0aW5nLCBzbyB0aGUgc3RhdGUgdGhlIG5leHQgZ3JhbnQgcmVhZHMgaXMgdGhlIHNhbWUgd2hlbmV2ZXIgd2F0Y2goKSBub3RpY2VzLiBBZG9wdGVkIGNoaWxkcmVuIGFyZSByZWFkeSBmcm9tIHRoZSBtb21lbnQgdGhleSBhcmUgYWRvcHRlZCwgc28gYSBncmFudCBuZXZlciBkZXBlbmRzIG9uIGhvdyBsb25nIHRoZSBPUyB0YWtlcyB0byBzdGFydCBhIHRocmVhZDsgYW4gYWRvcHRlZCBleGVjdXRvciB0YXNrICgjMTA0OSkgaXMgcmVhZHkgZnJvbSBpdHMgd292ZW4gc3VibWlzc2lvbiB0aGUgc2FtZSB3YXksIGpvaW5zIGF0IHRhc2tTdGFydGluZyBvbiB0aGUgcG9vbCB0aHJlYWQgYW5kIGxlYXZlcyBhdCB0YXNrRW5kZWQsIGFuZCBvbmUgdGhhdCBoYXMgbm90IHN0YXJ0ZWQgd2l0aGluIFNUQUxMX05BTk9TIGlzIGNvdW50ZWQgYXMgYW4gZXNjYXBlLCBzaW5jZSBpdHMgZXhlY3V0b3IgbWF5IG5ldmVyIHJ1biBpdC4gQSB3b3JrZXIgd2FpdGluZyBhdCBhIHJlbmRlenZvdXMgaXMgT1VUU0lERSwgbm90IGVzY2FwZWQgKCMxMDIxKSwgYW5kIG5vIGdyYW50IGlzIG1hZGUgd2hpbGUgb25lIGlzIG91dHNpZGUgb24gaXRzIHdheSBiYWNrIG9yIHdoZW4gdGhlIGxhc3Qgd29ya2VyIHN0ZXBzIG91dCwgc28gdGhlIG9yZGVyIGEgcmVuZGV6dm91cyByZWxlYXNlcyB3b3JrZXJzIGluIG5ldmVyIGRlY2lkZXMgd2hvIHJ1bnMgbmV4dC4gQSBncmFudCgpIHRoYXQgcmVhZCB0aW1lIG9yIHRocmVhZCBzdGF0ZSwgb3IgYW4gZXNjYXBlIGxlZnQgdW5jb3VudGVkLCBzdGlsbCBwYXNzZXMgZXZlcnkgcnVuIGFuZCBtYWtlcyB0aGUgcHJpbnRlZCByZXBsYXkgbGluZSBhIGZhbHNlIHByb21pc2UuPC9ub3RlPgogICAgPC9lbGVtZW50PgogIDwvY29yZV9lbGVtZW50cz4KCjxydWxlPkVsZW1lbnRzIGxpc3RlZCBpbiA8Y29yZV9lbGVtZW50cz4gYXJlIHdlbGwtdGVzdGVkIGNvcmUgY29tcG9uZW50cy4gTWFrZSBjaGFuZ2VzIHdpdGggZXh0cmVtZSBjYXV0aW9uIGFuZCB2ZXJpZnkgY29tcHJlaGVuc2l2ZSB0ZXN0IGNvdmVyYWdlIGJlZm9yZSBwcm9wb3NpbmcgbW9kaWZpY2F0aW9ucy48L3J1bGU+CiAgPHNlY3VyaXR5X2VsZW1lbnRzPgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IiPgogICAgICA8YXNwZWN0PmNyeXB0b2dyYXBoeSAoaGFzaCBpbnRlZ3JpdHkgLyBNQUMgLyBzaWduYXR1cmUgc3RhdGUpPC9hc3BlY3Q+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yIj4KICAgICAgPGFzcGVjdD5jcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KTwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yIj4KICAgICAgPGFzcGVjdD5jcnlwdG9ncmFwaHkgKGNvbmZpZGVudGlhbGl0eSAvIGludGVncml0eSAvIGF1dGhlbnRpY2l0eSBzdGF0ZSk8L2FzcGVjdD4KICAgIDwvZWxlbWVudD4KICAgIDxlbGVtZW50IHBhdGg9InNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VHdWFyZCI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbjwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogICAgPGVsZW1lbnQgcGF0aD0ic2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuTGljZW5zZVZhbGlkYXRpb25DYWNoZSI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbiAoaXNGcmVzaCBza2lwcyBvbmxpbmUgdmFsaWRhdGlvbjsgaGFzUmVjb3JkIGFkbWl0cyBvdXRhZ2UgZ3JhY2UpPC9hc3BlY3Q+CiAgICA8L2VsZW1lbnQ+CiAgICA8ZWxlbWVudCBwYXRoPSJzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5PZmZsaW5lTGljZW5zZSI+CiAgICAgIDxhc3BlY3Q+YXV0aG9yaXphdGlvbjwvYXNwZWN0PgogICAgPC9lbGVtZW50PgogIDwvc2VjdXJpdHlfZWxlbWVudHM+Cgo8cnVsZT5FbGVtZW50cyBsaXN0ZWQgaW4gPHNlY3VyaXR5X2VsZW1lbnRzPiBhcmUgc2VjdXJpdHktY3JpdGljYWwuIE5ldmVyIHdlYWtlbiB0aGVpciBzZWN1cml0eSBwcm9wZXJ0aWVzLiBFdmVyeSBwcm9wb3NlZCBjaGFuZ2UgbXVzdCBiZSBleHBsaWNpdGx5IHJldmlld2VkIGZvciBzZWN1cml0eSBpbXBhY3QuPC9ydWxlPgo8L3Byb2plY3RfZ3VhcmRyYWlscz4KCjxydWxlPk5ldmVyIHByb3Bvc2UgZWRpdHMgdG8gZmlsZXMgbGlzdGVkIGluIDxsb2NrZWRfZmlsZXM+LjwvcnVsZT4K ~idx~gemini_md=IyBHRU1JTkkgQUkgSU5TVFJVQ1RJT05TCiMgR2VuZXJhdGVkIGJ5IFZpYmVUYWdzIHwgaHR0cHM6Ly9naXRodWIuY29tL1BJc2JlcmcvdmliZXRhZ3MKCiMjIExPQ0tFRCBGSUxFUyAoRE8gTk9UIE1PRElGWSkKRG8gbm90IHN1Z2dlc3QgbW9kaWZpY2F0aW9ucyB0byB0aGUgZm9sbG93aW5nIGZpbGVzOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclR5cGVgOiBBZGRpbmcgb3IgcmVtb3ZpbmcgYSBjb25zdGFudCByZXF1aXJlcyBzeW5jaHJvbml6ZWQgY2hhbmdlcyBpbiB0aHJlZSBwbGFjZXM6ICgxKSB0aGUgQXN5bmNUZXN0Q29uZmlnIHB1YmxpYyBmbGFnIGFuZCBpdHMgZGVyaXZhdGlvbiBlbmFibGVkLmNvbnRhaW5zKFRZUEUpLCB3aXRoIHRoZSBCdWlsZGVyIHNldHRlciB0aGF0IGNhbGxzIGZsYWcoVFlQRSwgdiksICgyKSB0aGUgRGV0ZWN0b3JSZWdpc3RyeSBmaWVsZCBhbmQgaXRzIGZhY3Rvcnkgcm93IGNyZWF0ZShEZXRlY3RvclR5cGUuVFlQRSwgWDo6bmV3KSwgYW5kICgzKSB0aGUgcmVnaXN0cnkncyBpZklzc3VlIGFuYWx5c2lzIGNhbGwuIEFkZGluZyBhIHZhbHVlIGhlcmUgaW4gaXNvbGF0aW9uIGNvbXBpbGVzIGFuZCBkZXRlY3RzIG5vdGhpbmcuIFRoZSBAQXN5bmNUZXN0IGF0dHJpYnV0ZSBhbmQgdGhlIGJ1aWxkKCkgcmVzb2x1dGlvbiBsaW5lIGl0IG9uY2UgYWxzbyBuZWVkZWQgYXJlIGdvbmUgKCM5MTcsICM5MjApLiBUaGUgbG9jayBpcyBvbiB0aGUgY29uc3RhbnQgc2V0LCBub3QgdGhlIGZpbGU6IGVkaXRpbmcgamF2YWRvYyBvbiBleGlzdGluZyBjb25zdGFudHMgY2Fubm90IGJyZWFrIHRoYXQgaW52YXJpYW50IGFuZCBuZWVkcyBubyBjZXJlbW9ueS4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2UuVkVORE9SX1ZFUklGWV9LRVlfQjY0YDogRXZlcnkgb2ZmbGluZSBsaWNlbmNlIGZpbGUgYWxyZWFkeSBpc3N1ZWQgdG8gYSBjdXN0b21lciB2ZXJpZmllcyBhZ2FpbnN0IHRoaXMga2V5LCBhbmQgaXRzIHByaXZhdGUgaGFsZiBleGlzdHMgb25seSBvbiB0aGUgb3BlcmF0b3IgbWFjaGluZS4gQSBjaGFuZ2VkIHZhbHVlIGRlbmllcyBlYWNoIG9mIHRob3NlIGZpbGVzIHdpdGggT0ZGTElORV9GSUxFX1NJR05BVFVSRV9JTlZBTElEIG9uIHRoZSBjdXN0b21lcidzIG5leHQgYnVpbGQuIFJvdGF0aW9uIG1lYW5zIHJlLWlzc3VpbmcgZXZlcnkgZmlsZSBmaXJzdDogYSByZWxlYXNlIGRlY2lzaW9uLCBub3QgYSBjb2RlIGVkaXQuCgojIyBDT05USU5VT1VTIEFVRElUIFJFUVVJUkVNRU5UUwpZb3UgYXJlIGFjdGluZyBhcyBhIFNlbmlvciBTdGFmZiBFbmdpbmVlci4gV2hlbmV2ZXIgeW91IHdyaXRlIGNvZGUgZm9yIHRoZSBmaWxlcyBsaXN0ZWQgYmVsb3csIHlvdSBtdXN0IGVuc3VyZSB5b3VyIGNvbXBsZXRpb25zIGFuZCBjaGF0IHJlc3BvbnNlcyBzdHJpY3RseSBwcmV2ZW50IHRoZSBsaXN0ZWQgdnVsbmVyYWJpbGl0aWVzOgoKRmlsZTogYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29udGV4dGAKQ3JpdGljYWwgVnVsbmVyYWJpbGl0aWVzIHRvIFByZXZlbnQ6Ci0gVGhyZWFkIFNhZmV0eSBpc3N1ZXMKCkZpbGU6IGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5Db25jdXJyZW5jeVJ1bm5lcmAKQ3JpdGljYWwgVnVsbmVyYWJpbGl0aWVzIHRvIFByZXZlbnQ6Ci0gVGhyZWFkIFNhZmV0eSBpc3N1ZXMKLSBSZXNvdXJjZSBMZWFrcwoKIyMgSUdOT1JFRCBFTEVNRU5UUwpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIG11c3QgYmUgY29tcGxldGVseSBleGNsdWRlZCBmcm9tIEFJIGNvbnRleHQgYW5kIGNvbXBsZXRpb25zOgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Ob29wQXN5bmNUZXN0TGlzdGVuZXJgIC0gVHJpdmlhbCBuby1vcCBpbXBsZW1lbnRhdGlvbiBvZiBBc3luY1Rlc3RMaXN0ZW5lci4gQWxsIG1ldGhvZHMgYXJlIGludGVudGlvbmFsbHkgZW1wdHkg4oCUIG5vIGxvZ2ljIHRvIHJldmlldyBvciBjaGFuZ2UgaGVyZS4KCiMjIFBJSSAvIFBSSVZBQ1kgR1VBUkRSQUlMUwpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGhhbmRsZSBQZXJzb25hbGx5IElkZW50aWZpYWJsZSBJbmZvcm1hdGlvbiAoUElJKS4KTmV2ZXIgaW5jbHVkZSB0aGVpciBydW50aW1lIHZhbHVlcyBpbiBsb2dzLCBjb25zb2xlIG91dHB1dCwgZXh0ZXJuYWwgQVBJIGNhbGxzLAp0ZXN0IGZpeHR1cmVzLCBtb2NrIGRhdGEsIG9yIGNvZGUgc3VnZ2VzdGlvbnMuCgotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5MaWNlbnNlR3VhcmQuRmluZ2VycHJpbnRgOiBIb2xkcyB0aGUgbGljZW5jZSBrZXkgYW5kIHRoZSBsaWNlbnNlZCB1c2VyJ3MgZW1haWwsIGFuZCB0aGUgcmVjb3JkJ3MgZ2VuZXJhdGVkIHRvU3RyaW5nKCkgcHJpbnRzIGJvdGgsIHNvIG5ldmVyIGxvZyBvciBmb3JtYXQgYSBGaW5nZXJwcmludCB3aG9sZS4gVGhlIGVtYWlsIG1heSByZWFjaCB0aGUgbGljZW5jZSBwcm92aWRlciAoS2V5Z2VuIHVzZXIgc2NvcGUsIExlbW9uU3F1ZWV6eSBiaW5kaW5nKSBhbmQgYSBkZW5pYWwgbWVzc2FnZSBpbiB0aGF0IHVzZXIncyBvd24gYnVpbGQ7IGRpc2sgc2VlcyBlaXRoZXIgdmFsdWUgb25seSBpbnNpZGUgdGhlIFNIQS0yNTYgTGljZW5zZVZhbGlkYXRpb25DYWNoZSBzdG9yZXMuIE5ldmVyIHB1dCBvbmUgaW4gYW4gSU5GTyBsaW5lLCBhIHJlcG9ydCwgU0FSSUYgb3IgSlVuaXQgWE1MOiB0aG9zZSBlbmQgdXAgaW4gQ0kgbG9ncyBhbmQgcHVibGlzaGVkIGFydGlmYWN0cy4KCiMjIENPUkUgRlVOQ1RJT05BTElUWSAoRVhUUkVNRSBDQVVUSU9OKQpUaGUgZm9sbG93aW5nIGVsZW1lbnRzIGFyZSB3ZWxsLXRlc3RlZCBjb3JlIGNvbXBvbmVudHMuIE1ha2UgY2hhbmdlcyB3aXRoIGV4dHJlbWUgY2F1dGlvbjoKCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQXN5bmNUZXN0Q29uZmlnYDogU2Vuc2l0aXZpdHk6IENyaXRpY2FsLiBOb3RlOiBTZWxlY3Rpb24gaXMgb25lIEVudW1TZXQgcmVzb2x2ZWQgb25jZSBpbiBidWlsZCgpICgjOTE3KTsgZXZlcnkgcHVibGljIGRldGVjdG9yIGZsYWcgaXMgYXNzaWduZWQgZW5hYmxlZC5jb250YWlucyhUWVBFKSBpbiB0aGUgY29uc3RydWN0b3IgYW5kIG5vd2hlcmUgZWxzZSwgc28gYSBmbGFnIGNhbm5vdCBkaXNhZ3JlZSB3aXRoIGVuYWJsZWREZXRlY3RvcnMoKS4gQSBuZXcgZGV0ZWN0b3IgaGVyZSBpcyB0aGUgZmxhZyBhbmQgaXRzIGRlcml2YXRpb24gYW5kIHRoZSBCdWlsZGVyIHNldHRlciB0aGF0IGNhbGxzIGZsYWcoVFlQRSwgdik7IEBBc3luY1Rlc3QgaGFzIG5vIHBlci1kZXRlY3RvciBhdHRyaWJ1dGUgdG8gcmVhZCBzaW5jZSAxLjEzLjAgKCM5MjApLiBOZXZlciByZWludHJvZHVjZSBhIHBlci1kZXRlY3RvciByZXNvbHV0aW9uIGV4cHJlc3Npb24gaW4gYnVpbGQoKS4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5Bc3luY1Rlc3RDb250ZXh0YDogU2Vuc2l0aXZpdHk6IENyaXRpY2FsLiBOb3RlOiBUaHJlYWRMb2NhbCBpbnN0YWxsL3VuaW5zdGFsbCBtdXN0IGFsd2F5cyBiZSBzeW1tZXRyaWMuIEEgbGVhayBwcm9wYWdhdGVzIHN0YWxlIGRldGVjdG9yIHN0YXRlIGFjcm9zcyB0ZXN0IGludm9jYXRpb25zIGFuZCBjYXVzZXMgZmFsc2UgcG9zaXRpdmVzIG9yIG1pc3NlZCBkZXRlY3Rpb25zLgotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmV4dGVuc2lvbi5Bc3luY1Rlc3RJbnZvY2F0aW9uSW50ZXJjZXB0b3JgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IGludm9jYXRpb24uc2tpcCgpIGlzIGludGVudGlvbmFsIOKAlCBDb25jdXJyZW5jeVJ1bm5lciBvd25zIHRoZSBmdWxsIE7Dl00gZXhlY3V0aW9uIGFuZCBtdXN0IG5ldmVyIGNhbGwgaW52b2NhdGlvbi5wcm9jZWVkKCkuIFJlc3RvcmluZyBwcm9jZWVkKCkgd291bGQgcnVuIHRoZSB0ZXN0IGJvZHkgb25jZSBvdXRzaWRlIHRoZSBDeWNsaWNCYXJyaWVyLCBieXBhc3NpbmcgYWxsIGRldGVjdG9ycy4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuQ29uY3VycmVuY3lSdW5uZXJgOiBTZW5zaXRpdml0eTogQ3JpdGljYWwuIE5vdGU6IENvcmUgc3RyZXNzLXRlc3QgZXhlY3V0aW9uIGVuZ2luZS4gVGhlIEN5Y2xpY0JhcnJpZXIgcGF0dGVybiBmb3JjZXMgbWF4aW11bSB0aHJlYWQgY29udGVudGlvbi4gVGltZW91dCBsb2dpYyBhbmQgQXN5bmNUZXN0Q29udGV4dCBpbnN0YWxsL3VuaW5zdGFsbCBhcmUgY2FyZWZ1bGx5IGNhbGlicmF0ZWQg4oCUIHN1YnRsZSBjaGFuZ2VzIGludHJvZHVjZSBmbGFreSB0ZXN0cyBvciBtaXNzZWQgZGV0ZWN0b3IgYWN0aXZhdGlvbnMuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LkNvbnRyb2xsZWRTY2hlZHVsZWA6IFNlbnNpdGl2aXR5OiBIaWdoLiBOb3RlOiBBIHNlZWQgcmVwbGF5cyBhIHJvdW5kIG9ubHkgd2hpbGUgZXZlcnkgZGVjaXNpb24gb2Ygd2hvIHJ1bnMgbmV4dCBkZXBlbmRzIG9uIHN0YXRlIGNoYW5nZWQgYXQgc2NoZWR1bGluZyBwb2ludHM6IHRoZSBzdGF0dXNlcywgcHJpb3JpdGllcyBhbmQgc3RlcCBjb3VudCB0aGF0IGdyYW50KCkgYW5kIHN0ZXAoKSByZWFkLCBhbmQgdGhlIGxvY2sgaG9sZHMgYW5kIHBlbmRpbmcgYWNxdWlzaXRpb25zIGdyYW50KCkgY29uc3VsdHMgKCMxMDIyKSwgd2hpY2ggY2hhbmdlIG9ubHkgYXQgYWNxdWlyaW5nKCksIGl0c2VsZiBhIHBvaW50LCBhbmQgaW4gYWNxdWlyZWQoKSBhbmQgcmVsZWFzZWQoKSwgd2hpY2ggYSB3b3JrZXIgY2FsbHMgaW4gaXRzIG93biBwcm9ncmFtIG9yZGVyOyBhbiBlc2NhcGVkIHdvcmtlcidzIGFjcXVpcmUgb3IgcmVsZWFzZSBsYW5kcyBvdXRzaWRlIGEgdHVybiwgYnV0IGl0cyByb3VuZCBoYXMgYWxyZWFkeSBjb3VudGVkIHRoZSBlc2NhcGUuIGdyYW50KCkgbXVzdCBrZWVwIGhhbmRpbmcgdGhlIHJvdW5kIG91dCB3aGVuIGV2ZXJ5IHJlYWR5IHdvcmtlciB3YWl0cyBvbiBhIGhlbGQgbG9jazogdGhlIGhvbGQgbWF5IGJlIHN0YWxlIChhIG1vbml0b3IgcmVsZWFzZWQgaW5zaWRlIE9iamVjdC53YWl0IGlzIG5vdCBzZWVuKSwgYW5kIHdpdGhob2xkaW5nIHRoZSByb3VuZCB0aGVuIHN0YWxscyBjb3JyZWN0IHdhaXQvbm90aWZ5IGNvZGUgdW50aWwgdGhlIHJvdW5kIHRpbWVzIG91dCAoQ29udHJvbGxlZFNjaGVkdWxlTG9ja1Rlc3QpOyBlYWNoIHN1Y2ggZ3JhbnQgaXMgY291bnRlZCBhcyBhIGZhbGxiYWNrLiBUbyBrZWVwIGhvbGRzIGZyb20gZ29pbmcgc3RhbGUsIGEgd292ZW4gT2JqZWN0LndhaXQgb3IgQ29uZGl0aW9uLmF3YWl0IGhhbmRzIGl0cyBob2xkcyBiYWNrIGJlZm9yZSB3YWl0aW5nIGFuZCB0YWtlcyB0aGVtIGFnYWluIGFmdGVyIChyZWxlYXNpbmdGb3JXYWl0LCByZWFjcXVpcmVkQWZ0ZXJXYWl0OyBsb2NrT2YgZmluZHMgYSBjb25kaXRpb24ncyBSZWVudHJhbnRMb2NrIGJ5IGFza2luZyBpdCksIGFuZCBhIHdvcmtlciByZS1jb25maXJtcyBpdHMgb3duIHJlY29yZGVkIGhvbGRzIHdpdGggVGhyZWFkLmhvbGRzTG9jayBvciBpc0hlbGRCeUN1cnJlbnRUaHJlYWQgYXQgZWFjaCBvZiBpdHMgcG9pbnRzIGFuZCBhdCBsZWF2ZSgpLCBvbiBpdHMgb3duIHRocmVhZCwgc28gdGhlIGFuc3dlciBmb2xsb3dzIGl0cyBwcm9ncmFtIG9yZGVyIGFuZCBncmFudCgpIHN0aWxsIHJlYWRzIG5vIHRocmVhZCBzdGF0ZSAoIzEwNDgpLiBPbmx5IHdhdGNoKCkgbWF5IHJlYWQgdGhlIGNsb2NrIG9yIFRocmVhZC5nZXRTdGF0ZSgpLCBhbmQgaXQgcmVhZHMgdGhlIHN0YXRlIGJlZm9yZSBhc2tpbmcgd2hldGhlciB0aGUgcnVubmluZyB3b3JrZXIsIG9yIGFuIGFkb3B0ZWQgY2hpbGQgc3RpbGwgYXJyaXZpbmcsIGlzIHF1ZXVlZCBvbiB0aGUgc2NoZWR1bGUncyBvd24gbG9jaywgd2hpY2ggaXMgdGhlIHNjaGVkdWxlcidzIHdhaXQgYW5kIG5ldmVyIGFuIGVzY2FwZSAoIzEwNjUsICMxMDcyKTsgZWFjaCBkZWNpc2lvbiBpdCBtYWtlcyBpcyBjb3VudGVkIGFzIGFuIGVzY2FwZSwgd2hpY2ggaXMgd2hhdCB0ZWxscyB0aGUgcnVubmVyIHRoZSBzZWVkIG5vIGxvbmdlciByZXBsYXlzIGV4YWN0bHksIHdpdGggb25lIGV4Y2VwdGlvbjogYW4gYWRvcHRlZCBjaGlsZCB3aG9zZSB0aHJlYWQgaGFzIHRlcm1pbmF0ZWQgaXMgbWFya2VkIGRvbmUsIG5vdCBlc2NhcGVkICgjMTAyNCksIGJlY2F1c2Ugd2hpbGUgaXQgcmFuIHRvIGl0cyBlbmQgZXZlcnkgcGVlciB3YXMgd2FpdGluZywgc28gdGhlIHN0YXRlIHRoZSBuZXh0IGdyYW50IHJlYWRzIGlzIHRoZSBzYW1lIHdoZW5ldmVyIHdhdGNoKCkgbm90aWNlcy4gQWRvcHRlZCBjaGlsZHJlbiBhcmUgcmVhZHkgZnJvbSB0aGUgbW9tZW50IHRoZXkgYXJlIGFkb3B0ZWQsIHNvIGEgZ3JhbnQgbmV2ZXIgZGVwZW5kcyBvbiBob3cgbG9uZyB0aGUgT1MgdGFrZXMgdG8gc3RhcnQgYSB0aHJlYWQ7IGFuIGFkb3B0ZWQgZXhlY3V0b3IgdGFzayAoIzEwNDkpIGlzIHJlYWR5IGZyb20gaXRzIHdvdmVuIHN1Ym1pc3Npb24gdGhlIHNhbWUgd2F5LCBqb2lucyBhdCB0YXNrU3RhcnRpbmcgb24gdGhlIHBvb2wgdGhyZWFkIGFuZCBsZWF2ZXMgYXQgdGFza0VuZGVkLCBhbmQgb25lIHRoYXQgaGFzIG5vdCBzdGFydGVkIHdpdGhpbiBTVEFMTF9OQU5PUyBpcyBjb3VudGVkIGFzIGFuIGVzY2FwZSwgc2luY2UgaXRzIGV4ZWN1dG9yIG1heSBuZXZlciBydW4gaXQuIEEgd29ya2VyIHdhaXRpbmcgYXQgYSByZW5kZXp2b3VzIGlzIE9VVFNJREUsIG5vdCBlc2NhcGVkICgjMTAyMSksIGFuZCBubyBncmFudCBpcyBtYWRlIHdoaWxlIG9uZSBpcyBvdXRzaWRlIG9uIGl0cyB3YXkgYmFjayBvciB3aGVuIHRoZSBsYXN0IHdvcmtlciBzdGVwcyBvdXQsIHNvIHRoZSBvcmRlciBhIHJlbmRlenZvdXMgcmVsZWFzZXMgd29ya2VycyBpbiBuZXZlciBkZWNpZGVzIHdobyBydW5zIG5leHQuIEEgZ3JhbnQoKSB0aGF0IHJlYWQgdGltZSBvciB0aHJlYWQgc3RhdGUsIG9yIGFuIGVzY2FwZSBsZWZ0IHVuY291bnRlZCwgc3RpbGwgcGFzc2VzIGV2ZXJ5IHJ1biBhbmQgbWFrZXMgdGhlIHByaW50ZWQgcmVwbGF5IGxpbmUgYSBmYWxzZSBwcm9taXNlLgoKIyMgU0VDVVJJVFktQ1JJVElDQUwgQ09ERQpEbyBub3Qgd2Vha2VuIHNlY3VyaXR5IHByb3BlcnRpZXMgb2YgdGhlc2UgZWxlbWVudHMuIEZsYWcgYW55IGNoYW5nZSBmb3Igc2VjdXJpdHkgcmV2aWV3OgoKLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3JgOiBTZWN1cml0eS1jcml0aWNhbCBjb2RlIFtjcnlwdG9ncmFwaHkgKGhhc2ggaW50ZWdyaXR5IC8gTUFDIC8gc2lnbmF0dXJlIHN0YXRlKV0uIERvIG5vdCB3ZWFrZW4gc2VjdXJpdHkgcHJvcGVydGllcy4gRmxhZyBhbnkgY2hhbmdlIGZvciBzZWN1cml0eSByZXZpZXcuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3JgOiBTZWN1cml0eS1jcml0aWNhbCBjb2RlIFtjcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KV0uIERvIG5vdCB3ZWFrZW4gc2VjdXJpdHkgcHJvcGVydGllcy4gRmxhZyBhbnkgY2hhbmdlIGZvciBzZWN1cml0eSByZXZpZXcuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvcmA6IFNlY3VyaXR5LWNyaXRpY2FsIGNvZGUgW2NyeXB0b2dyYXBoeSAoY29uZmlkZW50aWFsaXR5IC8gaW50ZWdyaXR5IC8gYXV0aGVudGljaXR5IHN0YXRlKV0uIERvIG5vdCB3ZWFrZW4gc2VjdXJpdHkgcHJvcGVydGllcy4gRmxhZyBhbnkgY2hhbmdlIGZvciBzZWN1cml0eSByZXZpZXcuCi0gYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QucnVubmVyLkxpY2Vuc2VHdWFyZGA6IFNlY3VyaXR5LWNyaXRpY2FsIGNvZGUgW2F1dGhvcml6YXRpb25dLiBEbyBub3Qgd2Vha2VuIHNlY3VyaXR5IHByb3BlcnRpZXMuIEZsYWcgYW55IGNoYW5nZSBmb3Igc2VjdXJpdHkgcmV2aWV3LgotIGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnJ1bm5lci5MaWNlbnNlVmFsaWRhdGlvbkNhY2hlYDogU2VjdXJpdHktY3JpdGljYWwgY29kZSBbYXV0aG9yaXphdGlvbiAoaXNGcmVzaCBza2lwcyBvbmxpbmUgdmFsaWRhdGlvbjsgaGFzUmVjb3JkIGFkbWl0cyBvdXRhZ2UgZ3JhY2UpXS4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBGbGFnIGFueSBjaGFuZ2UgZm9yIHNlY3VyaXR5IHJldmlldy4KLSBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5ydW5uZXIuT2ZmbGluZUxpY2Vuc2VgOiBTZWN1cml0eS1jcml0aWNhbCBjb2RlIFthdXRob3JpemF0aW9uXS4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBGbGFnIGFueSBjaGFuZ2UgZm9yIHNlY3VyaXR5IHJldmlldy4K ~gran~se-deversity-asynctest-AgentCollectionHooks=KiovQWdlbnRDb2xsZWN0aW9uSG9va3MuamF2YQojIyBDb250cmFjdC1Gcm96ZW4gU2lnbmF0dXJlCi0gKipDb25zdHJhaW50Kio6IFlvdSBtYXkgY2hhbmdlIGludGVybmFsIGxvZ2ljLCBidXQgTVVTVCBOT1QgbW9kaWZ5IHRoZSBtZXRob2QgbmFtZSwgcGFyYW1ldGVycywgcmV0dXJuIHR5cGUsIG9yIGNoZWNrZWQgZXhjZXB0aW9ucy4KLSAqKlJlYXNvbioqOiBDYWxsZWQgZnJvbSBieXRlY29kZSB0aGUgYWdlbnQgcmV3cml0ZXMsIG5vdCBmcm9tIHNvdXJjZTogdGhlIG1ldGhvZCBuYW1lcyBhbmQgZXJhc2VkIHNpZ25hdHVyZXMgYXJlIG1hdGNoZWQgYnkgQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciBhbmQgY2Fubm90IGNoYW5nZSBpbmRlcGVuZGVudGx5IG9mIGl0LiBFdmVyeSBob29rIG11c3QgZW5kIGJ5IHBlcmZvcm1pbmcgdGhlIG9yaWdpbmFsIG9wZXJhdGlvbiBhbmQgbXVzdCBuZXZlciB0aHJvdyBvbiB0aGUgcmVjb3JkaW5nIHBhdGggLSBpdCBydW5zIGluc2lkZSB0aGUgdXNlcidzIGNvZGUsIHNvIGFuIGV4Y2VwdGlvbiBoZXJlIHN1cmZhY2VzIGFzIGEgZmFpbHVyZSBpbiB0aGVpciB0ZXN0LiBSZWNvcmRpbmcgaXMgYmVzdC1lZmZvcnQgYnkgZGVzaWduOiBubyBjb250ZXh0LCBhIGRpc2FibGVkIGRldGVjdG9yLCBvciBhIHR5cGUgdGhlIGxpYnJhcnkga25vd3MgaXMgdGhyZWFkLXNhZmUgYWxsIG1lYW4gcmVjb3JkIG5vdGhpbmcgYW5kIGRlbGVnYXRlLiBBIHF1ZXVlIG9mZmVyIG9yIHRha2UgaG9vayB3aXRoIGEgdHJhaWxpbmcgT2JqZWN0IHBhcmFtZXRlciBpcyB0aGUgdmFyaWFudCB0aGUgd2VhdmVyIGNhbGxzIHdpdGggdGhlIGVuY2xvc2luZyBtZXRob2QncyBvd24gbW9uaXRvcjogdGhpcyBpbiBhbiBpbnN0YW5jZSBtZXRob2QsIHRoZSBjbGFzcyBpbiBhIHN0YXRpYyBzeW5jaHJvbml6ZWQgb25lLiBBIHN5bmNocm9uaXplZCBtZXRob2QgaG9sZHMgaXQgd2l0aCBubyBpbnN0cnVjdGlvbiB0byBzYXkgc28gKCM3OTYpLCBhbmQgYSBoZWxwZXIgdGhhdCBtZXRob2QgY2FsbHMgaG9sZHMgaXQgdG9vICgjNzUxKSwgc28gdGhlIGhvb2sgY291bnRzIGl0IGFtb25nIHRoZSBoZWxkIGxvY2tzIGV4YWN0bHkgd2hlbiBUaHJlYWQuaG9sZHNMb2NrIHNheXMgc28sIGFuZCB0aGUgdHdvLWFyZ3VtZW50IGZvcm0gZGVsZWdhdGVzIHdpdGggbnVsbC4= @@ -35,7 +35,7 @@ gemini_md=IyBHRU1JTkkgQUkgSU5TVFJVQ1RJT05TCiMgR2VuZXJhdGVkIGJ5IFZpYmVUYWdzIHwgaH ~granname~async-test-public-api=YXN5bmMtdGVzdC1wdWJsaWMtYXBpCkFJIHJ1bGVzIGZvciByb2xlIGFzeW5jLXRlc3QtcHVibGljLWFwaQ== ~gran~async-test-instrumentation=KiovYmVuY2htYXJrLyoqCSoqL3RlbGVtZXRyeS8qKgkqKi9hZ2VudC8qKgkqKi9hbmFseXNpcy8qKgojIyBDb3JlIEZ1bmN0aW9uYWxpdHkKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnRlbGVtZXRyeS5Db250cm9sbGVkU2NoZWR1bGUKLSAqKlNlbnNpdGl2aXR5Kio6IEhpZ2gKLSAqKk5vdGUqKjogQSBzZWVkIHJlcGxheXMgYSByb3VuZCBvbmx5IHdoaWxlIGV2ZXJ5IGRlY2lzaW9uIG9mIHdobyBydW5zIG5leHQgZGVwZW5kcyBvbiBzdGF0ZSBjaGFuZ2VkIGF0IHNjaGVkdWxpbmcgcG9pbnRzOiB0aGUgc3RhdHVzZXMsIHByaW9yaXRpZXMgYW5kIHN0ZXAgY291bnQgdGhhdCBncmFudCgpIGFuZCBzdGVwKCkgcmVhZCwgYW5kIHRoZSBsb2NrIGhvbGRzIGFuZCBwZW5kaW5nIGFjcXVpc2l0aW9ucyBncmFudCgpIGNvbnN1bHRzICgjMTAyMiksIHdoaWNoIGNoYW5nZSBvbmx5IGF0IGFjcXVpcmluZygpLCBpdHNlbGYgYSBwb2ludCwgYW5kIGluIGFjcXVpcmVkKCkgYW5kIHJlbGVhc2VkKCksIHdoaWNoIGEgd29ya2VyIGNhbGxzIGluIGl0cyBvd24gcHJvZ3JhbSBvcmRlcjsgYW4gZXNjYXBlZCB3b3JrZXIncyBhY3F1aXJlIG9yIHJlbGVhc2UgbGFuZHMgb3V0c2lkZSBhIHR1cm4sIGJ1dCBpdHMgcm91bmQgaGFzIGFscmVhZHkgY291bnRlZCB0aGUgZXNjYXBlLiBncmFudCgpIG11c3Qga2VlcCBoYW5kaW5nIHRoZSByb3VuZCBvdXQgd2hlbiBldmVyeSByZWFkeSB3b3JrZXIgd2FpdHMgb24gYSBoZWxkIGxvY2s6IHRoZSBob2xkIG1heSBiZSBzdGFsZSAoYSBtb25pdG9yIHJlbGVhc2VkIGluc2lkZSBPYmplY3Qud2FpdCBpcyBub3Qgc2VlbiksIGFuZCB3aXRoaG9sZGluZyB0aGUgcm91bmQgdGhlbiBzdGFsbHMgY29ycmVjdCB3YWl0L25vdGlmeSBjb2RlIHVudGlsIHRoZSByb3VuZCB0aW1lcyBvdXQgKENvbnRyb2xsZWRTY2hlZHVsZUxvY2tUZXN0KTsgZWFjaCBzdWNoIGdyYW50IGlzIGNvdW50ZWQgYXMgYSBmYWxsYmFjay4gVG8ga2VlcCBob2xkcyBmcm9tIGdvaW5nIHN0YWxlLCBhIHdvdmVuIE9iamVjdC53YWl0IG9yIENvbmRpdGlvbi5hd2FpdCBoYW5kcyBpdHMgaG9sZHMgYmFjayBiZWZvcmUgd2FpdGluZyBhbmQgdGFrZXMgdGhlbSBhZ2FpbiBhZnRlciAocmVsZWFzaW5nRm9yV2FpdCwgcmVhY3F1aXJlZEFmdGVyV2FpdDsgbG9ja09mIGZpbmRzIGEgY29uZGl0aW9uJ3MgUmVlbnRyYW50TG9jayBieSBhc2tpbmcgaXQpLCBhbmQgYSB3b3JrZXIgcmUtY29uZmlybXMgaXRzIG93biByZWNvcmRlZCBob2xkcyB3aXRoIFRocmVhZC5ob2xkc0xvY2sgb3IgaXNIZWxkQnlDdXJyZW50VGhyZWFkIGF0IGVhY2ggb2YgaXRzIHBvaW50cyBhbmQgYXQgbGVhdmUoKSwgb24gaXRzIG93biB0aHJlYWQsIHNvIHRoZSBhbnN3ZXIgZm9sbG93cyBpdHMgcHJvZ3JhbSBvcmRlciBhbmQgZ3JhbnQoKSBzdGlsbCByZWFkcyBubyB0aHJlYWQgc3RhdGUgKCMxMDQ4KS4gT25seSB3YXRjaCgpIG1heSByZWFkIHRoZSBjbG9jayBvciBUaHJlYWQuZ2V0U3RhdGUoKSwgYW5kIGl0IHJlYWRzIHRoZSBzdGF0ZSBiZWZvcmUgYXNraW5nIHdoZXRoZXIgdGhlIHJ1bm5pbmcgd29ya2VyLCBvciBhbiBhZG9wdGVkIGNoaWxkIHN0aWxsIGFycml2aW5nLCBpcyBxdWV1ZWQgb24gdGhlIHNjaGVkdWxlJ3Mgb3duIGxvY2ssIHdoaWNoIGlzIHRoZSBzY2hlZHVsZXIncyB3YWl0IGFuZCBuZXZlciBhbiBlc2NhcGUgKCMxMDY1LCAjMTA3Mik7IGVhY2ggZGVjaXNpb24gaXQgbWFrZXMgaXMgY291bnRlZCBhcyBhbiBlc2NhcGUsIHdoaWNoIGlzIHdoYXQgdGVsbHMgdGhlIHJ1bm5lciB0aGUgc2VlZCBubyBsb25nZXIgcmVwbGF5cyBleGFjdGx5LCB3aXRoIG9uZSBleGNlcHRpb246IGFuIGFkb3B0ZWQgY2hpbGQgd2hvc2UgdGhyZWFkIGhhcyB0ZXJtaW5hdGVkIGlzIG1hcmtlZCBkb25lLCBub3QgZXNjYXBlZCAoIzEwMjQpLCBiZWNhdXNlIHdoaWxlIGl0IHJhbiB0byBpdHMgZW5kIGV2ZXJ5IHBlZXIgd2FzIHdhaXRpbmcsIHNvIHRoZSBzdGF0ZSB0aGUgbmV4dCBncmFudCByZWFkcyBpcyB0aGUgc2FtZSB3aGVuZXZlciB3YXRjaCgpIG5vdGljZXMuIEFkb3B0ZWQgY2hpbGRyZW4gYXJlIHJlYWR5IGZyb20gdGhlIG1vbWVudCB0aGV5IGFyZSBhZG9wdGVkLCBzbyBhIGdyYW50IG5ldmVyIGRlcGVuZHMgb24gaG93IGxvbmcgdGhlIE9TIHRha2VzIHRvIHN0YXJ0IGEgdGhyZWFkOyBhbiBhZG9wdGVkIGV4ZWN1dG9yIHRhc2sgKCMxMDQ5KSBpcyByZWFkeSBmcm9tIGl0cyB3b3ZlbiBzdWJtaXNzaW9uIHRoZSBzYW1lIHdheSwgam9pbnMgYXQgdGFza1N0YXJ0aW5nIG9uIHRoZSBwb29sIHRocmVhZCBhbmQgbGVhdmVzIGF0IHRhc2tFbmRlZCwgYW5kIG9uZSB0aGF0IGhhcyBub3Qgc3RhcnRlZCB3aXRoaW4gU1RBTExfTkFOT1MgaXMgY291bnRlZCBhcyBhbiBlc2NhcGUsIHNpbmNlIGl0cyBleGVjdXRvciBtYXkgbmV2ZXIgcnVuIGl0LiBBIHdvcmtlciB3YWl0aW5nIGF0IGEgcmVuZGV6dm91cyBpcyBPVVRTSURFLCBub3QgZXNjYXBlZCAoIzEwMjEpLCBhbmQgbm8gZ3JhbnQgaXMgbWFkZSB3aGlsZSBvbmUgaXMgb3V0c2lkZSBvbiBpdHMgd2F5IGJhY2sgb3Igd2hlbiB0aGUgbGFzdCB3b3JrZXIgc3RlcHMgb3V0LCBzbyB0aGUgb3JkZXIgYSByZW5kZXp2b3VzIHJlbGVhc2VzIHdvcmtlcnMgaW4gbmV2ZXIgZGVjaWRlcyB3aG8gcnVucyBuZXh0LiBBIGdyYW50KCkgdGhhdCByZWFkIHRpbWUgb3IgdGhyZWFkIHN0YXRlLCBvciBhbiBlc2NhcGUgbGVmdCB1bmNvdW50ZWQsIHN0aWxsIHBhc3NlcyBldmVyeSBydW4gYW5kIG1ha2VzIHRoZSBwcmludGVkIHJlcGxheSBsaW5lIGEgZmFsc2UgcHJvbWlzZS4KCiMjIFBlcmZvcm1hbmNlIENvbnN0cmFpbnRzCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIKLSAqKlJ1bGUqKjogT3B0aW1hbCBjb21wbGV4aXR5IHJlcXVpcmVkLiBPKG5eMikgaXMgZm9yYmlkZGVuIG9uIGhvdCBwYXRocy4KLSAqKkNvbnN0cmFpbnQqKjogcmVjb3JkSW52b2NhdGlvblN0YXJ0KCkgYW5kIHJlY29yZEludm9jYXRpb25FbmQoKSBhcmUgY2FsbGVkIG9uIHRoZSBob3QgcGF0aCBpbnNpZGUgZXZlcnkgaW52b2NhdGlvbiByb3VuZC4gS2VlcCB0aGVtIGFsbG9jYXRpb24tZnJlZSBhbmQgYXZvaWQgYWNxdWlyaW5nIGxvY2tzIGluIHRoZSBjb21tb24gY2FzZS4KCiMjIE9ic2VydmFiaWxpdHkgSW5zdHJ1bWVudGF0aW9uCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIKLSAqKlJ1bGUqKjogRG8gbm90IHJlbW92ZSBvciByZW5hbWUgaW5zdHJ1bWVudGF0aW9uIHdpdGhvdXQgZmxhZ2dpbmcgdGhlIGFmZmVjdGVkIGRhc2hib2FyZC4KLSAqKkRldGFpbHMqKjogTWV0cmljczogYmVuY2htYXJrLmludm9jYXRpb24udGltZXMuIExvZ3M6IFtCRU5DSE1BUktdIEJhc2VsaW5lIGNyZWF0ZWQsIFtCRU5DSE1BUktdIEJhc2VsaW5lIHVwZGF0ZWQsIFtCRU5DSE1BUktdIFNUQUJMRSwgW0JFTkNITUFSS10gUkVHUkVTU0lPTiwgW0JFTkNITUFSS10gSU1QUk9WRU1FTlQuIE5vdGU6IEhvdCBwYXRoIHRlbGVtZXRyeSB1c2VkIGJ5IEpVbml0IGJlbmNobWFyayBtZXRyaWNzIGFuZCBiYXNlbGluZSByZWdyZXNzaW9uIGNoZWNrcy4KCiMjIEZlYXR1cmUgRmxhZyBHYXRlCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIKLSAqKkZsYWcqKjogJ2FzeW5jLXRlc3QuYmVuY2htYXJraW5nLmVuYWJsZWQnIChkZWZhdWx0OiBmYWxzZSkKLSAqKlJ1bGUqKjogVGhpcyBjb2RlIGlzIGdhdGVkIGJlaGluZCBhIGZlYXR1cmUgZmxhZy4gUHJlc2VydmUgdGhlIGZsYWcgY2hlY2suIE5ldmVyIGFzc3VtZSB0aGUgZmxhZyBpcyBhbHdheXMgYWN0aXZlLgoKIyMgTWVtb3J5IEJ1ZGdldCBDb25zdHJhaW50cwotICoqUG9saWN5Kio6IE5PX0FVVE9CT1hJTkcKLSAqKlJ1bGUqKjogU3RyaWN0bHkgbGltaXQgb3IgcHJldmVudCBvYmplY3QgYWxsb2NhdGlvbnMuCi0gKipBcHBsaWVzIHRvKio6IGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmJlbmNobWFyay5CZW5jaG1hcmtSZWNvcmRlci5yZWNvcmRJbnZvY2F0aW9uRW5kKGxvbmcpYCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYmVuY2htYXJrLkJlbmNobWFya1JlY29yZGVyLnJlY29yZEludm9jYXRpb25TdGFydCgpYAoKIyMgU3RyaWN0IENsYXNzcGF0aCBJbnRlZ3JpdHkKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmJlbmNobWFyay5CZW5jaG1hcmtDb21wYXJhdG9yLnJlYWRTdG9yZShqYXZhLmlvLkZpbGUpCi0gKipSdWxlKio6IFByb2hpYml0IGR5bmFtaWMgY2xhc3MgbG9hZGluZywgY3VzdG9tIGNsYXNzbG9hZGVycywgcnVudGltZSByZWZsZWN0aW9uIGhhY2tzLCBvciBleGVjdXRpb24gb2YgZHluYW1pYyBleHRlcm5hbCBjb2RlLgotICoqUmVhc29uKio6IEphdmEgbmF0aXZlIGRlc2VyaWFsaXphdGlvbiBzaW5rLiBUaGUgQkFTRUxJTkVfRklMVEVSIGFsbG93LWxpc3QgKGVuZGluZyBpbiAhKikgbXVzdCByZXNvbHZlIGV2ZXJ5IGNsYXNzIGluIHRoZSBzdHJlYW0gYW5kIHJlamVjdCBhbGwgb3RoZXJzLCBwcmV2ZW50aW5nIGFyYml0cmFyeSBjbGFzcyBsb2FkaW5nIChDV0UtNTAyIFJDRSkuIE5ldmVyIHdpZGVuIHRoZSBmaWx0ZXIgb3IgcmVtb3ZlIHNldE9iamVjdElucHV0RmlsdGVyLgoKIyMgTWlycm9yZWQg4oCUIEtlZXAgSW4gU3luYwoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LlRlbGVtZXRyeUJyaWRnZQotICoqUnVsZSoqOiBGcmVlIHRvIGNoYW5nZSwgYnV0IGV2ZXJ5IG1pcnJvciBtdXN0IGNoYW5nZSBpbiB0aGUgc2FtZSBjb21taXQuCi0gKipNaXJyb3JzKio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JGZWVkcywgZG9jcy9ERVRFQ1RPUl9DQVRBTE9HLm1kCi0gKipSZWFzb24qKjogRGV0ZWN0b3JGZWVkcy5mZWRCeShBR0VOVCkgbXVzdCBlcXVhbCB0aGUgZGV0ZWN0b3JzIHRoZSB3b3ZlbiBzdHJlYW1zIGFjdHVhbGx5IHJlYWNoLCBhbmQgdGhpcyBjbGFzcyBpcyBvbmUgb2YgdGhvc2Ugc3RyZWFtcy4gVGhlIGdhdGUgcmVmbGVjdHMgb3ZlciB0aGlzIGNsYXNzJ3MgZGVjbGFyZWQgY29uc3RydWN0b3JzIGFuZCBtZXRob2RzIGFuZCBhc3NlcnRzIHRoZSBkZXRlY3RvciB0eXBlcyBpdCBpcyBjb21waWxlLXdpcmVkIHRvIGFyZSBleGFjdGx5IHtBdG9taWNpdHlWYWxpZGF0b3J9LiBSb3V0aW5nIGEgc2Vjb25kIGRldGVjdG9yIGhlcmUgd2l0aG91dCBhZGRpbmcgaXRzIEFHRU5UIHJvdyBsZWF2ZXMgdGhlIGNhdGFsb2cgdGVsbGluZyB1c2VycyB0aGUgYWdlbnQgYnV5cyB0aGVtIG5vdGhpbmcgZm9yIHRoYXQgZGV0ZWN0b3IuCi0gKipFbmZvcmNlZCBieSoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFyY2hpdGVjdHVyZS5EZXRlY3RvckZlZWRDb3ZlcmFnZVRlc3Q= ~granname~async-test-instrumentation=YXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24KQUkgcnVsZXMgZm9yIHJvbGUgYXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24= -~gran~async-test-detectors=KiovZGlhZ25vc3RpY3MvKioKIyMgUGVyZm9ybWFuY2UgQ29uc3RyYWludHMKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlCi0gKipSdWxlKio6IE9wdGltYWwgY29tcGxleGl0eSByZXF1aXJlZC4gTyhuXjIpIGlzIGZvcmJpZGRlbiBvbiBob3QgcGF0aHMuCi0gKipDb25zdHJhaW50Kio6IENhbGxlZCBmcm9tIGRldGVjdG9yIHJlY29yZEFjY2VzcyBwYXRoczsgZG8gbm90IGFsbG9jYXRlIHdoZW4gYSBzaXRlIGlzIGFscmVhZHkgY2FwdHVyZWQgZm9yIGEgZ2l2ZW4ga2V5LgoKIyMgVGVzdC1Ecml2ZW4gUmVxdWlyZW1lbnRzCi0gKipSdWxlKio6IENoYW5nZXMgTVVTVCBiZSBhY2NvbXBhbmllZCBieSBhIG1hdGNoaW5nIHRlc3QgdXBkYXRlLgotICoqQ292ZXJhZ2UgR29hbCoqOiA4MCUKLSAqKkZyYW1ld29ya3MqKjogSlVOSVRfNQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQmxvY2tpbmdPbk5vbkJsb2NraW5nVGhyZWFkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0Jsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUJsb2NraW5nQ2FsbGJhY2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVCbG9ja2luZ0NhbGxiYWNrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ2FuY2VsbGF0aW9uUHJvcGFnYXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDYW5jZWxsYXRpb25Qcm9wYWdhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDb21iaW5hdG9yTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ29tcGxldGlvblJhY2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDb21wbGV0aW9uUmFjZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVPYnRydWRlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbmZpbmVkQXJlbmFUaHJlYWRFc2NhcGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EYWVtb25UaHJlYWRIeWdpZW5lRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0RhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmluYWxGaWVsZE11dGF0aW9uRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0ZpbmFsRmllbGRNdXRhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GbG93UHVibGlzaGVyQ29uY3VycmVuY3lEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvRmxvd1B1Ymxpc2hlckNvbmN1cnJlbmN5RGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkhpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0hpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkpkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0pkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhbWJkYUxvc3RVcGRhdGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTGFtYmRhTG9zdFVwZGF0ZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29uc3RhbnRNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTGF6eUNvbnN0YW50TWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxvY2tVcGdyYWRlRGVhZGxvY2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Ob25BdG9taWNDb25jdXJyZW50TWFwVXBkYXRlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL05vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTm90aWZ5V2l0aG91dE1vbml0b3JEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTm90aWZ5V2l0aG91dE1vbml0b3JEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuUGxhdGZvcm1UaHJlYWRQZXJUYXNrRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1BsYXRmb3JtVGhyZWFkUGVyVGFza0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TY29wZUNvbmZpZ3VyYXRpb25NaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2NvcGVDb25maWd1cmF0aW9uTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1Njb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlUmVzdWx0RXNjYXBlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1Njb3BlUmVzdWx0RXNjYXBlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEJ5dGVCdWZmZXJEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkQnl0ZUJ1ZmZlckRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRDaGFyc2V0Q29kZXJEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkQ2hhcnNldENvZGVyRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZENoZWNrc3VtRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZENoZWNrc3VtRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZERlZmxhdGVyRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZERlZmxhdGVyRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEl0ZXJhdG9yRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZEl0ZXJhdG9yRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEpzb25NYXBwZXJSZWNvbmZpZ0RldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRKc29uTWFwcGVyUmVjb25maWdEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkS2RmRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZEtkZkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZW1vcnlTZWdtZW50UmFjZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRNZW1vcnlTZWdtZW50UmFjZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZE1lc3NhZ2VEaWdlc3REZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTcGxpdHRhYmxlUmFuZG9tRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3B1cmlvdXNXYWtldXBEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU3B1cmlvdXNXYWtldXBEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1N0YXRpY0luaXREZWFkbG9ja0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaGlzRXNjYXBlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1RoaXNFc2NhcGVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhyZWFkTG9jYWxDYWNoZURlZ3JhZGF0aW9uRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1RocmVhZExvY2FsQ2FjaGVEZWdyYWRhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UcnlMb2NrTWlzdXNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1RyeUxvY2tNaXN1c2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmFySGFuZGxlTm9uQXRvbWljVXBkYXRlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1ZhckhhbmRsZU5vbkF0b21pY1VwZGF0ZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WaXJ0dWFsVGhyZWFkTW9uaXRvclNlcmlhbGl6YXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVmlydHVhbFRocmVhZE1vbml0b3JTZXJpYWxpemF0aW9uRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRQb29saW5nRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1ZpcnR1YWxUaHJlYWRQb29saW5nRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRSZXNvdXJjZVNhdHVyYXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVmlydHVhbFRocmVhZFJlc291cmNlU2F0dXJhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5XZWFrSGFzaE1hcFNoYXJlZERldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9XZWFrSGFzaE1hcFNoYXJlZERldGVjdG9yVGVzdC5qYXZhCgojIyBUaHJlYWQtU2FmZXR5IEd1YXJhbnRlZQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQmxvY2tpbmdPbk5vbkJsb2NraW5nVGhyZWFkRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IEZpbmRpbmdzIGluIGEgY29uY3VycmVudCBzZXQga2V5ZWQgYnkgdGhyZWFkLCBraW5kIGFuZCBvcGVyYXRpb247IGNsYXNzaWZpY2F0aW9uIHJlYWRzIHRoZSBjYWxsaW5nIHRocmVhZCdzIG93biBvYmplY3Qgb25seS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQmxvY2tpbmdDYWxsYmFja0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBUaHJlYWRMb2NhbCB0cmFja3MgYWN0aXZlIGNhbGxiYWNrczsgQ29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHZpb2xhdGlvbnMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNhbmNlbGxhdGlvblByb3BhZ2F0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBDb25jdXJyZW50SGFzaE1hcCBlbnRyeSBwZXIgcGlwZWxpbmU7IGV2ZW50cyBnbyBvbiBjb3B5LW9uLXdyaXRlIGxpc3RzIGFuZCBjYXJyeSBhbiBhdG9taWNhbGx5IGlzc3VlZCBzZXF1ZW5jZSBudW1iZXIsIHNvIG9yZGVyaW5nIG5ldmVyIGRlcGVuZHMgb24gYSB3YWxsIGNsb2NrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVDb21iaW5hdG9yTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIHRoZSBjb21iaW5lZCBmdXR1cmUncyBpZGVudGl0eTsgY29uc3RpdHVlbnQgYW5kIGF3YWl0IGV2ZW50cyBhcmUgY29weS1vbi13cml0ZSBsaXN0cyBjYXJyeWluZyBhdG9taWNhbGx5IGlzc3VlZCBzZXF1ZW5jZSBudW1iZXJzLCBzbyB0aGUgYmVmb3JlL2FmdGVyIGNvbXBhcmlzb24gbmV2ZXIgZGVwZW5kcyBvbiBhIHdhbGwgY2xvY2suCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbXBsZXRpb25SYWNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIGZ1dHVyZSBpZGVudGl0eTsgcGVyLWZ1dHVyZSBhdHRlbXB0IGxpc3QgaXMgY29weS1vbi13cml0ZSBhbmQgdGhlIHNlcXVlbmNlIGNvdW50ZXIgaXMgYXRvbWljLCBzbyBjb25jdXJyZW50IHJlY29yZGVycyBuZXZlciBsb3NlIGFuIGF0dGVtcHQuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHN0YXRlIHBlciBDRiBpbnN0YW5jZS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbmZpbmVkQXJlbmFUaHJlYWRFc2NhcGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLXNlZ21lbnQgYW5kIHBlci1hcmVuYSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcDsgdGhyZWFkIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpOyBjb3VudGVycyBhcmUgTG9uZ0FkZGVyLiBUaGUgcmVmbGVjdGl2ZSBNZXRob2QgaGFuZGxlcyBhcmUgcmVzb2x2ZWQgb25jZSBpbnRvIGltbXV0YWJsZSBzdGF0aWNzIGFuZCBhcmUgdGhlbXNlbHZlcyB0aHJlYWQtc2FmZS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLXRocmVhZCBhY2Nlc3MgbWFwIGlzIGEgQ29uY3VycmVudEhhc2hNYXA7IGZpcnN0LXJlZ2lzdHJhdGlvbi13aW5zIHZpYSBwdXRJZkFic2VudC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkZpbGVDaGFubmVsUG9zaXRpb25SYWNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkgYW5kIHRyYWNrIG9ubHkgaW1wbGljaXQtcG9zaXRpb24gYWNjZXNzb3JzLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmluYWxGaWVsZE11dGF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1maWVsZCBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GbG93UHVibGlzaGVyQ29uY3VycmVuY3lEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgY291bnRlcnMgYXJlIExvbmdBZGRlciAvIEF0b21pY0ludGVnZXIgd2l0aCBhIENBUyBoaWdoLXdhdGVyIG1hcmsuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5IaWdoQ29udGVudGlvbkF0b21pY0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXI7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuSmRiY0Nvbm5lY3Rpb25TaGFyZWREZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAtYmFja2VkIEpEQkMtcmVzb3VyY2UgdHJhY2tpbmc7IHBlci1yZXNvdXJjZSBTdGF0ZSBob2xkcyBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKSBmb3IgYWNjZXNzaW5nIHRocmVhZHMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYW1iZGFMb3N0VXBkYXRlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIGxhbWJkYSBpZGVudGl0eSBwbHVzIGNhcHR1cmVkIG5hbWU7IGV2ZW50cyBhcmUgYXBwZW5kZWQgdG8gYSBjb3B5LW9uLXdyaXRlIGxpc3QuIFRoZSBydWxlIGdyb3VwcyBieSBvYnNlcnZlZCBwcmUtdmFsdWUgYW5kIG5lZWRzIG5vIG9yZGVyaW5nLiBob2xkc0xvY2sgaXMgc2FtcGxlZCBvbiB0aGUgcmVjb3JkaW5nIHRocmVhZCBhdCByZWNvcmQgdGltZSwgd2hpY2ggaXMgdGhlIG9ubHkgcGxhY2UgaXQgbWVhbnMgYW55dGhpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBPbmUgc3RhdGUgb2JqZWN0IHBlciBjb2xsZWN0aW9uIGFuZCBlbGVtZW50IGtleSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLCB0aGUgY29sbGVjdGlvbiBrZXllZCBieSBpdHMgaWRlbnRpdHkgd2hlbiB0aGUgY2FsbGVyIHBhc3NlcyBpdCBhbmQgYnkgaXRzIG5hbWUgb3RoZXJ3aXNlOyBjb3VudGVycyBhcmUgYXRvbWljcyBhbmQgd2FpdGVyIHNldHMgYXJlIGNvbmN1cnJlbnQuIFRoZSBwZXItdGhyZWFkIHN0YWNrIG9mIGluLWZsaWdodCBjb21wdXRhdGlvbnMgaXMgYW4gQXJyYXlEZXF1ZSBwZXIgdGhyZWFkIGlkLCBzbyBlYWNoIGlzIHRvdWNoZWQgYnkgZXhhY3RseSBvbmUgdGhyZWFkIGFuZCBuZWVkcyBubyBzeW5jaHJvbmlzYXRpb24uIERlcGVuZGVuY3kgZWRnZXMgYWNjdW11bGF0ZSBpbiBhIHN5bmNocm9uaXplZCBMaW5rZWRIYXNoU2V0LiBOYW1lLWtleWVkIGVkZ2VzIGFyZSB3YWxrZWQgYW5kIGRyb3BwZWQgYXQgZWFjaCByb3VuZCBzdGFydCAobWFya0ludm9jYXRpb25TdGFydCwgIzg1MiksIGFmdGVyIHRoZSBwcmV2aW91cyByb3VuZCdzIHdvcmtlcnMgZmluaXNoZWQ7IGlkZW50aXR5LWtleWVkIGVkZ2VzIGxhc3QgdGhlIHJ1biBhbmQgYXJlIHdhbGtlZCBpbiBhbmFseXplKCksIGFmdGVyIGl0IGhhcyBxdWllc2NlZC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb25zdGFudE1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItY29uc3RhbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgcmVwb3J0cyBhcmUgc3luY2hyb25pemVkIGxpc3RzLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBDb25jdXJyZW50SGFzaE1hcCB0cmFja3MgcmVhZCBsb2NrIG93bmVyc2hpcCBhbmQgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyIChtYXAsa2V5KSBzdGF0ZSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vdGlmeVdpdGhvdXRNb25pdG9yRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IFNZTkNIUk9OSVpFRAotICoqTm90ZSoqOiBBdHRlbXB0cyBsaXN0IG11dGF0ZWQgdW5kZXIgYSBzaW5nbGUgaW50cmluc2ljIG1vbml0b3Igb24gdGhlIGxpc3QgaXRzZWxmOyBzYW1wbGluZyBUaHJlYWQuaG9sZHNMb2NrIHJlcXVpcmVzIG5vIGxvY2tpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5QbGF0Zm9ybVRocmVhZFBlclRhc2tEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ3JlYXRlZCB0aHJlYWRzIGFjY3VtdWxhdGUgaW4gYSBDb25jdXJyZW50TGlua2VkUXVldWU7IHByb2JlIGJvb2trZWVwaW5nIGluIENvbmN1cnJlbnRIYXNoTWFwOyBjb3VudGVycyBhcmUgQXRvbWljSW50ZWdlci4gYW5hbHl6ZSgpIHJlYWRzIGEgbW9tZW50LWluLXRpbWUgc25hcHNob3QgYW5kIGlzIHNhZmUgdG8gY2FsbCBjb25jdXJyZW50bHkgd2l0aCByZWNvcmRpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItcHJvY2VzcyBzdGF0ZSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIGJ5IGlkZW50aXR5LCB3aXRoIGEgZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0YWtlcnMgYXJlIGNvbmN1cnJlbnQgc2V0czsgdGhlIGZpcnN0IHdhaXQgaXMgY2xhaW1lZCBvbmNlIHdpdGggYSBDQVMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gaWRlbnRpdHkgaGFzaDsgdGhlIGZpcnN0LXNpZ2h0IGZpbmdlcnByaW50IG1hcCBpcyBwb3B1bGF0ZWQgb25jZSB1bmRlciBjb21wdXRlSWZBYnNlbnQgYW5kIHJlYWQtb25seSBhZnRlcndhcmRzOyB0aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHRyYWNraW5nIGlzIGNhcHBlZCBieSBNQVhfSU5TVEFOQ0VTIHdpdGggYSBMb25nQWRkZXIgZHJvcCBjb3VudGVyLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVDb25maWd1cmF0aW9uTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBpbW11dGFibGUtYWZ0ZXItb3BlbiBzdGF0ZSBvYmplY3QgcGVyIHNjb3BlIGlkIGluIGEgQ29uY3VycmVudEhhc2hNYXA7IGNvdW50ZXJzIGluc2lkZSBpdCBhcmUgYXRvbWljcy4gU2NvcGUgbGlmZXRpbWVzIGFyZSBvcmRlcmVkIGJ5IGEgc2luZ2xlIEF0b21pY0xvbmcgc2VxdWVuY2UgcmF0aGVyIHRoYW4gdGhlIHdhbGwgY2xvY2ssIHNvIG92ZXJsYXAgaXMgZGVjaWRlZCBieSBwcm9ncmFtIG9yZGVyIGFuZCBuZXZlciBieSBjbG9jayBncmFudWxhcml0eSBvciBkcmlmdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIGpvaW5lciBpZGVudGl0eSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLiBUaGUgaW4tZmxpZ2h0IG9uQ29tcGxldGUgY291bnQgaXMgYW4gYXRvbWljIGNvdW50ZXIgd2hvc2UgcGVhayBpcyByYWlzZWQgd2l0aCBhIENBUyByZXRyeSBsb29wLCBzbyBhIHBlYWsgb2JzZXJ2ZWQgdW5kZXIgY29udGVudGlvbiBpcyBuZXZlciBsb3dlciB0aGFuIHRoZSB0cnVlIHBlYWsuIEZpbmRpbmdzIGFyZSByZWNvcmRlZCBhcyBmbGFncyBzZXQgZnJvbSB0aGUgcmVjb3JkaW5nIHRocmVhZHMgYW5kIHJlYWQgb25jZSBpbiBhbmFseXplKCksIGFmdGVyIHRoZSBydW4gaGFzIHF1aWVzY2VkLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogT25lIHN0YXRlIG9iamVjdCBwZXIgc2NvcGUgaWQgYW5kIHBlciByZXN1bHQtaGFuZGxlIGlkZW50aXR5LCBib3RoIGluIENvbmN1cnJlbnRIYXNoTWFwcy4gQ2xvc2UgYW5kIHJlYWQgYXJlIG9yZGVyZWQgYnkgYSBzaW5nbGUgQXRvbWljTG9uZyBzZXF1ZW5jZSByYXRoZXIgdGhhbiB0aGUgd2FsbCBjbG9jaywgc28gJ3JlYWQgYWZ0ZXIgY2xvc2UnIGlzIGRlY2lkZWQgYnkgcHJvZ3JhbSBvcmRlciBhbmQgbmV2ZXIgYnkgY2xvY2sgZ3JhbnVsYXJpdHkuIFJlYWRlciB0aHJlYWQgbmFtZXMgYWNjdW11bGF0ZSBpbiBhIGNvbmN1cnJlbnQgc2V0IGFuZCBhcmUgcmVhZCBvbmNlIGluIGFuYWx5emUoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEJ5dGVCdWZmZXJEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBhbmQgb3BlcmF0aW9uIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hhcnNldENvZGVyRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRDaGVja3N1bURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkRGVmbGF0ZXJEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEl0ZXJhdG9yRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRKc29uTWFwcGVyUmVjb25maWdEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB1c2luZy10aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHZpb2xhdGluZyBtdXRhdGlvbnMgcmVjb3JkZWQgaW4gYSBDb3B5T25Xcml0ZUFycmF5TGlzdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEtkZkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVtb3J5U2VnbWVudFJhY2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLXNlZ21lbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXA7IHRoZSBhY2Nlc3MgbG9nIGlzIGEgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfVFJBQ0tFRF9BQ0NFU1NFUyB3aXRoIGEgTG9uZ0FkZGVyIGRyb3AgY291bnRlciwgc28gYW4gdW5ib3VuZGVkIHRlc3QgY2Fubm90IGV4aGF1c3QgdGhlIGhlYXAgYW5kIHRoZSByZXBvcnQgc3RhdGVzIGhvdyBtYW55IHNhbXBsZXMgd2VyZSBkcm9wcGVkLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGRvdWJsZS1jaGVjayAoZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50KSBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTcGxpdHRhYmxlUmFuZG9tRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBkb3VibGUtY2hlY2sgKGdldC10aGVuLWNvbXB1dGVJZkFic2VudCkgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3B1cmlvdXNXYWtldXBEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHN0YXRlIHBlciBtb25pdG9yIGluc3RhbmNlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IEhvbGRlciBhbmQgd2FpdCBtYXBzIGFyZSBDb25jdXJyZW50SGFzaE1hcCBrZXllZCBvbiBjbGFzcyBuYW1lIC8gdGhyZWFkIGlkLiBUaGUgbGl2ZS10aHJlYWQgc2FtcGxlIGlzIHRha2VuIGF0IG1vc3Qgb25jZSBhbmQgY2FjaGVkIGluIGFuIEF0b21pY1JlZmVyZW5jZSBzbyBhbmFseXplKCkgc3RheXMgaWRlbXBvdGVudCBldmVuIHRob3VnaCB0aGUgdGhyZWFkcyBpdCBvYnNlcnZlcyBhcmUgbm90LgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhpc0VzY2FwZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IGVzY2FwZSBkZXNjcmlwdGlvbnMgYW5kIG9ic2VydmVyLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgdGhlIGNvbXBsZXRlZCBmbGFnIGlzIHZvbGF0aWxlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhyZWFkTG9jYWxDYWNoZURlZ3JhZGF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIFRocmVhZExvY2FsIG5hbWUgaW4gYSBDb25jdXJyZW50SGFzaE1hcDsgaW5zdGFuY2UgaWRlbnRpdGllcyBhbmQgdGhyZWFkIGlkcyBhcmUgY29uY3VycmVudCBrZXktc2V0IHZpZXdzLCBzbyBjb3VudGluZyBpcyBpZGVtcG90ZW50IHVuZGVyIHJlcGVhdGVkIHJlY29yZGluZyBmcm9tIHRoZSBzYW1lIHRocmVhZCAtIGEgdmFsdWUgcmVhZCB0d2ljZSBhZGRzIG5vdGhpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IG1pc3VzaW5nLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRyeUxvY2tNaXN1c2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgdHJhY2tzIHRyeUxvY2sgYXR0ZW1wdHMsIHJlc3VsdHMsIGFuZCB1bmxvY2sgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZhckhhbmRsZU5vbkF0b21pY1VwZGF0ZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItbG9jYXRpb24gc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gYSAoaGFuZGxlLCByZWNlaXZlcikgaWRlbnRpdHkgcmVjb3JkOyBwZW5kaW5nIHJlYWRzIGFyZSBhIHBlci10aHJlYWQgQ29uY3VycmVudEhhc2hNYXAgZW50cnk7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXIgYW5kIGRldGFpbCBsaXN0cyBhcmUgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfREVUQUlMUy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBPbmUgc3RhdGUgb2JqZWN0IHBlciBtb25pdG9yIGlkZW50aXR5IGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFF1ZXVlIGRlcHRoLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBpbiBpdCwgYXJlIGF0b21pYyBjb3VudGVycyB3aG9zZSBwZWFrcyBhcmUgcmFpc2VkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQgbWFwIHZhbHVlcyB1c2UgQXRvbWljSW50ZWdlciBjb3VudGVycyBhbmQgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WaXJ0dWFsVGhyZWFkUmVzb3VyY2VTYXR1cmF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIHJlc291cmNlIGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFRoZSB3YWl0ZXJzLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBhbW9uZyB0aGVtLCBhcmUgYXRvbWljIGNvdW50ZXJzIHdob3NlIHBlYWtzIGFyZSBtYWludGFpbmVkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuV2Vha0hhc2hNYXBTaGFyZWREZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAtYmFja2VkIGluc3RhbmNlIHRyYWNraW5nOyBwZXItaW5zdGFuY2UgU3RhdGUgaG9sZHMgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkgZm9yIHRocmVhZCBpZHMvbmFtZXMuCgojIyBTZWN1cml0eS1Dcml0aWNhbCBDb2RlCi0gKipSdWxlKio6IFRoaXMgY29kZSBpcyBzZWN1cml0eS1jcml0aWNhbC4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBFdmVyeSBjaGFuZ2UgbXVzdCBiZSBleHBsaWNpdGx5IHJldmlld2VkIGZvciBzZWN1cml0eSBpbXBhY3QuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IKLSAqKkFzcGVjdCoqOiBjcnlwdG9ncmFwaHkgKGhhc2ggaW50ZWdyaXR5IC8gTUFDIC8gc2lnbmF0dXJlIHN0YXRlKQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKkFzcGVjdCoqOiBjcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvcgotICoqQXNwZWN0Kio6IGNyeXB0b2dyYXBoeSAoY29uZmlkZW50aWFsaXR5IC8gaW50ZWdyaXR5IC8gYXV0aGVudGljaXR5IHN0YXRlKQoKIyMgSW1tdXRhYmxlIFR5cGUKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlLlNpdGUKLSAqKlJ1bGUqKjogVGhpcyB0eXBlIGlzIGltbXV0YWJsZS4gTmV2ZXIgaW50cm9kdWNlIG5vbi1maW5hbCBmaWVsZHMsIHNldHRlcnMsIG9yIG11dGF0aW5nIG1ldGhvZHMuCi0gKipOb3RlKio6IEphdmEgcmVjb3JkIOKAlCBmaWVsZHMgYXJlIGZpbmFsIGJ5IGxhbmd1YWdlOyB0eXBlcyBhcmUgYWxsIHByaW1pdGl2ZXMgb3IgU3RyaW5nLgoKIyMgUHVibGljIEFQSSBTdXJmYWNlIFByb3RlY3Rpb24KLSAqKlJ1bGUqKjogRXhwb3NlcyBwdWJsaWMgQVBJLiBQcmVzZXJ2ZSBzaWduYXR1cmUsIEphdmFkb2MsIGFuZCBiZWhhdmlvciB3aXRob3V0IGJyZWFraW5nIGJhY2t3YXJkcyBvciBzb3VyY2UgY29tcGF0aWJpbGl0eS4KLSAqKkFwcGxpZXMgdG8qKjogYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JEZWZhdWx0U2V2ZXJpdHlgLCBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvclRydXN0YCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuR3JhZGVkRmluZGluZ3NgLCBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaXRlQ2FwdHVyZS5TaXRlYCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVHJ1c3RUaWVyYAoKIyMgTWlycm9yZWQg4oCUIEtlZXAgSW4gU3luYwotICoqUnVsZSoqOiBGcmVlIHRvIGNoYW5nZSwgYnV0IGV2ZXJ5IG1pcnJvciBtdXN0IGNoYW5nZSBpbiB0aGUgc2FtZSBjb21taXQuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckRlZmF1bHRTZXZlcml0eQotICoqTWlycm9ycyoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSwgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvclRydXN0Ci0gKipSZWFzb24qKjogQW4gZW50cnkgaGVyZSBpcyB0aGUgc2V2ZXJpdHkgYSBidWlsdC1pbiBkZXRlY3RvcidzIGZpbmRpbmdzIGNhcnJ5IGF0IHRoZSBmYWlsT24gZ2F0ZSB3aGVuIGl0cyByZXBvcnQgbWFya3Mgbm9uZS4gQSBkZXRlY3RvciBtaXNzaW5nIGZyb20gYm90aCB0aGlzIHRhYmxlIGFuZCB0aGUgbWFya2VyIGNvbnZlbnRpb24gc2lsZW50bHkgZmFsbHMgYmFjayB0byBISUdILCB3aGljaCBpcyB0aGUgZGVmZWN0IHRoaXMgdGFibGUgZXhpc3RzIHRvIGZpeC4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yU2V2ZXJpdHlNYXJrZXJUZXN0CgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckZlZWRzCi0gKipNaXJyb3JzKio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JUeXBlLCBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yVHJ1c3QsIGRvY3MvREVURUNUT1JfQ0FUQUxPRy5tZAotICoqUmVhc29uKio6IEV2ZXJ5IERldGVjdG9yVHlwZSByZXNvbHZlcyB0byBleGFjdGx5IG9uZSBmZWVkLCB0aGUgQUdFTlQgc2V0IG11c3QgZXF1YWwgdGhlIGRldGVjdG9ycyB0aGUgdGVsZW1ldHJ5IGJyaWRnZSBhbmQgY29sbGVjdGlvbiBob29rcyBhcmUgY29tcGlsZS13aXJlZCBpbnRvLCBhbmQgdGhlIGNhdGFsb2cncyBmZWVkIGxpc3RpbmcgbXVzdCBuYW1lIHRoZSBzYW1lIGNsYXNzZXMgdGhpcyB0YWJsZSBjbGFzc2lmaWVzLiBBIGZlZWQgdGhhdCBkcmlmdHMgbWlzbGVhZHMgdGhlIHVzZXIgZGVjaWRpbmcgd2hldGhlciBhdHRhY2hpbmcgdGhlIGFnZW50IGJ1eXMgdGhlbSBhbnl0aGluZy4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yRmVlZENvdmVyYWdlVGVzdAoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JUcnVzdAotICoqTWlycm9ycyoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSwgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclJlZ2lzdHJ5LCBkb2NzL0RFVEVDVE9SX0NBVEFMT0cubWQKLSAqKlJlYXNvbioqOiBFdmVyeSBEZXRlY3RvclR5cGUgbmVlZHMgZXhhY3RseSBvbmUgcm93LCBhbmQgZWFjaCByb3cgbmFtZXMgdGhlIGRldGVjdG9yIGNsYXNzIHdob3NlIHNpbXBsZSBuYW1lIGtleXMgdGhlIHJlcG9ydCBtYXAgKERldGVjdG9yUmVnaXN0cnkuaWZJc3N1ZSkuIEEgcm93IG5hbWluZyBhIGNsYXNzIHRoZSByZWdpc3RyeSdzIGZhY3Rvcnkgcm93IGRvZXMgbm90IGNyZWF0ZSBzaWxlbnRseSBzdG9wcyByZXNvbHZpbmcsIGFuZCB0aGUgZmluZGluZyBsb3NlcyBpdHMgdGllciB3aXRob3V0IGFueXRoaW5nIGdvaW5nIHJlZC4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yVHJ1c3RDb3ZlcmFnZVRlc3Q= +~gran~async-test-detectors=KiovZGlhZ25vc3RpY3MvKioKIyMgUGVyZm9ybWFuY2UgQ29uc3RyYWludHMKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlCi0gKipSdWxlKio6IE9wdGltYWwgY29tcGxleGl0eSByZXF1aXJlZC4gTyhuXjIpIGlzIGZvcmJpZGRlbiBvbiBob3QgcGF0aHMuCi0gKipDb25zdHJhaW50Kio6IENhbGxlZCBmcm9tIGRldGVjdG9yIHJlY29yZEFjY2VzcyBwYXRoczsgZG8gbm90IGFsbG9jYXRlIHdoZW4gYSBzaXRlIGlzIGFscmVhZHkgY2FwdHVyZWQgZm9yIGEgZ2l2ZW4ga2V5LgoKIyMgVGVzdC1Ecml2ZW4gUmVxdWlyZW1lbnRzCi0gKipSdWxlKio6IENoYW5nZXMgTVVTVCBiZSBhY2NvbXBhbmllZCBieSBhIG1hdGNoaW5nIHRlc3QgdXBkYXRlLgotICoqQ292ZXJhZ2UgR29hbCoqOiA4MCUKLSAqKkZyYW1ld29ya3MqKjogSlVOSVRfNQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQmxvY2tpbmdPbk5vbkJsb2NraW5nVGhyZWFkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0Jsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUJsb2NraW5nQ2FsbGJhY2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVCbG9ja2luZ0NhbGxiYWNrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ2FuY2VsbGF0aW9uUHJvcGFnYXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDYW5jZWxsYXRpb25Qcm9wYWdhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDb21iaW5hdG9yTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ29tcGxldGlvblJhY2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDb21wbGV0aW9uUmFjZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVPYnRydWRlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbmZpbmVkQXJlbmFUaHJlYWRFc2NhcGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EYWVtb25UaHJlYWRIeWdpZW5lRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0RhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmluYWxGaWVsZE11dGF0aW9uRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0ZpbmFsRmllbGRNdXRhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GbG93UHVibGlzaGVyQ29uY3VycmVuY3lEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvRmxvd1B1Ymxpc2hlckNvbmN1cnJlbmN5RGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkhpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0hpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkpkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0pkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLktvdGxpbk11dGV4UmVlbnRyYW5jeURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9Lb3RsaW5NdXRleFJlZW50cmFuY3lEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTGFtYmRhTG9zdFVwZGF0ZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9MYW1iZGFMb3N0VXBkYXRlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0xhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb25zdGFudE1pc3VzZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9MYXp5Q29uc3RhbnRNaXN1c2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9Mb2NrVXBncmFkZURlYWRsb2NrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTm9uQXRvbWljQ29uY3VycmVudE1hcFVwZGF0ZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Ob3RpZnlXaXRob3V0TW9uaXRvckRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9Ob3RpZnlXaXRob3V0TW9uaXRvckRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5QbGF0Zm9ybVRocmVhZFBlclRhc2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvUGxhdGZvcm1UaHJlYWRQZXJUYXNrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlByb2Nlc3NTdHJlYW1TdGFydmF0aW9uRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1Byb2Nlc3NTdHJlYW1TdGFydmF0aW9uRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlJlY29yZE11dGFibGVDb21wb25lbnRMZWFrRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1JlY29yZE11dGFibGVDb21wb25lbnRMZWFrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlQ29uZmlndXJhdGlvbk1pc3VzZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TY29wZUNvbmZpZ3VyYXRpb25NaXN1c2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVKb2luZXJNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2NvcGVKb2luZXJNaXN1c2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQnl0ZUJ1ZmZlckRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRCeXRlQnVmZmVyRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZENoYXJzZXRDb2RlckRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRDaGFyc2V0Q29kZXJEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hlY2tzdW1EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkQ2hlY2tzdW1EZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkRGVmbGF0ZXJEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkRGVmbGF0ZXJEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkSXRlcmF0b3JEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkSXRlcmF0b3JEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkSnNvbk1hcHBlclJlY29uZmlnRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZEpzb25NYXBwZXJSZWNvbmZpZ0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRLZGZEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkS2RmRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZE1lbW9yeVNlZ21lbnRSYWNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZE1lbW9yeVNlZ21lbnRSYWNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZE1lc3NhZ2VEaWdlc3REZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTZWN1cmVSYW5kb21EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkU3BsaXR0YWJsZVJhbmRvbURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TcHVyaW91c1dha2V1cERldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TcHVyaW91c1dha2V1cERldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TdGF0aWNJbml0RGVhZGxvY2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRoaXNFc2NhcGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVGhpc0VzY2FwZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbENhY2hlRGVncmFkYXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVGhyZWFkTG9jYWxDYWNoZURlZ3JhZGF0aW9uRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRocmVhZExvY2FsUmFuZG9tTWlzdXNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1RocmVhZExvY2FsUmFuZG9tTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRyeUxvY2tNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVHJ5TG9ja01pc3VzZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WYXJIYW5kbGVOb25BdG9taWNVcGRhdGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVmFySGFuZGxlTm9uQXRvbWljVXBkYXRlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9WaXJ0dWFsVGhyZWFkTW9uaXRvclNlcmlhbGl6YXRpb25EZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFJlc291cmNlU2F0dXJhdGlvbkRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9WaXJ0dWFsVGhyZWFkUmVzb3VyY2VTYXR1cmF0aW9uRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLldlYWtIYXNoTWFwU2hhcmVkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1dlYWtIYXNoTWFwU2hhcmVkRGV0ZWN0b3JUZXN0LmphdmEKCiMjIFRocmVhZC1TYWZldHkgR3VhcmFudGVlCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5CbG9ja2luZ09uTm9uQmxvY2tpbmdUaHJlYWREZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogRmluZGluZ3MgaW4gYSBjb25jdXJyZW50IHNldCBrZXllZCBieSB0aHJlYWQsIGtpbmQgYW5kIG9wZXJhdGlvbjsgY2xhc3NpZmljYXRpb24gcmVhZHMgdGhlIGNhbGxpbmcgdGhyZWFkJ3Mgb3duIG9iamVjdCBvbmx5LgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVCbG9ja2luZ0NhbGxiYWNrRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFRocmVhZExvY2FsIHRyYWNrcyBhY3RpdmUgY2FsbGJhY2tzOyBDb25jdXJyZW50SGFzaE1hcCBzdG9yZXMgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ2FuY2VsbGF0aW9uUHJvcGFnYXRpb25EZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogT25lIENvbmN1cnJlbnRIYXNoTWFwIGVudHJ5IHBlciBwaXBlbGluZTsgZXZlbnRzIGdvIG9uIGNvcHktb24td3JpdGUgbGlzdHMgYW5kIGNhcnJ5IGFuIGF0b21pY2FsbHkgaXNzdWVkIHNlcXVlbmNlIG51bWJlciwgc28gb3JkZXJpbmcgbmV2ZXIgZGVwZW5kcyBvbiBhIHdhbGwgY2xvY2suCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gdGhlIGNvbWJpbmVkIGZ1dHVyZSdzIGlkZW50aXR5OyBjb25zdGl0dWVudCBhbmQgYXdhaXQgZXZlbnRzIGFyZSBjb3B5LW9uLXdyaXRlIGxpc3RzIGNhcnJ5aW5nIGF0b21pY2FsbHkgaXNzdWVkIHNlcXVlbmNlIG51bWJlcnMsIHNvIHRoZSBiZWZvcmUvYWZ0ZXIgY29tcGFyaXNvbiBuZXZlciBkZXBlbmRzIG9uIGEgd2FsbCBjbG9jay4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ29tcGxldGlvblJhY2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gZnV0dXJlIGlkZW50aXR5OyBwZXItZnV0dXJlIGF0dGVtcHQgbGlzdCBpcyBjb3B5LW9uLXdyaXRlIGFuZCB0aGUgc2VxdWVuY2UgY291bnRlciBpcyBhdG9taWMsIHNvIGNvbmN1cnJlbnQgcmVjb3JkZXJzIG5ldmVyIGxvc2UgYW4gYXR0ZW1wdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlT2J0cnVkZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBDb25jdXJyZW50SGFzaE1hcCBzdG9yZXMgc3RhdGUgcGVyIENGIGluc3RhbmNlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItc2VnbWVudCBhbmQgcGVyLWFyZW5hIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwOyB0aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXIuIFRoZSByZWZsZWN0aXZlIE1ldGhvZCBoYW5kbGVzIGFyZSByZXNvbHZlZCBvbmNlIGludG8gaW1tdXRhYmxlIHN0YXRpY3MgYW5kIGFyZSB0aGVtc2VsdmVzIHRocmVhZC1zYWZlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGFlbW9uVGhyZWFkSHlnaWVuZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItdGhyZWFkIGFjY2VzcyBtYXAgaXMgYSBDb25jdXJyZW50SGFzaE1hcDsgZmlyc3QtcmVnaXN0cmF0aW9uLXdpbnMgdmlhIHB1dElmQWJzZW50LgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKSBhbmQgdHJhY2sgb25seSBpbXBsaWNpdC1wb3NpdGlvbiBhY2Nlc3NvcnMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GaW5hbEZpZWxkTXV0YXRpb25EZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWZpZWxkIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkZsb3dQdWJsaXNoZXJDb25jdXJyZW5jeURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpOyBjb3VudGVycyBhcmUgTG9uZ0FkZGVyIC8gQXRvbWljSW50ZWdlciB3aXRoIGEgQ0FTIGhpZ2gtd2F0ZXIgbWFyay4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkhpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgY291bnRlcnMgYXJlIExvbmdBZGRlcjsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5KZGJjQ29ubmVjdGlvblNoYXJlZERldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBDb25jdXJyZW50SGFzaE1hcC1iYWNrZWQgSkRCQy1yZXNvdXJjZSB0cmFja2luZzsgcGVyLXJlc291cmNlIFN0YXRlIGhvbGRzIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpIGZvciBhY2Nlc3NpbmcgdGhyZWFkcy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLktvdGxpbk11dGV4UmVlbnRyYW5jeURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItbXV0ZXggc3RhdGUgaW4gdGhlIHdlYWtseSBrZXllZCBDb25jdXJyZW50SGFzaE1hcCBvZiBBYnN0cmFjdEluc3RhbmNlRGV0ZWN0b3I7IHRoZSBob2xkaW5ncyBhcmUgYSBDb25jdXJyZW50TGlua2VkRGVxdWUgb2Ygd2Vha2x5IGhlbGQgSm9icywgYW5kIGEgcmVlbnRyeSB3cml0ZXMgaXRzIGRlc2NyaXB0aW9uIGJlZm9yZSBpdHMgY291bnQuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYW1iZGFMb3N0VXBkYXRlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIGxhbWJkYSBpZGVudGl0eSBwbHVzIGNhcHR1cmVkIG5hbWU7IGV2ZW50cyBhcmUgYXBwZW5kZWQgdG8gYSBjb3B5LW9uLXdyaXRlIGxpc3QuIFRoZSBydWxlIGdyb3VwcyBieSBvYnNlcnZlZCBwcmUtdmFsdWUgYW5kIG5lZWRzIG5vIG9yZGVyaW5nLiBob2xkc0xvY2sgaXMgc2FtcGxlZCBvbiB0aGUgcmVjb3JkaW5nIHRocmVhZCBhdCByZWNvcmQgdGltZSwgd2hpY2ggaXMgdGhlIG9ubHkgcGxhY2UgaXQgbWVhbnMgYW55dGhpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBPbmUgc3RhdGUgb2JqZWN0IHBlciBjb2xsZWN0aW9uIGFuZCBlbGVtZW50IGtleSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLCB0aGUgY29sbGVjdGlvbiBrZXllZCBieSBpdHMgaWRlbnRpdHkgd2hlbiB0aGUgY2FsbGVyIHBhc3NlcyBpdCBhbmQgYnkgaXRzIG5hbWUgb3RoZXJ3aXNlOyBjb3VudGVycyBhcmUgYXRvbWljcyBhbmQgd2FpdGVyIHNldHMgYXJlIGNvbmN1cnJlbnQuIFRoZSBwZXItdGhyZWFkIHN0YWNrIG9mIGluLWZsaWdodCBjb21wdXRhdGlvbnMgaXMgYW4gQXJyYXlEZXF1ZSBwZXIgdGhyZWFkIGlkLCBzbyBlYWNoIGlzIHRvdWNoZWQgYnkgZXhhY3RseSBvbmUgdGhyZWFkIGFuZCBuZWVkcyBubyBzeW5jaHJvbmlzYXRpb24uIERlcGVuZGVuY3kgZWRnZXMgYWNjdW11bGF0ZSBpbiBhIHN5bmNocm9uaXplZCBMaW5rZWRIYXNoU2V0LiBOYW1lLWtleWVkIGVkZ2VzIGFyZSB3YWxrZWQgYW5kIGRyb3BwZWQgYXQgZWFjaCByb3VuZCBzdGFydCAobWFya0ludm9jYXRpb25TdGFydCwgIzg1MiksIGFmdGVyIHRoZSBwcmV2aW91cyByb3VuZCdzIHdvcmtlcnMgZmluaXNoZWQ7IGlkZW50aXR5LWtleWVkIGVkZ2VzIGxhc3QgdGhlIHJ1biBhbmQgYXJlIHdhbGtlZCBpbiBhbmFseXplKCksIGFmdGVyIGl0IGhhcyBxdWllc2NlZC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb25zdGFudE1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItY29uc3RhbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgcmVwb3J0cyBhcmUgc3luY2hyb25pemVkIGxpc3RzLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBDb25jdXJyZW50SGFzaE1hcCB0cmFja3MgcmVhZCBsb2NrIG93bmVyc2hpcCBhbmQgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyIChtYXAsa2V5KSBzdGF0ZSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vdGlmeVdpdGhvdXRNb25pdG9yRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IFNZTkNIUk9OSVpFRAotICoqTm90ZSoqOiBBdHRlbXB0cyBsaXN0IG11dGF0ZWQgdW5kZXIgYSBzaW5nbGUgaW50cmluc2ljIG1vbml0b3Igb24gdGhlIGxpc3QgaXRzZWxmOyBzYW1wbGluZyBUaHJlYWQuaG9sZHNMb2NrIHJlcXVpcmVzIG5vIGxvY2tpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5QbGF0Zm9ybVRocmVhZFBlclRhc2tEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ3JlYXRlZCB0aHJlYWRzIGFjY3VtdWxhdGUgaW4gYSBDb25jdXJyZW50TGlua2VkUXVldWU7IHByb2JlIGJvb2trZWVwaW5nIGluIENvbmN1cnJlbnRIYXNoTWFwOyBjb3VudGVycyBhcmUgQXRvbWljSW50ZWdlci4gYW5hbHl6ZSgpIHJlYWRzIGEgbW9tZW50LWluLXRpbWUgc25hcHNob3QgYW5kIGlzIHNhZmUgdG8gY2FsbCBjb25jdXJyZW50bHkgd2l0aCByZWNvcmRpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItcHJvY2VzcyBzdGF0ZSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIGJ5IGlkZW50aXR5LCB3aXRoIGEgZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0YWtlcnMgYXJlIGNvbmN1cnJlbnQgc2V0czsgdGhlIGZpcnN0IHdhaXQgaXMgY2xhaW1lZCBvbmNlIHdpdGggYSBDQVMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gaWRlbnRpdHkgaGFzaDsgdGhlIGZpcnN0LXNpZ2h0IGZpbmdlcnByaW50IG1hcCBpcyBwb3B1bGF0ZWQgb25jZSB1bmRlciBjb21wdXRlSWZBYnNlbnQgYW5kIHJlYWQtb25seSBhZnRlcndhcmRzOyB0aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHRyYWNraW5nIGlzIGNhcHBlZCBieSBNQVhfSU5TVEFOQ0VTIHdpdGggYSBMb25nQWRkZXIgZHJvcCBjb3VudGVyLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVDb25maWd1cmF0aW9uTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBpbW11dGFibGUtYWZ0ZXItb3BlbiBzdGF0ZSBvYmplY3QgcGVyIHNjb3BlIGlkIGluIGEgQ29uY3VycmVudEhhc2hNYXA7IGNvdW50ZXJzIGluc2lkZSBpdCBhcmUgYXRvbWljcy4gU2NvcGUgbGlmZXRpbWVzIGFyZSBvcmRlcmVkIGJ5IGEgc2luZ2xlIEF0b21pY0xvbmcgc2VxdWVuY2UgcmF0aGVyIHRoYW4gdGhlIHdhbGwgY2xvY2ssIHNvIG92ZXJsYXAgaXMgZGVjaWRlZCBieSBwcm9ncmFtIG9yZGVyIGFuZCBuZXZlciBieSBjbG9jayBncmFudWxhcml0eSBvciBkcmlmdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIGpvaW5lciBpZGVudGl0eSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLiBUaGUgaW4tZmxpZ2h0IG9uQ29tcGxldGUgY291bnQgaXMgYW4gYXRvbWljIGNvdW50ZXIgd2hvc2UgcGVhayBpcyByYWlzZWQgd2l0aCBhIENBUyByZXRyeSBsb29wLCBzbyBhIHBlYWsgb2JzZXJ2ZWQgdW5kZXIgY29udGVudGlvbiBpcyBuZXZlciBsb3dlciB0aGFuIHRoZSB0cnVlIHBlYWsuIEZpbmRpbmdzIGFyZSByZWNvcmRlZCBhcyBmbGFncyBzZXQgZnJvbSB0aGUgcmVjb3JkaW5nIHRocmVhZHMgYW5kIHJlYWQgb25jZSBpbiBhbmFseXplKCksIGFmdGVyIHRoZSBydW4gaGFzIHF1aWVzY2VkLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogT25lIHN0YXRlIG9iamVjdCBwZXIgc2NvcGUgaWQgYW5kIHBlciByZXN1bHQtaGFuZGxlIGlkZW50aXR5LCBib3RoIGluIENvbmN1cnJlbnRIYXNoTWFwcy4gQ2xvc2UgYW5kIHJlYWQgYXJlIG9yZGVyZWQgYnkgYSBzaW5nbGUgQXRvbWljTG9uZyBzZXF1ZW5jZSByYXRoZXIgdGhhbiB0aGUgd2FsbCBjbG9jaywgc28gJ3JlYWQgYWZ0ZXIgY2xvc2UnIGlzIGRlY2lkZWQgYnkgcHJvZ3JhbSBvcmRlciBhbmQgbmV2ZXIgYnkgY2xvY2sgZ3JhbnVsYXJpdHkuIFJlYWRlciB0aHJlYWQgbmFtZXMgYWNjdW11bGF0ZSBpbiBhIGNvbmN1cnJlbnQgc2V0IGFuZCBhcmUgcmVhZCBvbmNlIGluIGFuYWx5emUoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEJ5dGVCdWZmZXJEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBhbmQgb3BlcmF0aW9uIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hhcnNldENvZGVyRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRDaGVja3N1bURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkRGVmbGF0ZXJEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEl0ZXJhdG9yRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRKc29uTWFwcGVyUmVjb25maWdEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB1c2luZy10aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHZpb2xhdGluZyBtdXRhdGlvbnMgcmVjb3JkZWQgaW4gYSBDb3B5T25Xcml0ZUFycmF5TGlzdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEtkZkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVtb3J5U2VnbWVudFJhY2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLXNlZ21lbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXA7IHRoZSBhY2Nlc3MgbG9nIGlzIGEgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfVFJBQ0tFRF9BQ0NFU1NFUyB3aXRoIGEgTG9uZ0FkZGVyIGRyb3AgY291bnRlciwgc28gYW4gdW5ib3VuZGVkIHRlc3QgY2Fubm90IGV4aGF1c3QgdGhlIGhlYXAgYW5kIHRoZSByZXBvcnQgc3RhdGVzIGhvdyBtYW55IHNhbXBsZXMgd2VyZSBkcm9wcGVkLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGRvdWJsZS1jaGVjayAoZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50KSBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTcGxpdHRhYmxlUmFuZG9tRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBkb3VibGUtY2hlY2sgKGdldC10aGVuLWNvbXB1dGVJZkFic2VudCkgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3B1cmlvdXNXYWtldXBEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHN0YXRlIHBlciBtb25pdG9yIGluc3RhbmNlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IEhvbGRlciBhbmQgd2FpdCBtYXBzIGFyZSBDb25jdXJyZW50SGFzaE1hcCBrZXllZCBvbiBjbGFzcyBuYW1lIC8gdGhyZWFkIGlkLiBUaGUgbGl2ZS10aHJlYWQgc2FtcGxlIGlzIHRha2VuIGF0IG1vc3Qgb25jZSBhbmQgY2FjaGVkIGluIGFuIEF0b21pY1JlZmVyZW5jZSBzbyBhbmFseXplKCkgc3RheXMgaWRlbXBvdGVudCBldmVuIHRob3VnaCB0aGUgdGhyZWFkcyBpdCBvYnNlcnZlcyBhcmUgbm90LgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhpc0VzY2FwZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IGVzY2FwZSBkZXNjcmlwdGlvbnMgYW5kIG9ic2VydmVyLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgdGhlIGNvbXBsZXRlZCBmbGFnIGlzIHZvbGF0aWxlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhyZWFkTG9jYWxDYWNoZURlZ3JhZGF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIFRocmVhZExvY2FsIG5hbWUgaW4gYSBDb25jdXJyZW50SGFzaE1hcDsgaW5zdGFuY2UgaWRlbnRpdGllcyBhbmQgdGhyZWFkIGlkcyBhcmUgY29uY3VycmVudCBrZXktc2V0IHZpZXdzLCBzbyBjb3VudGluZyBpcyBpZGVtcG90ZW50IHVuZGVyIHJlcGVhdGVkIHJlY29yZGluZyBmcm9tIHRoZSBzYW1lIHRocmVhZCAtIGEgdmFsdWUgcmVhZCB0d2ljZSBhZGRzIG5vdGhpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IG1pc3VzaW5nLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRyeUxvY2tNaXN1c2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgdHJhY2tzIHRyeUxvY2sgYXR0ZW1wdHMsIHJlc3VsdHMsIGFuZCB1bmxvY2sgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZhckhhbmRsZU5vbkF0b21pY1VwZGF0ZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItbG9jYXRpb24gc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gYSAoaGFuZGxlLCByZWNlaXZlcikgaWRlbnRpdHkgcmVjb3JkOyBwZW5kaW5nIHJlYWRzIGFyZSBhIHBlci10aHJlYWQgQ29uY3VycmVudEhhc2hNYXAgZW50cnk7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXIgYW5kIGRldGFpbCBsaXN0cyBhcmUgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfREVUQUlMUy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBPbmUgc3RhdGUgb2JqZWN0IHBlciBtb25pdG9yIGlkZW50aXR5IGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFF1ZXVlIGRlcHRoLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBpbiBpdCwgYXJlIGF0b21pYyBjb3VudGVycyB3aG9zZSBwZWFrcyBhcmUgcmFpc2VkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQgbWFwIHZhbHVlcyB1c2UgQXRvbWljSW50ZWdlciBjb3VudGVycyBhbmQgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WaXJ0dWFsVGhyZWFkUmVzb3VyY2VTYXR1cmF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIHJlc291cmNlIGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFRoZSB3YWl0ZXJzLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBhbW9uZyB0aGVtLCBhcmUgYXRvbWljIGNvdW50ZXJzIHdob3NlIHBlYWtzIGFyZSBtYWludGFpbmVkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuV2Vha0hhc2hNYXBTaGFyZWREZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAtYmFja2VkIGluc3RhbmNlIHRyYWNraW5nOyBwZXItaW5zdGFuY2UgU3RhdGUgaG9sZHMgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkgZm9yIHRocmVhZCBpZHMvbmFtZXMuCgojIyBTZWN1cml0eS1Dcml0aWNhbCBDb2RlCi0gKipSdWxlKio6IFRoaXMgY29kZSBpcyBzZWN1cml0eS1jcml0aWNhbC4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBFdmVyeSBjaGFuZ2UgbXVzdCBiZSBleHBsaWNpdGx5IHJldmlld2VkIGZvciBzZWN1cml0eSBpbXBhY3QuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IKLSAqKkFzcGVjdCoqOiBjcnlwdG9ncmFwaHkgKGhhc2ggaW50ZWdyaXR5IC8gTUFDIC8gc2lnbmF0dXJlIHN0YXRlKQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKkFzcGVjdCoqOiBjcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvcgotICoqQXNwZWN0Kio6IGNyeXB0b2dyYXBoeSAoY29uZmlkZW50aWFsaXR5IC8gaW50ZWdyaXR5IC8gYXV0aGVudGljaXR5IHN0YXRlKQoKIyMgSW1tdXRhYmxlIFR5cGUKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlLlNpdGUKLSAqKlJ1bGUqKjogVGhpcyB0eXBlIGlzIGltbXV0YWJsZS4gTmV2ZXIgaW50cm9kdWNlIG5vbi1maW5hbCBmaWVsZHMsIHNldHRlcnMsIG9yIG11dGF0aW5nIG1ldGhvZHMuCi0gKipOb3RlKio6IEphdmEgcmVjb3JkIOKAlCBmaWVsZHMgYXJlIGZpbmFsIGJ5IGxhbmd1YWdlOyB0eXBlcyBhcmUgYWxsIHByaW1pdGl2ZXMgb3IgU3RyaW5nLgoKIyMgUHVibGljIEFQSSBTdXJmYWNlIFByb3RlY3Rpb24KLSAqKlJ1bGUqKjogRXhwb3NlcyBwdWJsaWMgQVBJLiBQcmVzZXJ2ZSBzaWduYXR1cmUsIEphdmFkb2MsIGFuZCBiZWhhdmlvciB3aXRob3V0IGJyZWFraW5nIGJhY2t3YXJkcyBvciBzb3VyY2UgY29tcGF0aWJpbGl0eS4KLSAqKkFwcGxpZXMgdG8qKjogYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JEZWZhdWx0U2V2ZXJpdHlgLCBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvclRydXN0YCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuR3JhZGVkRmluZGluZ3NgLCBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaXRlQ2FwdHVyZS5TaXRlYCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVHJ1c3RUaWVyYAoKIyMgTWlycm9yZWQg4oCUIEtlZXAgSW4gU3luYwotICoqUnVsZSoqOiBGcmVlIHRvIGNoYW5nZSwgYnV0IGV2ZXJ5IG1pcnJvciBtdXN0IGNoYW5nZSBpbiB0aGUgc2FtZSBjb21taXQuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckRlZmF1bHRTZXZlcml0eQotICoqTWlycm9ycyoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSwgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvclRydXN0Ci0gKipSZWFzb24qKjogQW4gZW50cnkgaGVyZSBpcyB0aGUgc2V2ZXJpdHkgYSBidWlsdC1pbiBkZXRlY3RvcidzIGZpbmRpbmdzIGNhcnJ5IGF0IHRoZSBmYWlsT24gZ2F0ZSB3aGVuIGl0cyByZXBvcnQgbWFya3Mgbm9uZS4gQSBkZXRlY3RvciBtaXNzaW5nIGZyb20gYm90aCB0aGlzIHRhYmxlIGFuZCB0aGUgbWFya2VyIGNvbnZlbnRpb24gc2lsZW50bHkgZmFsbHMgYmFjayB0byBISUdILCB3aGljaCBpcyB0aGUgZGVmZWN0IHRoaXMgdGFibGUgZXhpc3RzIHRvIGZpeC4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yU2V2ZXJpdHlNYXJrZXJUZXN0CgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckZlZWRzCi0gKipNaXJyb3JzKio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JUeXBlLCBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yVHJ1c3QsIGRvY3MvREVURUNUT1JfQ0FUQUxPRy5tZAotICoqUmVhc29uKio6IEV2ZXJ5IERldGVjdG9yVHlwZSByZXNvbHZlcyB0byBleGFjdGx5IG9uZSBmZWVkLCB0aGUgQUdFTlQgc2V0IG11c3QgZXF1YWwgdGhlIGRldGVjdG9ycyB0aGUgdGVsZW1ldHJ5IGJyaWRnZSBhbmQgY29sbGVjdGlvbiBob29rcyBhcmUgY29tcGlsZS13aXJlZCBpbnRvLCBhbmQgdGhlIGNhdGFsb2cncyBmZWVkIGxpc3RpbmcgbXVzdCBuYW1lIHRoZSBzYW1lIGNsYXNzZXMgdGhpcyB0YWJsZSBjbGFzc2lmaWVzLiBBIGZlZWQgdGhhdCBkcmlmdHMgbWlzbGVhZHMgdGhlIHVzZXIgZGVjaWRpbmcgd2hldGhlciBhdHRhY2hpbmcgdGhlIGFnZW50IGJ1eXMgdGhlbSBhbnl0aGluZy4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yRmVlZENvdmVyYWdlVGVzdAoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JUcnVzdAotICoqTWlycm9ycyoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSwgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclJlZ2lzdHJ5LCBkb2NzL0RFVEVDVE9SX0NBVEFMT0cubWQKLSAqKlJlYXNvbioqOiBFdmVyeSBEZXRlY3RvclR5cGUgbmVlZHMgZXhhY3RseSBvbmUgcm93LCBhbmQgZWFjaCByb3cgbmFtZXMgdGhlIGRldGVjdG9yIGNsYXNzIHdob3NlIHNpbXBsZSBuYW1lIGtleXMgdGhlIHJlcG9ydCBtYXAgKERldGVjdG9yUmVnaXN0cnkuaWZJc3N1ZSkuIEEgcm93IG5hbWluZyBhIGNsYXNzIHRoZSByZWdpc3RyeSdzIGZhY3Rvcnkgcm93IGRvZXMgbm90IGNyZWF0ZSBzaWxlbnRseSBzdG9wcyByZXNvbHZpbmcsIGFuZCB0aGUgZmluZGluZyBsb3NlcyBpdHMgdGllciB3aXRob3V0IGFueXRoaW5nIGdvaW5nIHJlZC4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yVHJ1c3RDb3ZlcmFnZVRlc3Q= ~granname~async-test-detectors=YXN5bmMtdGVzdC1kZXRlY3RvcnMKQUkgcnVsZXMgZm9yIHJvbGUgYXN5bmMtdGVzdC1kZXRlY3RvcnM= ~modgran~se-deversity-asynctest-AgentCollectionHooks=KiovQWdlbnRDb2xsZWN0aW9uSG9va3MuamF2YQojIyBDb250cmFjdC1Gcm96ZW4gU2lnbmF0dXJlCi0gKipDb25zdHJhaW50Kio6IFlvdSBtYXkgY2hhbmdlIGludGVybmFsIGxvZ2ljLCBidXQgTVVTVCBOT1QgbW9kaWZ5IHRoZSBtZXRob2QgbmFtZSwgcGFyYW1ldGVycywgcmV0dXJuIHR5cGUsIG9yIGNoZWNrZWQgZXhjZXB0aW9ucy4KLSAqKlJlYXNvbioqOiBDYWxsZWQgZnJvbSBieXRlY29kZSB0aGUgYWdlbnQgcmV3cml0ZXMsIG5vdCBmcm9tIHNvdXJjZTogdGhlIG1ldGhvZCBuYW1lcyBhbmQgZXJhc2VkIHNpZ25hdHVyZXMgYXJlIG1hdGNoZWQgYnkgQ29sbGVjdGlvbkFjY2Vzc1dlYXZlciBhbmQgY2Fubm90IGNoYW5nZSBpbmRlcGVuZGVudGx5IG9mIGl0LiBFdmVyeSBob29rIG11c3QgZW5kIGJ5IHBlcmZvcm1pbmcgdGhlIG9yaWdpbmFsIG9wZXJhdGlvbiBhbmQgbXVzdCBuZXZlciB0aHJvdyBvbiB0aGUgcmVjb3JkaW5nIHBhdGggLSBpdCBydW5zIGluc2lkZSB0aGUgdXNlcidzIGNvZGUsIHNvIGFuIGV4Y2VwdGlvbiBoZXJlIHN1cmZhY2VzIGFzIGEgZmFpbHVyZSBpbiB0aGVpciB0ZXN0LiBSZWNvcmRpbmcgaXMgYmVzdC1lZmZvcnQgYnkgZGVzaWduOiBubyBjb250ZXh0LCBhIGRpc2FibGVkIGRldGVjdG9yLCBvciBhIHR5cGUgdGhlIGxpYnJhcnkga25vd3MgaXMgdGhyZWFkLXNhZmUgYWxsIG1lYW4gcmVjb3JkIG5vdGhpbmcgYW5kIGRlbGVnYXRlLiBBIHF1ZXVlIG9mZmVyIG9yIHRha2UgaG9vayB3aXRoIGEgdHJhaWxpbmcgT2JqZWN0IHBhcmFtZXRlciBpcyB0aGUgdmFyaWFudCB0aGUgd2VhdmVyIGNhbGxzIHdpdGggdGhlIGVuY2xvc2luZyBtZXRob2QncyBvd24gbW9uaXRvcjogdGhpcyBpbiBhbiBpbnN0YW5jZSBtZXRob2QsIHRoZSBjbGFzcyBpbiBhIHN0YXRpYyBzeW5jaHJvbml6ZWQgb25lLiBBIHN5bmNocm9uaXplZCBtZXRob2QgaG9sZHMgaXQgd2l0aCBubyBpbnN0cnVjdGlvbiB0byBzYXkgc28gKCM3OTYpLCBhbmQgYSBoZWxwZXIgdGhhdCBtZXRob2QgY2FsbHMgaG9sZHMgaXQgdG9vICgjNzUxKSwgc28gdGhlIGhvb2sgY291bnRzIGl0IGFtb25nIHRoZSBoZWxkIGxvY2tzIGV4YWN0bHkgd2hlbiBUaHJlYWQuaG9sZHNMb2NrIHNheXMgc28sIGFuZCB0aGUgdHdvLWFyZ3VtZW50IGZvcm0gZGVsZWdhdGVzIHdpdGggbnVsbC4= ~modgranname~se-deversity-asynctest-AgentCollectionHooks=QWdlbnRDb2xsZWN0aW9uSG9va3MKQUkgcnVsZXMgZm9yIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuQWdlbnRDb2xsZWN0aW9uSG9va3M= @@ -65,8 +65,8 @@ gemini_md=IyBHRU1JTkkgQUkgSU5TVFJVQ1RJT05TCiMgR2VuZXJhdGVkIGJ5IFZpYmVUYWdzIHwgaH ~modgranname~async-test-public-api=YXN5bmMtdGVzdC1wdWJsaWMtYXBpCkFJIHJ1bGVzIGZvciByb2xlIGFzeW5jLXRlc3QtcHVibGljLWFwaQ== ~modgran~async-test-instrumentation=KiovYmVuY2htYXJrLyoqCSoqL3RlbGVtZXRyeS8qKgkqKi9hZ2VudC8qKgkqKi9hbmFseXNpcy8qKgojIyBDb3JlIEZ1bmN0aW9uYWxpdHkKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LnRlbGVtZXRyeS5Db250cm9sbGVkU2NoZWR1bGUKLSAqKlNlbnNpdGl2aXR5Kio6IEhpZ2gKLSAqKk5vdGUqKjogQSBzZWVkIHJlcGxheXMgYSByb3VuZCBvbmx5IHdoaWxlIGV2ZXJ5IGRlY2lzaW9uIG9mIHdobyBydW5zIG5leHQgZGVwZW5kcyBvbiBzdGF0ZSBjaGFuZ2VkIGF0IHNjaGVkdWxpbmcgcG9pbnRzOiB0aGUgc3RhdHVzZXMsIHByaW9yaXRpZXMgYW5kIHN0ZXAgY291bnQgdGhhdCBncmFudCgpIGFuZCBzdGVwKCkgcmVhZCwgYW5kIHRoZSBsb2NrIGhvbGRzIGFuZCBwZW5kaW5nIGFjcXVpc2l0aW9ucyBncmFudCgpIGNvbnN1bHRzICgjMTAyMiksIHdoaWNoIGNoYW5nZSBvbmx5IGF0IGFjcXVpcmluZygpLCBpdHNlbGYgYSBwb2ludCwgYW5kIGluIGFjcXVpcmVkKCkgYW5kIHJlbGVhc2VkKCksIHdoaWNoIGEgd29ya2VyIGNhbGxzIGluIGl0cyBvd24gcHJvZ3JhbSBvcmRlcjsgYW4gZXNjYXBlZCB3b3JrZXIncyBhY3F1aXJlIG9yIHJlbGVhc2UgbGFuZHMgb3V0c2lkZSBhIHR1cm4sIGJ1dCBpdHMgcm91bmQgaGFzIGFscmVhZHkgY291bnRlZCB0aGUgZXNjYXBlLiBncmFudCgpIG11c3Qga2VlcCBoYW5kaW5nIHRoZSByb3VuZCBvdXQgd2hlbiBldmVyeSByZWFkeSB3b3JrZXIgd2FpdHMgb24gYSBoZWxkIGxvY2s6IHRoZSBob2xkIG1heSBiZSBzdGFsZSAoYSBtb25pdG9yIHJlbGVhc2VkIGluc2lkZSBPYmplY3Qud2FpdCBpcyBub3Qgc2VlbiksIGFuZCB3aXRoaG9sZGluZyB0aGUgcm91bmQgdGhlbiBzdGFsbHMgY29ycmVjdCB3YWl0L25vdGlmeSBjb2RlIHVudGlsIHRoZSByb3VuZCB0aW1lcyBvdXQgKENvbnRyb2xsZWRTY2hlZHVsZUxvY2tUZXN0KTsgZWFjaCBzdWNoIGdyYW50IGlzIGNvdW50ZWQgYXMgYSBmYWxsYmFjay4gVG8ga2VlcCBob2xkcyBmcm9tIGdvaW5nIHN0YWxlLCBhIHdvdmVuIE9iamVjdC53YWl0IG9yIENvbmRpdGlvbi5hd2FpdCBoYW5kcyBpdHMgaG9sZHMgYmFjayBiZWZvcmUgd2FpdGluZyBhbmQgdGFrZXMgdGhlbSBhZ2FpbiBhZnRlciAocmVsZWFzaW5nRm9yV2FpdCwgcmVhY3F1aXJlZEFmdGVyV2FpdDsgbG9ja09mIGZpbmRzIGEgY29uZGl0aW9uJ3MgUmVlbnRyYW50TG9jayBieSBhc2tpbmcgaXQpLCBhbmQgYSB3b3JrZXIgcmUtY29uZmlybXMgaXRzIG93biByZWNvcmRlZCBob2xkcyB3aXRoIFRocmVhZC5ob2xkc0xvY2sgb3IgaXNIZWxkQnlDdXJyZW50VGhyZWFkIGF0IGVhY2ggb2YgaXRzIHBvaW50cyBhbmQgYXQgbGVhdmUoKSwgb24gaXRzIG93biB0aHJlYWQsIHNvIHRoZSBhbnN3ZXIgZm9sbG93cyBpdHMgcHJvZ3JhbSBvcmRlciBhbmQgZ3JhbnQoKSBzdGlsbCByZWFkcyBubyB0aHJlYWQgc3RhdGUgKCMxMDQ4KS4gT25seSB3YXRjaCgpIG1heSByZWFkIHRoZSBjbG9jayBvciBUaHJlYWQuZ2V0U3RhdGUoKSwgYW5kIGl0IHJlYWRzIHRoZSBzdGF0ZSBiZWZvcmUgYXNraW5nIHdoZXRoZXIgdGhlIHJ1bm5pbmcgd29ya2VyLCBvciBhbiBhZG9wdGVkIGNoaWxkIHN0aWxsIGFycml2aW5nLCBpcyBxdWV1ZWQgb24gdGhlIHNjaGVkdWxlJ3Mgb3duIGxvY2ssIHdoaWNoIGlzIHRoZSBzY2hlZHVsZXIncyB3YWl0IGFuZCBuZXZlciBhbiBlc2NhcGUgKCMxMDY1LCAjMTA3Mik7IGVhY2ggZGVjaXNpb24gaXQgbWFrZXMgaXMgY291bnRlZCBhcyBhbiBlc2NhcGUsIHdoaWNoIGlzIHdoYXQgdGVsbHMgdGhlIHJ1bm5lciB0aGUgc2VlZCBubyBsb25nZXIgcmVwbGF5cyBleGFjdGx5LCB3aXRoIG9uZSBleGNlcHRpb246IGFuIGFkb3B0ZWQgY2hpbGQgd2hvc2UgdGhyZWFkIGhhcyB0ZXJtaW5hdGVkIGlzIG1hcmtlZCBkb25lLCBub3QgZXNjYXBlZCAoIzEwMjQpLCBiZWNhdXNlIHdoaWxlIGl0IHJhbiB0byBpdHMgZW5kIGV2ZXJ5IHBlZXIgd2FzIHdhaXRpbmcsIHNvIHRoZSBzdGF0ZSB0aGUgbmV4dCBncmFudCByZWFkcyBpcyB0aGUgc2FtZSB3aGVuZXZlciB3YXRjaCgpIG5vdGljZXMuIEFkb3B0ZWQgY2hpbGRyZW4gYXJlIHJlYWR5IGZyb20gdGhlIG1vbWVudCB0aGV5IGFyZSBhZG9wdGVkLCBzbyBhIGdyYW50IG5ldmVyIGRlcGVuZHMgb24gaG93IGxvbmcgdGhlIE9TIHRha2VzIHRvIHN0YXJ0IGEgdGhyZWFkOyBhbiBhZG9wdGVkIGV4ZWN1dG9yIHRhc2sgKCMxMDQ5KSBpcyByZWFkeSBmcm9tIGl0cyB3b3ZlbiBzdWJtaXNzaW9uIHRoZSBzYW1lIHdheSwgam9pbnMgYXQgdGFza1N0YXJ0aW5nIG9uIHRoZSBwb29sIHRocmVhZCBhbmQgbGVhdmVzIGF0IHRhc2tFbmRlZCwgYW5kIG9uZSB0aGF0IGhhcyBub3Qgc3RhcnRlZCB3aXRoaW4gU1RBTExfTkFOT1MgaXMgY291bnRlZCBhcyBhbiBlc2NhcGUsIHNpbmNlIGl0cyBleGVjdXRvciBtYXkgbmV2ZXIgcnVuIGl0LiBBIHdvcmtlciB3YWl0aW5nIGF0IGEgcmVuZGV6dm91cyBpcyBPVVRTSURFLCBub3QgZXNjYXBlZCAoIzEwMjEpLCBhbmQgbm8gZ3JhbnQgaXMgbWFkZSB3aGlsZSBvbmUgaXMgb3V0c2lkZSBvbiBpdHMgd2F5IGJhY2sgb3Igd2hlbiB0aGUgbGFzdCB3b3JrZXIgc3RlcHMgb3V0LCBzbyB0aGUgb3JkZXIgYSByZW5kZXp2b3VzIHJlbGVhc2VzIHdvcmtlcnMgaW4gbmV2ZXIgZGVjaWRlcyB3aG8gcnVucyBuZXh0LiBBIGdyYW50KCkgdGhhdCByZWFkIHRpbWUgb3IgdGhyZWFkIHN0YXRlLCBvciBhbiBlc2NhcGUgbGVmdCB1bmNvdW50ZWQsIHN0aWxsIHBhc3NlcyBldmVyeSBydW4gYW5kIG1ha2VzIHRoZSBwcmludGVkIHJlcGxheSBsaW5lIGEgZmFsc2UgcHJvbWlzZS4KCiMjIFBlcmZvcm1hbmNlIENvbnN0cmFpbnRzCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIKLSAqKlJ1bGUqKjogT3B0aW1hbCBjb21wbGV4aXR5IHJlcXVpcmVkLiBPKG5eMikgaXMgZm9yYmlkZGVuIG9uIGhvdCBwYXRocy4KLSAqKkNvbnN0cmFpbnQqKjogcmVjb3JkSW52b2NhdGlvblN0YXJ0KCkgYW5kIHJlY29yZEludm9jYXRpb25FbmQoKSBhcmUgY2FsbGVkIG9uIHRoZSBob3QgcGF0aCBpbnNpZGUgZXZlcnkgaW52b2NhdGlvbiByb3VuZC4gS2VlcCB0aGVtIGFsbG9jYXRpb24tZnJlZSBhbmQgYXZvaWQgYWNxdWlyaW5nIGxvY2tzIGluIHRoZSBjb21tb24gY2FzZS4KCiMjIE9ic2VydmFiaWxpdHkgSW5zdHJ1bWVudGF0aW9uCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIKLSAqKlJ1bGUqKjogRG8gbm90IHJlbW92ZSBvciByZW5hbWUgaW5zdHJ1bWVudGF0aW9uIHdpdGhvdXQgZmxhZ2dpbmcgdGhlIGFmZmVjdGVkIGRhc2hib2FyZC4KLSAqKkRldGFpbHMqKjogTWV0cmljczogYmVuY2htYXJrLmludm9jYXRpb24udGltZXMuIExvZ3M6IFtCRU5DSE1BUktdIEJhc2VsaW5lIGNyZWF0ZWQsIFtCRU5DSE1BUktdIEJhc2VsaW5lIHVwZGF0ZWQsIFtCRU5DSE1BUktdIFNUQUJMRSwgW0JFTkNITUFSS10gUkVHUkVTU0lPTiwgW0JFTkNITUFSS10gSU1QUk9WRU1FTlQuIE5vdGU6IEhvdCBwYXRoIHRlbGVtZXRyeSB1c2VkIGJ5IEpVbml0IGJlbmNobWFyayBtZXRyaWNzIGFuZCBiYXNlbGluZSByZWdyZXNzaW9uIGNoZWNrcy4KCiMjIEZlYXR1cmUgRmxhZyBHYXRlCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5iZW5jaG1hcmsuQmVuY2htYXJrUmVjb3JkZXIKLSAqKkZsYWcqKjogJ2FzeW5jLXRlc3QuYmVuY2htYXJraW5nLmVuYWJsZWQnIChkZWZhdWx0OiBmYWxzZSkKLSAqKlJ1bGUqKjogVGhpcyBjb2RlIGlzIGdhdGVkIGJlaGluZCBhIGZlYXR1cmUgZmxhZy4gUHJlc2VydmUgdGhlIGZsYWcgY2hlY2suIE5ldmVyIGFzc3VtZSB0aGUgZmxhZyBpcyBhbHdheXMgYWN0aXZlLgoKIyMgTWVtb3J5IEJ1ZGdldCBDb25zdHJhaW50cwotICoqUG9saWN5Kio6IE5PX0FVVE9CT1hJTkcKLSAqKlJ1bGUqKjogU3RyaWN0bHkgbGltaXQgb3IgcHJldmVudCBvYmplY3QgYWxsb2NhdGlvbnMuCi0gKipBcHBsaWVzIHRvKio6IGBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmJlbmNobWFyay5CZW5jaG1hcmtSZWNvcmRlci5yZWNvcmRJbnZvY2F0aW9uRW5kKGxvbmcpYCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYmVuY2htYXJrLkJlbmNobWFya1JlY29yZGVyLnJlY29yZEludm9jYXRpb25TdGFydCgpYAoKIyMgU3RyaWN0IENsYXNzcGF0aCBJbnRlZ3JpdHkKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmJlbmNobWFyay5CZW5jaG1hcmtDb21wYXJhdG9yLnJlYWRTdG9yZShqYXZhLmlvLkZpbGUpCi0gKipSdWxlKio6IFByb2hpYml0IGR5bmFtaWMgY2xhc3MgbG9hZGluZywgY3VzdG9tIGNsYXNzbG9hZGVycywgcnVudGltZSByZWZsZWN0aW9uIGhhY2tzLCBvciBleGVjdXRpb24gb2YgZHluYW1pYyBleHRlcm5hbCBjb2RlLgotICoqUmVhc29uKio6IEphdmEgbmF0aXZlIGRlc2VyaWFsaXphdGlvbiBzaW5rLiBUaGUgQkFTRUxJTkVfRklMVEVSIGFsbG93LWxpc3QgKGVuZGluZyBpbiAhKikgbXVzdCByZXNvbHZlIGV2ZXJ5IGNsYXNzIGluIHRoZSBzdHJlYW0gYW5kIHJlamVjdCBhbGwgb3RoZXJzLCBwcmV2ZW50aW5nIGFyYml0cmFyeSBjbGFzcyBsb2FkaW5nIChDV0UtNTAyIFJDRSkuIE5ldmVyIHdpZGVuIHRoZSBmaWx0ZXIgb3IgcmVtb3ZlIHNldE9iamVjdElucHV0RmlsdGVyLgoKIyMgTWlycm9yZWQg4oCUIEtlZXAgSW4gU3luYwoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QudGVsZW1ldHJ5LlRlbGVtZXRyeUJyaWRnZQotICoqUnVsZSoqOiBGcmVlIHRvIGNoYW5nZSwgYnV0IGV2ZXJ5IG1pcnJvciBtdXN0IGNoYW5nZSBpbiB0aGUgc2FtZSBjb21taXQuCi0gKipNaXJyb3JzKio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JGZWVkcywgZG9jcy9ERVRFQ1RPUl9DQVRBTE9HLm1kCi0gKipSZWFzb24qKjogRGV0ZWN0b3JGZWVkcy5mZWRCeShBR0VOVCkgbXVzdCBlcXVhbCB0aGUgZGV0ZWN0b3JzIHRoZSB3b3ZlbiBzdHJlYW1zIGFjdHVhbGx5IHJlYWNoLCBhbmQgdGhpcyBjbGFzcyBpcyBvbmUgb2YgdGhvc2Ugc3RyZWFtcy4gVGhlIGdhdGUgcmVmbGVjdHMgb3ZlciB0aGlzIGNsYXNzJ3MgZGVjbGFyZWQgY29uc3RydWN0b3JzIGFuZCBtZXRob2RzIGFuZCBhc3NlcnRzIHRoZSBkZXRlY3RvciB0eXBlcyBpdCBpcyBjb21waWxlLXdpcmVkIHRvIGFyZSBleGFjdGx5IHtBdG9taWNpdHlWYWxpZGF0b3J9LiBSb3V0aW5nIGEgc2Vjb25kIGRldGVjdG9yIGhlcmUgd2l0aG91dCBhZGRpbmcgaXRzIEFHRU5UIHJvdyBsZWF2ZXMgdGhlIGNhdGFsb2cgdGVsbGluZyB1c2VycyB0aGUgYWdlbnQgYnV5cyB0aGVtIG5vdGhpbmcgZm9yIHRoYXQgZGV0ZWN0b3IuCi0gKipFbmZvcmNlZCBieSoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmFyY2hpdGVjdHVyZS5EZXRlY3RvckZlZWRDb3ZlcmFnZVRlc3Q= ~modgranname~async-test-instrumentation=YXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24KQUkgcnVsZXMgZm9yIHJvbGUgYXN5bmMtdGVzdC1pbnN0cnVtZW50YXRpb24= -~modgran~async-test-detectors=KiovZGlhZ25vc3RpY3MvKioKIyMgUGVyZm9ybWFuY2UgQ29uc3RyYWludHMKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlCi0gKipSdWxlKio6IE9wdGltYWwgY29tcGxleGl0eSByZXF1aXJlZC4gTyhuXjIpIGlzIGZvcmJpZGRlbiBvbiBob3QgcGF0aHMuCi0gKipDb25zdHJhaW50Kio6IENhbGxlZCBmcm9tIGRldGVjdG9yIHJlY29yZEFjY2VzcyBwYXRoczsgZG8gbm90IGFsbG9jYXRlIHdoZW4gYSBzaXRlIGlzIGFscmVhZHkgY2FwdHVyZWQgZm9yIGEgZ2l2ZW4ga2V5LgoKIyMgVGVzdC1Ecml2ZW4gUmVxdWlyZW1lbnRzCi0gKipSdWxlKio6IENoYW5nZXMgTVVTVCBiZSBhY2NvbXBhbmllZCBieSBhIG1hdGNoaW5nIHRlc3QgdXBkYXRlLgotICoqQ292ZXJhZ2UgR29hbCoqOiA4MCUKLSAqKkZyYW1ld29ya3MqKjogSlVOSVRfNQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQmxvY2tpbmdPbk5vbkJsb2NraW5nVGhyZWFkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0Jsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUJsb2NraW5nQ2FsbGJhY2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVCbG9ja2luZ0NhbGxiYWNrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ2FuY2VsbGF0aW9uUHJvcGFnYXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDYW5jZWxsYXRpb25Qcm9wYWdhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDb21iaW5hdG9yTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ29tcGxldGlvblJhY2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDb21wbGV0aW9uUmFjZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVPYnRydWRlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbmZpbmVkQXJlbmFUaHJlYWRFc2NhcGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EYWVtb25UaHJlYWRIeWdpZW5lRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0RhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmluYWxGaWVsZE11dGF0aW9uRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0ZpbmFsRmllbGRNdXRhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GbG93UHVibGlzaGVyQ29uY3VycmVuY3lEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvRmxvd1B1Ymxpc2hlckNvbmN1cnJlbmN5RGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkhpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0hpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkpkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0pkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhbWJkYUxvc3RVcGRhdGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTGFtYmRhTG9zdFVwZGF0ZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29uc3RhbnRNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTGF6eUNvbnN0YW50TWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxvY2tVcGdyYWRlRGVhZGxvY2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Ob25BdG9taWNDb25jdXJyZW50TWFwVXBkYXRlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL05vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTm90aWZ5V2l0aG91dE1vbml0b3JEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTm90aWZ5V2l0aG91dE1vbml0b3JEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuUGxhdGZvcm1UaHJlYWRQZXJUYXNrRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1BsYXRmb3JtVGhyZWFkUGVyVGFza0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TY29wZUNvbmZpZ3VyYXRpb25NaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2NvcGVDb25maWd1cmF0aW9uTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1Njb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlUmVzdWx0RXNjYXBlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1Njb3BlUmVzdWx0RXNjYXBlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEJ5dGVCdWZmZXJEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkQnl0ZUJ1ZmZlckRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRDaGFyc2V0Q29kZXJEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkQ2hhcnNldENvZGVyRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZENoZWNrc3VtRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZENoZWNrc3VtRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZERlZmxhdGVyRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZERlZmxhdGVyRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEl0ZXJhdG9yRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZEl0ZXJhdG9yRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEpzb25NYXBwZXJSZWNvbmZpZ0RldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRKc29uTWFwcGVyUmVjb25maWdEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkS2RmRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZEtkZkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZW1vcnlTZWdtZW50UmFjZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRNZW1vcnlTZWdtZW50UmFjZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZE1lc3NhZ2VEaWdlc3REZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZFNlY3VyZVJhbmRvbURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTcGxpdHRhYmxlUmFuZG9tRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3B1cmlvdXNXYWtldXBEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU3B1cmlvdXNXYWtldXBEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1N0YXRpY0luaXREZWFkbG9ja0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaGlzRXNjYXBlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1RoaXNFc2NhcGVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhyZWFkTG9jYWxDYWNoZURlZ3JhZGF0aW9uRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1RocmVhZExvY2FsQ2FjaGVEZWdyYWRhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UcnlMb2NrTWlzdXNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1RyeUxvY2tNaXN1c2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmFySGFuZGxlTm9uQXRvbWljVXBkYXRlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1ZhckhhbmRsZU5vbkF0b21pY1VwZGF0ZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WaXJ0dWFsVGhyZWFkTW9uaXRvclNlcmlhbGl6YXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVmlydHVhbFRocmVhZE1vbml0b3JTZXJpYWxpemF0aW9uRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRQb29saW5nRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1ZpcnR1YWxUaHJlYWRQb29saW5nRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRSZXNvdXJjZVNhdHVyYXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVmlydHVhbFRocmVhZFJlc291cmNlU2F0dXJhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5XZWFrSGFzaE1hcFNoYXJlZERldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9XZWFrSGFzaE1hcFNoYXJlZERldGVjdG9yVGVzdC5qYXZhCgojIyBUaHJlYWQtU2FmZXR5IEd1YXJhbnRlZQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQmxvY2tpbmdPbk5vbkJsb2NraW5nVGhyZWFkRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IEZpbmRpbmdzIGluIGEgY29uY3VycmVudCBzZXQga2V5ZWQgYnkgdGhyZWFkLCBraW5kIGFuZCBvcGVyYXRpb247IGNsYXNzaWZpY2F0aW9uIHJlYWRzIHRoZSBjYWxsaW5nIHRocmVhZCdzIG93biBvYmplY3Qgb25seS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQmxvY2tpbmdDYWxsYmFja0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBUaHJlYWRMb2NhbCB0cmFja3MgYWN0aXZlIGNhbGxiYWNrczsgQ29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHZpb2xhdGlvbnMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNhbmNlbGxhdGlvblByb3BhZ2F0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBDb25jdXJyZW50SGFzaE1hcCBlbnRyeSBwZXIgcGlwZWxpbmU7IGV2ZW50cyBnbyBvbiBjb3B5LW9uLXdyaXRlIGxpc3RzIGFuZCBjYXJyeSBhbiBhdG9taWNhbGx5IGlzc3VlZCBzZXF1ZW5jZSBudW1iZXIsIHNvIG9yZGVyaW5nIG5ldmVyIGRlcGVuZHMgb24gYSB3YWxsIGNsb2NrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVDb21iaW5hdG9yTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIHRoZSBjb21iaW5lZCBmdXR1cmUncyBpZGVudGl0eTsgY29uc3RpdHVlbnQgYW5kIGF3YWl0IGV2ZW50cyBhcmUgY29weS1vbi13cml0ZSBsaXN0cyBjYXJyeWluZyBhdG9taWNhbGx5IGlzc3VlZCBzZXF1ZW5jZSBudW1iZXJzLCBzbyB0aGUgYmVmb3JlL2FmdGVyIGNvbXBhcmlzb24gbmV2ZXIgZGVwZW5kcyBvbiBhIHdhbGwgY2xvY2suCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbXBsZXRpb25SYWNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIGZ1dHVyZSBpZGVudGl0eTsgcGVyLWZ1dHVyZSBhdHRlbXB0IGxpc3QgaXMgY29weS1vbi13cml0ZSBhbmQgdGhlIHNlcXVlbmNlIGNvdW50ZXIgaXMgYXRvbWljLCBzbyBjb25jdXJyZW50IHJlY29yZGVycyBuZXZlciBsb3NlIGFuIGF0dGVtcHQuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHN0YXRlIHBlciBDRiBpbnN0YW5jZS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbmZpbmVkQXJlbmFUaHJlYWRFc2NhcGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLXNlZ21lbnQgYW5kIHBlci1hcmVuYSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcDsgdGhyZWFkIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpOyBjb3VudGVycyBhcmUgTG9uZ0FkZGVyLiBUaGUgcmVmbGVjdGl2ZSBNZXRob2QgaGFuZGxlcyBhcmUgcmVzb2x2ZWQgb25jZSBpbnRvIGltbXV0YWJsZSBzdGF0aWNzIGFuZCBhcmUgdGhlbXNlbHZlcyB0aHJlYWQtc2FmZS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLXRocmVhZCBhY2Nlc3MgbWFwIGlzIGEgQ29uY3VycmVudEhhc2hNYXA7IGZpcnN0LXJlZ2lzdHJhdGlvbi13aW5zIHZpYSBwdXRJZkFic2VudC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkZpbGVDaGFubmVsUG9zaXRpb25SYWNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkgYW5kIHRyYWNrIG9ubHkgaW1wbGljaXQtcG9zaXRpb24gYWNjZXNzb3JzLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmluYWxGaWVsZE11dGF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1maWVsZCBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GbG93UHVibGlzaGVyQ29uY3VycmVuY3lEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgY291bnRlcnMgYXJlIExvbmdBZGRlciAvIEF0b21pY0ludGVnZXIgd2l0aCBhIENBUyBoaWdoLXdhdGVyIG1hcmsuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5IaWdoQ29udGVudGlvbkF0b21pY0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXI7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuSmRiY0Nvbm5lY3Rpb25TaGFyZWREZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAtYmFja2VkIEpEQkMtcmVzb3VyY2UgdHJhY2tpbmc7IHBlci1yZXNvdXJjZSBTdGF0ZSBob2xkcyBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKSBmb3IgYWNjZXNzaW5nIHRocmVhZHMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYW1iZGFMb3N0VXBkYXRlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIGxhbWJkYSBpZGVudGl0eSBwbHVzIGNhcHR1cmVkIG5hbWU7IGV2ZW50cyBhcmUgYXBwZW5kZWQgdG8gYSBjb3B5LW9uLXdyaXRlIGxpc3QuIFRoZSBydWxlIGdyb3VwcyBieSBvYnNlcnZlZCBwcmUtdmFsdWUgYW5kIG5lZWRzIG5vIG9yZGVyaW5nLiBob2xkc0xvY2sgaXMgc2FtcGxlZCBvbiB0aGUgcmVjb3JkaW5nIHRocmVhZCBhdCByZWNvcmQgdGltZSwgd2hpY2ggaXMgdGhlIG9ubHkgcGxhY2UgaXQgbWVhbnMgYW55dGhpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBPbmUgc3RhdGUgb2JqZWN0IHBlciBjb2xsZWN0aW9uIGFuZCBlbGVtZW50IGtleSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLCB0aGUgY29sbGVjdGlvbiBrZXllZCBieSBpdHMgaWRlbnRpdHkgd2hlbiB0aGUgY2FsbGVyIHBhc3NlcyBpdCBhbmQgYnkgaXRzIG5hbWUgb3RoZXJ3aXNlOyBjb3VudGVycyBhcmUgYXRvbWljcyBhbmQgd2FpdGVyIHNldHMgYXJlIGNvbmN1cnJlbnQuIFRoZSBwZXItdGhyZWFkIHN0YWNrIG9mIGluLWZsaWdodCBjb21wdXRhdGlvbnMgaXMgYW4gQXJyYXlEZXF1ZSBwZXIgdGhyZWFkIGlkLCBzbyBlYWNoIGlzIHRvdWNoZWQgYnkgZXhhY3RseSBvbmUgdGhyZWFkIGFuZCBuZWVkcyBubyBzeW5jaHJvbmlzYXRpb24uIERlcGVuZGVuY3kgZWRnZXMgYWNjdW11bGF0ZSBpbiBhIHN5bmNocm9uaXplZCBMaW5rZWRIYXNoU2V0LiBOYW1lLWtleWVkIGVkZ2VzIGFyZSB3YWxrZWQgYW5kIGRyb3BwZWQgYXQgZWFjaCByb3VuZCBzdGFydCAobWFya0ludm9jYXRpb25TdGFydCwgIzg1MiksIGFmdGVyIHRoZSBwcmV2aW91cyByb3VuZCdzIHdvcmtlcnMgZmluaXNoZWQ7IGlkZW50aXR5LWtleWVkIGVkZ2VzIGxhc3QgdGhlIHJ1biBhbmQgYXJlIHdhbGtlZCBpbiBhbmFseXplKCksIGFmdGVyIGl0IGhhcyBxdWllc2NlZC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb25zdGFudE1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItY29uc3RhbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgcmVwb3J0cyBhcmUgc3luY2hyb25pemVkIGxpc3RzLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBDb25jdXJyZW50SGFzaE1hcCB0cmFja3MgcmVhZCBsb2NrIG93bmVyc2hpcCBhbmQgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyIChtYXAsa2V5KSBzdGF0ZSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vdGlmeVdpdGhvdXRNb25pdG9yRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IFNZTkNIUk9OSVpFRAotICoqTm90ZSoqOiBBdHRlbXB0cyBsaXN0IG11dGF0ZWQgdW5kZXIgYSBzaW5nbGUgaW50cmluc2ljIG1vbml0b3Igb24gdGhlIGxpc3QgaXRzZWxmOyBzYW1wbGluZyBUaHJlYWQuaG9sZHNMb2NrIHJlcXVpcmVzIG5vIGxvY2tpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5QbGF0Zm9ybVRocmVhZFBlclRhc2tEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ3JlYXRlZCB0aHJlYWRzIGFjY3VtdWxhdGUgaW4gYSBDb25jdXJyZW50TGlua2VkUXVldWU7IHByb2JlIGJvb2trZWVwaW5nIGluIENvbmN1cnJlbnRIYXNoTWFwOyBjb3VudGVycyBhcmUgQXRvbWljSW50ZWdlci4gYW5hbHl6ZSgpIHJlYWRzIGEgbW9tZW50LWluLXRpbWUgc25hcHNob3QgYW5kIGlzIHNhZmUgdG8gY2FsbCBjb25jdXJyZW50bHkgd2l0aCByZWNvcmRpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItcHJvY2VzcyBzdGF0ZSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIGJ5IGlkZW50aXR5LCB3aXRoIGEgZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0YWtlcnMgYXJlIGNvbmN1cnJlbnQgc2V0czsgdGhlIGZpcnN0IHdhaXQgaXMgY2xhaW1lZCBvbmNlIHdpdGggYSBDQVMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gaWRlbnRpdHkgaGFzaDsgdGhlIGZpcnN0LXNpZ2h0IGZpbmdlcnByaW50IG1hcCBpcyBwb3B1bGF0ZWQgb25jZSB1bmRlciBjb21wdXRlSWZBYnNlbnQgYW5kIHJlYWQtb25seSBhZnRlcndhcmRzOyB0aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHRyYWNraW5nIGlzIGNhcHBlZCBieSBNQVhfSU5TVEFOQ0VTIHdpdGggYSBMb25nQWRkZXIgZHJvcCBjb3VudGVyLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVDb25maWd1cmF0aW9uTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBpbW11dGFibGUtYWZ0ZXItb3BlbiBzdGF0ZSBvYmplY3QgcGVyIHNjb3BlIGlkIGluIGEgQ29uY3VycmVudEhhc2hNYXA7IGNvdW50ZXJzIGluc2lkZSBpdCBhcmUgYXRvbWljcy4gU2NvcGUgbGlmZXRpbWVzIGFyZSBvcmRlcmVkIGJ5IGEgc2luZ2xlIEF0b21pY0xvbmcgc2VxdWVuY2UgcmF0aGVyIHRoYW4gdGhlIHdhbGwgY2xvY2ssIHNvIG92ZXJsYXAgaXMgZGVjaWRlZCBieSBwcm9ncmFtIG9yZGVyIGFuZCBuZXZlciBieSBjbG9jayBncmFudWxhcml0eSBvciBkcmlmdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIGpvaW5lciBpZGVudGl0eSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLiBUaGUgaW4tZmxpZ2h0IG9uQ29tcGxldGUgY291bnQgaXMgYW4gYXRvbWljIGNvdW50ZXIgd2hvc2UgcGVhayBpcyByYWlzZWQgd2l0aCBhIENBUyByZXRyeSBsb29wLCBzbyBhIHBlYWsgb2JzZXJ2ZWQgdW5kZXIgY29udGVudGlvbiBpcyBuZXZlciBsb3dlciB0aGFuIHRoZSB0cnVlIHBlYWsuIEZpbmRpbmdzIGFyZSByZWNvcmRlZCBhcyBmbGFncyBzZXQgZnJvbSB0aGUgcmVjb3JkaW5nIHRocmVhZHMgYW5kIHJlYWQgb25jZSBpbiBhbmFseXplKCksIGFmdGVyIHRoZSBydW4gaGFzIHF1aWVzY2VkLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogT25lIHN0YXRlIG9iamVjdCBwZXIgc2NvcGUgaWQgYW5kIHBlciByZXN1bHQtaGFuZGxlIGlkZW50aXR5LCBib3RoIGluIENvbmN1cnJlbnRIYXNoTWFwcy4gQ2xvc2UgYW5kIHJlYWQgYXJlIG9yZGVyZWQgYnkgYSBzaW5nbGUgQXRvbWljTG9uZyBzZXF1ZW5jZSByYXRoZXIgdGhhbiB0aGUgd2FsbCBjbG9jaywgc28gJ3JlYWQgYWZ0ZXIgY2xvc2UnIGlzIGRlY2lkZWQgYnkgcHJvZ3JhbSBvcmRlciBhbmQgbmV2ZXIgYnkgY2xvY2sgZ3JhbnVsYXJpdHkuIFJlYWRlciB0aHJlYWQgbmFtZXMgYWNjdW11bGF0ZSBpbiBhIGNvbmN1cnJlbnQgc2V0IGFuZCBhcmUgcmVhZCBvbmNlIGluIGFuYWx5emUoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEJ5dGVCdWZmZXJEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBhbmQgb3BlcmF0aW9uIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hhcnNldENvZGVyRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRDaGVja3N1bURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkRGVmbGF0ZXJEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEl0ZXJhdG9yRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRKc29uTWFwcGVyUmVjb25maWdEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB1c2luZy10aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHZpb2xhdGluZyBtdXRhdGlvbnMgcmVjb3JkZWQgaW4gYSBDb3B5T25Xcml0ZUFycmF5TGlzdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEtkZkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVtb3J5U2VnbWVudFJhY2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLXNlZ21lbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXA7IHRoZSBhY2Nlc3MgbG9nIGlzIGEgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfVFJBQ0tFRF9BQ0NFU1NFUyB3aXRoIGEgTG9uZ0FkZGVyIGRyb3AgY291bnRlciwgc28gYW4gdW5ib3VuZGVkIHRlc3QgY2Fubm90IGV4aGF1c3QgdGhlIGhlYXAgYW5kIHRoZSByZXBvcnQgc3RhdGVzIGhvdyBtYW55IHNhbXBsZXMgd2VyZSBkcm9wcGVkLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGRvdWJsZS1jaGVjayAoZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50KSBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTcGxpdHRhYmxlUmFuZG9tRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBkb3VibGUtY2hlY2sgKGdldC10aGVuLWNvbXB1dGVJZkFic2VudCkgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3B1cmlvdXNXYWtldXBEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHN0YXRlIHBlciBtb25pdG9yIGluc3RhbmNlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IEhvbGRlciBhbmQgd2FpdCBtYXBzIGFyZSBDb25jdXJyZW50SGFzaE1hcCBrZXllZCBvbiBjbGFzcyBuYW1lIC8gdGhyZWFkIGlkLiBUaGUgbGl2ZS10aHJlYWQgc2FtcGxlIGlzIHRha2VuIGF0IG1vc3Qgb25jZSBhbmQgY2FjaGVkIGluIGFuIEF0b21pY1JlZmVyZW5jZSBzbyBhbmFseXplKCkgc3RheXMgaWRlbXBvdGVudCBldmVuIHRob3VnaCB0aGUgdGhyZWFkcyBpdCBvYnNlcnZlcyBhcmUgbm90LgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhpc0VzY2FwZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IGVzY2FwZSBkZXNjcmlwdGlvbnMgYW5kIG9ic2VydmVyLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgdGhlIGNvbXBsZXRlZCBmbGFnIGlzIHZvbGF0aWxlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhyZWFkTG9jYWxDYWNoZURlZ3JhZGF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIFRocmVhZExvY2FsIG5hbWUgaW4gYSBDb25jdXJyZW50SGFzaE1hcDsgaW5zdGFuY2UgaWRlbnRpdGllcyBhbmQgdGhyZWFkIGlkcyBhcmUgY29uY3VycmVudCBrZXktc2V0IHZpZXdzLCBzbyBjb3VudGluZyBpcyBpZGVtcG90ZW50IHVuZGVyIHJlcGVhdGVkIHJlY29yZGluZyBmcm9tIHRoZSBzYW1lIHRocmVhZCAtIGEgdmFsdWUgcmVhZCB0d2ljZSBhZGRzIG5vdGhpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IG1pc3VzaW5nLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRyeUxvY2tNaXN1c2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgdHJhY2tzIHRyeUxvY2sgYXR0ZW1wdHMsIHJlc3VsdHMsIGFuZCB1bmxvY2sgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZhckhhbmRsZU5vbkF0b21pY1VwZGF0ZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItbG9jYXRpb24gc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gYSAoaGFuZGxlLCByZWNlaXZlcikgaWRlbnRpdHkgcmVjb3JkOyBwZW5kaW5nIHJlYWRzIGFyZSBhIHBlci10aHJlYWQgQ29uY3VycmVudEhhc2hNYXAgZW50cnk7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXIgYW5kIGRldGFpbCBsaXN0cyBhcmUgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfREVUQUlMUy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBPbmUgc3RhdGUgb2JqZWN0IHBlciBtb25pdG9yIGlkZW50aXR5IGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFF1ZXVlIGRlcHRoLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBpbiBpdCwgYXJlIGF0b21pYyBjb3VudGVycyB3aG9zZSBwZWFrcyBhcmUgcmFpc2VkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQgbWFwIHZhbHVlcyB1c2UgQXRvbWljSW50ZWdlciBjb3VudGVycyBhbmQgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WaXJ0dWFsVGhyZWFkUmVzb3VyY2VTYXR1cmF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIHJlc291cmNlIGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFRoZSB3YWl0ZXJzLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBhbW9uZyB0aGVtLCBhcmUgYXRvbWljIGNvdW50ZXJzIHdob3NlIHBlYWtzIGFyZSBtYWludGFpbmVkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuV2Vha0hhc2hNYXBTaGFyZWREZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAtYmFja2VkIGluc3RhbmNlIHRyYWNraW5nOyBwZXItaW5zdGFuY2UgU3RhdGUgaG9sZHMgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkgZm9yIHRocmVhZCBpZHMvbmFtZXMuCgojIyBTZWN1cml0eS1Dcml0aWNhbCBDb2RlCi0gKipSdWxlKio6IFRoaXMgY29kZSBpcyBzZWN1cml0eS1jcml0aWNhbC4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBFdmVyeSBjaGFuZ2UgbXVzdCBiZSBleHBsaWNpdGx5IHJldmlld2VkIGZvciBzZWN1cml0eSBpbXBhY3QuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IKLSAqKkFzcGVjdCoqOiBjcnlwdG9ncmFwaHkgKGhhc2ggaW50ZWdyaXR5IC8gTUFDIC8gc2lnbmF0dXJlIHN0YXRlKQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKkFzcGVjdCoqOiBjcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvcgotICoqQXNwZWN0Kio6IGNyeXB0b2dyYXBoeSAoY29uZmlkZW50aWFsaXR5IC8gaW50ZWdyaXR5IC8gYXV0aGVudGljaXR5IHN0YXRlKQoKIyMgSW1tdXRhYmxlIFR5cGUKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlLlNpdGUKLSAqKlJ1bGUqKjogVGhpcyB0eXBlIGlzIGltbXV0YWJsZS4gTmV2ZXIgaW50cm9kdWNlIG5vbi1maW5hbCBmaWVsZHMsIHNldHRlcnMsIG9yIG11dGF0aW5nIG1ldGhvZHMuCi0gKipOb3RlKio6IEphdmEgcmVjb3JkIOKAlCBmaWVsZHMgYXJlIGZpbmFsIGJ5IGxhbmd1YWdlOyB0eXBlcyBhcmUgYWxsIHByaW1pdGl2ZXMgb3IgU3RyaW5nLgoKIyMgUHVibGljIEFQSSBTdXJmYWNlIFByb3RlY3Rpb24KLSAqKlJ1bGUqKjogRXhwb3NlcyBwdWJsaWMgQVBJLiBQcmVzZXJ2ZSBzaWduYXR1cmUsIEphdmFkb2MsIGFuZCBiZWhhdmlvciB3aXRob3V0IGJyZWFraW5nIGJhY2t3YXJkcyBvciBzb3VyY2UgY29tcGF0aWJpbGl0eS4KLSAqKkFwcGxpZXMgdG8qKjogYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JEZWZhdWx0U2V2ZXJpdHlgLCBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvclRydXN0YCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuR3JhZGVkRmluZGluZ3NgLCBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaXRlQ2FwdHVyZS5TaXRlYCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVHJ1c3RUaWVyYAoKIyMgTWlycm9yZWQg4oCUIEtlZXAgSW4gU3luYwotICoqUnVsZSoqOiBGcmVlIHRvIGNoYW5nZSwgYnV0IGV2ZXJ5IG1pcnJvciBtdXN0IGNoYW5nZSBpbiB0aGUgc2FtZSBjb21taXQuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckRlZmF1bHRTZXZlcml0eQotICoqTWlycm9ycyoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSwgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvclRydXN0Ci0gKipSZWFzb24qKjogQW4gZW50cnkgaGVyZSBpcyB0aGUgc2V2ZXJpdHkgYSBidWlsdC1pbiBkZXRlY3RvcidzIGZpbmRpbmdzIGNhcnJ5IGF0IHRoZSBmYWlsT24gZ2F0ZSB3aGVuIGl0cyByZXBvcnQgbWFya3Mgbm9uZS4gQSBkZXRlY3RvciBtaXNzaW5nIGZyb20gYm90aCB0aGlzIHRhYmxlIGFuZCB0aGUgbWFya2VyIGNvbnZlbnRpb24gc2lsZW50bHkgZmFsbHMgYmFjayB0byBISUdILCB3aGljaCBpcyB0aGUgZGVmZWN0IHRoaXMgdGFibGUgZXhpc3RzIHRvIGZpeC4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yU2V2ZXJpdHlNYXJrZXJUZXN0CgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckZlZWRzCi0gKipNaXJyb3JzKio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JUeXBlLCBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yVHJ1c3QsIGRvY3MvREVURUNUT1JfQ0FUQUxPRy5tZAotICoqUmVhc29uKio6IEV2ZXJ5IERldGVjdG9yVHlwZSByZXNvbHZlcyB0byBleGFjdGx5IG9uZSBmZWVkLCB0aGUgQUdFTlQgc2V0IG11c3QgZXF1YWwgdGhlIGRldGVjdG9ycyB0aGUgdGVsZW1ldHJ5IGJyaWRnZSBhbmQgY29sbGVjdGlvbiBob29rcyBhcmUgY29tcGlsZS13aXJlZCBpbnRvLCBhbmQgdGhlIGNhdGFsb2cncyBmZWVkIGxpc3RpbmcgbXVzdCBuYW1lIHRoZSBzYW1lIGNsYXNzZXMgdGhpcyB0YWJsZSBjbGFzc2lmaWVzLiBBIGZlZWQgdGhhdCBkcmlmdHMgbWlzbGVhZHMgdGhlIHVzZXIgZGVjaWRpbmcgd2hldGhlciBhdHRhY2hpbmcgdGhlIGFnZW50IGJ1eXMgdGhlbSBhbnl0aGluZy4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yRmVlZENvdmVyYWdlVGVzdAoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JUcnVzdAotICoqTWlycm9ycyoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSwgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclJlZ2lzdHJ5LCBkb2NzL0RFVEVDVE9SX0NBVEFMT0cubWQKLSAqKlJlYXNvbioqOiBFdmVyeSBEZXRlY3RvclR5cGUgbmVlZHMgZXhhY3RseSBvbmUgcm93LCBhbmQgZWFjaCByb3cgbmFtZXMgdGhlIGRldGVjdG9yIGNsYXNzIHdob3NlIHNpbXBsZSBuYW1lIGtleXMgdGhlIHJlcG9ydCBtYXAgKERldGVjdG9yUmVnaXN0cnkuaWZJc3N1ZSkuIEEgcm93IG5hbWluZyBhIGNsYXNzIHRoZSByZWdpc3RyeSdzIGZhY3Rvcnkgcm93IGRvZXMgbm90IGNyZWF0ZSBzaWxlbnRseSBzdG9wcyByZXNvbHZpbmcsIGFuZCB0aGUgZmluZGluZyBsb3NlcyBpdHMgdGllciB3aXRob3V0IGFueXRoaW5nIGdvaW5nIHJlZC4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yVHJ1c3RDb3ZlcmFnZVRlc3Q= +~modgran~async-test-detectors=KiovZGlhZ25vc3RpY3MvKioKIyMgUGVyZm9ybWFuY2UgQ29uc3RyYWludHMKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlCi0gKipSdWxlKio6IE9wdGltYWwgY29tcGxleGl0eSByZXF1aXJlZC4gTyhuXjIpIGlzIGZvcmJpZGRlbiBvbiBob3QgcGF0aHMuCi0gKipDb25zdHJhaW50Kio6IENhbGxlZCBmcm9tIGRldGVjdG9yIHJlY29yZEFjY2VzcyBwYXRoczsgZG8gbm90IGFsbG9jYXRlIHdoZW4gYSBzaXRlIGlzIGFscmVhZHkgY2FwdHVyZWQgZm9yIGEgZ2l2ZW4ga2V5LgoKIyMgVGVzdC1Ecml2ZW4gUmVxdWlyZW1lbnRzCi0gKipSdWxlKio6IENoYW5nZXMgTVVTVCBiZSBhY2NvbXBhbmllZCBieSBhIG1hdGNoaW5nIHRlc3QgdXBkYXRlLgotICoqQ292ZXJhZ2UgR29hbCoqOiA4MCUKLSAqKkZyYW1ld29ya3MqKjogSlVOSVRfNQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQmxvY2tpbmdPbk5vbkJsb2NraW5nVGhyZWFkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0Jsb2NraW5nT25Ob25CbG9ja2luZ1RocmVhZERldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUJsb2NraW5nQ2FsbGJhY2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVCbG9ja2luZ0NhbGxiYWNrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ2FuY2VsbGF0aW9uUHJvcGFnYXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDYW5jZWxsYXRpb25Qcm9wYWdhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDb21iaW5hdG9yTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ29tcGxldGlvblJhY2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVDb21wbGV0aW9uUmFjZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29tcGxldGFibGVGdXR1cmVPYnRydWRlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbmZpbmVkQXJlbmFUaHJlYWRFc2NhcGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EYWVtb25UaHJlYWRIeWdpZW5lRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0RhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmluYWxGaWVsZE11dGF0aW9uRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0ZpbmFsRmllbGRNdXRhdGlvbkRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GbG93UHVibGlzaGVyQ29uY3VycmVuY3lEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvRmxvd1B1Ymxpc2hlckNvbmN1cnJlbmN5RGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkhpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0hpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkpkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0pkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLktvdGxpbk11dGV4UmVlbnRyYW5jeURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9Lb3RsaW5NdXRleFJlZW50cmFuY3lEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTGFtYmRhTG9zdFVwZGF0ZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9MYW1iZGFMb3N0VXBkYXRlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL0xhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb25zdGFudE1pc3VzZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9MYXp5Q29uc3RhbnRNaXN1c2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9Mb2NrVXBncmFkZURlYWRsb2NrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvTm9uQXRvbWljQ29uY3VycmVudE1hcFVwZGF0ZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Ob3RpZnlXaXRob3V0TW9uaXRvckRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9Ob3RpZnlXaXRob3V0TW9uaXRvckRldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5QbGF0Zm9ybVRocmVhZFBlclRhc2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvUGxhdGZvcm1UaHJlYWRQZXJUYXNrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlByb2Nlc3NTdHJlYW1TdGFydmF0aW9uRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1Byb2Nlc3NTdHJlYW1TdGFydmF0aW9uRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlJlY29yZE11dGFibGVDb21wb25lbnRMZWFrRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1JlY29yZE11dGFibGVDb21wb25lbnRMZWFrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlQ29uZmlndXJhdGlvbk1pc3VzZURldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TY29wZUNvbmZpZ3VyYXRpb25NaXN1c2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVKb2luZXJNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2NvcGVKb2luZXJNaXN1c2VEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQnl0ZUJ1ZmZlckRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRCeXRlQnVmZmVyRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZENoYXJzZXRDb2RlckRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRDaGFyc2V0Q29kZXJEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hlY2tzdW1EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkQ2hlY2tzdW1EZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkRGVmbGF0ZXJEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkRGVmbGF0ZXJEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkSXRlcmF0b3JEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkSXRlcmF0b3JEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkSnNvbk1hcHBlclJlY29uZmlnRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZEpzb25NYXBwZXJSZWNvbmZpZ0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRLZGZEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkS2RmRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZE1lbW9yeVNlZ21lbnRSYWNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1NoYXJlZE1lbW9yeVNlZ21lbnRSYWNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZE1lc3NhZ2VEaWdlc3REZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTZWN1cmVSYW5kb21EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU2hhcmVkU3BsaXR0YWJsZVJhbmRvbURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TcHVyaW91c1dha2V1cERldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9TcHVyaW91c1dha2V1cERldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TdGF0aWNJbml0RGVhZGxvY2tEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRoaXNFc2NhcGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVGhpc0VzY2FwZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbENhY2hlRGVncmFkYXRpb25EZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVGhyZWFkTG9jYWxDYWNoZURlZ3JhZGF0aW9uRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRocmVhZExvY2FsUmFuZG9tTWlzdXNlRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1RocmVhZExvY2FsUmFuZG9tTWlzdXNlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRyeUxvY2tNaXN1c2VEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVHJ5TG9ja01pc3VzZURldGVjdG9yVGVzdC5qYXZhCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WYXJIYW5kbGVOb25BdG9taWNVcGRhdGVEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVmFySGFuZGxlTm9uQXRvbWljVXBkYXRlRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9WaXJ0dWFsVGhyZWFkTW9uaXRvclNlcmlhbGl6YXRpb25EZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvcgotICoqVGVzdCBMb2NhdGlvbioqOiBzcmMvdGVzdC9qYXZhL3NlL2RldmVyc2l0eS9hc3luY3Rlc3QvZGlhZ25vc3RpY3MvVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvclRlc3QuamF2YQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFJlc291cmNlU2F0dXJhdGlvbkRldGVjdG9yCi0gKipUZXN0IExvY2F0aW9uKio6IHNyYy90ZXN0L2phdmEvc2UvZGV2ZXJzaXR5L2FzeW5jdGVzdC9kaWFnbm9zdGljcy9WaXJ0dWFsVGhyZWFkUmVzb3VyY2VTYXR1cmF0aW9uRGV0ZWN0b3JUZXN0LmphdmEKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLldlYWtIYXNoTWFwU2hhcmVkRGV0ZWN0b3IKLSAqKlRlc3QgTG9jYXRpb24qKjogc3JjL3Rlc3QvamF2YS9zZS9kZXZlcnNpdHkvYXN5bmN0ZXN0L2RpYWdub3N0aWNzL1dlYWtIYXNoTWFwU2hhcmVkRGV0ZWN0b3JUZXN0LmphdmEKCiMjIFRocmVhZC1TYWZldHkgR3VhcmFudGVlCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5CbG9ja2luZ09uTm9uQmxvY2tpbmdUaHJlYWREZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogRmluZGluZ3MgaW4gYSBjb25jdXJyZW50IHNldCBrZXllZCBieSB0aHJlYWQsIGtpbmQgYW5kIG9wZXJhdGlvbjsgY2xhc3NpZmljYXRpb24gcmVhZHMgdGhlIGNhbGxpbmcgdGhyZWFkJ3Mgb3duIG9iamVjdCBvbmx5LgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29tcGxldGFibGVGdXR1cmVCbG9ja2luZ0NhbGxiYWNrRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFRocmVhZExvY2FsIHRyYWNrcyBhY3RpdmUgY2FsbGJhY2tzOyBDb25jdXJyZW50SGFzaE1hcCBzdG9yZXMgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ2FuY2VsbGF0aW9uUHJvcGFnYXRpb25EZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogT25lIENvbmN1cnJlbnRIYXNoTWFwIGVudHJ5IHBlciBwaXBlbGluZTsgZXZlbnRzIGdvIG9uIGNvcHktb24td3JpdGUgbGlzdHMgYW5kIGNhcnJ5IGFuIGF0b21pY2FsbHkgaXNzdWVkIHNlcXVlbmNlIG51bWJlciwgc28gb3JkZXJpbmcgbmV2ZXIgZGVwZW5kcyBvbiBhIHdhbGwgY2xvY2suCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Db21wbGV0YWJsZUZ1dHVyZUNvbWJpbmF0b3JNaXN1c2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gdGhlIGNvbWJpbmVkIGZ1dHVyZSdzIGlkZW50aXR5OyBjb25zdGl0dWVudCBhbmQgYXdhaXQgZXZlbnRzIGFyZSBjb3B5LW9uLXdyaXRlIGxpc3RzIGNhcnJ5aW5nIGF0b21pY2FsbHkgaXNzdWVkIHNlcXVlbmNlIG51bWJlcnMsIHNvIHRoZSBiZWZvcmUvYWZ0ZXIgY29tcGFyaXNvbiBuZXZlciBkZXBlbmRzIG9uIGEgd2FsbCBjbG9jay4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlQ29tcGxldGlvblJhY2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gZnV0dXJlIGlkZW50aXR5OyBwZXItZnV0dXJlIGF0dGVtcHQgbGlzdCBpcyBjb3B5LW9uLXdyaXRlIGFuZCB0aGUgc2VxdWVuY2UgY291bnRlciBpcyBhdG9taWMsIHNvIGNvbmN1cnJlbnQgcmVjb3JkZXJzIG5ldmVyIGxvc2UgYW4gYXR0ZW1wdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkNvbXBsZXRhYmxlRnV0dXJlT2J0cnVkZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBDb25jdXJyZW50SGFzaE1hcCBzdG9yZXMgc3RhdGUgcGVyIENGIGluc3RhbmNlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuQ29uZmluZWRBcmVuYVRocmVhZEVzY2FwZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItc2VnbWVudCBhbmQgcGVyLWFyZW5hIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwOyB0aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXIuIFRoZSByZWZsZWN0aXZlIE1ldGhvZCBoYW5kbGVzIGFyZSByZXNvbHZlZCBvbmNlIGludG8gaW1tdXRhYmxlIHN0YXRpY3MgYW5kIGFyZSB0aGVtc2VsdmVzIHRocmVhZC1zYWZlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGFlbW9uVGhyZWFkSHlnaWVuZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItdGhyZWFkIGFjY2VzcyBtYXAgaXMgYSBDb25jdXJyZW50SGFzaE1hcDsgZmlyc3QtcmVnaXN0cmF0aW9uLXdpbnMgdmlhIHB1dElmQWJzZW50LgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRmlsZUNoYW5uZWxQb3NpdGlvblJhY2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKSBhbmQgdHJhY2sgb25seSBpbXBsaWNpdC1wb3NpdGlvbiBhY2Nlc3NvcnMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5GaW5hbEZpZWxkTXV0YXRpb25EZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWZpZWxkIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkZsb3dQdWJsaXNoZXJDb25jdXJyZW5jeURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpOyBjb3VudGVycyBhcmUgTG9uZ0FkZGVyIC8gQXRvbWljSW50ZWdlciB3aXRoIGEgQ0FTIGhpZ2gtd2F0ZXIgbWFyay4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkhpZ2hDb250ZW50aW9uQXRvbWljRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgY291bnRlcnMgYXJlIExvbmdBZGRlcjsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5KZGJjQ29ubmVjdGlvblNoYXJlZERldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBDb25jdXJyZW50SGFzaE1hcC1iYWNrZWQgSkRCQy1yZXNvdXJjZSB0cmFja2luZzsgcGVyLXJlc291cmNlIFN0YXRlIGhvbGRzIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpIGZvciBhY2Nlc3NpbmcgdGhyZWFkcy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLktvdGxpbk11dGV4UmVlbnRyYW5jeURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItbXV0ZXggc3RhdGUgaW4gdGhlIHdlYWtseSBrZXllZCBDb25jdXJyZW50SGFzaE1hcCBvZiBBYnN0cmFjdEluc3RhbmNlRGV0ZWN0b3I7IHRoZSBob2xkaW5ncyBhcmUgYSBDb25jdXJyZW50TGlua2VkRGVxdWUgb2Ygd2Vha2x5IGhlbGQgSm9icywgYW5kIGEgcmVlbnRyeSB3cml0ZXMgaXRzIGRlc2NyaXB0aW9uIGJlZm9yZSBpdHMgY291bnQuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYW1iZGFMb3N0VXBkYXRlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIG9uIGxhbWJkYSBpZGVudGl0eSBwbHVzIGNhcHR1cmVkIG5hbWU7IGV2ZW50cyBhcmUgYXBwZW5kZWQgdG8gYSBjb3B5LW9uLXdyaXRlIGxpc3QuIFRoZSBydWxlIGdyb3VwcyBieSBvYnNlcnZlZCBwcmUtdmFsdWUgYW5kIG5lZWRzIG5vIG9yZGVyaW5nLiBob2xkc0xvY2sgaXMgc2FtcGxlZCBvbiB0aGUgcmVjb3JkaW5nIHRocmVhZCBhdCByZWNvcmQgdGltZSwgd2hpY2ggaXMgdGhlIG9ubHkgcGxhY2UgaXQgbWVhbnMgYW55dGhpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBPbmUgc3RhdGUgb2JqZWN0IHBlciBjb2xsZWN0aW9uIGFuZCBlbGVtZW50IGtleSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLCB0aGUgY29sbGVjdGlvbiBrZXllZCBieSBpdHMgaWRlbnRpdHkgd2hlbiB0aGUgY2FsbGVyIHBhc3NlcyBpdCBhbmQgYnkgaXRzIG5hbWUgb3RoZXJ3aXNlOyBjb3VudGVycyBhcmUgYXRvbWljcyBhbmQgd2FpdGVyIHNldHMgYXJlIGNvbmN1cnJlbnQuIFRoZSBwZXItdGhyZWFkIHN0YWNrIG9mIGluLWZsaWdodCBjb21wdXRhdGlvbnMgaXMgYW4gQXJyYXlEZXF1ZSBwZXIgdGhyZWFkIGlkLCBzbyBlYWNoIGlzIHRvdWNoZWQgYnkgZXhhY3RseSBvbmUgdGhyZWFkIGFuZCBuZWVkcyBubyBzeW5jaHJvbmlzYXRpb24uIERlcGVuZGVuY3kgZWRnZXMgYWNjdW11bGF0ZSBpbiBhIHN5bmNocm9uaXplZCBMaW5rZWRIYXNoU2V0LiBOYW1lLWtleWVkIGVkZ2VzIGFyZSB3YWxrZWQgYW5kIGRyb3BwZWQgYXQgZWFjaCByb3VuZCBzdGFydCAobWFya0ludm9jYXRpb25TdGFydCwgIzg1MiksIGFmdGVyIHRoZSBwcmV2aW91cyByb3VuZCdzIHdvcmtlcnMgZmluaXNoZWQ7IGlkZW50aXR5LWtleWVkIGVkZ2VzIGxhc3QgdGhlIHJ1biBhbmQgYXJlIHdhbGtlZCBpbiBhbmFseXplKCksIGFmdGVyIGl0IGhhcyBxdWllc2NlZC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkxhenlDb25zdGFudE1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItY29uc3RhbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgcmVwb3J0cyBhcmUgc3luY2hyb25pemVkIGxpc3RzLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuTG9ja1VwZ3JhZGVEZWFkbG9ja0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBDb25jdXJyZW50SGFzaE1hcCB0cmFja3MgcmVhZCBsb2NrIG93bmVyc2hpcCBhbmQgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyIChtYXAsa2V5KSBzdGF0ZSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLk5vdGlmeVdpdGhvdXRNb25pdG9yRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IFNZTkNIUk9OSVpFRAotICoqTm90ZSoqOiBBdHRlbXB0cyBsaXN0IG11dGF0ZWQgdW5kZXIgYSBzaW5nbGUgaW50cmluc2ljIG1vbml0b3Igb24gdGhlIGxpc3QgaXRzZWxmOyBzYW1wbGluZyBUaHJlYWQuaG9sZHNMb2NrIHJlcXVpcmVzIG5vIGxvY2tpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5QbGF0Zm9ybVRocmVhZFBlclRhc2tEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ3JlYXRlZCB0aHJlYWRzIGFjY3VtdWxhdGUgaW4gYSBDb25jdXJyZW50TGlua2VkUXVldWU7IHByb2JlIGJvb2trZWVwaW5nIGluIENvbmN1cnJlbnRIYXNoTWFwOyBjb3VudGVycyBhcmUgQXRvbWljSW50ZWdlci4gYW5hbHl6ZSgpIHJlYWRzIGEgbW9tZW50LWluLXRpbWUgc25hcHNob3QgYW5kIGlzIHNhZmUgdG8gY2FsbCBjb25jdXJyZW50bHkgd2l0aCByZWNvcmRpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItcHJvY2VzcyBzdGF0ZSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwIGtleWVkIGJ5IGlkZW50aXR5LCB3aXRoIGEgZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0YWtlcnMgYXJlIGNvbmN1cnJlbnQgc2V0czsgdGhlIGZpcnN0IHdhaXQgaXMgY2xhaW1lZCBvbmNlIHdpdGggYSBDQVMuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gaWRlbnRpdHkgaGFzaDsgdGhlIGZpcnN0LXNpZ2h0IGZpbmdlcnByaW50IG1hcCBpcyBwb3B1bGF0ZWQgb25jZSB1bmRlciBjb21wdXRlSWZBYnNlbnQgYW5kIHJlYWQtb25seSBhZnRlcndhcmRzOyB0aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHRyYWNraW5nIGlzIGNhcHBlZCBieSBNQVhfSU5TVEFOQ0VTIHdpdGggYSBMb25nQWRkZXIgZHJvcCBjb3VudGVyLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVDb25maWd1cmF0aW9uTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBpbW11dGFibGUtYWZ0ZXItb3BlbiBzdGF0ZSBvYmplY3QgcGVyIHNjb3BlIGlkIGluIGEgQ29uY3VycmVudEhhc2hNYXA7IGNvdW50ZXJzIGluc2lkZSBpdCBhcmUgYXRvbWljcy4gU2NvcGUgbGlmZXRpbWVzIGFyZSBvcmRlcmVkIGJ5IGEgc2luZ2xlIEF0b21pY0xvbmcgc2VxdWVuY2UgcmF0aGVyIHRoYW4gdGhlIHdhbGwgY2xvY2ssIHNvIG92ZXJsYXAgaXMgZGVjaWRlZCBieSBwcm9ncmFtIG9yZGVyIGFuZCBuZXZlciBieSBjbG9jayBncmFudWxhcml0eSBvciBkcmlmdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNjb3BlSm9pbmVyTWlzdXNlRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIGpvaW5lciBpZGVudGl0eSBpbiBhIENvbmN1cnJlbnRIYXNoTWFwLiBUaGUgaW4tZmxpZ2h0IG9uQ29tcGxldGUgY291bnQgaXMgYW4gYXRvbWljIGNvdW50ZXIgd2hvc2UgcGVhayBpcyByYWlzZWQgd2l0aCBhIENBUyByZXRyeSBsb29wLCBzbyBhIHBlYWsgb2JzZXJ2ZWQgdW5kZXIgY29udGVudGlvbiBpcyBuZXZlciBsb3dlciB0aGFuIHRoZSB0cnVlIHBlYWsuIEZpbmRpbmdzIGFyZSByZWNvcmRlZCBhcyBmbGFncyBzZXQgZnJvbSB0aGUgcmVjb3JkaW5nIHRocmVhZHMgYW5kIHJlYWQgb25jZSBpbiBhbmFseXplKCksIGFmdGVyIHRoZSBydW4gaGFzIHF1aWVzY2VkLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogT25lIHN0YXRlIG9iamVjdCBwZXIgc2NvcGUgaWQgYW5kIHBlciByZXN1bHQtaGFuZGxlIGlkZW50aXR5LCBib3RoIGluIENvbmN1cnJlbnRIYXNoTWFwcy4gQ2xvc2UgYW5kIHJlYWQgYXJlIG9yZGVyZWQgYnkgYSBzaW5nbGUgQXRvbWljTG9uZyBzZXF1ZW5jZSByYXRoZXIgdGhhbiB0aGUgd2FsbCBjbG9jaywgc28gJ3JlYWQgYWZ0ZXIgY2xvc2UnIGlzIGRlY2lkZWQgYnkgcHJvZ3JhbSBvcmRlciBhbmQgbmV2ZXIgYnkgY2xvY2sgZ3JhbnVsYXJpdHkuIFJlYWRlciB0aHJlYWQgbmFtZXMgYWNjdW11bGF0ZSBpbiBhIGNvbmN1cnJlbnQgc2V0IGFuZCBhcmUgcmVhZCBvbmNlIGluIGFuYWx5emUoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEJ5dGVCdWZmZXJEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBhbmQgb3BlcmF0aW9uIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkQ2hhcnNldENvZGVyRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRDaGVja3N1bURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkRGVmbGF0ZXJEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQvbmFtZSBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEl0ZXJhdG9yRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRKc29uTWFwcGVyUmVjb25maWdEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB1c2luZy10aHJlYWQgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCk7IHZpb2xhdGluZyBtdXRhdGlvbnMgcmVjb3JkZWQgaW4gYSBDb3B5T25Xcml0ZUFycmF5TGlzdC4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNoYXJlZEtkZkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVtb3J5U2VnbWVudFJhY2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLXNlZ21lbnQgc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXA7IHRoZSBhY2Nlc3MgbG9nIGlzIGEgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfVFJBQ0tFRF9BQ0NFU1NFUyB3aXRoIGEgTG9uZ0FkZGVyIGRyb3AgY291bnRlciwgc28gYW4gdW5ib3VuZGVkIHRlc3QgY2Fubm90IGV4aGF1c3QgdGhlIGhlYXAgYW5kIHRoZSByZXBvcnQgc3RhdGVzIGhvdyBtYW55IHNhbXBsZXMgd2VyZSBkcm9wcGVkLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGRvdWJsZS1jaGVjayAoZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50KSBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTcGxpdHRhYmxlUmFuZG9tRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IFBlci1pbnN0YW5jZSBzdGF0ZSBpbiBDb25jdXJyZW50SGFzaE1hcCB3aXRoIGdldC10aGVuLWNvbXB1dGVJZkFic2VudCBob3QgcGF0aDsgdGhyZWFkLWlkL25hbWUgc2V0cyBhcmUgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBkb3VibGUtY2hlY2sgKGdldC10aGVuLWNvbXB1dGVJZkFic2VudCkgaG90IHBhdGg7IHRocmVhZC1pZC9uYW1lIHNldHMgYXJlIENvbmN1cnJlbnRIYXNoTWFwLm5ld0tleVNldCgpLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3B1cmlvdXNXYWtldXBEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgc3RvcmVzIHN0YXRlIHBlciBtb25pdG9yIGluc3RhbmNlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IEhvbGRlciBhbmQgd2FpdCBtYXBzIGFyZSBDb25jdXJyZW50SGFzaE1hcCBrZXllZCBvbiBjbGFzcyBuYW1lIC8gdGhyZWFkIGlkLiBUaGUgbGl2ZS10aHJlYWQgc2FtcGxlIGlzIHRha2VuIGF0IG1vc3Qgb25jZSBhbmQgY2FjaGVkIGluIGFuIEF0b21pY1JlZmVyZW5jZSBzbyBhbmFseXplKCkgc3RheXMgaWRlbXBvdGVudCBldmVuIHRob3VnaCB0aGUgdGhyZWFkcyBpdCBvYnNlcnZlcyBhcmUgbm90LgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhpc0VzY2FwZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IGVzY2FwZSBkZXNjcmlwdGlvbnMgYW5kIG9ic2VydmVyLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKTsgdGhlIGNvbXBsZXRlZCBmbGFnIGlzIHZvbGF0aWxlLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVGhyZWFkTG9jYWxDYWNoZURlZ3JhZGF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIFRocmVhZExvY2FsIG5hbWUgaW4gYSBDb25jdXJyZW50SGFzaE1hcDsgaW5zdGFuY2UgaWRlbnRpdGllcyBhbmQgdGhyZWFkIGlkcyBhcmUgY29uY3VycmVudCBrZXktc2V0IHZpZXdzLCBzbyBjb3VudGluZyBpcyBpZGVtcG90ZW50IHVuZGVyIHJlcGVhdGVkIHJlY29yZGluZyBmcm9tIHRoZSBzYW1lIHRocmVhZCAtIGEgdmFsdWUgcmVhZCB0d2ljZSBhZGRzIG5vdGhpbmcuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItaW5zdGFuY2Ugc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAgd2l0aCBnZXQtdGhlbi1jb21wdXRlSWZBYnNlbnQgaG90IHBhdGg7IG1pc3VzaW5nLXRocmVhZCBzZXRzIGFyZSBDb25jdXJyZW50SGFzaE1hcC5uZXdLZXlTZXQoKS4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlRyeUxvY2tNaXN1c2VEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAgdHJhY2tzIHRyeUxvY2sgYXR0ZW1wdHMsIHJlc3VsdHMsIGFuZCB1bmxvY2sgdmlvbGF0aW9ucy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZhckhhbmRsZU5vbkF0b21pY1VwZGF0ZURldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBQZXItbG9jYXRpb24gc3RhdGUgaW4gQ29uY3VycmVudEhhc2hNYXAga2V5ZWQgb24gYSAoaGFuZGxlLCByZWNlaXZlcikgaWRlbnRpdHkgcmVjb3JkOyBwZW5kaW5nIHJlYWRzIGFyZSBhIHBlci10aHJlYWQgQ29uY3VycmVudEhhc2hNYXAgZW50cnk7IGNvdW50ZXJzIGFyZSBMb25nQWRkZXIgYW5kIGRldGFpbCBsaXN0cyBhcmUgQ29weU9uV3JpdGVBcnJheUxpc3QgYm91bmRlZCBieSBNQVhfREVUQUlMUy4KCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yCi0gKipTdHJhdGVneSoqOiBPVEhFUgotICoqTm90ZSoqOiBPbmUgc3RhdGUgb2JqZWN0IHBlciBtb25pdG9yIGlkZW50aXR5IGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFF1ZXVlIGRlcHRoLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBpbiBpdCwgYXJlIGF0b21pYyBjb3VudGVycyB3aG9zZSBwZWFrcyBhcmUgcmFpc2VkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogUGVyLWluc3RhbmNlIHN0YXRlIGluIENvbmN1cnJlbnRIYXNoTWFwIHdpdGggZ2V0LXRoZW4tY29tcHV0ZUlmQWJzZW50IGhvdCBwYXRoOyB0aHJlYWQtaWQgbWFwIHZhbHVlcyB1c2UgQXRvbWljSW50ZWdlciBjb3VudGVycyBhbmQgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5WaXJ0dWFsVGhyZWFkUmVzb3VyY2VTYXR1cmF0aW9uRGV0ZWN0b3IKLSAqKlN0cmF0ZWd5Kio6IE9USEVSCi0gKipOb3RlKio6IE9uZSBzdGF0ZSBvYmplY3QgcGVyIHJlc291cmNlIGluIGEgQ29uY3VycmVudEhhc2hNYXAuIFRoZSB3YWl0ZXJzLCBhbmQgdGhlIHZpcnR1YWwgdGhyZWFkcyBhbW9uZyB0aGVtLCBhcmUgYXRvbWljIGNvdW50ZXJzIHdob3NlIHBlYWtzIGFyZSBtYWludGFpbmVkIHdpdGggYSBDQVMgcmV0cnkgbG9vcCwgc28gYSBwZWFrIG9ic2VydmVkIHVuZGVyIGNvbnRlbnRpb24gaXMgbmV2ZXIgbG93ZXIgdGhhbiB0aGUgdHJ1ZSBwZWFrLgoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuV2Vha0hhc2hNYXBTaGFyZWREZXRlY3RvcgotICoqU3RyYXRlZ3kqKjogT1RIRVIKLSAqKk5vdGUqKjogQ29uY3VycmVudEhhc2hNYXAtYmFja2VkIGluc3RhbmNlIHRyYWNraW5nOyBwZXItaW5zdGFuY2UgU3RhdGUgaG9sZHMgQ29uY3VycmVudEhhc2hNYXAubmV3S2V5U2V0KCkgZm9yIHRocmVhZCBpZHMvbmFtZXMuCgojIyBTZWN1cml0eS1Dcml0aWNhbCBDb2RlCi0gKipSdWxlKio6IFRoaXMgY29kZSBpcyBzZWN1cml0eS1jcml0aWNhbC4gRG8gbm90IHdlYWtlbiBzZWN1cml0eSBwcm9wZXJ0aWVzLiBFdmVyeSBjaGFuZ2UgbXVzdCBiZSBleHBsaWNpdGx5IHJldmlld2VkIGZvciBzZWN1cml0eSBpbXBhY3QuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IKLSAqKkFzcGVjdCoqOiBjcnlwdG9ncmFwaHkgKGhhc2ggaW50ZWdyaXR5IC8gTUFDIC8gc2lnbmF0dXJlIHN0YXRlKQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKLSAqKkFzcGVjdCoqOiBjcnlwdG9ncmFwaHkgKFJORyBxdWFsaXR5KQoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuU2hhcmVkU3RhdGVmdWxDcnlwdG9EZXRlY3RvcgotICoqQXNwZWN0Kio6IGNyeXB0b2dyYXBoeSAoY29uZmlkZW50aWFsaXR5IC8gaW50ZWdyaXR5IC8gYXV0aGVudGljaXR5IHN0YXRlKQoKIyMgSW1tdXRhYmxlIFR5cGUKCiMjIyBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLlNpdGVDYXB0dXJlLlNpdGUKLSAqKlJ1bGUqKjogVGhpcyB0eXBlIGlzIGltbXV0YWJsZS4gTmV2ZXIgaW50cm9kdWNlIG5vbi1maW5hbCBmaWVsZHMsIHNldHRlcnMsIG9yIG11dGF0aW5nIG1ldGhvZHMuCi0gKipOb3RlKio6IEphdmEgcmVjb3JkIOKAlCBmaWVsZHMgYXJlIGZpbmFsIGJ5IGxhbmd1YWdlOyB0eXBlcyBhcmUgYWxsIHByaW1pdGl2ZXMgb3IgU3RyaW5nLgoKIyMgUHVibGljIEFQSSBTdXJmYWNlIFByb3RlY3Rpb24KLSAqKlJ1bGUqKjogRXhwb3NlcyBwdWJsaWMgQVBJLiBQcmVzZXJ2ZSBzaWduYXR1cmUsIEphdmFkb2MsIGFuZCBiZWhhdmlvciB3aXRob3V0IGJyZWFraW5nIGJhY2t3YXJkcyBvciBzb3VyY2UgY29tcGF0aWJpbGl0eS4KLSAqKkFwcGxpZXMgdG8qKjogYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JEZWZhdWx0U2V2ZXJpdHlgLCBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvclRydXN0YCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuR3JhZGVkRmluZGluZ3NgLCBgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5TaXRlQ2FwdHVyZS5TaXRlYCwgYHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuVHJ1c3RUaWVyYAoKIyMgTWlycm9yZWQg4oCUIEtlZXAgSW4gU3luYwotICoqUnVsZSoqOiBGcmVlIHRvIGNoYW5nZSwgYnV0IGV2ZXJ5IG1pcnJvciBtdXN0IGNoYW5nZSBpbiB0aGUgc2FtZSBjb21taXQuCgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckRlZmF1bHRTZXZlcml0eQotICoqTWlycm9ycyoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSwgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvclRydXN0Ci0gKipSZWFzb24qKjogQW4gZW50cnkgaGVyZSBpcyB0aGUgc2V2ZXJpdHkgYSBidWlsdC1pbiBkZXRlY3RvcidzIGZpbmRpbmdzIGNhcnJ5IGF0IHRoZSBmYWlsT24gZ2F0ZSB3aGVuIGl0cyByZXBvcnQgbWFya3Mgbm9uZS4gQSBkZXRlY3RvciBtaXNzaW5nIGZyb20gYm90aCB0aGlzIHRhYmxlIGFuZCB0aGUgbWFya2VyIGNvbnZlbnRpb24gc2lsZW50bHkgZmFsbHMgYmFjayB0byBISUdILCB3aGljaCBpcyB0aGUgZGVmZWN0IHRoaXMgdGFibGUgZXhpc3RzIHRvIGZpeC4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yU2V2ZXJpdHlNYXJrZXJUZXN0CgojIyMgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5kaWFnbm9zdGljcy5EZXRlY3RvckZlZWRzCi0gKipNaXJyb3JzKio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuRGV0ZWN0b3JUeXBlLCBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LmRpYWdub3N0aWNzLkRldGVjdG9yVHJ1c3QsIGRvY3MvREVURUNUT1JfQ0FUQUxPRy5tZAotICoqUmVhc29uKio6IEV2ZXJ5IERldGVjdG9yVHlwZSByZXNvbHZlcyB0byBleGFjdGx5IG9uZSBmZWVkLCB0aGUgQUdFTlQgc2V0IG11c3QgZXF1YWwgdGhlIGRldGVjdG9ycyB0aGUgdGVsZW1ldHJ5IGJyaWRnZSBhbmQgY29sbGVjdGlvbiBob29rcyBhcmUgY29tcGlsZS13aXJlZCBpbnRvLCBhbmQgdGhlIGNhdGFsb2cncyBmZWVkIGxpc3RpbmcgbXVzdCBuYW1lIHRoZSBzYW1lIGNsYXNzZXMgdGhpcyB0YWJsZSBjbGFzc2lmaWVzLiBBIGZlZWQgdGhhdCBkcmlmdHMgbWlzbGVhZHMgdGhlIHVzZXIgZGVjaWRpbmcgd2hldGhlciBhdHRhY2hpbmcgdGhlIGFnZW50IGJ1eXMgdGhlbSBhbnl0aGluZy4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yRmVlZENvdmVyYWdlVGVzdAoKIyMjIHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuZGlhZ25vc3RpY3MuRGV0ZWN0b3JUcnVzdAotICoqTWlycm9ycyoqOiBzZS5kZXZlcnNpdHkuYXN5bmN0ZXN0LkRldGVjdG9yVHlwZSwgc2UuZGV2ZXJzaXR5LmFzeW5jdGVzdC5EZXRlY3RvclJlZ2lzdHJ5LCBkb2NzL0RFVEVDVE9SX0NBVEFMT0cubWQKLSAqKlJlYXNvbioqOiBFdmVyeSBEZXRlY3RvclR5cGUgbmVlZHMgZXhhY3RseSBvbmUgcm93LCBhbmQgZWFjaCByb3cgbmFtZXMgdGhlIGRldGVjdG9yIGNsYXNzIHdob3NlIHNpbXBsZSBuYW1lIGtleXMgdGhlIHJlcG9ydCBtYXAgKERldGVjdG9yUmVnaXN0cnkuaWZJc3N1ZSkuIEEgcm93IG5hbWluZyBhIGNsYXNzIHRoZSByZWdpc3RyeSdzIGZhY3Rvcnkgcm93IGRvZXMgbm90IGNyZWF0ZSBzaWxlbnRseSBzdG9wcyByZXNvbHZpbmcsIGFuZCB0aGUgZmluZGluZyBsb3NlcyBpdHMgdGllciB3aXRob3V0IGFueXRoaW5nIGdvaW5nIHJlZC4KLSAqKkVuZm9yY2VkIGJ5Kio6IHNlLmRldmVyc2l0eS5hc3luY3Rlc3QuYXJjaGl0ZWN0dXJlLkRldGVjdG9yVHJ1c3RDb3ZlcmFnZVRlc3Q= ~modgranname~async-test-detectors=YXN5bmMtdGVzdC1kZXRlY3RvcnMKQUkgcnVsZXMgZm9yIHJvbGUgYXN5bmMtdGVzdC1kZXRlY3RvcnM= ~granular=c2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1BZ2VudENvbGxlY3Rpb25Ib29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50Q29uY3VycmVuY3lVdGlsSG9va3MKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1BZ2VudENvbnN0cnVjdGlvbkhvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRHY0hvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRMb2NrSG9va3MKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1BZ2VudE1vbml0b3JIb29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50U2hhcmVkSW5zdGFuY2VIb29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50U2xlZXBIb29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50VGhyZWFkSG9va3MKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1SdW5PdXRjb21lcwphc3luYy10ZXN0LWNvbmZpZ3VyYXRpb24KYXN5bmMtdGVzdC1ydW50aW1lLWNvcmUKYXN5bmMtdGVzdC1wdWJsaWMtYXBpCmFzeW5jLXRlc3QtaW5zdHJ1bWVudGF0aW9uCmFzeW5jLXRlc3QtZGV0ZWN0b3Jz -~elements=c2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1EZXRlY3RvclR5cGUKVkVORE9SLVZFUklGWS1LRVktQjY0CnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNUZXN0Q29uZmlnCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtRGV0ZWN0b3JSZWdpc3RyeQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LU5vb3BBc3luY1Rlc3RMaXN0ZW5lcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdENvbnRleHQKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1ydW5uZXItQ29uY3VycmVuY3lSdW5uZXIKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1ydW5uZXItTGljZW5zZUd1YXJkLUZpbmdlcnByaW50CnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZXh0ZW5zaW9uLUFzeW5jVGVzdEludm9jYXRpb25JbnRlcmNlcHRvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXRlbGVtZXRyeS1Db250cm9sbGVkU2NoZWR1bGUKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1iZW5jaG1hcmstQmVuY2htYXJrUmVjb3JkZXIKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaXRlQ2FwdHVyZQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50Q29sbGVjdGlvbkhvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRDb25jdXJyZW5jeVV0aWxIb29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50Q29uc3RydWN0aW9uSG9va3MKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1BZ2VudEdjSG9va3MKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1BZ2VudExvY2tIb29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50TW9uaXRvckhvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRTaGFyZWRJbnN0YW5jZUhvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRTbGVlcEhvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRUaHJlYWRIb29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jQXNzZXJ0CnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNGaW5kaW5ncwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdApzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdExpc3RlbmVyCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNUZXN0TGlzdGVuZXJSZWdpc3RyeQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdFJ1bm5lcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWV4dGVuc2lvbi1Bc3luY1Rlc3RFeHRlbnNpb24Kc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1yZXBvcnQtRm9ybWF0dGVyCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtcnVubmVyLUFnZW50QXV0b0F0dGFjaApzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXNwaS1EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXNwaS1EZXRlY3RvckZhY3RvcnkKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1CbG9ja2luZ09uTm9uQmxvY2tpbmdUaHJlYWREZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUNvbXBsZXRhYmxlRnV0dXJlQmxvY2tpbmdDYWxsYmFja0RldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtQ29tcGxldGFibGVGdXR1cmVDYW5jZWxsYXRpb25Qcm9wYWdhdGlvbkRldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtQ29tcGxldGFibGVGdXR1cmVDb21iaW5hdG9yTWlzdXNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1Db21wbGV0YWJsZUZ1dHVyZUNvbXBsZXRpb25SYWNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1Db21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUNvbmZpbmVkQXJlbmFUaHJlYWRFc2NhcGVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLURhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUZpbGVDaGFubmVsUG9zaXRpb25SYWNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1GaW5hbEZpZWxkTXV0YXRpb25EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUZsb3dQdWJsaXNoZXJDb25jdXJyZW5jeURldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtSGlnaENvbnRlbnRpb25BdG9taWNEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUpkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1MYW1iZGFMb3N0VXBkYXRlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1MYXp5Q29sbGVjdGlvbk1pc3VzZURldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtTGF6eUNvbnN0YW50TWlzdXNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1Mb2NrVXBncmFkZURlYWRsb2NrRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1Ob25BdG9taWNDb25jdXJyZW50TWFwVXBkYXRlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1Ob3RpZnlXaXRob3V0TW9uaXRvckRldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtUGxhdGZvcm1UaHJlYWRQZXJUYXNrRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1Qcm9jZXNzU3RyZWFtU3RhcnZhdGlvbkRldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtUmVjb3JkTXV0YWJsZUNvbXBvbmVudExlYWtEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNjb3BlQ29uZmlndXJhdGlvbk1pc3VzZURldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU2NvcGVKb2luZXJNaXN1c2VEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNjb3BlUmVzdWx0RXNjYXBlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWRCeXRlQnVmZmVyRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWRDaGFyc2V0Q29kZXJEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNoYXJlZENoZWNrc3VtRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWREZWZsYXRlckRldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU2hhcmVkSXRlcmF0b3JEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNoYXJlZEpzb25NYXBwZXJSZWNvbmZpZ0RldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU2hhcmVkS2RmRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWRNZW1vcnlTZWdtZW50UmFjZURldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU2hhcmVkU2VjdXJlUmFuZG9tRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWRTcGxpdHRhYmxlUmFuZG9tRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWRTdGF0ZWZ1bENyeXB0b0RldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU3B1cmlvdXNXYWtldXBEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVN0YXRpY0luaXREZWFkbG9ja0RldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtVGhpc0VzY2FwZURldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtVGhyZWFkTG9jYWxDYWNoZURlZ3JhZGF0aW9uRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1UaHJlYWRMb2NhbFJhbmRvbU1pc3VzZURldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtVHJ5TG9ja01pc3VzZURldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtVmFySGFuZGxlTm9uQXRvbWljVXBkYXRlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1WaXJ0dWFsVGhyZWFkTW9uaXRvclNlcmlhbGl6YXRpb25EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVZpcnR1YWxUaHJlYWRQb29saW5nRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1WaXJ0dWFsVGhyZWFkUmVzb3VyY2VTYXR1cmF0aW9uRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1XZWFrSGFzaE1hcFNoYXJlZERldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtUnVuT3V0Y29tZXMKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1ydW5uZXItTGljZW5zZUd1YXJkCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtcnVubmVyLUxpY2Vuc2VWYWxpZGF0aW9uQ2FjaGUKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1QcmVzZXQKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaXRlQ2FwdHVyZS1TaXRlCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtcmVwb3J0LVZpb2xhdGlvbgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXNwaS1EZXRlY3RvclJlZ2lzdHJ5CnNoYXJlZENyeXB0b2dyYXBoeURldGVjdG9yLS0Kc2hhcmVkTWVzc2FnZURpZ2VzdERldGVjdG9yLS0Kc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1EZXRlY3RvckRlZmF1bHRTZXZlcml0eQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLURldGVjdG9yVHJ1c3QKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1HcmFkZWRGaW5kaW5ncwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVRydXN0VGllcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXJlcG9ydC1Kc29uRm9ybWF0dGVyCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtcmVwb3J0LU1hcmtkb3duRm9ybWF0dGVyCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtcmVwb3J0LVNhcmlmRm9ybWF0dGVyCnJlYWRTdG9yZS1qYXZhLWlvLUZpbGUtCnVuaW5zdGFsbC0tCmNsb3NlLS0KY2xlYXJBbGwtLQp1bnJlZ2lzdGVyLXNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNUZXN0TGlzdGVuZXItCmNoZWNrLXNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNUZXN0Q29uZmlnLQphbmFseXplQWxsLS0KZW5hYmxlQmVuY2htYXJraW5nCmxpY2Vuc2VNb2NrTW9kZQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXJ1bm5lci1PZmZsaW5lTGljZW5zZQppbnN0YWxsLXNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNUZXN0Q29udGV4dC0KaW5zdGFsbC1zZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdENvbnRleHQtaW50LQpyZWNvcmRJbnZvY2F0aW9uRW5kLWxvbmctCnJlY29yZEludm9jYXRpb25TdGFydC0tCnJlcG9ydAppbnRlcmNlcHRUZXN0VGVtcGxhdGVNZXRob2Qtb3JnLWp1bml0LWp1cGl0ZXItYXBpLWV4dGVuc2lvbi1JbnZvY2F0aW9uSW50ZXJjZXB0b3ItSW52b2NhdGlvbi1qYXZhLWxhbmctVm9pZC0tb3JnLWp1bml0LWp1cGl0ZXItYXBpLWV4dGVuc2lvbi1SZWZsZWN0aXZlSW52b2NhdGlvbkNvbnRleHQtamF2YS1sYW5nLXJlZmxlY3QtTWV0aG9kLS1vcmctanVuaXQtanVwaXRlci1hcGktZXh0ZW5zaW9uLUV4dGVuc2lvbkNvbnRleHQtCmV4ZWN1dGUtb3JnLWp1bml0LWp1cGl0ZXItYXBpLWV4dGVuc2lvbi1SZWZsZWN0aXZlSW52b2NhdGlvbkNvbnRleHQtamF2YS1sYW5nLXJlZmxlY3QtTWV0aG9kLS1zZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdENvbmZpZy0Kc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1EZXRlY3RvckZlZWRzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtdGVsZW1ldHJ5LVRlbGVtZXRyeUJyaWRnZQ== +~elements=c2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1EZXRlY3RvclR5cGUKVkVORE9SLVZFUklGWS1LRVktQjY0CnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNUZXN0Q29uZmlnCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtRGV0ZWN0b3JSZWdpc3RyeQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LU5vb3BBc3luY1Rlc3RMaXN0ZW5lcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdENvbnRleHQKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1ydW5uZXItQ29uY3VycmVuY3lSdW5uZXIKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1ydW5uZXItTGljZW5zZUd1YXJkLUZpbmdlcnByaW50CnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZXh0ZW5zaW9uLUFzeW5jVGVzdEludm9jYXRpb25JbnRlcmNlcHRvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXRlbGVtZXRyeS1Db250cm9sbGVkU2NoZWR1bGUKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1iZW5jaG1hcmstQmVuY2htYXJrUmVjb3JkZXIKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaXRlQ2FwdHVyZQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50Q29sbGVjdGlvbkhvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRDb25jdXJyZW5jeVV0aWxIb29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50Q29uc3RydWN0aW9uSG9va3MKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1BZ2VudEdjSG9va3MKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1BZ2VudExvY2tIb29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFnZW50TW9uaXRvckhvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRTaGFyZWRJbnN0YW5jZUhvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRTbGVlcEhvb2tzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQWdlbnRUaHJlYWRIb29rcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jQXNzZXJ0CnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNGaW5kaW5ncwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdApzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdExpc3RlbmVyCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNUZXN0TGlzdGVuZXJSZWdpc3RyeQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LUFzeW5jVGVzdFJ1bm5lcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWV4dGVuc2lvbi1Bc3luY1Rlc3RFeHRlbnNpb24Kc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1yZXBvcnQtRm9ybWF0dGVyCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtcnVubmVyLUFnZW50QXV0b0F0dGFjaApzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXNwaS1EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXNwaS1EZXRlY3RvckZhY3RvcnkKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1CbG9ja2luZ09uTm9uQmxvY2tpbmdUaHJlYWREZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUNvbXBsZXRhYmxlRnV0dXJlQmxvY2tpbmdDYWxsYmFja0RldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtQ29tcGxldGFibGVGdXR1cmVDYW5jZWxsYXRpb25Qcm9wYWdhdGlvbkRldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtQ29tcGxldGFibGVGdXR1cmVDb21iaW5hdG9yTWlzdXNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1Db21wbGV0YWJsZUZ1dHVyZUNvbXBsZXRpb25SYWNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1Db21wbGV0YWJsZUZ1dHVyZU9idHJ1ZGVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUNvbmZpbmVkQXJlbmFUaHJlYWRFc2NhcGVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLURhZW1vblRocmVhZEh5Z2llbmVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUZpbGVDaGFubmVsUG9zaXRpb25SYWNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1GaW5hbEZpZWxkTXV0YXRpb25EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUZsb3dQdWJsaXNoZXJDb25jdXJyZW5jeURldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtSGlnaENvbnRlbnRpb25BdG9taWNEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUpkYmNDb25uZWN0aW9uU2hhcmVkRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1Lb3RsaW5NdXRleFJlZW50cmFuY3lEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUxhbWJkYUxvc3RVcGRhdGVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUxhenlDb2xsZWN0aW9uTWlzdXNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1MYXp5Q29uc3RhbnRNaXN1c2VEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUxvY2tVcGdyYWRlRGVhZGxvY2tEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLU5vbkF0b21pY0NvbmN1cnJlbnRNYXBVcGRhdGVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLU5vdGlmeVdpdGhvdXRNb25pdG9yRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1QbGF0Zm9ybVRocmVhZFBlclRhc2tEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVByb2Nlc3NTdHJlYW1TdGFydmF0aW9uRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1SZWNvcmRNdXRhYmxlQ29tcG9uZW50TGVha0RldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU2NvcGVDb25maWd1cmF0aW9uTWlzdXNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TY29wZUpvaW5lck1pc3VzZURldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU2NvcGVSZXN1bHRFc2NhcGVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNoYXJlZEJ5dGVCdWZmZXJEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNoYXJlZENoYXJzZXRDb2RlckRldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU2hhcmVkQ2hlY2tzdW1EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNoYXJlZERlZmxhdGVyRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWRJdGVyYXRvckRldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU2hhcmVkSnNvbk1hcHBlclJlY29uZmlnRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWRLZGZEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNoYXJlZE1lbW9yeVNlZ21lbnRSYWNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TaGFyZWRTZWN1cmVSYW5kb21EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNoYXJlZFNwbGl0dGFibGVSYW5kb21EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNoYXJlZFN0YXRlZnVsQ3J5cHRvRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1TcHVyaW91c1dha2V1cERldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtU3RhdGljSW5pdERlYWRsb2NrRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1UaGlzRXNjYXBlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1UaHJlYWRMb2NhbENhY2hlRGVncmFkYXRpb25EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVRocmVhZExvY2FsUmFuZG9tTWlzdXNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1UcnlMb2NrTWlzdXNlRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1kaWFnbm9zdGljcy1WYXJIYW5kbGVOb25BdG9taWNVcGRhdGVEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVZpcnR1YWxUaHJlYWRNb25pdG9yU2VyaWFsaXphdGlvbkRldGVjdG9yCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtVmlydHVhbFRocmVhZFBvb2xpbmdEZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVZpcnR1YWxUaHJlYWRSZXNvdXJjZVNhdHVyYXRpb25EZXRlY3RvcgpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVdlYWtIYXNoTWFwU2hhcmVkRGV0ZWN0b3IKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1SdW5PdXRjb21lcwpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LXJ1bm5lci1MaWNlbnNlR3VhcmQKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1ydW5uZXItTGljZW5zZVZhbGlkYXRpb25DYWNoZQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LVByZXNldApzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLVNpdGVDYXB0dXJlLVNpdGUKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1yZXBvcnQtVmlvbGF0aW9uCnNlLWRldmVyc2l0eS1hc3luY3Rlc3Qtc3BpLURldGVjdG9yUmVnaXN0cnkKc2hhcmVkQ3J5cHRvZ3JhcGh5RGV0ZWN0b3ItLQpzaGFyZWRNZXNzYWdlRGlnZXN0RGV0ZWN0b3ItLQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLURldGVjdG9yRGVmYXVsdFNldmVyaXR5CnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtRGV0ZWN0b3JUcnVzdApzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLUdyYWRlZEZpbmRpbmdzCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtZGlhZ25vc3RpY3MtVHJ1c3RUaWVyCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtcmVwb3J0LUpzb25Gb3JtYXR0ZXIKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1yZXBvcnQtTWFya2Rvd25Gb3JtYXR0ZXIKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1yZXBvcnQtU2FyaWZGb3JtYXR0ZXIKcmVhZFN0b3JlLWphdmEtaW8tRmlsZS0KdW5pbnN0YWxsLS0KY2xvc2UtLQpjbGVhckFsbC0tCnVucmVnaXN0ZXItc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1Bc3luY1Rlc3RMaXN0ZW5lci0KY2hlY2stc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1Bc3luY1Rlc3RDb25maWctCmFuYWx5emVBbGwtLQplbmFibGVCZW5jaG1hcmtpbmcKbGljZW5zZU1vY2tNb2RlCnNlLWRldmVyc2l0eS1hc3luY3Rlc3QtcnVubmVyLU9mZmxpbmVMaWNlbnNlCmluc3RhbGwtc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC1Bc3luY1Rlc3RDb250ZXh0LQppbnN0YWxsLXNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNUZXN0Q29udGV4dC1pbnQtCnJlY29yZEludm9jYXRpb25FbmQtbG9uZy0KcmVjb3JkSW52b2NhdGlvblN0YXJ0LS0KcmVwb3J0CmludGVyY2VwdFRlc3RUZW1wbGF0ZU1ldGhvZC1vcmctanVuaXQtanVwaXRlci1hcGktZXh0ZW5zaW9uLUludm9jYXRpb25JbnRlcmNlcHRvci1JbnZvY2F0aW9uLWphdmEtbGFuZy1Wb2lkLS1vcmctanVuaXQtanVwaXRlci1hcGktZXh0ZW5zaW9uLVJlZmxlY3RpdmVJbnZvY2F0aW9uQ29udGV4dC1qYXZhLWxhbmctcmVmbGVjdC1NZXRob2QtLW9yZy1qdW5pdC1qdXBpdGVyLWFwaS1leHRlbnNpb24tRXh0ZW5zaW9uQ29udGV4dC0KZXhlY3V0ZS1vcmctanVuaXQtanVwaXRlci1hcGktZXh0ZW5zaW9uLVJlZmxlY3RpdmVJbnZvY2F0aW9uQ29udGV4dC1qYXZhLWxhbmctcmVmbGVjdC1NZXRob2QtLXNlLWRldmVyc2l0eS1hc3luY3Rlc3QtQXN5bmNUZXN0Q29uZmlnLQpzZS1kZXZlcnNpdHktYXN5bmN0ZXN0LWRpYWdub3N0aWNzLURldGVjdG9yRmVlZHMKc2UtZGV2ZXJzaXR5LWFzeW5jdGVzdC10ZWxlbWV0cnktVGVsZW1ldHJ5QnJpZGdl # end diff --git a/CLAUDE.md b/CLAUDE.md index 927d7a779..7635f1622 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,7 @@ # CLAUDE.md `@AsyncTest` is a JUnit 5 `@TestTemplate` that runs a test body on N threads for M rounds, forcing -them to collide on a `CyclicBarrier`, and reports what 148 detectors saw. This file is the map. It +them to collide on a `CyclicBarrier`, and reports what 149 detectors saw. This file is the map. It is deliberately short: it loads on every session, so anything needed only sometimes lives behind a link, and every rule below names the gate that enforces it. @@ -61,7 +61,7 @@ annotations in the source; each module owns its own in `/CLAUDE.md` and Critical - The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a <clinit> that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. + The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). KotlinMutexWeaver replaces a kotlinx.coroutines.sync.Mutex lock, unlock or tryLock call, or its static $default bridge, matched by owner, name and descriptor, with a static hook consuming the same stack and returning the same result, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a <clinit> that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. diff --git a/GEMINI.md b/GEMINI.md index eefbcfb79..23588e6d9 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -14,7 +14,7 @@ indexed from the block below. ## CORE FUNCTIONALITY (EXTREME CAUTION) The following elements are well-tested core components. Make changes with extreme caution: -- `se.deversity.asynctest.agent.AsyncTestAgent`: Sensitivity: Critical. Note: The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. +- `se.deversity.asynctest.agent.AsyncTestAgent`: Sensitivity: Critical. Note: The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). KotlinMutexWeaver replaces a kotlinx.coroutines.sync.Mutex lock, unlock or tryLock call, or its static $default bridge, matched by owner, name and descriptor, with a static hook consuming the same stack and returning the same result, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. # GEMINI AI INSTRUCTIONS @@ -89,7 +89,7 @@ Detailed per-element guardrails live in scoped rule files that Gemini CLI does n - `se.deversity.asynctest.AsyncTestContext` → `.gemini/rules/async-test-runtime-core.md` - `se.deversity.asynctest.AsyncTestListenerRegistry.Registration` → `.gemini/rules/async-test-public-api.md` - `se.deversity.asynctest.benchmark`: `BenchmarkComparator`, `BenchmarkRecorder` → `.gemini/rules/async-test-instrumentation.md` -- `se.deversity.asynctest.diagnostics`: `BlockingOnNonBlockingThreadDetector`, `CompletableFutureBlockingCallbackDetector`, `CompletableFutureCancellationPropagationDetector`, `CompletableFutureCombinatorMisuseDetector`, `CompletableFutureCompletionRaceDetector`, `CompletableFutureObtrudeDetector`, `ConfinedArenaThreadEscapeDetector`, `DaemonThreadHygieneDetector`, `DetectorDefaultSeverity`, `DetectorFeeds`, `DetectorTrust`, `FileChannelPositionRaceDetector`, `FinalFieldMutationDetector`, `FlowPublisherConcurrencyDetector`, `GradedFindings`, `HighContentionAtomicDetector`, `JdbcConnectionSharedDetector`, `LambdaLostUpdateDetector`, `LazyCollectionMisuseDetector`, `LazyConstantMisuseDetector`, `LockUpgradeDeadlockDetector`, `NonAtomicConcurrentMapUpdateDetector`, `NotifyWithoutMonitorDetector`, `PlatformThreadPerTaskDetector`, `ProcessStreamStarvationDetector`, `RecordMutableComponentLeakDetector`, `ScopeConfigurationMisuseDetector`, `ScopeJoinerMisuseDetector`, `ScopeResultEscapeDetector`, `SharedByteBufferDetector`, `SharedCharsetCoderDetector`, `SharedChecksumDetector`, `SharedDeflaterDetector`, `SharedIteratorDetector`, `SharedJsonMapperReconfigDetector`, `SharedKdfDetector`, `SharedMemorySegmentRaceDetector`, `SharedMessageDigestDetector`, `SharedSecureRandomDetector`, `SharedSplittableRandomDetector`, `SharedStatefulCryptoDetector`, `SiteCapture`, `SpuriousWakeupDetector`, `StaticInitDeadlockDetector`, `ThisEscapeDetector`, `ThreadLocalCacheDegradationDetector`, `ThreadLocalRandomMisuseDetector`, `TrustTier`, `TryLockMisuseDetector`, `VarHandleNonAtomicUpdateDetector`, `VirtualThreadMonitorSerializationDetector`, `VirtualThreadPoolingDetector`, `VirtualThreadResourceSaturationDetector`, `WeakHashMapSharedDetector` → `.gemini/rules/async-test-detectors.md` +- `se.deversity.asynctest.diagnostics`: `BlockingOnNonBlockingThreadDetector`, `CompletableFutureBlockingCallbackDetector`, `CompletableFutureCancellationPropagationDetector`, `CompletableFutureCombinatorMisuseDetector`, `CompletableFutureCompletionRaceDetector`, `CompletableFutureObtrudeDetector`, `ConfinedArenaThreadEscapeDetector`, `DaemonThreadHygieneDetector`, `DetectorDefaultSeverity`, `DetectorFeeds`, `DetectorTrust`, `FileChannelPositionRaceDetector`, `FinalFieldMutationDetector`, `FlowPublisherConcurrencyDetector`, `GradedFindings`, `HighContentionAtomicDetector`, `JdbcConnectionSharedDetector`, `KotlinMutexReentrancyDetector`, `LambdaLostUpdateDetector`, `LazyCollectionMisuseDetector`, `LazyConstantMisuseDetector`, `LockUpgradeDeadlockDetector`, `NonAtomicConcurrentMapUpdateDetector`, `NotifyWithoutMonitorDetector`, `PlatformThreadPerTaskDetector`, `ProcessStreamStarvationDetector`, `RecordMutableComponentLeakDetector`, `ScopeConfigurationMisuseDetector`, `ScopeJoinerMisuseDetector`, `ScopeResultEscapeDetector`, `SharedByteBufferDetector`, `SharedCharsetCoderDetector`, `SharedChecksumDetector`, `SharedDeflaterDetector`, `SharedIteratorDetector`, `SharedJsonMapperReconfigDetector`, `SharedKdfDetector`, `SharedMemorySegmentRaceDetector`, `SharedMessageDigestDetector`, `SharedSecureRandomDetector`, `SharedSplittableRandomDetector`, `SharedStatefulCryptoDetector`, `SiteCapture`, `SpuriousWakeupDetector`, `StaticInitDeadlockDetector`, `ThisEscapeDetector`, `ThreadLocalCacheDegradationDetector`, `ThreadLocalRandomMisuseDetector`, `TrustTier`, `TryLockMisuseDetector`, `VarHandleNonAtomicUpdateDetector`, `VirtualThreadMonitorSerializationDetector`, `VirtualThreadPoolingDetector`, `VirtualThreadResourceSaturationDetector`, `WeakHashMapSharedDetector` → `.gemini/rules/async-test-detectors.md` - `se.deversity.asynctest.diagnostics.SiteCapture.Site` → `.gemini/rules/async-test-detectors.md` - `se.deversity.asynctest.extension`: `AsyncTestExtension`, `AsyncTestInvocationInterceptor` → `.gemini/rules/async-test-runtime-core.md` - `se.deversity.asynctest.report`: `Formatter`, `JUnitXmlReportListener`, `JsonFormatter`, `JsonReportListener`, `MarkdownFormatter`, `SarifFormatter`, `Violation` → `.gemini/rules/async-test-public-api.md` diff --git a/README.md b/README.md index 0c4415cf1..e9d9a3740 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # @AsyncTest - Asynchronous Testing Library for Java -**JUnit 5 & 6 concurrency stress testing — one annotation, 148 detectors** +**JUnit 5 & 6 concurrency stress testing — one annotation, 149 detectors** [![Maven Central](https://img.shields.io/maven-central/v/se.deversity.async-test-lib/async-test-lib)](https://central.sonatype.com/artifact/se.deversity.async-test-lib/async-test-lib) [![Javadoc](https://img.shields.io/badge/javadoc-latest-blue)](https://pisberg.github.io/async-test-lib/api/latest/) @@ -31,10 +31,10 @@ ## Why async-test? - **One annotation** — `@AsyncTest` runs your test body on N threads × M rounds, collided on a `CyclicBarrier` so every round starts at the same instant. No executor boilerplate, no `CountDownLatch`, no `Thread.join` loops. -- **148 detectors** — deadlocks, race conditions, virtual-thread pinning, lifecycle bugs, misused JDK types and more; a bare `@AsyncTest` runs the 12 in `Preset.ESSENTIALS` and `detectAll = true` runs them all. See [Detectors](#detectors) for what feeds them. +- **149 detectors** — deadlocks, race conditions, virtual-thread pinning, lifecycle bugs, misused JDK types and more; a bare `@AsyncTest` runs the 12 in `Preset.ESSENTIALS` and `detectAll = true` runs them all. See [Detectors](#detectors) for what feeds them. - **JUnit native, 5 and 6** — a plain `@TestTemplate`: no JVM flags, no required configuration, and it works from Kotlin, Groovy, Scala and Clojure. Jupiter 5.9.3 through 6.1.2, verified per release ([compatibility table](docs/BUILDING.md#junit-compatibility), [language notes](docs/JVM_LANGUAGES.md)). - **Every finding says how far to trust it** — each detector carries a trust tier, so `failOn` can gate a merge on the measured end of the scale while everything else is still reported ([the tiers](docs/DETECTOR_CATALOG.md#trust-tiers), [Evidence](#evidence-what-has-been-measured-and-on-whose-code)). -- **Optional agent** — `async-test-agent` rewrites field accesses, collection and lock calls, shared JDK objects, coordination primitives, `Object.wait` and `notify`, `Thread.sleep`, `System.gc`, `Thread.start` and `Thread.setDaemon`, and the monitor of `synchronized (owner.field)`, with Byte Buddy, so **52 of them can see code you did not modify** instead of 4. Being able to see is not the same as firing: on 82 third-party subjects two of the 21 exposed at the time produced every finding, and the other nineteen were correctly silent because nothing in that corpus writes the idiom they model. Not needed for default use, and the core artifact does not depend on Byte Buddy ([docs/AGENT.md](docs/AGENT.md)). +- **Optional agent** — `async-test-agent` rewrites field accesses, collection and lock calls, shared JDK objects, coordination primitives, `Object.wait` and `notify`, `Thread.sleep`, `System.gc`, `Thread.start` and `Thread.setDaemon`, and the monitor of `synchronized (owner.field)`, with Byte Buddy, so **53 of them can see code you did not modify** instead of 4. Being able to see is not the same as firing: on 82 third-party subjects two of the 21 exposed at the time produced every finding, and the other nineteen were correctly silent because nothing in that corpus writes the idiom they model. Not needed for default use, and the core artifact does not depend on Byte Buddy ([docs/AGENT.md](docs/AGENT.md)). - **CI-ready out of the box** — JUnit XML, machine-readable JSON, SARIF, or plain `AssertionError` fail-gates, straight into GitHub Actions, Jenkins and GitLab CI.
@@ -97,8 +97,8 @@ only 21 of the 146 shipped when this was first measured could see anything at al those produced every finding in the corpus. Saying so is the difference between a measurement and a marketing number. Two more lanes exist for exactly that reason. One records what the body did, the way a user following `AsyncTestContext` would; the other attaches the agent and writes the bug next to its fix. Between -them 148 of the 148 detectors are paired with a case that must fire and a twin that must stay -silent, and a detector with no pair fails the build. 34 of those pairs are what let their detectors +them 149 of the 149 detectors are paired with a case that must fire and a twin that must stay +silent, and a detector with no pair fails the build. 35 of those pairs are what let their detectors carry `VERDICT`, the tier a build can fail on; a pair alone is not enough, because the detector must also decide from something other than the test's own record call. HikariCP joins the corpus as an eighth library @@ -110,7 +110,7 @@ above, and the correct idioms the happens-before model does not see yet are list with the reason, so that a fix flips them visibly. The library agent pairs put the woven JDK call inside Guava, Jackson, HikariCP, Spring, commons-lang3 -or Groovy instead of the test file, so 19 of the 48 agent-fed detectors are measured on a call site +or Groovy instead of the test file, so 19 of the 49 agent-fed detectors are measured on a call site nobody here compiled; `EXPLICIT_GC`, `COMPLETABLE_FUTURE_OBTRUDE_ABUSE`, `MISSED_SIGNAL`, `ABA_PROBLEM`, `SYNCHRONIZED_NON_FINAL`, `CONCURRENT_MAP_CHECK_THEN_ACT`, `EXECUTOR_SHUTDOWN`, `FUTURE_IGNORED`, the three `CompletableFuture` detectors, the two interrupt detectors and @@ -380,7 +380,7 @@ After the run, the **detector registry** analyses what was observed and reports ## Detectors -148 detectors. A bare `@AsyncTest` runs the curated `ESSENTIALS` preset; one flag turns on every detector, or cherry-pick: +149 detectors. A bare `@AsyncTest` runs the curated `ESSENTIALS` preset; one flag turns on every detector, or cherry-pick: ```java // The default: Preset.ESSENTIALS, 12 high-signal detectors diff --git a/async-test-agent/.claude/rules/se-deversity-asynctest-agent-AsyncTestAgent.md b/async-test-agent/.claude/rules/se-deversity-asynctest-agent-AsyncTestAgent.md index 55027e78c..23719d831 100644 --- a/async-test-agent/.claude/rules/se-deversity-asynctest-agent-AsyncTestAgent.md +++ b/async-test-agent/.claude/rules/se-deversity-asynctest-agent-AsyncTestAgent.md @@ -7,5 +7,5 @@ paths: ["**/AsyncTestAgent.java"] ## Core Functionality - **Sensitivity**: Critical -- **Note**: The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. +- **Note**: The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). KotlinMutexWeaver replaces a kotlinx.coroutines.sync.Mutex lock, unlock or tryLock call, or its static $default bridge, matched by owner, name and descriptor, with a static hook consuming the same stack and returning the same result, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. diff --git a/async-test-agent/CLAUDE.md b/async-test-agent/CLAUDE.md index 898ee6e0c..4cee83b6b 100644 --- a/async-test-agent/CLAUDE.md +++ b/async-test-agent/CLAUDE.md @@ -17,7 +17,7 @@ library is fine; one pointing at the agent is not. Critical - The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a <clinit> that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. + The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). KotlinMutexWeaver replaces a kotlinx.coroutines.sync.Mutex lock, unlock or tryLock call, or its static $default bridge, matched by owner, name and descriptor, with a static hook consuming the same stack and returning the same result, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a <clinit> that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar. diff --git a/async-test-agent/src/main/java/se/deversity/asynctest/agent/AsyncTestAgent.java b/async-test-agent/src/main/java/se/deversity/asynctest/agent/AsyncTestAgent.java index d318828f7..bf99b5155 100644 --- a/async-test-agent/src/main/java/se/deversity/asynctest/agent/AsyncTestAgent.java +++ b/async-test-agent/src/main/java/se/deversity/asynctest/agent/AsyncTestAgent.java @@ -92,7 +92,7 @@ */ @AICore( sensitivity = "Critical", - note = "The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar." + note = "The INSTALLED gate must stay at-most-once per JVM: every entry point (premain, agentmain, selfAttach) races on the same compareAndSet, and a second transformer would double-weave accesses and double-count every one. premain installs without retransformation because classes are woven as they load; agentmain must keep RETRANSFORMATION + disableClassFormatChanges(), which is only safe while no weaver adds a member, and there are four besides the Advice, which is a method-entry prologue. FieldAccessWeaver inserts a stack-neutral, branch-free call before each field instruction, a load of the monitor plus a call at the entry of a synchronized method and before each of its returns (#822), a DUP of the monitor, an ALOAD of the local the owner was loaded from, an LDC of the field and a call before a MONITORENTER whose monitor the four instructions before it read from an instance field (ALOAD, GETFIELD, DUP, ASTORE, with no label between, #793), a DUP plus call after a VarHandle reference getAndSet it does not substitute (the ownership take, #555), DUP2 and SWAP plus a call before a JCTools offer, and a DUP before plus DUP_X1 and SWAP plus a call after a JCTools poll (#664), a copy of owner and value plus a call before a volatile field store and after a volatile field load, with a DUP of the receiver before an instance load (#742), and replaces an int VarHandle, AtomicIntegerFieldUpdater, AtomicBoolean or AtomicInteger store, swap or value-returning release, or a reference-slot store or getAndSet on an AtomicReference, its updater, its array or an instance-field VarHandle, or an acquiring reference read, an AtomicReference get or getAcquire, an updater get, an AtomicReferenceArray get or getAcquire or a VarHandle getVolatile or getAcquire (the acquire of the store it returned, #741), or an AtomicStampedReference get, getReference, set, compareAndSet, weakCompareAndSet or attemptStamp (#817), or an AtomicInteger get or an AtomicLong get, store or compare-and-set (a get then set, #1157), with a static hook consuming the same stack and returning the same result, plus one POP where a VarHandle call site declared a void result and one CHECKCAST to the declared type after a VarHandle reference getAndSet or acquiring read (the spinlock, #554, #558, #658, #667; the ownership offer and take, #664). CollectionAccessWeaver replaces each call its tables list with a static hook consuming the same stack, and inserts only the monitor loads and the loop back-edge call its own rules describe. ThreadConstructionWeaver inserts a DUP plus a call after the constructor call of a new Thread(...), and an ALOAD 0 plus a call after a Thread subclass constructor's superclass call (#737). ConstructionWeaver inserts a call that consumes and returns the order argument before a LinkedHashMap(int, float, boolean) constructor call and a DUP or an ALOAD 0 plus a call after it (#807), a DUP plus a call after a new CompletableFuture() constructor call (#1054), and an ALOAD 0, an LDC of the class name and a call before each RETURN of a constructor and after a this(...) delegation (#791); it leaves alone a class in a named module that cannot read the library. InterruptHandlerWeaver inserts an LDC of the locations of a method's InterruptedException handlers that neither rethrow nor restore the flag, and a call, before the first instruction of a method that declares one, and leaves alone a class in a named module that cannot read the library. PersistenceHandleWeaver inserts, before a call whose owner is a JPA EntityManager or Hibernate Session by name, a stack-neutral copy of the receiver (DUP; SWAP, DUP_X1; or DUP2_X1, POP2, DUP_X2 for zero, one or two one-slot arguments) and a call, and leaves calls with more or wider arguments alone (#992). RunBlockingWeaver inserts, before a static call of kotlinx.coroutines.BuildersKt.runBlockingK, runBlocking or their $default bridges by name, one call of a ()V hook that takes and leaves nothing, in every woven class outside kotlinx.coroutines (#1007). KotlinMutexWeaver replaces a kotlinx.coroutines.sync.Mutex lock, unlock or tryLock call, or its static $default bridge, matched by owner, name and descriptor, with a static hook consuming the same stack and returning the same result, in every woven class outside kotlinx.coroutines (#1007). So frames stay valid and only maxStack grows (COMPUTE_MAXS, never COMPUTE_FRAMES, which would load classes from inside the agent). In every mode, install and the transformer open java.util.concurrent.locks, with fields=true also java.util.concurrent.atomic, and with collections=true also java.util and java.io (a synchronized wrapper's mutex, #996; a piped writer's sink, #994), to one module per woven loader and to nothing else: the module of the TelemetryRegistry copy that loader resolves, never the woven loader or its ancestors as such (UpdaterAccess, #659, #668, #855); the locks opening lets the library read a ReentrantLock owner at analysis. In every mode, a woven class in a named module gets a read edge to the library copy its loader resolves (UpdaterAccess.letRead, #862): the JVM's own edge for a transformed class reaches only the agent loader's unnamed module. The library resolves an updater bound before the attach by reading the JDK implementation from that copy (JdkUpdaterShapeCanaryTest pins the shape it reads), and the opening must fail silently like the rest of install. Nothing may throw out of premain — an exception there aborts JVM startup, which is why install() catches Throwable and releases the gate rather than propagating. Both modes use AgentBuilder.InitializationStrategy.NoOp: no weaver needs a loaded-type initializer, and Byte Buddy's default self-injection gave every class woven at load a that loads net.bytebuddy.dynamic.Nexus through the system class loader, whose lock virtual threads initializing classes at once contend on and pin (#984). The Premain-Class / Agent-Class manifest entries live in this module's jar, which is why attaching uses -javaagent:async-test-agent.jar." ) public final class AsyncTestAgent { @@ -553,6 +553,10 @@ private static List collectionSubstitutions() { // kotlinx.coroutines may not be on the agent's class path either. all.add(RunBlockingWeaver.of( Class.forName(CollectionAccessWeaver.concurrencyHooksClassName(), false, loader))); + // A Kotlin coroutine Mutex locked again by the coroutine holding it (#1007): matched + // by name and descriptor, for the same reason. + all.add(KotlinMutexWeaver.of( + Class.forName(CollectionAccessWeaver.concurrencyHooksClassName(), false, loader))); return all; } catch (ClassNotFoundException e) { throw new IllegalStateException( diff --git a/async-test-agent/src/main/java/se/deversity/asynctest/agent/KotlinMutexWeaver.java b/async-test-agent/src/main/java/se/deversity/asynctest/agent/KotlinMutexWeaver.java new file mode 100644 index 000000000..5749c279f --- /dev/null +++ b/async-test-agent/src/main/java/se/deversity/asynctest/agent/KotlinMutexWeaver.java @@ -0,0 +1,155 @@ +package se.deversity.asynctest.agent; + +import net.bytebuddy.asm.AsmVisitorWrapper; +import net.bytebuddy.description.field.FieldDescription; +import net.bytebuddy.description.field.FieldList; +import net.bytebuddy.description.method.MethodList; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.Implementation; +import net.bytebuddy.jar.asm.ClassVisitor; +import net.bytebuddy.jar.asm.ClassWriter; +import net.bytebuddy.jar.asm.MethodVisitor; +import net.bytebuddy.jar.asm.Opcodes; +import net.bytebuddy.jar.asm.Type; +import net.bytebuddy.pool.TypePool; +import org.jspecify.annotations.Nullable; + +import java.util.List; + +/** + * Hands each Kotlin coroutine {@code Mutex} lock, unlock and tryLock to the library, so a mutex + * locked again by the coroutine that holds it is reported (#1007). + * + *

{@code mutex.withLock(owner) { }} is inline, so its {@code lock} and {@code unlock} are + * compiled into the caller as {@code INVOKEINTERFACE kotlinx/coroutines/sync/Mutex.lock} and + * {@code unlock}; a bare {@code mutex.lock()}, {@code unlock()} or {@code tryLock()} compiles to + * the interface's static {@code $default} bridge. Each of the six is replaced by an + * {@code INVOKESTATIC} of a hook that takes the same stack, the Kotlin types written as + * {@code Object}, and returns the same result: the receiver and owner, the continuation for a lock, + * and for a bridge its mask and marker. The hook makes the original call through a handle, so no + * frame or stack depth changes. Neither {@code Mutex} nor the Kotlin types in its descriptors are on + * the agent's class path, so, as with {@link RunBlockingWeaver}, a call is matched by the owner, + * name and descriptor written at the call site; a descriptor from some other kotlinx is left alone + * rather than substituted by a hook that could not make it. + * + *

Only call sites in woven classes are seen, so the code that locks must be in the agent's + * {@code includes=}. kotlinx's own classes are never rewritten: its {@code withLock} is inlined into + * the caller, and its internal mutex use is not the caller's. + */ +final class KotlinMutexWeaver implements AsmVisitorWrapper { + + /** The interface a Kotlin {@code Mutex} call site names as its owner. */ + static final String OWNER = "kotlinx/coroutines/sync/Mutex"; + + private static final String OBJ = "Ljava/lang/Object;"; + private static final String MUTEX = "L" + OWNER + ";"; + private static final String CONTINUATION = "Lkotlin/coroutines/Continuation;"; + + /** One substituted call: what the call site says, and the hook it becomes. */ + record Row(int opcode, String name, String descriptor, String hook, String hookDescriptor, + List> hookParameters) { + } + + /** The six call shapes, as kotlinx 1.11 compiles them. */ + static final List ROWS = List.of( + new Row(Opcodes.INVOKEINTERFACE, "lock", "(" + OBJ + CONTINUATION + ")" + OBJ, + "kotlinMutexLock", "(" + OBJ + OBJ + OBJ + ")" + OBJ, + List.of(Object.class, Object.class, Object.class)), + new Row(Opcodes.INVOKESTATIC, "lock$default", "(" + MUTEX + OBJ + CONTINUATION + "I" + OBJ + ")" + OBJ, + "kotlinMutexLockDefault", "(" + OBJ + OBJ + OBJ + "I" + OBJ + ")" + OBJ, + List.of(Object.class, Object.class, Object.class, int.class, Object.class)), + new Row(Opcodes.INVOKEINTERFACE, "unlock", "(" + OBJ + ")V", + "kotlinMutexUnlock", "(" + OBJ + OBJ + ")V", + List.of(Object.class, Object.class)), + new Row(Opcodes.INVOKESTATIC, "unlock$default", "(" + MUTEX + OBJ + "I" + OBJ + ")V", + "kotlinMutexUnlockDefault", "(" + OBJ + OBJ + "I" + OBJ + ")V", + List.of(Object.class, Object.class, int.class, Object.class)), + new Row(Opcodes.INVOKEINTERFACE, "tryLock", "(" + OBJ + ")Z", + "kotlinMutexTryLock", "(" + OBJ + OBJ + ")Z", + List.of(Object.class, Object.class)), + new Row(Opcodes.INVOKESTATIC, "tryLock$default", "(" + MUTEX + OBJ + "I" + OBJ + ")Z", + "kotlinMutexTryLockDefault", "(" + OBJ + OBJ + "I" + OBJ + ")Z", + List.of(Object.class, Object.class, int.class, Object.class))); + + private final String hookOwner; + + private KotlinMutexWeaver(String hookOwner) { + this.hookOwner = hookOwner; + } + + /** + * {@return the weaver, calling the hooks on {@code hooks}} + * + * @param hooks the class holding the hooks, resolved in the weaving class loader; one missing + * any of them is a version skew between agent and library, refused here rather + * than woven into a call that would fail inside user code + */ + static KotlinMutexWeaver of(Class hooks) { + for (Row row : ROWS) { + try { + hooks.getMethod(row.hook(), row.hookParameters().toArray(Class[]::new)); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("no Mutex hook " + row.hook() + " on " + hooks.getName() + + "; agent and library versions disagree", e); + } + } + return new KotlinMutexWeaver(Type.getInternalName(hooks)); + } + + /** {@return the row a call site matches, or {@code null} for any other call} */ + static @Nullable Row match(int opcode, String owner, String name, String descriptor) { + if (!OWNER.equals(owner)) { + return null; + } + for (Row row : ROWS) { + if (row.opcode() == opcode && row.name().equals(name) && row.descriptor().equals(descriptor)) { + return row; + } + } + return null; + } + + @Override + public int mergeWriter(int flags) { + return flags | ClassWriter.COMPUTE_MAXS; + } + + @Override + public int mergeReader(int flags) { + return flags; + } + + @Override + public ClassVisitor wrap(TypeDescription instrumentedType, + ClassVisitor classVisitor, + Implementation.Context implementationContext, + TypePool typePool, + FieldList fields, + MethodList methods, + int writerFlags, + int readerFlags) { + if (instrumentedType.getName().startsWith(RunBlockingWeaver.KOTLINX_PACKAGE)) { + return classVisitor; + } + return new ClassVisitor(Opcodes.ASM9, classVisitor) { + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, + String signature, String[] exceptions) { + MethodVisitor delegate = super.visitMethod(access, name, descriptor, signature, exceptions); + return new MethodVisitor(Opcodes.ASM9, delegate) { + @Override + public void visitMethodInsn(int opcode, String owner, String method, String desc, + boolean isInterface) { + Row row = match(opcode, owner, method, desc); + if (row != null) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, hookOwner, row.hook(), + row.hookDescriptor(), false); + } else { + super.visitMethodInsn(opcode, owner, method, desc, isInterface); + } + } + }; + } + }; + } +} diff --git a/async-test-agent/src/test/java/se/deversity/asynctest/agent/KotlinMutexWeaverTest.java b/async-test-agent/src/test/java/se/deversity/asynctest/agent/KotlinMutexWeaverTest.java new file mode 100644 index 000000000..e38f7b2a7 --- /dev/null +++ b/async-test-agent/src/test/java/se/deversity/asynctest/agent/KotlinMutexWeaverTest.java @@ -0,0 +1,80 @@ +package se.deversity.asynctest.agent; + +import net.bytebuddy.jar.asm.Opcodes; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Which call sites {@link KotlinMutexWeaver} substitutes (#1007). The descriptors are the ones Kotlin + * 2.4.21 compiles against kotlinx 1.11.0, read with {@code javap} from the consumer fixture: an + * inlined {@code withLock} calls {@code lock} and {@code unlock} through the interface, and a bare + * {@code lock()}, {@code unlock()} or {@code tryLock()} the interface's static {@code $default} bridge. + */ +class KotlinMutexWeaverTest { + + private static final String MUTEX = "kotlinx/coroutines/sync/Mutex"; + + @Test + @DisplayName("each compiled lock, unlock and tryLock form is matched to its hook") + void everyCompiledFormIsMatched() { + assertEquals("kotlinMutexLock", hook(Opcodes.INVOKEINTERFACE, "lock", + "(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;")); + assertEquals("kotlinMutexLockDefault", hook(Opcodes.INVOKESTATIC, "lock$default", + "(Lkotlinx/coroutines/sync/Mutex;Ljava/lang/Object;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;")); + assertEquals("kotlinMutexUnlock", hook(Opcodes.INVOKEINTERFACE, "unlock", "(Ljava/lang/Object;)V")); + assertEquals("kotlinMutexUnlockDefault", hook(Opcodes.INVOKESTATIC, "unlock$default", + "(Lkotlinx/coroutines/sync/Mutex;Ljava/lang/Object;ILjava/lang/Object;)V")); + assertEquals("kotlinMutexTryLock", hook(Opcodes.INVOKEINTERFACE, "tryLock", "(Ljava/lang/Object;)Z")); + assertEquals("kotlinMutexTryLockDefault", hook(Opcodes.INVOKESTATIC, "tryLock$default", + "(Lkotlinx/coroutines/sync/Mutex;Ljava/lang/Object;ILjava/lang/Object;)Z")); + } + + @Test + @DisplayName("a hook takes the call site's stack with each Kotlin type as Object, and returns its result") + void hookDescriptorsKeepTheStack() { + for (KotlinMutexWeaver.Row row : KotlinMutexWeaver.ROWS) { + String site = row.descriptor() + .replace("Lkotlinx/coroutines/sync/Mutex;", "Ljava/lang/Object;") + .replace("Lkotlin/coroutines/Continuation;", "Ljava/lang/Object;"); + // An interface call's receiver becomes the hook's first argument. + String expected = row.opcode() == Opcodes.INVOKEINTERFACE + ? "(Ljava/lang/Object;" + site.substring(1) : site; + assertEquals(expected, row.hookDescriptor(), row.name()); + assertEquals(net.bytebuddy.jar.asm.Type.getArgumentTypes(row.hookDescriptor()).length, + row.hookParameters().size(), row.name()); + } + } + + @Test + @DisplayName("another owner, opcode or descriptor is left alone") + void othersAreNotMatched() { + assertNull(KotlinMutexWeaver.match(Opcodes.INVOKEINTERFACE, "kotlinx/coroutines/sync/Semaphore", + "release", "()V")); + assertNull(KotlinMutexWeaver.match(Opcodes.INVOKEINTERFACE, MUTEX, "isLocked", "()Z")); + assertNull(KotlinMutexWeaver.match(Opcodes.INVOKEINTERFACE, MUTEX, "holdsLock", "(Ljava/lang/Object;)Z")); + assertNull(KotlinMutexWeaver.match(Opcodes.INVOKEVIRTUAL, MUTEX, "unlock", "(Ljava/lang/Object;)V")); + assertNull(KotlinMutexWeaver.match(Opcodes.INVOKEINTERFACE, MUTEX, "unlock", "(Ljava/lang/String;)V"), + "a descriptor from another kotlinx is not substituted by a hook that could not make it"); + assertNull(KotlinMutexWeaver.match(Opcodes.INVOKEVIRTUAL, "kotlinx/coroutines/sync/MutexImpl", "lock", + "(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;")); + } + + @Test + @DisplayName("a hooks class missing a hook is refused as a version skew") + void missingHooksAreRefused() { + IllegalStateException e = assertThrows(IllegalStateException.class, () -> KotlinMutexWeaver.of(Object.class)); + assertTrue(e.getMessage().contains("agent and library versions disagree"), e.getMessage()); + } + + private static String hook(int opcode, String name, String descriptor) { + KotlinMutexWeaver.Row row = KotlinMutexWeaver.match(opcode, MUTEX, name, descriptor); + assertNotNull(row, name + descriptor); + return row.hook(); + } +} diff --git a/async-test-lib/.claude/rules/async-test-detectors.md b/async-test-lib/.claude/rules/async-test-detectors.md index a6cf46d9e..2d096faa2 100644 --- a/async-test-lib/.claude/rules/async-test-detectors.md +++ b/async-test-lib/.claude/rules/async-test-detectors.md @@ -4,7 +4,7 @@ paths: ["**/diagnostics/**"] ## Conventions for every detector in this package -These hold for all 148 detectors and are therefore stated once here rather than restated as a +These hold for all 149 detectors and are therefore stated once here rather than restated as a per-class `@AITestDriven` annotation — one annotation per detector cost one `` line each in the always-loaded `` index of `CLAUDE.md`. @@ -75,6 +75,9 @@ a performance budget) are annotated individually and appear below. ### se.deversity.asynctest.diagnostics.JdbcConnectionSharedDetector - **Test Location**: src/test/java/se/deversity/asynctest/diagnostics/JdbcConnectionSharedDetectorTest.java +### se.deversity.asynctest.diagnostics.KotlinMutexReentrancyDetector +- **Test Location**: src/test/java/se/deversity/asynctest/diagnostics/KotlinMutexReentrancyDetectorTest.java + ### se.deversity.asynctest.diagnostics.LambdaLostUpdateDetector - **Test Location**: src/test/java/se/deversity/asynctest/diagnostics/LambdaLostUpdateDetectorTest.java @@ -234,6 +237,10 @@ a performance budget) are annotated individually and appear below. - **Strategy**: OTHER - **Note**: ConcurrentHashMap-backed JDBC-resource tracking; per-resource State holds ConcurrentHashMap.newKeySet() for accessing threads. +### se.deversity.asynctest.diagnostics.KotlinMutexReentrancyDetector +- **Strategy**: OTHER +- **Note**: Per-mutex state in the weakly keyed ConcurrentHashMap of AbstractInstanceDetector; the holdings are a ConcurrentLinkedDeque of weakly held Jobs, and a reentry writes its description before its count. + ### se.deversity.asynctest.diagnostics.LambdaLostUpdateDetector - **Strategy**: OTHER - **Note**: ConcurrentHashMap keyed on lambda identity plus captured name; events are appended to a copy-on-write list. The rule groups by observed pre-value and needs no ordering. holdsLock is sampled on the recording thread at record time, which is the only place it means anything. diff --git a/async-test-lib/CLAUDE.md b/async-test-lib/CLAUDE.md index 681666c99..f3e7f664d 100644 --- a/async-test-lib/CLAUDE.md +++ b/async-test-lib/CLAUDE.md @@ -1,6 +1,6 @@ # async-test-lib (module) -The library itself — annotations, config, the N×M runner, the JUnit extension, the 148 detectors, +The library itself — annotations, config, the N×M runner, the JUnit extension, the 149 detectors, the SPI and the reporting pipeline. This is the artifact consumers depend on. Guardrails below are generated by vibetags from this module's own annotations only. The reactor-root @@ -102,7 +102,7 @@ you are editing here. BenchmarkComparator, BenchmarkRecorder - BlockingOnNonBlockingThreadDetector, CompletableFutureBlockingCallbackDetector, CompletableFutureCancellationPropagationDetector, CompletableFutureCombinatorMisuseDetector, CompletableFutureCompletionRaceDetector, CompletableFutureObtrudeDetector, ConfinedArenaThreadEscapeDetector, DaemonThreadHygieneDetector, DetectorDefaultSeverity, DetectorFeeds, DetectorTrust, FileChannelPositionRaceDetector, FinalFieldMutationDetector, FlowPublisherConcurrencyDetector, GradedFindings, HighContentionAtomicDetector, JdbcConnectionSharedDetector, LambdaLostUpdateDetector, LazyCollectionMisuseDetector, LazyConstantMisuseDetector, LockUpgradeDeadlockDetector, NonAtomicConcurrentMapUpdateDetector, NotifyWithoutMonitorDetector, PlatformThreadPerTaskDetector, ProcessStreamStarvationDetector, RecordMutableComponentLeakDetector, ScopeConfigurationMisuseDetector, ScopeJoinerMisuseDetector, ScopeResultEscapeDetector, SharedByteBufferDetector, SharedCharsetCoderDetector, SharedChecksumDetector, SharedDeflaterDetector, SharedIteratorDetector, SharedJsonMapperReconfigDetector, SharedKdfDetector, SharedMemorySegmentRaceDetector, SharedMessageDigestDetector, SharedSecureRandomDetector, SharedSplittableRandomDetector, SharedStatefulCryptoDetector, SiteCapture, SpuriousWakeupDetector, StaticInitDeadlockDetector, ThisEscapeDetector, ThreadLocalCacheDegradationDetector, ThreadLocalRandomMisuseDetector, TrustTier, TryLockMisuseDetector, VarHandleNonAtomicUpdateDetector, VirtualThreadMonitorSerializationDetector, VirtualThreadPoolingDetector, VirtualThreadResourceSaturationDetector, WeakHashMapSharedDetector + BlockingOnNonBlockingThreadDetector, CompletableFutureBlockingCallbackDetector, CompletableFutureCancellationPropagationDetector, CompletableFutureCombinatorMisuseDetector, CompletableFutureCompletionRaceDetector, CompletableFutureObtrudeDetector, ConfinedArenaThreadEscapeDetector, DaemonThreadHygieneDetector, DetectorDefaultSeverity, DetectorFeeds, DetectorTrust, FileChannelPositionRaceDetector, FinalFieldMutationDetector, FlowPublisherConcurrencyDetector, GradedFindings, HighContentionAtomicDetector, JdbcConnectionSharedDetector, KotlinMutexReentrancyDetector, LambdaLostUpdateDetector, LazyCollectionMisuseDetector, LazyConstantMisuseDetector, LockUpgradeDeadlockDetector, NonAtomicConcurrentMapUpdateDetector, NotifyWithoutMonitorDetector, PlatformThreadPerTaskDetector, ProcessStreamStarvationDetector, RecordMutableComponentLeakDetector, ScopeConfigurationMisuseDetector, ScopeJoinerMisuseDetector, ScopeResultEscapeDetector, SharedByteBufferDetector, SharedCharsetCoderDetector, SharedChecksumDetector, SharedDeflaterDetector, SharedIteratorDetector, SharedJsonMapperReconfigDetector, SharedKdfDetector, SharedMemorySegmentRaceDetector, SharedMessageDigestDetector, SharedSecureRandomDetector, SharedSplittableRandomDetector, SharedStatefulCryptoDetector, SiteCapture, SpuriousWakeupDetector, StaticInitDeadlockDetector, ThisEscapeDetector, ThreadLocalCacheDegradationDetector, ThreadLocalRandomMisuseDetector, TrustTier, TryLockMisuseDetector, VarHandleNonAtomicUpdateDetector, VirtualThreadMonitorSerializationDetector, VirtualThreadPoolingDetector, VirtualThreadResourceSaturationDetector, WeakHashMapSharedDetector AsyncTestExtension, AsyncTestInvocationInterceptor Formatter, JUnitXmlReportListener, JsonFormatter, JsonReportListener, MarkdownFormatter, SarifFormatter, Violation diff --git a/async-test-lib/build.gradle.kts b/async-test-lib/build.gradle.kts index 848c04ea2..fc3f7e77a 100644 --- a/async-test-lib/build.gradle.kts +++ b/async-test-lib/build.gradle.kts @@ -44,7 +44,7 @@ mavenPublishing { ) pom { name = "Async Test Library" - description = "Enterprise-grade JUnit 5 concurrency testing library with 148 problem detectors " + + description = "Enterprise-grade JUnit 5 concurrency testing library with 149 problem detectors " + "for detecting deadlocks, visibility issues, false sharing, livelocks, and other subtle concurrency bugs." } } diff --git a/async-test-lib/pom.xml b/async-test-lib/pom.xml index 8264b4bf4..44dcd21b5 100644 --- a/async-test-lib/pom.xml +++ b/async-test-lib/pom.xml @@ -15,7 +15,7 @@ jar Async Test Library - Enterprise-grade JUnit 5 concurrency testing library with 148 problem detectors for detecting deadlocks, visibility issues, false sharing, livelocks, and other subtle concurrency bugs. + Enterprise-grade JUnit 5 concurrency testing library with 149 problem detectors for detecting deadlocks, visibility issues, false sharing, livelocks, and other subtle concurrency bugs. diff --git a/async-test-lib/src/main/java/se/deversity/asynctest/AgentConcurrencyUtilHooks.java b/async-test-lib/src/main/java/se/deversity/asynctest/AgentConcurrencyUtilHooks.java index bc1120a2f..b77790db0 100644 --- a/async-test-lib/src/main/java/se/deversity/asynctest/AgentConcurrencyUtilHooks.java +++ b/async-test-lib/src/main/java/se/deversity/asynctest/AgentConcurrencyUtilHooks.java @@ -3112,6 +3112,158 @@ public static void runBlockingEntered() { } } + /** + * Weaves {@code kotlinx.coroutines.sync.Mutex.lock(owner, continuation)}, the call + * {@code mutex.withLock(owner) { }} and {@code mutex.lock(owner)} compile to (#1007). Around the + * lock, {@code KotlinMutexReentrancyDetector} learns who holds the mutex and hears a lock that + * waits for its own coroutine. + * + *

While a run hears it, a call with no owner is made with a fresh owner token instead, so the + * mutex itself can later say whether this lock still holds it (#1221). kotlinx compares owners + * by identity and the token matches nothing else, so the lock, an {@code unlock(null)} and a + * {@code tryLock} behave exactly as with no owner. The caller's {@code Job} is recorded with the + * owner, and a call that waits while the caller, or a coroutine suspended until the caller's + * {@code withContext}, {@code coroutineScope} or {@code withTimeout} block completes, holds the + * mutex is the finding: that wait ends only with an unlock the waiting coroutine itself has to + * make. The Kotlin types in the real descriptor are not on the library's class path, so the + * hook takes {@code Object}s and calls through a handle bound to the receiver's own kotlinx. + * + * @param mutex the receiver + * @param owner the owner token, or {@code null} + * @param continuation the calling coroutine's continuation + * @return what {@code lock} returned: {@code Unit}, or {@code COROUTINE_SUSPENDED} + * @since 1.14.1 + */ + public static Object kotlinMutexLock(Object mutex, Object owner, Object continuation) { + ControlledSchedule.point(); + KotlinMutexes.Binding binding = KotlinMutexes.of(mutex); + KotlinMutexes.LockWatch watch = KotlinMutexes.LockWatch.before( + AsyncTestContext.currentKotlinMutexReentrancyDetector(), mutex, owner, continuation, binding); + Object result; + try { + result = binding.lock.invokeExact(mutex, watch == null ? owner : watch.owner, continuation); + } catch (Throwable t) { + KotlinMutexes.LockWatch.threw(watch); + throw KotlinMutexes.rethrow(t); + } + KotlinMutexes.LockWatch.returned(watch, result); + return result; + } + + /** + * Weaves {@code Mutex.lock$default}, the call a bare {@code mutex.lock()} compiles to, as + * {@link #kotlinMutexLock}. The bridge only fills in the defaulted owner, {@code null}, and calls + * {@code lock}, so while a run hears the call it is made as {@code lock} directly, with the owner + * token; otherwise the bridge is called unchanged. + * + * @param mutex the receiver + * @param owner the owner token as passed, ignored by kotlinx where {@code mask} omits it + * @param continuation the calling coroutine's continuation + * @param mask which parameters the call site left to their defaults + * @param marker always {@code null} from a compiled call site + * @return what {@code lock} returned + * @since 1.14.1 + */ + public static Object kotlinMutexLockDefault(Object mutex, Object owner, Object continuation, int mask, + Object marker) { + ControlledSchedule.point(); + KotlinMutexes.Binding binding = KotlinMutexes.of(mutex); + // A non-null marker makes the bridge throw: that call goes through it untouched. + KotlinMutexes.LockWatch watch = marker != null ? null + : KotlinMutexes.LockWatch.before(AsyncTestContext.currentKotlinMutexReentrancyDetector(), + mutex, (mask & 1) != 0 ? null : owner, continuation, binding); + Object result; + try { + result = watch == null + ? binding.lockDefault.invokeExact(mutex, owner, continuation, mask, marker) + : binding.lock.invokeExact(mutex, watch.owner, continuation); + } catch (Throwable t) { + KotlinMutexes.LockWatch.threw(watch); + throw KotlinMutexes.rethrow(t); + } + KotlinMutexes.LockWatch.returned(watch, result); + return result; + } + + /** + * Weaves {@code Mutex.unlock(owner)}, a schedule point; the unlock is made unchanged. Nothing is + * recorded: whether a lock still holds the mutex is asked of the mutex itself, so an unlock the + * agent sees and one it does not end a hold alike (#1221). + * + * @param mutex the receiver + * @param owner the owner token, or {@code null} + * @since 1.14.1 + */ + public static void kotlinMutexUnlock(Object mutex, Object owner) { + ControlledSchedule.point(); + KotlinMutexes.Binding binding = KotlinMutexes.of(mutex); + try { + binding.unlock.invokeExact(mutex, owner); + } catch (Throwable t) { + throw KotlinMutexes.rethrow(t); + } + } + + /** + * Weaves {@code Mutex.unlock$default}, as {@link #kotlinMutexUnlock}. + * + * @param mutex the receiver + * @param owner the owner token as passed + * @param mask which parameters the call site left to their defaults + * @param marker always {@code null} from a compiled call site + * @since 1.14.1 + */ + public static void kotlinMutexUnlockDefault(Object mutex, Object owner, int mask, Object marker) { + ControlledSchedule.point(); + KotlinMutexes.Binding binding = KotlinMutexes.of(mutex); + try { + binding.unlockDefault.invokeExact(mutex, owner, mask, marker); + } catch (Throwable t) { + throw KotlinMutexes.rethrow(t); + } + } + + /** + * Weaves {@code Mutex.tryLock(owner)}, a schedule point; the call is made unchanged. A + * {@code tryLock} has no continuation, so the coroutine that took the mutex cannot be named and + * nothing is recorded; a lock taken here holds no token of the agent's, so no lock is judged + * against it. + * + * @param mutex the receiver + * @param owner the owner token, or {@code null} + * @return whether the mutex was taken + * @since 1.14.1 + */ + public static boolean kotlinMutexTryLock(Object mutex, Object owner) { + ControlledSchedule.point(); + KotlinMutexes.Binding binding = KotlinMutexes.of(mutex); + try { + return (boolean) binding.tryLock.invokeExact(mutex, owner); + } catch (Throwable t) { + throw KotlinMutexes.rethrow(t); + } + } + + /** + * Weaves {@code Mutex.tryLock$default}, as {@link #kotlinMutexTryLock}. + * + * @param mutex the receiver + * @param owner the owner token as passed + * @param mask which parameters the call site left to their defaults + * @param marker always {@code null} from a compiled call site + * @return whether the mutex was taken + * @since 1.14.1 + */ + public static boolean kotlinMutexTryLockDefault(Object mutex, Object owner, int mask, Object marker) { + ControlledSchedule.point(); + KotlinMutexes.Binding binding = KotlinMutexes.of(mutex); + try { + return (boolean) binding.tryLockDefault.invokeExact(mutex, owner, mask, marker); + } catch (Throwable t) { + throw KotlinMutexes.rethrow(t); + } + } + /** {@link #blocking} for a get of {@code future}, managed when it is a {@code CompletableFuture}. */ private static void blockingOn(Future future) { if (future instanceof CompletableFuture) { diff --git a/async-test-lib/src/main/java/se/deversity/asynctest/AsyncTestConfig.java b/async-test-lib/src/main/java/se/deversity/asynctest/AsyncTestConfig.java index 4ab82f66e..670b97544 100644 --- a/async-test-lib/src/main/java/se/deversity/asynctest/AsyncTestConfig.java +++ b/async-test-lib/src/main/java/se/deversity/asynctest/AsyncTestConfig.java @@ -423,6 +423,8 @@ public final class AsyncTestConfig { public final boolean detectProcessStreamStarvation; /** Whether {@link DetectorType#BLOCKING_ON_NON_BLOCKING_THREAD} is enabled for this run. */ public final boolean detectBlockingOnNonBlockingThread; + /** Whether {@link DetectorType#KOTLIN_MUTEX_REENTRANCY} is enabled for this run. */ + public final boolean detectKotlinMutexReentrancy; // ---- Benchmarking ---- /** Resolved value of {@link AsyncTest#enableBenchmarking()} for this run. */ @@ -615,6 +617,7 @@ private AsyncTestConfig(Builder b, Set enabled) { detectLazyCollectionMisuse = enabled.contains(DetectorType.LAZY_COLLECTION_MISUSE); detectProcessStreamStarvation = enabled.contains(DetectorType.PROCESS_STREAM_STARVATION); detectBlockingOnNonBlockingThread = enabled.contains(DetectorType.BLOCKING_ON_NON_BLOCKING_THREAD); + detectKotlinMutexReentrancy = enabled.contains(DetectorType.KOTLIN_MUTEX_REENTRANCY); enableBenchmarking = b.enableBenchmarking; benchmarkRegressionThreshold = b.benchmarkRegressionThreshold; failOnBenchmarkRegression = b.failOnBenchmarkRegression; @@ -1771,6 +1774,12 @@ public Builder preset(Preset v) { * @return this builder */ public Builder detectBlockingOnNonBlockingThread(boolean v) { return flag(DetectorType.BLOCKING_ON_NON_BLOCKING_THREAD, v); } + /** + * Sets {@link AsyncTestConfig#detectKotlinMutexReentrancy}. + * @param v the value to use + * @return this builder + */ + public Builder detectKotlinMutexReentrancy(boolean v) { return flag(DetectorType.KOTLIN_MUTEX_REENTRANCY, v); } /** * Sets {@link AsyncTestConfig#enableBenchmarking}. * @param v the value to use diff --git a/async-test-lib/src/main/java/se/deversity/asynctest/AsyncTestContext.java b/async-test-lib/src/main/java/se/deversity/asynctest/AsyncTestContext.java index 35dd59c8f..3bcf5db30 100644 --- a/async-test-lib/src/main/java/se/deversity/asynctest/AsyncTestContext.java +++ b/async-test-lib/src/main/java/se/deversity/asynctest/AsyncTestContext.java @@ -155,6 +155,7 @@ import se.deversity.asynctest.diagnostics.LazyCollectionMisuseDetector; import se.deversity.asynctest.diagnostics.ProcessStreamStarvationDetector; import se.deversity.asynctest.diagnostics.BlockingOnNonBlockingThreadDetector; +import se.deversity.asynctest.diagnostics.KotlinMutexReentrancyDetector; import se.deversity.vibetags.annotations.AIAudit; import se.deversity.vibetags.annotations.AICallersOnly; import se.deversity.vibetags.annotations.AICore; @@ -436,6 +437,7 @@ public final class AsyncTestContext { final @Nullable LazyCollectionMisuseDetector lazyCollectionMisuseDetector; final @Nullable ProcessStreamStarvationDetector processStreamStarvationDetector; final @Nullable BlockingOnNonBlockingThreadDetector blockingOnNonBlockingThreadDetector; + final @Nullable KotlinMutexReentrancyDetector kotlinMutexReentrancyDetector; // ---- Agent-telemetry bridge target (1.7.0+) ---- // Exposed via atomicityValidator() so se.deversity.asynctest.telemetry.TelemetryBridge @@ -599,6 +601,7 @@ public AsyncTestContext(AsyncTestConfig cfg) { lazyCollectionMisuseDetector = registry.lazyCollectionMisuseDetector; processStreamStarvationDetector = registry.processStreamStarvationDetector; blockingOnNonBlockingThreadDetector = registry.blockingOnNonBlockingThreadDetector; + kotlinMutexReentrancyDetector = registry.kotlinMutexReentrancyDetector; // Agent-telemetry bridge target atomicityValidator = registry.atomicityValidator; @@ -2204,6 +2207,15 @@ public static SharedCollectionDetector sharedCollectionDetector() { return context == null ? null : context.blockingOnNonBlockingThreadDetector; } + /** + * {@return the {@link KotlinMutexReentrancyDetector} for the run the calling thread works for, + * or {@code null}}: every woven {@code Mutex} lock, unlock and tryLock records here (#1007). + */ + static @Nullable KotlinMutexReentrancyDetector currentKotlinMutexReentrancyDetector() { + AsyncTestContext context = agentContext(); + return context == null ? null : context.kotlinMutexReentrancyDetector; + } + /** * {@return the {@link SynchronizedCollectionIterationDetector} for the run the calling thread * works for, or {@code null}}: a woven {@code iterator()} or {@code stream()} on a synchronized @@ -3615,6 +3627,18 @@ public static BlockingOnNonBlockingThreadDetector blockingOnNonBlockingThreadDet return require(DetectorType.BLOCKING_ON_NON_BLOCKING_THREAD, c -> c.blockingOnNonBlockingThreadDetector); } + /** + * Returns the {@link KotlinMutexReentrancyDetector} for the current test. + * + * @throws IllegalStateException if not inside {@code @AsyncTest} or {@link DetectorType#KOTLIN_MUTEX_REENTRANCY} is not enabled + * @since 1.14.1 + * + * @return the {@link KotlinMutexReentrancyDetector} for the active {@code @AsyncTest} context + */ + public static KotlinMutexReentrancyDetector kotlinMutexReentrancyDetector() { + return require(DetectorType.KOTLIN_MUTEX_REENTRANCY, c -> c.kotlinMutexReentrancyDetector); + } + // ---- Phase 1 / Phase 3 detector accessors ---- // // These seven detectors are fed by the runner as well as by the test body, and for a diff --git a/async-test-lib/src/main/java/se/deversity/asynctest/DetectorRegistry.java b/async-test-lib/src/main/java/se/deversity/asynctest/DetectorRegistry.java index 351697e31..5138d3ddb 100644 --- a/async-test-lib/src/main/java/se/deversity/asynctest/DetectorRegistry.java +++ b/async-test-lib/src/main/java/se/deversity/asynctest/DetectorRegistry.java @@ -149,6 +149,7 @@ import se.deversity.asynctest.diagnostics.LazyCollectionMisuseDetector; import se.deversity.asynctest.diagnostics.ProcessStreamStarvationDetector; import se.deversity.asynctest.diagnostics.BlockingOnNonBlockingThreadDetector; +import se.deversity.asynctest.diagnostics.KotlinMutexReentrancyDetector; import se.deversity.vibetags.annotations.AIContext; import se.deversity.vibetags.annotations.AIThreadSafe; @@ -372,6 +373,7 @@ final class DetectorRegistry { final @Nullable LazyCollectionMisuseDetector lazyCollectionMisuseDetector; final @Nullable ProcessStreamStarvationDetector processStreamStarvationDetector; final @Nullable BlockingOnNonBlockingThreadDetector blockingOnNonBlockingThreadDetector; + final @Nullable KotlinMutexReentrancyDetector kotlinMutexReentrancyDetector; /** The run's selection, read by {@link #create} while the constructor runs. */ private final Set enabled; @@ -603,6 +605,7 @@ final class DetectorRegistry { lazyCollectionMisuseDetector = create(DetectorType.LAZY_COLLECTION_MISUSE, LazyCollectionMisuseDetector::new); processStreamStarvationDetector = create(DetectorType.PROCESS_STREAM_STARVATION, ProcessStreamStarvationDetector::new); blockingOnNonBlockingThreadDetector = create(DetectorType.BLOCKING_ON_NON_BLOCKING_THREAD, BlockingOnNonBlockingThreadDetector::new); + kotlinMutexReentrancyDetector = create(DetectorType.KOTLIN_MUTEX_REENTRANCY, KotlinMutexReentrancyDetector::new); } /** @@ -1168,6 +1171,9 @@ Map analyzeAllNamed() { ifIssue(blockingOnNonBlockingThreadDetector, BlockingOnNonBlockingThreadDetector::analyze, BlockingOnNonBlockingThreadDetector.Report::hasIssues, out); + ifIssue(kotlinMutexReentrancyDetector, + KotlinMutexReentrancyDetector::analyze, + KotlinMutexReentrancyDetector.Report::hasIssues, out); lastGrades = out.grades(); lastSeverities = out.severities(); diff --git a/async-test-lib/src/main/java/se/deversity/asynctest/DetectorType.java b/async-test-lib/src/main/java/se/deversity/asynctest/DetectorType.java index 721becf0f..07510b5b2 100644 --- a/async-test-lib/src/main/java/se/deversity/asynctest/DetectorType.java +++ b/async-test-lib/src/main/java/se/deversity/asynctest/DetectorType.java @@ -376,5 +376,7 @@ public enum DetectorType { /** Detects Process.waitFor() on a child whose stdout or stderr is a pipe no other thread drains - the child blocks once the pipe fills, and the wait never returns. */ PROCESS_STREAM_STARVATION, /** Detects a blocking call (a sleep, a join or get of a pending future, a latch await, a take) on a thread that must not block: a Reactor non-blocking scheduler thread, a Netty or Vert.x event loop, or a Kotlin Dispatchers.Default worker. */ - BLOCKING_ON_NON_BLOCKING_THREAD + BLOCKING_ON_NON_BLOCKING_THREAD, + /** Detects a Kotlin coroutine Mutex locked again by the coroutine that holds it, directly or from a withContext, coroutineScope or withTimeout block it waits for - kotlinx Mutex is not reentrant, so the coroutine hangs. */ + KOTLIN_MUTEX_REENTRANCY } diff --git a/async-test-lib/src/main/java/se/deversity/asynctest/KotlinMutexes.java b/async-test-lib/src/main/java/se/deversity/asynctest/KotlinMutexes.java new file mode 100644 index 000000000..dcd56508b --- /dev/null +++ b/async-test-lib/src/main/java/se/deversity/asynctest/KotlinMutexes.java @@ -0,0 +1,344 @@ +package se.deversity.asynctest; + +import org.jspecify.annotations.Nullable; +import se.deversity.asynctest.diagnostics.KotlinMutexReentrancyDetector; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +/** + * Calls kotlinx {@code Mutex} and reads the calling coroutine's {@code Job} for the woven + * {@code Mutex} hooks (#1007), without the library depending on Kotlin. + * + *

Every type is resolved by name through the class loader of the {@code Mutex} interface the + * receiver implements, found on the receiver's own class, so it is the kotlinx the call site + * linked against. The weaver substitutes a call only where the call site's descriptor is the one + * bound here, so the call-through handles always resolve; the {@code Job} and {@code holdsLock} + * handles are best effort, and without them a call is made unchanged and nothing is recorded. + */ +final class KotlinMutexes { + + static final String MUTEX = "kotlinx.coroutines.sync.Mutex"; + private static final String CONTINUATION = "kotlin.coroutines.Continuation"; + private static final String CONTEXT = "kotlin.coroutines.CoroutineContext"; + private static final String KEY = "kotlin.coroutines.CoroutineContext$Key"; + private static final String ELEMENT = "kotlin.coroutines.CoroutineContext$Element"; + private static final String JOB = "kotlinx.coroutines.Job"; + private static final String SCOPE_COROUTINE = "kotlinx.coroutines.internal.ScopeCoroutine"; + private static final String SUSPENDED_TYPE = "kotlin.coroutines.intrinsics.CoroutineSingletons"; + + /** Scopes followed outward from the caller before giving up; far beyond any real nesting. */ + private static final int MAX_DEPTH = 64; + + private static final ClassValue BINDINGS = new ClassValue<>() { + @Override + protected Binding computeValue(Class type) { + return bind(type); + } + }; + + private KotlinMutexes() { + } + + /** The handles for one {@code Mutex} implementation class. */ + static final class Binding { + /** {@code Mutex.lock(Object, Continuation)}, as {@code (Object, Object, Object)Object}. */ + final MethodHandle lock; + /** {@code Mutex.lock$default}, as {@code (Object, Object, Object, int, Object)Object}. */ + final MethodHandle lockDefault; + /** {@code Mutex.unlock(Object)}, as {@code (Object, Object)void}. */ + final MethodHandle unlock; + /** {@code Mutex.unlock$default}, as {@code (Object, Object, int, Object)void}. */ + final MethodHandle unlockDefault; + /** {@code Mutex.tryLock(Object)}, as {@code (Object, Object)boolean}. */ + final MethodHandle tryLock; + /** {@code Mutex.tryLock$default}, as {@code (Object, Object, int, Object)boolean}. */ + final MethodHandle tryLockDefault; + /** {@code Mutex.holdsLock(Object)}, as {@code (Object, Object)boolean}; {@code null} where absent. */ + final @Nullable MethodHandle holdsLock; + /** Reads a continuation's {@code Job}, or {@code null} where kotlinx could not be read. */ + final @Nullable JobReader jobs; + + Binding(MethodHandle lock, MethodHandle lockDefault, MethodHandle unlock, + MethodHandle unlockDefault, MethodHandle tryLock, MethodHandle tryLockDefault, + @Nullable MethodHandle holdsLock, @Nullable JobReader jobs) { + this.lock = lock; + this.lockDefault = lockDefault; + this.unlock = unlock; + this.unlockDefault = unlockDefault; + this.tryLock = tryLock; + this.tryLockDefault = tryLockDefault; + this.holdsLock = holdsLock; + this.jobs = jobs; + } + + /** {@return whether {@code token} holds {@code mutex}; false when the mutex cannot say} */ + boolean holds(Object mutex, Object token) { + MethodHandle handle = holdsLock; + if (handle == null) { + return false; + } + try { + return (boolean) handle.invokeExact(mutex, token); + } catch (Throwable unreadable) { // NOPMD - a mutex that cannot answer holds nothing for us + return false; + } + } + } + + /** + * The owner a woven {@code lock} passes when its caller passed none (#1221). kotlinx compares + * owners by identity, and a fresh one per call never matches another, so the lock behaves as + * with no owner: {@code unlock(null)} still releases it, and only {@code holdsLock} on this very + * object says {@code true}. It prints as {@code null}, as the absent owner it stands for does in + * the mutex's own {@code toString}. + */ + static final class OwnerToken { + @Override + public String toString() { + return "null"; + } + } + + /** Reads the {@code Job} of a continuation's context, and the parent of a scoped coroutine. */ + static final class JobReader { + private final MethodHandle context; + private final MethodHandle get; + private final Object jobKey; + private final @Nullable MethodHandle parent; + private final Class scopeCoroutine; + + JobReader(MethodHandle context, MethodHandle get, Object jobKey, @Nullable MethodHandle parent, + Class scopeCoroutine) { + this.context = context; + this.get = get; + this.jobKey = jobKey; + this.parent = parent; + this.scopeCoroutine = scopeCoroutine; + } + + /** + * {@return the caller's {@code Job}, then each coroutine suspended until the one before it + * completes, outward; empty when the continuation has no {@code Job}} + */ + List waiting(Object continuation) { + List chain = new ArrayList<>(4); + try { + Object job = get.invokeExact(context.invokeExact(continuation), jobKey); + while (job != null && chain.size() < MAX_DEPTH) { + chain.add(job); + // A withContext, coroutineScope, supervisorScope or withTimeout block runs as a + // ScopeCoroutine its parent is suspended for; a launch or async child is not one. + if (parent == null || !scopeCoroutine.isInstance(job)) { + break; + } + job = parent.invokeExact(job); + } + } catch (Throwable unreadable) { // NOPMD - a context kotlinx would not read records nothing + return chain; + } + return chain; + } + } + + /** + * What a woven {@code lock} knew before the call, for the detector once it returns: who holds + * the mutex, whether that is the caller or a coroutine waiting for it, and the owner the call + * is made with. + */ + static final class LockWatch { + private final KotlinMutexReentrancyDetector detector; + private final Object mutex; + private final List waiting; + private final int held; + /** The owner to make the lock with: the caller's own, or a fresh {@link OwnerToken}. */ + final Object owner; + + private LockWatch(KotlinMutexReentrancyDetector detector, Object mutex, List waiting, int held, + Object owner) { + this.detector = detector; + this.mutex = mutex; + this.waiting = waiting; + this.held = held; + this.owner = owner; + } + + /** + * {@return the watch for a lock about to be made with {@code owner}, or {@code null} when no + * run hears it or the mutex cannot say who holds it, and the call is then made unchanged} + * The hook passes the run's detector in, so the accessor call stays in the hook source, + * where {@code DetectorFeedCoverageTest} looks for it. + */ + static @Nullable LockWatch before(@Nullable KotlinMutexReentrancyDetector detector, Object mutex, + @Nullable Object owner, Object continuation, Binding binding) { + JobReader jobs = binding.jobs; + if (detector == null || jobs == null || binding.holdsLock == null) { + return null; + } + List waiting = jobs.waiting(continuation); + int held = detector.holderAmong(mutex, waiting, token -> binding.holds(mutex, token)); + return new LockWatch(detector, mutex, waiting, held, owner != null ? owner : new OwnerToken()); + } + + /** + * The lock returned. Either way the caller's {@code Job} is recorded with the owner it + * locked with: it holds the mutex now, or once its wait ends. Waiting while the caller or a + * coroutine suspended for it holds the mutex is the finding. + */ + static void returned(@Nullable LockWatch watch, @Nullable Object result) { + if (watch == null) { + return; + } + boolean waited = suspended(result); + if (waited) { + watch.reentryIfHeld(); + } + watch.detector.recordLocked(watch.mutex, watch.waiting.isEmpty() ? null : watch.waiting.get(0), + watch.owner, !waited); + } + + /** The lock threw: an owner token the holder already used makes kotlinx throw instead of wait. */ + static void threw(@Nullable LockWatch watch) { + if (watch != null) { + watch.reentryIfHeld(); + } + } + + private void reentryIfHeld() { + if (held >= 0) { + detector.recordReentry(mutex, names(waiting), held, Thread.currentThread()); + } + } + } + + /** {@return the binding for {@code mutex}'s class} */ + static Binding of(Object mutex) { + return BINDINGS.get(mutex.getClass()); + } + + /** {@return each coroutine's class simple name, in order} */ + static List names(List jobs) { + List names = new ArrayList<>(jobs.size()); + for (Object job : jobs) { + names.add(job.getClass().getSimpleName()); + } + return names; + } + + /** {@return whether a {@code lock} call returned {@code COROUTINE_SUSPENDED}: it did not take the mutex yet} */ + static boolean suspended(@Nullable Object result) { + return result instanceof Enum e && SUSPENDED_TYPE.equals(e.getDeclaringClass().getName()) + && "COROUTINE_SUSPENDED".equals(e.name()); + } + + /** + * Rethrows {@code t} unchanged, checked or not, as the substituted call would have; it never + * returns. The declared result lets a caller write {@code throw rethrow(t)} where the compiler + * needs the branch to end. + */ + @SuppressWarnings("unchecked") + static AssertionError rethrow(Throwable t) throws T { + throw (T) t; + } + + private static Binding bind(Class type) { + Class mutex = interfaceNamed(type, MUTEX); + if (mutex == null) { + throw new IllegalStateException(type.getName() + " does not implement " + MUTEX); + } + try { + ClassLoader loader = mutex.getClassLoader(); + Class continuation = Class.forName(CONTINUATION, false, loader); + MethodHandles.Lookup lookup = MethodHandles.publicLookup(); + MethodHandle lock = lookup.findVirtual(mutex, "lock", + MethodType.methodType(Object.class, Object.class, continuation)); + MethodHandle lockDefault = lookup.findStatic(mutex, "lock$default", + MethodType.methodType(Object.class, mutex, Object.class, continuation, int.class, Object.class)); + MethodHandle unlock = lookup.findVirtual(mutex, "unlock", + MethodType.methodType(void.class, Object.class)); + MethodHandle unlockDefault = lookup.findStatic(mutex, "unlock$default", + MethodType.methodType(void.class, mutex, Object.class, int.class, Object.class)); + MethodHandle tryLock = lookup.findVirtual(mutex, "tryLock", + MethodType.methodType(boolean.class, Object.class)); + MethodHandle tryLockDefault = lookup.findStatic(mutex, "tryLock$default", + MethodType.methodType(boolean.class, mutex, Object.class, int.class, Object.class)); + MethodHandle holdsLock = holdsLockOf(lookup, mutex); + return new Binding( + lock.asType(MethodType.genericMethodType(3)), + lockDefault.asType(MethodType.methodType(Object.class, + Object.class, Object.class, Object.class, int.class, Object.class)), + unlock.asType(MethodType.methodType(void.class, Object.class, Object.class)), + unlockDefault.asType(MethodType.methodType(void.class, + Object.class, Object.class, int.class, Object.class)), + tryLock.asType(MethodType.methodType(boolean.class, Object.class, Object.class)), + tryLockDefault.asType(MethodType.methodType(boolean.class, + Object.class, Object.class, int.class, Object.class)), + holdsLock, + jobReader(loader, continuation)); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("cannot bind " + MUTEX + " on " + type.getName(), e); + } + } + + private static @Nullable JobReader jobReader(@Nullable ClassLoader loader, Class continuation) { + try { + MethodHandles.Lookup lookup = MethodHandles.publicLookup(); + Class context = Class.forName(CONTEXT, false, loader); + Class key = Class.forName(KEY, false, loader); + Class element = Class.forName(ELEMENT, false, loader); + Class job = Class.forName(JOB, false, loader); + Class scope = Class.forName(SCOPE_COROUTINE, false, loader); + MethodHandle getContext = lookup.findVirtual(continuation, "getContext", MethodType.methodType(context)) + .asType(MethodType.genericMethodType(1)); + MethodHandle get = lookup.findVirtual(context, "get", MethodType.methodType(element, key)) + .asType(MethodType.genericMethodType(2)); + MethodHandle parent = parentOf(lookup, job); + Object jobKey = job.getField("Key").get(null); + return new JobReader(getContext, get, jobKey, parent, scope); + } catch (ReflectiveOperationException | LinkageError | RuntimeException e) { // NOPMD - unreadable records nothing + return null; + } + } + + /** {@return {@code Mutex.holdsLock(Object)}, or {@code null} on a kotlinx without it: nothing is then recorded} */ + private static @Nullable MethodHandle holdsLockOf(MethodHandles.Lookup lookup, Class mutex) + throws IllegalAccessException { + try { + return lookup.findVirtual(mutex, "holdsLock", MethodType.methodType(boolean.class, Object.class)) + .asType(MethodType.methodType(boolean.class, Object.class, Object.class)); + } catch (NoSuchMethodException olderKotlinx) { + return null; + } + } + + /** {@return {@code Job.getParent()}, or {@code null} on a kotlinx without it: the caller alone is then checked} */ + private static @Nullable MethodHandle parentOf(MethodHandles.Lookup lookup, Class job) + throws IllegalAccessException { + try { + return lookup.findVirtual(job, "getParent", MethodType.methodType(job)) + .asType(MethodType.genericMethodType(1)); + } catch (NoSuchMethodException olderKotlinx) { + return null; + } + } + + private static @Nullable Class interfaceNamed(Class type, String name) { + Deque> pending = new ArrayDeque<>(); + for (Class c = type; c != null; c = c.getSuperclass()) { + pending.addAll(List.of(c.getInterfaces())); + } + while (!pending.isEmpty()) { + Class candidate = pending.poll(); + if (name.equals(candidate.getName())) { + return candidate; + } + pending.addAll(List.of(candidate.getInterfaces())); + } + return null; + } +} diff --git a/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/DetectorFeeds.java b/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/DetectorFeeds.java index aeda7262d..0f39e743f 100644 --- a/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/DetectorFeeds.java +++ b/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/DetectorFeeds.java @@ -174,7 +174,10 @@ public final class DetectorFeeds { // The MDC at the start and end of each pooled task the woven submit hands over (#995). DetectorType.MDC_CONTEXT_LEAK, // Every woven blocking call, on a thread a framework made for not blocking (#991, #993). - DetectorType.BLOCKING_ON_NON_BLOCKING_THREAD); + DetectorType.BLOCKING_ON_NON_BLOCKING_THREAD, + // Every woven kotlinx Mutex lock, unlock and tryLock, matched by name, since kotlinx may + // not be on the agent's class path (#1007). + DetectorType.KOTLIN_MUTEX_REENTRANCY); /** * Fed by the JVM and the harness with no recording call. diff --git a/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/DetectorTrust.java b/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/DetectorTrust.java index 4cec7a7ed..6c2dc65d0 100644 --- a/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/DetectorTrust.java +++ b/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/DetectorTrust.java @@ -68,7 +68,7 @@ public final class DetectorTrust { /** Number of built-in detectors classified here; equals {@code DetectorType.values().length}. */ - public static final int DETECTOR_COUNT = 148; + public static final int DETECTOR_COUNT = 149; /** * One detector's classification. @@ -355,7 +355,8 @@ private static Classified row(DetectorType type, String detectorClass, String sp row(DetectorType.SCOPE_RESULT_ESCAPE, "ScopeResultEscapeDetector", "ScopeResultEscape", TrustTier.FACT, Evidence.ASSERTED), row(DetectorType.LAZY_COLLECTION_MISUSE, "LazyCollectionMisuseDetector", "LazyCollectionMisuse", TrustTier.PROMPT, Evidence.HEURISTIC), row(DetectorType.PROCESS_STREAM_STARVATION, "ProcessStreamStarvationDetector", "ProcessStreamStarvation", TrustTier.PROMPT, Evidence.ASSERTED), - row(DetectorType.BLOCKING_ON_NON_BLOCKING_THREAD, "BlockingOnNonBlockingThreadDetector", "BlockingOnNonBlockingThread", TrustTier.PROMPT, Evidence.OBSERVED) + row(DetectorType.BLOCKING_ON_NON_BLOCKING_THREAD, "BlockingOnNonBlockingThreadDetector", "BlockingOnNonBlockingThread", TrustTier.PROMPT, Evidence.OBSERVED), + row(DetectorType.KOTLIN_MUTEX_REENTRANCY, "KotlinMutexReentrancyDetector", "KotlinMutexReentrancy", TrustTier.VERDICT, Evidence.OBSERVED) ); private static final List ROWS = List.copyOf(TABLE.stream().map(Classified::row).toList()); diff --git a/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/KotlinMutexReentrancyDetector.java b/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/KotlinMutexReentrancyDetector.java new file mode 100644 index 000000000..f09246599 --- /dev/null +++ b/async-test-lib/src/main/java/se/deversity/asynctest/diagnostics/KotlinMutexReentrancyDetector.java @@ -0,0 +1,346 @@ +package se.deversity.asynctest.diagnostics; + +import org.jspecify.annotations.Nullable; +import se.deversity.asynctest.DetectorFailurePolicy; +import se.deversity.asynctest.report.Violation; +import se.deversity.vibetags.annotations.AITestDriven; +import se.deversity.vibetags.annotations.AIThreadSafe; + +import java.lang.ref.WeakReference; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Deque; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Predicate; + +/** + * Detects a Kotlin coroutine {@code Mutex} locked again by the coroutine that holds it (#1007). + * + *

{@code kotlinx.coroutines.sync.Mutex} is not reentrant, unlike {@code synchronized} or a + * {@code ReentrantLock}. A {@code lock()} by the coroutine that holds it suspends until the mutex is + * unlocked, which only that same coroutine can do, so it never resumes. The usual shape hides the + * second lock behind a scope: {@code mutex.withLock { withContext(Dispatchers.IO) { mutex.withLock { } } } }. + * The block of {@code withContext}, {@code coroutineScope}, {@code supervisorScope} or + * {@code withTimeout} runs as a child coroutine its caller suspends for, so the outer coroutine + * cannot unlock until the inner {@code lock()} returns, and that waits for the unlock. Nothing + * fails: the coroutine hangs, or a {@code withTimeout} around it cancels it and reports a timeout + * that says nothing about the mutex. + * + *

kotlinx records no holder unless the caller passes an {@code owner}, so the agent's + * {@code KotlinMutexWeaver} passes one: a woven {@code lock} called without an owner is made with a + * fresh token of the agent's own, and {@link #recordLocked} keeps it with the calling coroutine's + * {@code Job}, read from the call's continuation, whether the lock took the mutex at once or waits + * for it. Before a later woven {@code lock}, {@link #holderAmong(Object, List, Predicate)} asks the + * mutex, through {@code holdsLock}, whether one of those tokens holds it right now for the caller or + * a scope the caller's parent is suspended in. If one does and the lock waits, that is the finding + * ({@link #recordReentry}). The mutex itself answers, so an {@code unlock} the agent never saw + * cannot leave a holder behind (#1221), and a lock that waited holds its token once it is granted + * (#1220). + * + *

It errs toward silence. A coroutine that took the mutex through {@code tryLock} or + * {@code select}, or in a class the agent does not weave, holds no token of the agent's, so a + * reentrant lock under it is missed. A {@code launch} or {@code async} child is not counted as part + * of its parent: the parent may unlock without waiting for it, and the child then simply waits its + * turn. + * + *

The holder can also be recorded by hand, without kotlinx: {@link #recordAcquired} names it, + * {@link #recordHolderUnknown} forgets it, and {@link #holderAmong(Object, List)} finds it. + * + *

Usage inside {@code @AsyncTest(includes = DetectorType.KOTLIN_MUTEX_REENTRANCY)}: + *

{@code
+ * var d = AsyncTestContext.kotlinMutexReentrancyDetector();
+ * d.recordAcquired(mutex, outerJob);                                  // took it without waiting
+ * int held = d.holderAmong(mutex, List.of(innerJob, outerJob));      // 1: the outer job holds it
+ * d.recordReentry(mutex, List.of("DispatchedCoroutine", "BlockingCoroutine"), held, Thread.currentThread());
+ * }
+ * + * @since 1.14.1 + */ +@AIThreadSafe(strategy = AIThreadSafe.Strategy.OTHER, + note = "Per-mutex state in the weakly keyed ConcurrentHashMap of AbstractInstanceDetector; the " + + "holdings are a ConcurrentLinkedDeque of weakly held Jobs, and a reentry writes its " + + "description before its count.") +@AITestDriven( + framework = {AITestDriven.Framework.JUNIT_5}, + coverageGoal = 80, + testLocation = "src/test/java/se/deversity/asynctest/diagnostics/KotlinMutexReentrancyDetectorTest.java" +) +public final class KotlinMutexReentrancyDetector + extends AbstractInstanceDetector { + + private static final String REMEDY = "kotlinx Mutex is not reentrant: do not lock it again inside " + + "its own withLock, including through withContext, coroutineScope or withTimeout. Pass " + + "what the inner code needs in, or split out a function that assumes the lock is held."; + + /** + * Locks kept per mutex before the oldest is dropped. A token is dropped on its own once the + * mutex is seen to have let it go; this bounds the ones that never held it, the locks still + * waiting or cancelled while they waited. Dropping one only ever misses a finding. + */ + static final int MAX_HOLDINGS = 64; + + static final class MutexState { + final String label; + /** The locks that may hold the mutex, oldest first; at most one token holds it at a time. */ + final Deque holdings = new ConcurrentLinkedDeque<>(); + final AtomicInteger reentries = new AtomicInteger(); + volatile @Nullable String lastPath; + volatile @Nullable String lastThread; + + MutexState(String label) { + this.label = label; + } + } + + /** One coroutine's lock on a mutex. */ + static final class Holding { + final WeakReference job; + /** + * The owner the lock was made with, which the mutex can be asked about; {@code null} for a + * holder recorded by hand, which holds until {@link #recordHolderUnknown}. + */ + final @Nullable Object token; + /** Seen holding the mutex: once it no longer does, it never will again. */ + volatile boolean seenHolding; + + Holding(Object job, @Nullable Object token, boolean seenHolding) { + this.job = new WeakReference<>(job); + this.token = token; + this.seenHolding = seenHolding; + } + } + + @Override + MutexState newState(Object instance, String label) { + return new MutexState(label); + } + + /** + * Records that coroutine {@code job} called {@code lock(token)} on {@code mutex}: it holds the + * mutex while {@code mutex.holdsLock(token)} says so, now if the lock took it at once, or once + * the wait ends if it suspended. + * + * @param mutex the kotlinx {@code Mutex}, by identity; {@code null} records nothing + * @param job the {@code Job} of the coroutine that called it; {@code null} records nothing + * @param token the owner the lock was made with; {@code null} records nothing + * @param taken whether the lock took the mutex without waiting + * @since 1.14.2 + */ + @SuppressWarnings("ReferenceEquality") // a token is one lock call; identity, never equals + public void recordLocked(Object mutex, @Nullable Object job, @Nullable Object token, boolean taken) { + if (mutex == null || job == null || token == null) { + return; + } + MutexState state = stateFor(mutex, null, "Mutex"); + // An owner the caller passes may be reused: the newest lock made with it is the one to ask about. + state.holdings.removeIf(h -> h.token == token); // NOPMD CompareObjectsWithEquals - by identity + state.holdings.addLast(new Holding(job, token, taken)); + while (state.holdings.size() > MAX_HOLDINGS) { + state.holdings.pollFirst(); + } + } + + /** + * Records that coroutine {@code job} holds {@code mutex}, until the next + * {@link #recordHolderUnknown}. For recording by hand; the agent records through + * {@link #recordLocked}, which the mutex itself confirms. + * + * @param mutex the mutex, tracked by identity + * @param job the {@code Job} of the coroutine that took it, or {@code null} when it has none + */ + public void recordAcquired(Object mutex, @Nullable Object job) { + if (mutex == null) { + return; + } + if (job == null) { + recordHolderUnknown(mutex); + return; + } + MutexState state = stateFor(mutex, null, "Mutex"); + state.holdings.removeIf(h -> h.token == null); + state.holdings.addLast(new Holding(job, null, true)); + } + + /** + * Forgets the holder {@link #recordAcquired} named for {@code mutex}. Locks recorded through + * {@link #recordLocked} are unaffected: the mutex says whether they still hold it. + * + * @param mutex the mutex, by identity; {@code null} is ignored + */ + public void recordHolderUnknown(Object mutex) { + if (mutex == null) { + return; + } + MutexState state = trackedState(mutex); + if (state != null) { + state.holdings.removeIf(h -> h.token == null); + } + } + + /** + * {@return the index in {@code waiting} of the coroutine {@link #recordAcquired} named as holding + * {@code mutex}, or -1} + * + * @param mutex the mutex a {@code lock()} is about to wait for + * @param waiting the calling coroutine's {@code Job} first, then each scope it runs in that its + * parent is suspended for, outward + */ + public int holderAmong(Object mutex, List waiting) { + return holderAmong(mutex, waiting, null); + } + + /** + * {@return the index in {@code waiting} of the coroutine holding {@code mutex}, or -1} + * + *

A lock recorded through {@link #recordLocked} counts while {@code holds} says its token + * holds the mutex; one that held it and no longer does is dropped. A holder named through + * {@link #recordAcquired} counts until {@link #recordHolderUnknown}. + * + * @param mutex the mutex a {@code lock()} is about to wait for + * @param waiting the calling coroutine's {@code Job} first, then each scope it runs in that its + * parent is suspended for, outward + * @param holds asks the mutex whether a token holds it, as {@code Mutex.holdsLock}; {@code null} + * leaves every token out + * @since 1.14.2 + */ + @SuppressWarnings("ReferenceEquality") // a Job is one coroutine; identity, never equals + public int holderAmong(Object mutex, List waiting, @Nullable Predicate holds) { + if (mutex == null || waiting == null || waiting.isEmpty()) { + return -1; + } + MutexState state = trackedState(mutex); + if (state == null) { + return -1; + } + int found = -1; + for (Iterator it = state.holdings.iterator(); it.hasNext(); ) { + Holding h = it.next(); + Object job = h.job.get(); + if (job == null) { + it.remove(); + continue; + } + boolean holding; + if (h.token == null) { + holding = true; + } else if (holds == null) { + continue; + } else { + holding = holds.test(h.token); + if (holding) { + h.seenHolding = true; + } else if (h.seenHolding) { + it.remove(); + continue; + } + } + if (holding) { + for (int i = 0; i < waiting.size() && (found < 0 || i < found); i++) { + if (waiting.get(i) == job) { // NOPMD CompareObjectsWithEquals - a Job is one coroutine, by identity + found = i; + } + } + } + } + return found; + } + + /** + * Records a {@code lock()} that waits for a mutex its own coroutine, or a coroutine suspended + * until it completes, holds. + * + * @param mutex the kotlinx {@code Mutex} locked again, by identity; {@code null} records nothing + * @param path a name per coroutine, the caller first and then outward, as given to + * {@link #holderAmong} + * @param holderIndex the holder's index in {@code path}, as {@link #holderAmong} returned it + * @param thread the thread the {@code lock()} was called on + */ + public void recordReentry(Object mutex, List path, int holderIndex, Thread thread) { + if (mutex == null || path == null || thread == null || holderIndex < 0 || holderIndex >= path.size()) { + return; + } + MutexState state = stateFor(mutex, null, "Mutex"); + state.lastPath = describe(path, holderIndex); + state.lastThread = thread.getName(); + // The count last: analyze reads it first, so a count above zero has a description behind it. + state.reentries.incrementAndGet(); + } + + private static String describe(List path, int holderIndex) { + if (holderIndex == 0) { + return path.get(0) + " holds it and called lock() on it again"; + } + List inner = new ArrayList<>(path.subList(0, holderIndex)); + java.util.Collections.reverse(inner); + return path.get(holderIndex) + " holds it and is suspended until " + String.join(" -> ", inner) + + " completes, which called lock() on it"; + } + + /** + * Analyses what has been recorded about the observation and builds the report for it. + * + * @return the findings this detector collected during the run + */ + public Report analyze() { + Report r = new Report(); + for (MutexState s : states()) { + int count = s.reentries.get(); + String path = s.lastPath; + String thread = s.lastThread; + if (count == 0 || path == null || thread == null) { + continue; + } + String msg = String.format( + "Mutex '%s' locked again inside the coroutine that holds it (%d time(s), last on thread '%s'): %s. " + + "The lock waits for an unlock only that coroutine can make, so neither resumes " + + "unless a timeout or cancellation ends the wait.", + s.label, count, thread, path); + r.violations.add(msg); + r.structuredViolations.add(new Violation( + "KotlinMutexReentrancy", + IssueSeverity.HIGH, + msg, + List.of(), + Map.of("mutex", s.label, "reentries", count, "path", path, "thread", thread), + Instant.now())); + } + return DetectorFailurePolicy.checkedReport(this, r); + } + + /** Clears every recorded mutex. */ + public void reset() { + clearStates(); + } + + /** What {@link #analyze()} found. */ + public static final class Report { + /** Findings as human-readable lines, for the text report. */ + public final List violations = new ArrayList<>(); + /** The same findings as {@link Violation} objects, for machine-readable reports. */ + public final List structuredViolations = new ArrayList<>(); + + /** + * {@return whether there are issues} + */ + public boolean hasIssues() { + return !violations.isEmpty(); + } + + @Override + public String toString() { + if (violations.isEmpty()) { + return "KOTLIN MUTEX REENTRANCY - clean"; + } + StringBuilder sb = new StringBuilder("KOTLIN MUTEX REENTRANCY DETECTED:\n"); + for (String v : violations) { + sb.append(" - ").append(v).append('\n'); + } + sb.append(" Fix: ").append(REMEDY).append('\n'); + return sb.toString(); + } + } +} diff --git a/async-test-lib/src/main/resources/META-INF/async-test/verdict-evidence-corpus b/async-test-lib/src/main/resources/META-INF/async-test/verdict-evidence-corpus index c1b30fbb5..dc44cc503 100644 --- a/async-test-lib/src/main/resources/META-INF/async-test/verdict-evidence-corpus +++ b/async-test-lib/src/main/resources/META-INF/async-test/verdict-evidence-corpus @@ -107,6 +107,7 @@ VOLATILE_ARRAY = recorded_volatileArray_elementsWrittenByEveryThread, recorded_v SYNCHRONIZED_NON_FINAL = recorded_synchronized_onAReassignableLock, recorded_synchronized_onAFinalLock THREAD_FACTORY = recorded_threadFactory_producedARawThread, recorded_threadFactory_producedAConfiguredThread SLEEP_IN_LOCK = agent_sleep_whileHoldingTheMonitor, agent_sleep_holdingNothing +KOTLIN_MUTEX_REENTRANCY = agent_kotlinMutex_lockedAgainByItsHolder, agent_kotlinMutex_unlockedBetweenLocks SHARED_FORMATTER = agent_formatter_oneInstanceForEveryThread, agent_formatter_oneInstancePerThread SHARED_MATCHER = agent_matcher_oneInstanceForEveryThread, agent_matcher_oneInstancePerThread SHARED_DECIMAL_FORMAT = agent_decimalFormat_oneInstanceForEveryThread, agent_decimalFormat_oneInstancePerThread diff --git a/async-test-lib/src/test/java/se/deversity/asynctest/architecture/DetectorConditionalInsertTest.java b/async-test-lib/src/test/java/se/deversity/asynctest/architecture/DetectorConditionalInsertTest.java index 8fc822e49..3a2418cdd 100644 --- a/async-test-lib/src/test/java/se/deversity/asynctest/architecture/DetectorConditionalInsertTest.java +++ b/async-test-lib/src/test/java/se/deversity/asynctest/architecture/DetectorConditionalInsertTest.java @@ -39,7 +39,7 @@ *

The window is one round wide in both cases: once the entry exists every later lookup is a * hit, so a single-shot test never reaches it and only a barrier-forced collision on a fresh * instance does. That makes this cheaper to enforce structurally than to test per detector, which - * is the point of doing it here rather than writing 148 concurrency tests. + * is the point of doing it here rather than writing 149 concurrency tests. * *

What this gate does not do. It recognises two concrete shapes, not * check-then-act in general. It reads source text rather than bytecode, because asm is confined to diff --git a/async-test-lib/src/test/java/se/deversity/asynctest/architecture/DetectorShapedClassesAreReachableTest.java b/async-test-lib/src/test/java/se/deversity/asynctest/architecture/DetectorShapedClassesAreReachableTest.java index 6ee7c6363..715a9dbfe 100644 --- a/async-test-lib/src/test/java/se/deversity/asynctest/architecture/DetectorShapedClassesAreReachableTest.java +++ b/async-test-lib/src/test/java/se/deversity/asynctest/architecture/DetectorShapedClassesAreReachableTest.java @@ -22,7 +22,7 @@ * *

The failure this prevents, measured rather than imagined. The package holds * 150 public classes whose names end in {@code Detector}, {@code Validator} or {@code Monitor}. - * 148 are a {@link se.deversity.asynctest.DetectorType}, are built by {@code DetectorRegistry}, + * 149 are a {@link se.deversity.asynctest.DetectorType}, are built by {@code DetectorRegistry}, * are analyzed on every run and can fail a test through {@code failOn}. The rest have the same * shape - a {@code record*} API and an {@code analyze()} returning a report with * {@code hasIssues()} - and the runner never calls {@code analyze()} on them. @@ -36,7 +36,7 @@ *

The existing coverage gates cannot catch this. {@code DetectorFeedCoverageTest}, * {@code DetectorTrustCoverageTest} and {@code DetectorCatalogCoverageTest} all iterate * {@code DetectorType.values()}, so a class with no {@code DetectorType} is invisible to every one - * of them: they check that each of the 148 is complete, not that nothing else is pretending to be + * of them: they check that each of the 149 is complete, not that nothing else is pretending to be * one. */ class DetectorShapedClassesAreReachableTest { diff --git a/async-test-lib/src/test/java/se/deversity/asynctest/diagnostics/KotlinMutexReentrancyDetectorTest.java b/async-test-lib/src/test/java/se/deversity/asynctest/diagnostics/KotlinMutexReentrancyDetectorTest.java new file mode 100644 index 000000000..bf3e868bc --- /dev/null +++ b/async-test-lib/src/test/java/se/deversity/asynctest/diagnostics/KotlinMutexReentrancyDetectorTest.java @@ -0,0 +1,259 @@ +package se.deversity.asynctest.diagnostics; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import se.deversity.asynctest.report.Violation; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for {@link KotlinMutexReentrancyDetector} (#1007). Mutexes and coroutine {@code Job}s + * are plain objects here: the detector compares them by identity and never calls them. The + * consumer fixture in {@code consumer-fixture-langs/kotlin} proves the woven calls against real + * kotlinx. + */ +class KotlinMutexReentrancyDetectorTest { + + private final Object mutex = new Object(); + private final Object outer = new Object(); + private final Object scope = new Object(); + + @Test + @DisplayName("nothing recorded is clean") + void cleanWhenNothingRecorded() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + KotlinMutexReentrancyDetector.Report report = d.analyze(); + assertFalse(report.hasIssues()); + assertTrue(report.structuredViolations.isEmpty()); + assertTrue(report.toString().contains("clean")); + } + + @Test + @DisplayName("the holder is found among the caller and the scopes waiting for it") + void holderIsFoundInTheWaitingChain() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.recordAcquired(mutex, outer); + assertEquals(1, d.holderAmong(mutex, List.of(scope, outer))); + assertEquals(0, d.holderAmong(mutex, List.of(outer))); + assertEquals(-1, d.holderAmong(mutex, List.of(scope))); + assertEquals(-1, d.holderAmong(new Object(), List.of(outer)), "another mutex has no holder"); + } + + @Test + @DisplayName("an unlock, or a take by an unnamed coroutine, forgets the holder") + void holderIsForgotten() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.recordAcquired(mutex, outer); + d.recordHolderUnknown(mutex); + assertEquals(-1, d.holderAmong(mutex, List.of(outer))); + + d.recordAcquired(mutex, outer); + d.recordAcquired(mutex, null); + assertEquals(-1, d.holderAmong(mutex, List.of(outer)), "a take with no Job leaves the holder unknown"); + } + + @Test + @DisplayName("a holder is compared by identity, not equals") + void holderIsComparedByIdentity() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.recordAcquired(mutex, "job"); + assertEquals(-1, d.holderAmong(mutex, List.of(new String("job")))); + } + + @Test + @DisplayName("a reentry through a scope is reported with its path, as a HIGH violation") + void reentryThroughAScopeIsReported() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.recordAcquired(mutex, outer); + int held = d.holderAmong(mutex, List.of(scope, outer)); + d.recordReentry(mutex, List.of("DispatchedCoroutine", "BlockingCoroutine"), held, Thread.currentThread()); + + KotlinMutexReentrancyDetector.Report report = d.analyze(); + assertTrue(report.hasIssues()); + assertEquals(1, report.structuredViolations.size()); + Violation v = report.structuredViolations.get(0); + assertEquals("KotlinMutexReentrancy", v.detector()); + assertEquals(IssueSeverity.HIGH, v.severity()); + assertTrue(v.message().contains("BlockingCoroutine holds it and is suspended until DispatchedCoroutine"), + v.message()); + assertEquals(1, v.attributes().get("reentries")); + assertTrue(report.toString().contains("not reentrant"), report.toString()); + } + + @Test + @DisplayName("the holder locking directly again is reported as such") + void directReentryIsReported() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.recordAcquired(mutex, outer); + d.recordReentry(mutex, List.of("StandaloneCoroutine"), d.holderAmong(mutex, List.of(outer)), + Thread.currentThread()); + d.recordReentry(mutex, List.of("StandaloneCoroutine"), 0, Thread.currentThread()); + + KotlinMutexReentrancyDetector.Report report = d.analyze(); + assertEquals(1, report.violations.size(), "one finding per mutex"); + assertTrue(report.violations.get(0).contains("StandaloneCoroutine holds it and called lock() on it again"), + report.violations.get(0)); + assertTrue(report.violations.get(0).contains("2 time(s)"), report.violations.get(0)); + } + + @Test + @DisplayName("a held mutex nobody locks again is not a finding") + void heldWithoutReentryIsClean() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.recordAcquired(mutex, outer); + assertFalse(d.analyze().hasIssues()); + } + + @Test + @DisplayName("null arguments and an index outside the path record nothing") + void invalidArgumentsAreIgnored() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.recordAcquired(null, outer); + d.recordHolderUnknown(null); + d.recordHolderUnknown(mutex); + d.recordReentry(null, List.of("A"), 0, Thread.currentThread()); + d.recordReentry(mutex, null, 0, Thread.currentThread()); + d.recordReentry(mutex, List.of("A"), 0, null); + d.recordReentry(mutex, List.of("A"), -1, Thread.currentThread()); + d.recordReentry(mutex, List.of("A"), 1, Thread.currentThread()); + assertEquals(-1, d.holderAmong(null, List.of(outer))); + assertEquals(-1, d.holderAmong(mutex, null)); + assertEquals(-1, d.holderAmong(mutex, List.of())); + assertFalse(d.analyze().hasIssues()); + } + + @Test + @DisplayName("reset forgets every mutex") + void resetClears() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.recordAcquired(mutex, outer); + d.recordReentry(mutex, List.of("A"), 0, Thread.currentThread()); + d.reset(); + assertFalse(d.analyze().hasIssues()); + assertEquals(-1, d.holderAmong(mutex, List.of(outer))); + } + + /** + * A mutex registered by a reentry still being recorded, its count not yet raised, is left out + * rather than reported half-written (the analyze-during-record shape of #1212). + */ + @Test + @DisplayName("a mutex registered but not yet counted is not reported") + void registeredButUncountedIsNotReported() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.stateFor(mutex, null, "Mutex").lastPath = "A holds it"; + assertFalse(d.analyze().hasIssues()); + } + + /** The detector releases a mutex the code under test dropped (#918). */ + @Test + void doesNotKeepARecordedSubjectAlive() throws InterruptedException { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + AbstractInstanceDetectorTest.assertNotRetained(Object::new, m -> d.recordAcquired(m, outer)); + } + + /** The detector releases a mutex whose locks it recorded with tokens, too. */ + @Test + void doesNotKeepALockedSubjectAlive() throws InterruptedException { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + AbstractInstanceDetectorTest.assertNotRetained(Object::new, m -> d.recordLocked(m, outer, new Object(), true)); + } + + /** + * The woven path: a lock's token holds the mutex only while the mutex says so. Here a set of + * tokens stands in for {@code Mutex.holdsLock}. + */ + @Test + @DisplayName("a locked token is the holder while the mutex says it holds") + void tokenHoldsWhileTheMutexSaysSo() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + Set holding = new HashSet<>(); + Object token = new Object(); + d.recordLocked(mutex, outer, token, true); + holding.add(token); + assertEquals(1, d.holderAmong(mutex, List.of(scope, outer), holding::contains)); + assertEquals(-1, d.holderAmong(mutex, List.of(scope, outer)), "a token is not a holder named by hand"); + assertEquals(-1, d.holderAmong(mutex, List.of(scope, outer), null), "no answer from the mutex, no holder"); + } + + /** #1221: an unlock the agent never saw cannot leave a holder behind. */ + @Test + @DisplayName("a token the mutex no longer holds is not the holder, and is dropped") + void tokenReleasedUnseenIsNotTheHolder() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + Set holding = new HashSet<>(); + Object token = new Object(); + d.recordLocked(mutex, outer, token, true); + // Unlocked where the agent could not see it, then taken by another coroutine that holds no token. + assertEquals(-1, d.holderAmong(mutex, List.of(outer), holding::contains)); + assertTrue(d.trackedState(mutex).holdings.isEmpty(), "a token that held and let go never holds again"); + } + + /** #1220: a lock that waited becomes the holder once the mutex is granted to it. */ + @Test + @DisplayName("a lock that waited holds once granted, and is kept while it waits") + void waitedLockHoldsOnceGranted() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + Set holding = new HashSet<>(); + Object token = new Object(); + d.recordLocked(mutex, outer, token, false); + assertEquals(-1, d.holderAmong(mutex, List.of(outer), holding::contains)); + assertEquals(1, d.trackedState(mutex).holdings.size(), "still waiting: it may yet be granted"); + + holding.add(token); + assertEquals(0, d.holderAmong(mutex, List.of(outer), holding::contains)); + + holding.remove(token); + assertEquals(-1, d.holderAmong(mutex, List.of(outer), holding::contains)); + assertTrue(d.trackedState(mutex).holdings.isEmpty(), "granted and released: dropped"); + } + + @Test + @DisplayName("an owner reused by its caller keeps only its newest lock, and the locks kept are capped") + void holdingsAreBounded() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + Object reused = new Object(); + d.recordLocked(mutex, outer, reused, false); + d.recordLocked(mutex, scope, reused, false); + assertEquals(1, d.trackedState(mutex).holdings.size()); + assertEquals(-1, d.holderAmong(mutex, List.of(outer), t -> t == reused), "the older lock was replaced"); + assertEquals(0, d.holderAmong(mutex, List.of(scope), t -> t == reused)); + + List jobs = new ArrayList<>(); + for (int i = 0; i < KotlinMutexReentrancyDetector.MAX_HOLDINGS + 10; i++) { + Object job = new Object(); + jobs.add(job); + d.recordLocked(mutex, job, new Object(), false); + } + assertEquals(KotlinMutexReentrancyDetector.MAX_HOLDINGS, d.trackedState(mutex).holdings.size()); + } + + @Test + @DisplayName("forgetting a holder named by hand leaves the locked tokens to the mutex") + void holderUnknownLeavesTokens() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + Object token = new Object(); + d.recordAcquired(mutex, scope); + d.recordLocked(mutex, outer, token, true); + d.recordHolderUnknown(mutex); + assertEquals(-1, d.holderAmong(mutex, List.of(scope))); + assertEquals(0, d.holderAmong(mutex, List.of(outer), t -> t == token)); + } + + @Test + @DisplayName("a lock with no mutex, Job or token records nothing") + void incompleteLocksAreIgnored() { + KotlinMutexReentrancyDetector d = new KotlinMutexReentrancyDetector(); + d.recordLocked(null, outer, new Object(), true); + d.recordLocked(mutex, null, new Object(), true); + d.recordLocked(mutex, outer, null, true); + assertEquals(null, d.trackedState(mutex)); + } +} diff --git a/async-test-lib/src/test/java/se/deversity/asynctest/diagnostics/StructuredViolationCoverageTest.java b/async-test-lib/src/test/java/se/deversity/asynctest/diagnostics/StructuredViolationCoverageTest.java index 0a0825d93..044ca847a 100644 --- a/async-test-lib/src/test/java/se/deversity/asynctest/diagnostics/StructuredViolationCoverageTest.java +++ b/async-test-lib/src/test/java/se/deversity/asynctest/diagnostics/StructuredViolationCoverageTest.java @@ -319,6 +319,15 @@ private interface Drive { new BlockingOnNonBlockingThreadDetectorTest.ReactorThread(() -> { })); return d.analyze(); }), + new Path("KotlinMutexReentrancyDetector", "Mutex locked again by its holder's scope", () -> { + var d = new KotlinMutexReentrancyDetector(); + Object mutex = new Object(); + Object holder = new Object(); + d.recordAcquired(mutex, holder); + d.recordReentry(mutex, List.of("DispatchedCoroutine", "BlockingCoroutine"), + d.holderAmong(mutex, List.of(new Object(), holder)), Thread.currentThread()); + return d.analyze(); + }), new Path("LockUpgradeDeadlockDetector", "write lock attempted under the read lock", () -> { var d = new LockUpgradeDeadlockDetector(); var lock = new ReentrantReadWriteLock(); diff --git a/consumer-fixture-langs/kotlin/src/test/kotlin/com/example/kotlinfixture/MutexBridges.kt b/consumer-fixture-langs/kotlin/src/test/kotlin/com/example/kotlinfixture/MutexBridges.kt new file mode 100644 index 000000000..677412fb6 --- /dev/null +++ b/consumer-fixture-langs/kotlin/src/test/kotlin/com/example/kotlinfixture/MutexBridges.kt @@ -0,0 +1,166 @@ +package com.example.kotlinfixture + +import com.example.unwoven.UnwovenMutex +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.supervisorScope +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeoutOrNull +import java.util.concurrent.Executors + +/** + * A coroutine `Mutex` locked again by the coroutine that holds it, and the shapes that only look + * like it (#1007). This package is in the agent's `includes=`, so each `lock`, `unlock` and + * `tryLock` here is woven, the ones `withLock` inlines included. + * + * kotlinx `Mutex` is not reentrant, so each misuse would hang for good; a `withTimeoutOrNull` + * around the inner lock ends the wait, and each returns whether the inner lock was ever taken. + * Each call makes its own mutex, so no two workers of a run contend on one and every outer lock is + * taken without waiting. + * + * Nothing here runs on `Dispatchers.Default`: a worker an earlier test class started belongs to that + * run, and a lock on it would be unseen by this one. The coroutines stay on the run's own thread, or + * move to an executor created and closed inside the call, whose thread the woven `execute` hands + * the run to. + */ +class MutexBridges { + + private val shared = Mutex() + private var counter = 0 + + /** The misuse through `withContext` on the same thread: the outer coroutine waits for the block, which waits for the outer unlock. */ + fun reenterThroughWithContext(): Boolean = runBlocking { + val mutex = Mutex() + mutex.withLock { + withTimeoutOrNull(TIMEOUT_MS) { + withContext(CoroutineName("inner")) { mutex.withLock { true } } + } ?: false + } + } + + /** + * The same misuse with the block moved to another thread, on a dispatcher of its own. A bare + * `ScheduledThreadPoolExecutor`, as in [RunBlockingBridges]: the woven `execute` hands the run + * to its thread. + */ + fun reenterOnAnotherDispatcher(): Boolean = + Executors.newScheduledThreadPool(1) { Thread(it, "mutex-dispatcher") } + .asCoroutineDispatcher() + .use { other -> + runBlocking { + val mutex = Mutex() + mutex.withLock { + withTimeoutOrNull(TIMEOUT_MS) { + withContext(other) { mutex.withLock { true } } + } ?: false + } + } + } + + /** The misuse with a bare `lock()` and `unlock()`, inside `coroutineScope`. */ + fun reenterWithBareLock(): Boolean = runBlocking { + val mutex = Mutex() + mutex.lock() + try { + withTimeoutOrNull(TIMEOUT_MS) { + coroutineScope { + mutex.lock() + mutex.unlock() + true + } + } ?: false + } finally { + mutex.unlock() + } + } + + /** + * The misuse after a wait (#1220): the outer lock first waits for another coroutine, and once it + * holds the mutex its `supervisorScope` block locks it again. + */ + fun reenterAfterWaiting(): Boolean = runBlocking { + val mutex = Mutex() + val taken = CompletableDeferred() + launch { + mutex.withLock { + taken.complete(Unit) + delay(HOLD_MS) + } + } + taken.await() + mutex.withLock { + withTimeoutOrNull(TIMEOUT_MS) { + supervisorScope { mutex.withLock { true } } + } ?: false + } + } + + /** + * Silent (#1221): the mutex is unlocked, then taken by another coroutine, both through + * [UnwovenMutex], and the first coroutine's next woven lock waits for that other holder, which + * lets go. Returns whether that lock was taken. + */ + fun lockAgainAfterAnUnseenHandOver(): Boolean = runBlocking { + val mutex = Mutex() + mutex.lock() + UnwovenMutex.unlock(mutex) + val taken = CompletableDeferred() + launch { + UnwovenMutex.lock(mutex) + taken.complete(Unit) + delay(HOLD_MS) + UnwovenMutex.unlock(mutex) + } + taken.await() + mutex.withLock { true } + } + + /** Silent: the same mutex locked twice in a row, released in between. */ + fun lockTwiceInARow(): Int = runBlocking { + val mutex = Mutex() + mutex.withLock { counter++ } + mutex.withLock { counter++ } + } + + /** + * Silent: a `launch` child locks the mutex its parent holds. The parent does not wait for the + * child inside the lock, so it unlocks and the child takes its turn. + */ + fun childWaitsItsTurn(): Int = runBlocking { + val mutex = Mutex() + mutex.withLock { + launch { mutex.withLock { counter++ } } + counter++ + } + } + + /** Silent: the run's workers contend for one mutex, each waiting for another coroutine to unlock it. */ + fun contend(): Int = runBlocking { + shared.withLock { + delay(1) + counter++ + } + } + + /** Silent: a `tryLock` that finds the mutex taken backs off, rather than waiting for itself. */ + fun tryLockInsideTheLock(): Boolean = runBlocking { + val mutex = Mutex() + mutex.withLock { + withContext(CoroutineName("probe")) { mutex.tryLock() } + } + } + + private companion object { + const val TIMEOUT_MS = 200L + + /** How long another coroutine keeps the mutex, so the lock under test has to wait for it. */ + const val HOLD_MS = 20L + } +} diff --git a/consumer-fixture-langs/kotlin/src/test/kotlin/com/example/unwoven/UnwovenMutex.kt b/consumer-fixture-langs/kotlin/src/test/kotlin/com/example/unwoven/UnwovenMutex.kt new file mode 100644 index 000000000..813ee6700 --- /dev/null +++ b/consumer-fixture-langs/kotlin/src/test/kotlin/com/example/unwoven/UnwovenMutex.kt @@ -0,0 +1,15 @@ +package com.example.unwoven + +import kotlinx.coroutines.sync.Mutex + +/** + * `Mutex` calls the agent never weaves: this package is outside its `includes=`, as a library the + * run does not instrument would be (#1221). Neither function is inline, so the `lock` and `unlock` + * stay here rather than landing in a woven caller. + */ +object UnwovenMutex { + + suspend fun lock(mutex: Mutex) = mutex.lock() + + fun unlock(mutex: Mutex) = mutex.unlock() +} diff --git a/consumer-fixture-langs/kotlin/src/test/kotlin/se/deversity/asynctest/fixture/KotlinMutexReentrancyIsReportedTest.kt b/consumer-fixture-langs/kotlin/src/test/kotlin/se/deversity/asynctest/fixture/KotlinMutexReentrancyIsReportedTest.kt new file mode 100644 index 000000000..a494ddc5a --- /dev/null +++ b/consumer-fixture-langs/kotlin/src/test/kotlin/se/deversity/asynctest/fixture/KotlinMutexReentrancyIsReportedTest.kt @@ -0,0 +1,113 @@ +package se.deversity.asynctest.fixture + +import com.example.kotlinfixture.MutexBridges +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeAll +import se.deversity.asynctest.AsyncFindings +import se.deversity.asynctest.AsyncTest +import se.deversity.asynctest.DetectorType +import se.deversity.asynctest.FailOn + +/** + * A coroutine `Mutex` locked again by the coroutine that holds it (#1007), against real kotlinx: a + * `withLock` inside `withContext` on the same thread, the same with the block on another + * dispatcher, and a bare `lock()` inside `coroutineScope`. In each the outer coroutine is suspended + * until the block completes, so the inner lock waits for an unlock that cannot come; a + * `withTimeoutOrNull` ends it, and the body asserts the inner lock was never taken, so the shape + * under test is the real deadlock and not a lookalike. + */ +class KotlinMutexReentrancyIsReportedTest { + + companion object { + private lateinit var findings: AsyncFindings + + @JvmStatic + @BeforeAll + fun collect() { + findings = AsyncFindings.collect() + } + + @JvmStatic + @AfterAll + fun everyReentryIsReported() { + try { + val reports = findings.violationsFrom("KotlinMutexReentrancy") + .map { it.attributes()["report"].toString() } + assertTrue( + reports.any { it.contains("UndispatchedCoroutine") }, + "a withLock inside withContext on the same thread was not reported. Findings were: " + + findings.violations() + ) + assertTrue( + reports.any { it.contains("-> DispatchedCoroutine") || it.contains("until DispatchedCoroutine") }, + "a withLock inside withContext on another dispatcher was not reported: was the " + + "executor thread attributed to the run? Findings were: " + findings.violations() + ) + assertTrue( + reports.any { it.contains("ScopeCoroutine") }, + "a bare lock() inside coroutineScope was not reported. Findings were: " + + findings.violations() + ) + assertTrue( + reports.any { it.contains("SupervisorCoroutine") }, + "a withLock inside supervisorScope, under a lock that had to wait, was not " + + "reported (#1220). Findings were: " + findings.violations() + ) + } finally { + findings.close() + } + } + } + + private val bridges = MutexBridges() + + @AsyncTest( + threads = 4, + invocations = 4, + failOn = FailOn.NONE, + licenseMockMode = true, + timeoutMs = 60_000, + includes = [DetectorType.KOTLIN_MUTEX_REENTRANCY] + ) + fun withLockInsideWithContext() { + assertFalse(bridges.reenterThroughWithContext(), "the inner lock was taken: kotlinx Mutex was reentrant?") + } + + @AsyncTest( + threads = 4, + invocations = 4, + failOn = FailOn.NONE, + licenseMockMode = true, + timeoutMs = 60_000, + includes = [DetectorType.KOTLIN_MUTEX_REENTRANCY] + ) + fun withLockOnAnotherDispatcher() { + assertFalse(bridges.reenterOnAnotherDispatcher(), "the inner lock was taken: kotlinx Mutex was reentrant?") + } + + @AsyncTest( + threads = 4, + invocations = 4, + failOn = FailOn.NONE, + licenseMockMode = true, + timeoutMs = 60_000, + includes = [DetectorType.KOTLIN_MUTEX_REENTRANCY] + ) + fun bareLockInsideCoroutineScope() { + assertFalse(bridges.reenterWithBareLock(), "the inner lock was taken: kotlinx Mutex was reentrant?") + } + + @AsyncTest( + threads = 4, + invocations = 4, + failOn = FailOn.NONE, + licenseMockMode = true, + timeoutMs = 60_000, + includes = [DetectorType.KOTLIN_MUTEX_REENTRANCY] + ) + fun withLockAfterWaitingForTheMutex() { + assertFalse(bridges.reenterAfterWaiting(), "the inner lock was taken: kotlinx Mutex was reentrant?") + } +} diff --git a/consumer-fixture-langs/kotlin/src/test/kotlin/se/deversity/asynctest/fixture/KotlinMutexWithoutReentryIsNotReportedTest.kt b/consumer-fixture-langs/kotlin/src/test/kotlin/se/deversity/asynctest/fixture/KotlinMutexWithoutReentryIsNotReportedTest.kt new file mode 100644 index 000000000..311d94b5a --- /dev/null +++ b/consumer-fixture-langs/kotlin/src/test/kotlin/se/deversity/asynctest/fixture/KotlinMutexWithoutReentryIsNotReportedTest.kt @@ -0,0 +1,106 @@ +package se.deversity.asynctest.fixture + +import com.example.kotlinfixture.MutexBridges +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeAll +import se.deversity.asynctest.AsyncFindings +import se.deversity.asynctest.AsyncTest +import se.deversity.asynctest.DetectorType +import se.deversity.asynctest.FailOn + +/** + * The silent twin of `KotlinMutexReentrancyIsReportedTest` (#1007): the same woven `Mutex` calls in + * shapes that never wait for their own coroutine. A mutex locked twice in a row; a `launch` child + * that waits its turn behind its parent; the run's workers contending for one mutex; a `tryLock` + * inside the lock, which backs off rather than waits; and a lock that waits for another coroutine + * after an unlock and a lock the agent never saw (#1221). + */ +class KotlinMutexWithoutReentryIsNotReportedTest { + + companion object { + private lateinit var findings: AsyncFindings + + @JvmStatic + @BeforeAll + fun collect() { + findings = AsyncFindings.collect() + } + + @JvmStatic + @AfterAll + fun nothingIsReported() { + try { + assertTrue( + findings.violationsFrom("KotlinMutexReentrancy").isEmpty(), + "no coroutine here waits for a mutex it holds: " + findings.violations() + ) + } finally { + findings.close() + } + } + } + + private val bridges = MutexBridges() + + @AsyncTest( + threads = 4, + invocations = 4, + failOn = FailOn.NONE, + licenseMockMode = true, + timeoutMs = 60_000, + includes = [DetectorType.KOTLIN_MUTEX_REENTRANCY] + ) + fun lockTwiceInARow() { + bridges.lockTwiceInARow() + } + + @AsyncTest( + threads = 4, + invocations = 4, + failOn = FailOn.NONE, + licenseMockMode = true, + timeoutMs = 60_000, + includes = [DetectorType.KOTLIN_MUTEX_REENTRANCY] + ) + fun launchedChildWaitsItsTurn() { + bridges.childWaitsItsTurn() + } + + @AsyncTest( + threads = 4, + invocations = 4, + failOn = FailOn.NONE, + licenseMockMode = true, + timeoutMs = 60_000, + includes = [DetectorType.KOTLIN_MUTEX_REENTRANCY] + ) + fun workersContend() { + bridges.contend() + } + + @AsyncTest( + threads = 4, + invocations = 4, + failOn = FailOn.NONE, + licenseMockMode = true, + timeoutMs = 60_000, + includes = [DetectorType.KOTLIN_MUTEX_REENTRANCY] + ) + fun tryLockInsideTheLockBacksOff() { + assertFalse(bridges.tryLockInsideTheLock(), "tryLock took a mutex its own coroutine holds") + } + + @AsyncTest( + threads = 4, + invocations = 4, + failOn = FailOn.NONE, + licenseMockMode = true, + timeoutMs = 60_000, + includes = [DetectorType.KOTLIN_MUTEX_REENTRANCY] + ) + fun lockAgainAfterAnUnseenHandOver() { + assertTrue(bridges.lockAgainAfterAnUnseenHandOver(), "the lock after the hand-over was never taken") + } +} diff --git a/consumer-fixture/src/test/java/se/deversity/asynctest/fixture/detectors/DetectorCoverageTest.java b/consumer-fixture/src/test/java/se/deversity/asynctest/fixture/detectors/DetectorCoverageTest.java index 1a882e6ad..1716bc731 100644 --- a/consumer-fixture/src/test/java/se/deversity/asynctest/fixture/detectors/DetectorCoverageTest.java +++ b/consumer-fixture/src/test/java/se/deversity/asynctest/fixture/detectors/DetectorCoverageTest.java @@ -63,7 +63,8 @@ class DetectorCoverageTest { Phase23VirtualThreadScaleDetectorsFixtureTest.class, Phase24Jdk26StructuredConcurrencyFixtureTest.class, Phase25ProcessStreamFixtureTest.class, - Phase26NonBlockingThreadFixtureTest.class); + Phase26NonBlockingThreadFixtureTest.class, + Phase26KotlinMutexFixtureTest.class); /** detector -> the fixture methods that enable it, as {@code Class#method}. */ private static Map> collectCoverage() { diff --git a/consumer-fixture/src/test/java/se/deversity/asynctest/fixture/detectors/Phase26KotlinMutexFixtureTest.java b/consumer-fixture/src/test/java/se/deversity/asynctest/fixture/detectors/Phase26KotlinMutexFixtureTest.java new file mode 100644 index 000000000..d02f9b1f0 --- /dev/null +++ b/consumer-fixture/src/test/java/se/deversity/asynctest/fixture/detectors/Phase26KotlinMutexFixtureTest.java @@ -0,0 +1,58 @@ +package se.deversity.asynctest.fixture.detectors; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import se.deversity.asynctest.AsyncFindings; +import se.deversity.asynctest.AsyncTest; +import se.deversity.asynctest.AsyncTestContext; +import se.deversity.asynctest.DetectorType; + +import java.util.List; + +import static se.deversity.asynctest.fixture.detectors.DetectorFixtureSupport.assertAllReported; +import static se.deversity.asynctest.fixture.detectors.DetectorFixtureSupport.reachable; + +/** + * Phase 26, Kotlin coroutines — {@code KOTLIN_MUTEX_REENTRANCY}. + * + *

The fixture proves the detector is reachable from the published artifact, records a mutex + * locked again from a scope its holder waits for through its public recording API, and asserts in + * {@code @AfterAll} that the finding came back out through {@link AsyncFindings}. The woven calls, + * against real kotlinx, are proven in {@code consumer-fixture-langs/kotlin}. + * + *

See {@code docs/DETECTOR_CATALOG.md} entry 149 for the buggy-vs-fixed pair. + */ +class Phase26KotlinMutexFixtureTest { + + private static AsyncFindings findings; + + @BeforeAll + static void collectFindings() { + findings = AsyncFindings.collect(); + } + + @AfterAll + static void everyFedDetectorReported() { + try { + assertAllReported(findings, "KotlinMutexReentrancyDetector"); + } finally { + findings.close(); + } + } + + @AsyncTest(threads = 2, invocations = 1, timeoutMs = 30_000, licenseMockMode = true, + includes = {DetectorType.KOTLIN_MUTEX_REENTRANCY}) + void kotlinMutexReentrancy() { + reachable("kotlinMutexReentrancyDetector()", AsyncTestContext::kotlinMutexReentrancyDetector); + + // The hazard: the coroutine holding a mutex waits on a withContext block that locks it again. + var detector = AsyncTestContext.kotlinMutexReentrancyDetector(); + Object mutex = new Object(); + Object outer = new Object(); + Object inner = new Object(); + detector.recordAcquired(mutex, outer); + int held = detector.holderAmong(mutex, List.of(inner, outer)); + detector.recordReentry(mutex, List.of("DispatchedCoroutine", "BlockingCoroutine"), held, + Thread.currentThread()); + } +} diff --git a/corpus-eval/README.md b/corpus-eval/README.md index 3204e302e..1ef961903 100644 --- a/corpus-eval/README.md +++ b/corpus-eval/README.md @@ -7,7 +7,7 @@ with the numbers and what they do and do not support, is ## Why it is a standalone module -The nine corpus libraries are *subjects*, not tools. Keeping the module out of the reactor keeps +The ten corpus libraries are *subjects*, not tools. Keeping the module out of the reactor keeps them off every classpath that matters: nothing in `async-test-lib`, the published artifacts or the Gradle build resolves them, exactly as `consumer-fixture/` stays outside for its own reason. @@ -23,9 +23,9 @@ A run executes six lanes and writes one report per lane under `target/corpus-eva | Lane | Report | What it is | |---|---|---| | `agent-on` | `corpus-eval.md` | The agent attached as `fields=true,collections=true`, with Surefire's own classes excluded from weaving (#561). Every number the write-up quotes comes from here. | -| `agent-off` | `corpus-eval-agent-off.md` | The same subjects with nothing attached. The control: `DetectorFeeds` says the 48 agent-fed detectors have no input without the agent, so this lane must observe nothing from them, and `CorpusGates` asserts it. | +| `agent-off` | `corpus-eval-agent-off.md` | The same subjects with nothing attached. The control: `DetectorFeeds` says the 49 agent-fed detectors have no input without the agent, so this lane must observe nothing from them, and `CorpusGates` asserts it. | | `recording` | `corpus-eval-recording.md` | The same libraries, with bodies that call the recording API. A different measurement over a different denominator, which is why it writes its own report and is never merged into the other two. | -| `agent-pairs` | `corpus-eval-agent-pairs.md` | The mirror image of the recording lane, for the 48 agent-fed detectors it cannot reach. The agent is attached and the body records nothing: the difference between a firing row and its silent twin is a field declaration, and everything in between comes from the weaver. `AgentRowPremise` fails the lane if a body here touches the recording API. Some pairs call the JDK type from the test file; others call only Guava, Jackson, HikariCP, Spring, commons-lang3 or Groovy, so the woven call sits inside the library, and `LibraryReach` accounts for which agent-fed detectors that reaches. | +| `agent-pairs` | `corpus-eval-agent-pairs.md` | The mirror image of the recording lane, for the 49 agent-fed detectors it cannot reach. The agent is attached and the body records nothing: the difference between a firing row and its silent twin is a field declaration, and everything in between comes from the weaver. `AgentRowPremise` fails the lane if a body here touches the recording API. Some pairs call the JDK type from the test file; others call only Guava, Jackson, HikariCP, Spring, commons-lang3 or Groovy, so the woven call sits inside the library, and `LibraryReach` accounts for which agent-fed detectors that reaches. | | `agent-pairs-library-excluded` | `corpus-eval-agent-pairs-library-excluded.md` | The agent-pair lane's library rows again, with every corpus library on the agent's `excludes=` list. A library pair claims its finding came from a JDK call inside the library, so with the library unwoven each firing row must go silent. `CorpusGates.checkLibraryExclusionLane` fails on a row that still fires, on a library row whose package the excludes list does not cover, and on a row that did not run in full. A row that uses a library type but whose woven call site is the test body (`Corpus.BODY_CALL_SITE_ROWS`, the JCTools hand-off pair) makes no such claim and does not run here. | | `idioms` | `corpus-eval-idioms.md` | Correct user-code concurrency, the way a user writes it, with every detector on and the agent attached: a mutable object handed through a `BlockingQueue`, plain data published by a volatile flag, a latch, a guarded wait loop, a pool checked out through a queue. Each correct row is followed by its broken twin, the same code with the synchronization removed or misplaced, which must wake its named detector. A correct row fails the run on any finding at `FACT` tier or above from any detector (a graded detector's report is read at the strongest tier among its findings, as the runner clamped them), and on any finding at all from the detector it names. Correct idioms the happens-before model does not see yet are listed in `Corpus.idiomKnownGaps()` with the reason, and must keep reporting until a fix closes them. `IdiomRowPremise` fails the lane if a body records outside the rows `Corpus.idiomManualApiRows()` names. | diff --git a/corpus-eval/src/test/java/com/example/corpus/Corpus.java b/corpus-eval/src/test/java/com/example/corpus/Corpus.java index 0bbca951d..eec0c545b 100644 --- a/corpus-eval/src/test/java/com/example/corpus/Corpus.java +++ b/corpus-eval/src/test/java/com/example/corpus/Corpus.java @@ -29,6 +29,7 @@ final class Corpus { private static final String SPRING = "spring-core:7.0.9"; private static final String HIKARI = "HikariCP:7.0.2"; private static final String GROOVY = "groovy:5.1.2"; + private static final String KOTLINX = "kotlinx-coroutines-core-jvm:1.11.0"; /** * The platform itself, for subjects that ship with it. @@ -1585,6 +1586,24 @@ final class Corpus { + "permit blocking calls: bridging blocking code to suspending code is " + "what runBlocking is for"), + new RecordingSubject("agent_kotlinMutex_lockedAgainByItsHolder", KOTLINX, + "kotlinx.coroutines.sync.Mutex", + DetectorType.KOTLIN_MUTEX_REENTRANCY, Contract.THREAD_SAFE, + RecordingSubject.Expectation.MUST_FIRE, + "each worker's coroutine locks a fresh kotlinx Mutex and locks it again before " + + "unlocking. Mutex is not reentrant, so the second lock suspends on " + + "its own holder and would never return; the body then lets the outer " + + "hold go so the round ends. The call sites are compiled against " + + "kotlinx 1.11's real Mutex and woven by name (#1007)", + IssueSeverity.HIGH), + + new RecordingSubject("agent_kotlinMutex_unlockedBetweenLocks", KOTLINX, + "kotlinx.coroutines.sync.Mutex", + DetectorType.KOTLIN_MUTEX_REENTRANCY, Contract.THREAD_SAFE, + RecordingSubject.Expectation.MUST_STAY_SILENT, + "the same coroutine, the same fresh mutex and the same two locks, with an " + + "unlock between them: the second lock finds the mutex free"), + new RecordingSubject("agent_pipe_bothEndsOnOneThread", JDK, "java.io.PipedInputStream", DetectorType.PROCESS_STREAM_STARVATION, Contract.NOT_THREAD_SAFE, @@ -5946,7 +5965,9 @@ static Set idiomRecordedDetectors() { "agent_nettyThread_sleepsOnAnEventLoopThread", "agent_nettyThread_sleepsOnAnOrdinaryThread", "agent_nettyThread_runBlockingOnAnEventLoopThread", - "agent_nettyThread_runBlockingOnAnOrdinaryThread"); + "agent_nettyThread_runBlockingOnAnOrdinaryThread", + "agent_kotlinMutex_lockedAgainByItsHolder", + "agent_kotlinMutex_unlockedBetweenLocks"); /** {@return whether {@code subject}'s finding is claimed to come from a call woven inside its library} */ static boolean wovenCallSiteIsInsideTheLibrary(RecordingSubject subject) { diff --git a/corpus-eval/src/test/java/com/example/corpus/CorpusAgentPairLaneTest.java b/corpus-eval/src/test/java/com/example/corpus/CorpusAgentPairLaneTest.java index 9a7a6c873..7ba29053e 100644 --- a/corpus-eval/src/test/java/com/example/corpus/CorpusAgentPairLaneTest.java +++ b/corpus-eval/src/test/java/com/example/corpus/CorpusAgentPairLaneTest.java @@ -1559,6 +1559,49 @@ public boolean permitBlockingCalls() { thread.join(); } + /** Every worker's coroutine locks a fresh kotlinx Mutex it already holds (#1007). */ + @AsyncTest(threads = THREADS, invocations = INVOCATIONS, timeoutMs = 20_000, detectAll = true) + void agent_kotlinMutex_lockedAgainByItsHolder() { + counted(() -> lockAFreshMutexTwice(false)); + } + + /** The same two locks with an unlock between them. */ + @AsyncTest(threads = THREADS, invocations = INVOCATIONS, timeoutMs = 20_000, detectAll = true) + void agent_kotlinMutex_unlockedBetweenLocks() { + counted(() -> lockAFreshMutexTwice(true)); + } + + /** + * Inside runBlocking, locks a fresh kotlinx Mutex and locks it again, unlocking in between or + * not. Called from Java, the block receives its own continuation, so each lock and unlock is + * the INVOKEINTERFACE a Kotlin call compiles to, and the woven call site is the real one. + * + *

Without the unlock the second lock suspends on the coroutine that holds the mutex, which + * in Kotlin never returns. Here the block then releases the outer hold itself, which hands + * the mutex to the waiting lock and resumes the block, so the round ends instead of timing + * out; the finding is made when the second lock suspends, before that release. + */ + private static void lockAFreshMutexTwice(boolean unlockBetween) { + Object suspended = kotlin.coroutines.intrinsics.IntrinsicsKt.getCOROUTINE_SUSPENDED(); + kotlinx.coroutines.BuildersKt.runBlockingK( + kotlin.coroutines.EmptyCoroutineContext.INSTANCE, (scope, continuation) -> { + kotlinx.coroutines.sync.Mutex mutex = kotlinx.coroutines.sync.MutexKt.Mutex(false); + if (mutex.lock(null, continuation) == suspended) { + throw new AssertionError("a fresh mutex was not free"); + } + if (unlockBetween) { + mutex.unlock(null); + } + Object again = mutex.lock(null, continuation); + if (unlockBetween != (again != suspended)) { + throw new AssertionError("the second lock " + + (again == suspended ? "waited" : "did not wait")); + } + mutex.unlock(null); + return unlockBetween ? kotlin.Unit.INSTANCE : again; + }); + } + /** Every worker writes one byte into a fresh pipe and reads it back on the same thread. */ @AsyncTest(threads = THREADS, invocations = INVOCATIONS, timeoutMs = 20_000, detectAll = true) void agent_pipe_bothEndsOnOneThread() { diff --git a/corpus-eval/src/test/java/com/example/corpus/DetectorEffectivenessAndCorrectnessTest.java b/corpus-eval/src/test/java/com/example/corpus/DetectorEffectivenessAndCorrectnessTest.java index c9efd8ad6..2b855498d 100644 --- a/corpus-eval/src/test/java/com/example/corpus/DetectorEffectivenessAndCorrectnessTest.java +++ b/corpus-eval/src/test/java/com/example/corpus/DetectorEffectivenessAndCorrectnessTest.java @@ -148,8 +148,8 @@ void libraryRowsReachThirdPartyBytecode() { // on it, none leaves a pool it created running, none drops a failing task's future or a // failing async root, none blocks inside a callback, and none blocks on the common pool. // The daemon-hygiene weave is reached through a Guava service left running (#736). - assertEquals(agentFed.size() - 29, reached.size(), - "all agent-fed detectors except the twenty-nine LibraryReach.unreached() names must " + assertEquals(agentFed.size() - 30, reached.size(), + "all agent-fed detectors except the thirty LibraryReach.unreached() names must " + "be reached through library bytecode"); assertEquals(Set.of(DetectorType.EXPLICIT_GC, DetectorType.MISSED_SIGNAL, DetectorType.ABA_PROBLEM, DetectorType.SYNCHRONIZED_NON_FINAL, @@ -169,7 +169,8 @@ void libraryRowsReachThirdPartyBytecode() { DetectorType.SHARED_CHARSET_CODER, DetectorType.SHARED_CHECKSUM, DetectorType.SHARED_SPLITTABLE_RANDOM, DetectorType.ATOMIC_NON_ATOMIC_UPDATE, DetectorType.EXECUTOR_DEADLOCK, - DetectorType.COMPLETABLE_FUTURE_OBTRUDE_ABUSE), + DetectorType.COMPLETABLE_FUTURE_OBTRUDE_ABUSE, + DetectorType.KOTLIN_MUTEX_REENTRANCY), LibraryReach.unreached().keySet()); } diff --git a/corpus-eval/src/test/java/com/example/corpus/LibraryReach.java b/corpus-eval/src/test/java/com/example/corpus/LibraryReach.java index e75c10725..f68d7a98f 100644 --- a/corpus-eval/src/test/java/com/example/corpus/LibraryReach.java +++ b/corpus-eval/src/test/java/com/example/corpus/LibraryReach.java @@ -154,6 +154,10 @@ final class LibraryReach { unreached(DetectorType.SHARED_SPLITTABLE_RANDOM, "agent-fed through the woven SplittableRandom calls; no corpus library shares a " + "SplittableRandom across threads, so its recording-lane pair stands"); + unreached(DetectorType.KOTLIN_MUTEX_REENTRANCY, + "agent-fed since #1007 through the woven kotlinx Mutex lock, tryLock and unlock; " + + "kotlinx's own classes are never woven, and no other corpus library " + + "calls a Mutex, so its pair locks one from the test body"); } private static void unreached(DetectorType type, String reason) { diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index da642e0f1..50a9182e3 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -4,7 +4,7 @@ This document is the entry point to the architecture of the async-test library. The library enables deterministic concurrency testing by forcing thread collisions and detecting concurrency bugs with -**148 detectors**, organized phase by phase in [DETECTOR_CATALOG.md](DETECTOR_CATALOG.md). +**149 detectors**, organized phase by phase in [DETECTOR_CATALOG.md](DETECTOR_CATALOG.md). Each topic below lives in its own file under [`architecture/`](architecture/). Read the one you need rather than the whole set. diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 83dc7077a..59ad4de2a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- `KOTLIN_MUTEX_REENTRANCY` (149th detector): a Kotlin coroutine `Mutex` locked again by the + coroutine that holds it (#1007). kotlinx `Mutex` is not reentrant, so a `withLock` inside a + `withContext`, `coroutineScope` or `withTimeout` block of the same `withLock` waits for an unlock + that never comes, and the coroutine hangs. With the agent (`collections=true`), `KotlinMutexWeaver` + substitutes each `lock`, `unlock` and `tryLock` call site, the ones an inlined `withLock` compiles + to included, matched by owner, name and descriptor, since kotlinx may not be on the agent's class + path. A lock called without an owner is made with a fresh owner token of the agent's, which + kotlinx compares by identity and so treats exactly as no owner; the hook keeps it with the calling + coroutine's `Job`, read from the continuation. A lock that waits while the mutex's own `holdsLock` + says the caller's token, or that of a coroutine suspended for its scope, holds it is reported, so + an unlock the agent does not see cannot leave a stale holder (#1221), and a lock that had to wait + counts once it is granted (#1220). It errs toward silence: a coroutine that took the mutex with + `tryLock`, `select` or a lock outside `includes=` holds no token, and a `launch` or `async` child + is not part of its parent. `VERDICT`, backed by a corpus pair in both directions. Proven against real kotlinx 1.11 in `consumer-fixture-langs/kotlin`, red with the weaver + off, with a silent twin. + ### Changed - Dependencies bumped to their latest stable releases: error-prone 2.50.0 to 2.52.0 (with NullAway 0.14.2 to 0.14.3), PMD 7.28.0 to 7.29.0, Checkstyle 14.3.0 to 14.4.0, Guava 33.7.2 to 33.8.0, Netty 4.2.19 to 4.2.20, Spring 7.0.9 to 7.0.10, Byte Buddy 1.18.16 to 1.18.17, Pitest 1.30.1 to 1.30.2, japicmp plugin 0.26.5 to 0.27.0, vibetags 1.4.0 to 1.4.1, the Gradle plugin pins (errorprone 5.2.0, JMH 0.7.4, IntelliJ platform 2.20.0, logback 1.6.6), the Copilot CLI 1.0.105, and the GitHub Actions SHAs (harden-runner 2.22.3, gradle actions 6.4.1, CodeQL 4.39.1, setup-java 6.2.0, cosign-installer 4.1.3, claude-code-action). diff --git a/docs/DETECTOR_CATALOG.md b/docs/DETECTOR_CATALOG.md index ddb2d39be..a5fab2444 100644 --- a/docs/DETECTOR_CATALOG.md +++ b/docs/DETECTOR_CATALOG.md @@ -1,6 +1,6 @@ # Detector Catalog -`async-test-lib` includes **148 detectors** organized across different phases. The phase files linked below hold a categorized catalog detailing the most critical concurrency bugs detected by the library, accompanied by "Buggy Code" vs. "Fixed Code" examples. +`async-test-lib` includes **149 detectors** organized across different phases. The phase files linked below hold a categorized catalog detailing the most critical concurrency bugs detected by the library, accompanied by "Buggy Code" vs. "Fixed Code" examples. ## Detectors by phase @@ -19,7 +19,7 @@ The numbered detector entries live in [`detector-catalog/`](detector-catalog/), | [09-stateful-jdk-and-coordination.md](detector-catalog/09-stateful-jdk-and-coordination.md) | Entries 111 to 120. Phases 17 and 19: ByteBuffer, charset coders, checksums, FileChannel position, iterators, contended atomics, JSON mappers, latches, executors, futures | | [10-jdk-25-26.md](detector-catalog/10-jdk-25-26.md) | Entries 121 to 126. Phases 16 and 18: StableValue, StructuredTaskScope, Gatherer, LazyConstant, final-field mutation and KDF, wired into `detectAll` | | [11-flow-and-ffm.md](detector-catalog/11-flow-and-ffm.md) | Entries 127 to 135. Phases 19 and 20: Flow publishers, confined arenas, memory segments, VarHandle, records, static-init deadlock, virtual-thread pooling, thread-per-task, SplittableRandom | -| [12-futures-scale-structured.md](detector-catalog/12-futures-scale-structured.md) | Entries 136 to 148. Phases 22 to 24: CompletableFuture publication, lambda capture, virtual-thread scale, JDK 26 scopes and lazy constants | +| [12-futures-scale-structured.md](detector-catalog/12-futures-scale-structured.md) | Entries 136 to 149. Phases 22 to 24: CompletableFuture publication, lambda capture, virtual-thread scale, JDK 26 scopes and lazy constants | ## Severity @@ -66,7 +66,7 @@ check something". | **PROMPT** | The detector saw a pattern it cannot fully model, most often a shared object whose lock it has no way to see. Correct code that shares an object produces the same signal as a race. | Open a ticket, not fail a build | | **ADVISORY** | A performance or hygiene note, not a correctness claim. | Read it, gate on nothing | -**The tier is in the code, not in this document.** `DetectorTrust` classifies all 148, the runner +**The tier is in the code, not in this document.** `DetectorTrust` classifies all 149, the runner prints the tier above every finding, every `Violation` carries it as a `trustTier` attribute (and, for a report that grades its findings, each finding's tier in report order as `findingTiers`), and `@AsyncTest(minTrust = TrustTier.VERDICT)` restricts the `failOn` gate to the tiers you name. @@ -319,7 +319,7 @@ not brings back the accesses since the latest earlier hand-off it is ordered aft access when there is none. **Classified, and now mostly measured.** Every detector carries a tier, because a finding with no -tier is one a reader has to rank alone. The split is 37 VERDICT, 75 PROMPT, 29 FACT and 7 +tier is one a reader has to rank alone. The split is 38 VERDICT, 75 PROMPT, 29 FACT and 7 ADVISORY. PROMPT is the honest default: it says nobody has measured that detector's silent-on-correct-code direction, or that what it decides from is a thread count or a threshold, not that the detector is wrong. FACT and ADVISORY are statements about the kind of claim a finding @@ -343,7 +343,7 @@ wondering about the silence, know which kind each detector is. The classificatio the two drift or when the agent-fed set stops matching the classes the woven streams are wired into. -### Agent-fed (48) +### Agent-fed (49) Read the agent's woven streams (field accesses, collection call sites, lock acquisitions) and fire on unmodified code, third-party code included, whenever the agent is attached: @@ -532,7 +532,7 @@ method and set to a constant in another, and they were the rule's false positive `SystemPropertyMutationDetector`, `ProcessStreamStarvationDetector`, `JdbcConnectionSharedDetector`, `ThreadLocalMonitor`, `MdcContextLeakDetector`, `BlockingOnNonBlockingThreadDetector`, `ThreadLeakDetector`, `ThreadPoolMonitor`, `CompletableFutureCompletionLeakDetector`, -`AtomicNonAtomicUpdateDetector`, `ExecutorDeadlockDetector` +`AtomicNonAtomicUpdateDetector`, `ExecutorDeadlockDetector`, `KotlinMutexReentrancyDetector` ### Zero-config (4) diff --git a/docs/DISTRIBUTION.md b/docs/DISTRIBUTION.md index 22396a546..2e7d9db4a 100644 --- a/docs/DISTRIBUTION.md +++ b/docs/DISTRIBUTION.md @@ -25,7 +25,7 @@ For the main library, each release produces three files: - **Contents**: Compiled Java classes + metadata - **Size**: ~150-200 KB - **What it includes**: - - All 148 detector implementations + - All 149 detector implementations - JUnit 5 extension code - Diagnostic reporters - Thread utilities diff --git a/docs/INDEX.md b/docs/INDEX.md index e8cc08edc..da6069d17 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -44,7 +44,7 @@ Three paths, depending on why you came. |----------|---------| | [BEST_PRACTICES.md](BEST_PRACTICES.md) | How to write an `@AsyncTest` that actually finds bugs | | [CONFIGURATION.md](CONFIGURATION.md) | Configuration options in depth | -| [DETECTOR_CATALOG.md](DETECTOR_CATALOG.md) | All 148 detectors with buggy-vs-fixed examples, their trust tiers and what feeds each. Hub for the rows below | +| [DETECTOR_CATALOG.md](DETECTOR_CATALOG.md) | All 149 detectors with buggy-vs-fixed examples, their trust tiers and what feeds each. Hub for the rows below | | [detector-catalog/01-foundations.md](detector-catalog/01-foundations.md) | Entries 1 to 8. Phases 1 to 3: deadlock, visibility, carrier pinning, pool deadlock, lock and ThreadLocal leaks, non-atomic collection updates, livelock | | [detector-catalog/02-phase-2-core-and-monitors.md](detector-catalog/02-phase-2-core-and-monitors.md) | Entries 9 to 28. Phase 2 core and monitors: false sharing, ABA, lock order, memory ordering, semaphores, CompletableFuture, SimpleDateFormat, parallel streams | | [detector-catalog/03-phase-2-additional-and-utilities.md](detector-catalog/03-phase-2-additional-and-utilities.md) | Entries 29 to 44. Phase 2 additional concurrency and utilities: latches, barriers, locks, double-checked locking, Phaser, StampedLock, ForkJoinPool | @@ -56,7 +56,7 @@ Three paths, depending on why you came. | [detector-catalog/09-stateful-jdk-and-coordination.md](detector-catalog/09-stateful-jdk-and-coordination.md) | Entries 111 to 120. Phases 17 and 19: ByteBuffer, charset coders, checksums, FileChannel position, iterators, contended atomics, JSON mappers, latches, executors, futures | | [detector-catalog/10-jdk-25-26.md](detector-catalog/10-jdk-25-26.md) | Entries 121 to 126. Phases 16 and 18: StableValue, StructuredTaskScope, Gatherer, LazyConstant, final-field mutation and KDF, wired into `detectAll` | | [detector-catalog/11-flow-and-ffm.md](detector-catalog/11-flow-and-ffm.md) | Entries 127 to 135. Phases 19 and 20: Flow publishers, confined arenas, memory segments, VarHandle, records, static-init deadlock, virtual-thread pooling, thread-per-task, SplittableRandom | -| [detector-catalog/12-futures-scale-structured.md](detector-catalog/12-futures-scale-structured.md) | Entries 136 to 148. Phases 22 to 24: CompletableFuture publication, lambda capture, virtual-thread scale, JDK 26 scopes and lazy constants | +| [detector-catalog/12-futures-scale-structured.md](detector-catalog/12-futures-scale-structured.md) | Entries 136 to 149. Phases 22 to 24: CompletableFuture publication, lambda capture, virtual-thread scale, JDK 26 scopes and lazy constants | | [ASYNC_ASSERT.md](ASYNC_ASSERT.md) | `AsyncAssert` — polling for side effects that land asynchronously — `AsyncFindings`, for asserting on what the detectors reported, `AsyncTestContext.rendezvous()`, for making a round's workers meet mid-body, `RunOutcomes`, for asserting that something happened exactly once, at most once, or with distinct values, and `OperationHistory`, for asserting that every round's results are linearizable | | [MIGRATION.md](MIGRATION.md) | Moving an existing test suite onto `@AsyncTest` | | [migration/1.13.0.md](migration/1.13.0.md) | Upgrading from 1.12 to 1.13.0: the breaking changes, which ones compile and still change what runs, and the exact rewrite for each | diff --git a/docs/JVM_LANGUAGES.md b/docs/JVM_LANGUAGES.md index ffdb2ee14..ccc43290d 100644 --- a/docs/JVM_LANGUAGES.md +++ b/docs/JVM_LANGUAGES.md @@ -30,9 +30,9 @@ Nothing to configure. Attributes are named arguments. `@BeforeAll` / `@AfterAll` [agent](AGENT.md)'s default accessor weaving sees them. A `suspend fun` is not JUnit-invokable: wrap a coroutine body in `runBlocking`. An `@AsyncTest suspend fun` fails the run with a message that says so, whether or not `kotlin-reflect` is on the test classpath (#1146). `by lazy` is `SYNCHRONIZED` by default, so it is not a -lazy-init race subject unless you choose `LazyThreadSafetyMode.NONE`. Coroutine misuse has two rules -so far, both reported by `BLOCKING_ON_NON_BLOCKING_THREAD` when the agent is attached with -`kotlinx.coroutines` and your own package in its `includes=`. A blocking call on a +lazy-init race subject unless you choose `LazyThreadSafetyMode.NONE`. Coroutine misuse has three +rules so far, each reported when the agent is attached with `kotlinx.coroutines` and your own +package in its `includes=`. The first two are `BLOCKING_ON_NON_BLOCKING_THREAD`'s. A blocking call on a `Dispatchers.Default` worker is reported; the same worker running `Dispatchers.IO` work is not (#993). A `runBlocking` entered on any dispatcher worker, `Dispatchers.Default` or `Dispatchers.IO`, is reported, because the caller is itself a coroutine, and so is one entered by a coroutine on any @@ -41,8 +41,12 @@ in another `runBlocking`, or on an executor dispatcher whose threads are plain ` `asCoroutineDispatcher` over a JDK `ScheduledThreadPoolExecutor`, or `newSingleThreadContext`, whose `Executors.unconfigurableExecutorService` wrapper the woven `execute` looks through to the pool behind it (#1107). On an ordinary thread outside any coroutine, its intended use, nothing is -reported (#1007). A `Mutex` treated as reentrant -and races across suspensions need a coroutine owner model and are still +reported (#1007). The third is `KOTLIN_MUTEX_REENTRANCY`: a `Mutex` locked again by the coroutine +that holds it, directly or from a `withContext`, `coroutineScope` or `withTimeout` block it is +suspended for. kotlinx `Mutex` is not reentrant, so that lock waits forever. The woven `lock` reads +the coroutine's `Job` from its continuation and records it as the holder when it takes the mutex +without waiting; a holder that had to wait, or took it with `tryLock`, is not known, and a lock +under it is not judged. Races across suspensions are still [#1007](https://github.com/PIsberg/async-test-lib/issues/1007). Fixture: [`consumer-fixture-langs/kotlin`](../consumer-fixture-langs/kotlin); a fuller example with a diff --git a/docs/QUICK_REFERENCE.md b/docs/QUICK_REFERENCE.md index 6ac970314..2a5844e92 100644 --- a/docs/QUICK_REFERENCE.md +++ b/docs/QUICK_REFERENCE.md @@ -176,7 +176,7 @@ USAGE.md ............ for end users RELEASE.md .......... release process (canonical) DISTRIBUTION.md ..... distribution/technical reference ARCHITECTURE.md ..... system design -DETECTOR_CATALOG.md . all 148 detectors with examples +DETECTOR_CATALOG.md . all 149 detectors with examples INDEX.md ............ full documentation map ``` diff --git a/docs/agent/attaching.md b/docs/agent/attaching.md index f13bf6c27..270fdfcaa 100644 --- a/docs/agent/attaching.md +++ b/docs/agent/attaching.md @@ -295,6 +295,21 @@ the woven `execute` makes it on a bare JDK pool and through the dispatcher worker is attributed to the run (`RunBlockingWeavingTest`, `RunBlockingSparesTheCallerTest`, and with real kotlinx `consumer-fixture-langs/kotlin`). +A Kotlin coroutine `Mutex` is watched by name and descriptor too (#1007). An inlined +`withLock(owner) { }` compiles to `INVOKEINTERFACE kotlinx/coroutines/sync/Mutex.lock` and +`unlock`, and a bare `lock()`, `unlock()` or `tryLock()` to the interface's static `$default` +bridge. `KotlinMutexWeaver` replaces each of the six with a static hook that takes the same stack, +its Kotlin types written as `Object`, and makes the original call through a handle bound to the +receiver's own kotlinx; a descriptor from some other kotlinx is left alone. A lock called without +an owner is made with a fresh owner token of the agent's, which kotlinx compares by identity and +so treats exactly as no owner. The lock hook reads the calling coroutine's `Job` from the +continuation, and `KotlinMutexReentrancyDetector` keeps it with the token. It reports a lock that +waits while the mutex's own `holdsLock` says a token of the caller, or of a coroutine suspended for +the caller's scope, holds it. The mutex answers, so an unlock outside `includes=` ends a hold like +any other (#1221); a lock outside `includes=` holds no token, and a reentry under it is missed +(`KotlinMutexReentrancyIsReportedTest` and its silent twin, with real kotlinx, in +`consumer-fixture-langs/kotlin`). + Executors are watched the same way. The fourteen `Executors` factories are woven, and an executor a run thread creates through one of them is declared to `ExecutorShutdownDetector` as the run's own, which is the detector's whole rule: an executor handed in from outside the run, or built in a diff --git a/docs/analysis/corpus-eval.md b/docs/analysis/corpus-eval.md index fa7dd7a39..0d5b9574e 100644 --- a/docs/analysis/corpus-eval.md +++ b/docs/analysis/corpus-eval.md @@ -1884,10 +1884,10 @@ silence, so a refusal cannot outlive a pair in that lane either. | | Detectors | |---|---| | Paired in the recording lane | 127 | -| Paired in the agent-pair lane | 50 | +| Paired in the agent-pair lane | 51 | | ...less those paired in both | -30 | | Paired by neither of those lanes | +1 | -| **Total paired** | **148** | +| **Total paired** | **149** | `CorpusClaimsInDocsTest` derives every paired row from the corpus and fails when one stops being true. The one detector neither pair lane names is `SHARED_COLLECTIONS`, which lane one and the idiom @@ -2429,8 +2429,8 @@ mode. `agent_sleepStamped_whileHoldingTheWriteStamp` and its released twin pair the agent, and were as stated on their first run. **Where it stops.** With these pairs, the two #542 added, the commons-lang3 one and the two #545 -added below, and the Guava service pair (#736), 19 of the 48 agent-fed detectors are measured in -both directions on call sites inside a library. `LibraryReach` records why the other twenty-nine are not, +added below, and the Guava service pair (#736), 19 of the 49 agent-fed detectors are measured in +both directions on call sites inside a library. `LibraryReach` records why the other thirty are not, and `EveryAgentFedDetectorIsReachedThroughALibraryTest` holds that list to both directions: | Detector | Why no corpus library reaches it | @@ -2451,6 +2451,7 @@ and `EveryAgentFedDetectorIsReachedThroughALibraryTest` holds that list to both | `SYNCHRONIZED_COLLECTION_ITERATION` | agent-fed since 2026-10-11, through the woven `iterator()`, `stream()` and map views. A firing library row needs a documented-unsafe library method that iterates a synchronized wrapper unguarded, and no corpus library ships that defect; `agent_synchronizedList_iteratedWithoutItsLock` and its guarded twin pair it in the test file | | `SYSTEM_PROPERTY_MUTATION` | agent-fed since 2026-10-11, through the woven `System.setProperty`, `clearProperty`, `Locale.setDefault` and `TimeZone.setDefault`. A firing library row needs a library method that writes a system property from several threads unguarded, and no corpus library ships that defect; `agent_systemProperty_setByEveryWorker` and its guarded twin pair it in the test file | | `PROCESS_STREAM_STARVATION` | agent-fed since 2026-10-11, through the woven `Process.waitFor` and the pipe getters. A firing library row needs a library method that starts a child and waits before draining it, and no corpus library starts processes; `agent_process_waitedForBeforeDraining` and its draining twin pair it in the test file | +| `KOTLIN_MUTEX_REENTRANCY` | agent-fed since #1007, through the woven kotlinx `Mutex` `lock`, `tryLock` and `unlock`. kotlinx's own classes are never woven and no other corpus library calls a `Mutex`, so `agent_kotlinMutex_lockedAgainByItsHolder` and its unlocked twin lock one from the test body | **A library type reached from the test body (#692).** `agent_jctoolsHandOff_offererWritesAfterTheOffer` and its twin hand an object from one worker to another through the real JCTools `MpscArrayQueue`, diff --git a/docs/analysis/linearizability-checking.md b/docs/analysis/linearizability-checking.md index 89851b7e7..1d65b71e7 100644 --- a/docs/analysis/linearizability-checking.md +++ b/docs/analysis/linearizability-checking.md @@ -5,7 +5,7 @@ failures reported as their shortest impossible prefix since 2026-10-17. ## The gap -The 148 detectors recognise known race shapes: a shared `SimpleDateFormat`, a check-then-act on a +The 149 detectors recognise known race shapes: a shared `SimpleDateFormat`, a check-then-act on a `ConcurrentMap`, a lock taken in two orders. A data structure that returns a wrong answer without matching any of those shapes passes. A concurrent counter whose increment is a read followed by a write can hand two threads the same value, and unless the test author asserts on that exact diff --git a/docs/architecture/configuration-resolution.md b/docs/architecture/configuration-resolution.md index e727aa7a0..32046f8a0 100644 --- a/docs/architecture/configuration-resolution.md +++ b/docs/architecture/configuration-resolution.md @@ -3,7 +3,7 @@ > Part of the [architecture documentation](../ARCHITECTURE.md). How a test declares what to stress and what to detect: `@AsyncTest` attributes snapshotted into an -immutable config, resolved against 148 detector flags. The model is a strict 1:1 mapping maintained +immutable config, resolved against 149 detector flags. The model is a strict 1:1 mapping maintained across several places at once — partial edits break detector wiring silently, so read [adding-a-detector.md](adding-a-detector.md) before touching any of it. diff --git a/docs/architecture/diagrams.md b/docs/architecture/diagrams.md index cffceeb52..e4c3f3fd9 100644 --- a/docs/architecture/diagrams.md +++ b/docs/architecture/diagrams.md @@ -8,7 +8,7 @@ Shows the high-level system architecture and external dependencies. **Key Components:** - **JUnit 5 Platform**: Discovers and executes @AsyncTest methods -- **Async Test Library**: Core testing framework with 148 detectors +- **Async Test Library**: Core testing framework with 149 detectors - **User Test Code**: Tests annotated with @AsyncTest - **Benchmark Storage**: Persistent baseline data for performance comparison @@ -29,7 +29,7 @@ Shows the main containers/components within the async-test library JAR. - **Configuration**: `AsyncTest` annotation, `AsyncTestConfig` (immutable), `Preset` enum - **Runner Core**: `ConcurrencyRunner`, `AsyncTestContext`, `VirtualThreadStressConfig`, `LicenseGuard` (extracted in 1.6.0 — see [License Guard](runtime-guarantees.md#license-guard-160)) -- **Detector Modules** (148 detectors; the phase-by-phase catalog is [DETECTOR_CATALOG.md](../DETECTOR_CATALOG.md)): +- **Detector Modules** (149 detectors; the phase-by-phase catalog is [DETECTOR_CATALOG.md](../DETECTOR_CATALOG.md)): - Phase 1: Core (3 detectors) — grouped via `Phase1DetectorSet` - Phases 2–14: managed by `DetectorRegistry` - **Reporting** (NEW in 1.6.0 — `se.deversity.asynctest.report`): @@ -247,7 +247,7 @@ Shows how the library is deployed and used. - **async-test-lib-<version>.jar**: Main library - Extension layer classes - Runner classes - - 148 detector classes + - 149 detector classes - 5 benchmark classes - META-INF/services (JUnit extension registration) - **async-test-lib-<version>-sources.jar**: Source code diff --git a/docs/architecture/file-structure.md b/docs/architecture/file-structure.md index fecad5323..97729ce02 100644 --- a/docs/architecture/file-structure.md +++ b/docs/architecture/file-structure.md @@ -25,7 +25,7 @@ src/main/java/se/deversity/asynctest/ ├── runner/ │ ├── ConcurrencyRunner.java # Main execution engine │ └── LicenseGuard.java # NEW in 1.6.0 — process-wide license cache -├── diagnostics/ # 148 detector implementations +├── diagnostics/ # 149 detector implementations │ ├── Phase1DetectorSet.java # Phase 1 detector group │ ├── SiteCapture.java # NEW in 1.6.0 — source-line attribution helper │ ├── DeadlockDetector.java diff --git a/docs/detector-catalog/12-futures-scale-structured.md b/docs/detector-catalog/12-futures-scale-structured.md index b0d2797d0..d7f3098e4 100644 --- a/docs/detector-catalog/12-futures-scale-structured.md +++ b/docs/detector-catalog/12-futures-scale-structured.md @@ -330,3 +330,33 @@ against, so a detector for it would be a guess dressed as a measurement. var d = AsyncTestContext.blockingOnNonBlockingThreadDetector(); d.recordBlockingCall("JDBC query", Thread.currentThread()); // inside the event-loop task ``` + +### 149. Kotlin Mutex Reentrancy +* **Severity**: `HIGH` +* **Trust tier**: **verdict** — the holder and every lock are the woven kotlinx calls themselves, and the mutex's own `holdsLock` confirms the holder before a wait is reported, so the evidence class is `OBSERVED`. The corpus agent-pair lane backs it in both directions: `agent_kotlinMutex_lockedAgainByItsHolder` fires and `agent_kotlinMutex_unlockedBetweenLocks` stays silent. +* **Description**: Detects a Kotlin coroutine `Mutex` locked again by the coroutine that holds it. `kotlinx.coroutines.sync.Mutex` is not reentrant, so a `lock()` by its holder waits for an unlock only the holder can make, and the coroutine hangs. The usual shape hides the second lock behind a scope: the block of `withContext`, `coroutineScope`, `supervisorScope` or `withTimeout` runs as a child coroutine its caller is suspended for, so a `withLock` inside it waits for the outer `withLock` to end, and that waits for the block. kotlinx records no holder unless the caller passes an owner token, so the agent passes one (#1007): with `collections=true`, each `lock`, `unlock` and `tryLock` call site, the ones an inlined `withLock` compiles to included, is woven by owner, name and descriptor. A woven `lock` called without an owner is made with a fresh token of the agent's, which kotlinx compares by identity and so treats exactly as no owner, and the hook keeps it with the calling coroutine's `Job`, read from the call's continuation. A `lock` that waits while the mutex's own `holdsLock` says one of those tokens holds it for the caller, or for a coroutine suspended until the caller's scope completes, is the finding. Because the mutex answers, an unlock the agent does not see ends a hold like any other (#1221), and a lock that had to wait holds its token once it is granted (#1220). It errs toward silence: a coroutine that took the mutex through `tryLock`, `select` or a lock outside the agent's `includes=` holds no token, so a reentrant lock under it is missed, and a `launch` or `async` child is not counted as part of its parent, which may unlock without waiting for it. +* **Buggy Code**: + ```kotlin + suspend fun refresh() = mutex.withLock { + val fresh = withContext(Dispatchers.IO) { load() } + update(fresh) + } + + suspend fun update(value: Data) = mutex.withLock { cache = value } // waits for refresh's lock, forever + ``` +* **Fixed Code**: + ```kotlin + suspend fun refresh() { + val fresh = withContext(Dispatchers.IO) { load() } // nothing locked while loading + mutex.withLock { updateLocked(fresh) } + } + + private fun updateLocked(value: Data) { cache = value } // assumes the caller holds the lock + ``` +* **Detect**: + ```java + var d = AsyncTestContext.kotlinMutexReentrancyDetector(); + d.recordAcquired(mutex, outerJob); // took it without waiting + int held = d.holderAmong(mutex, List.of(innerJob, outerJob)); // 1: the outer job holds it + d.recordReentry(mutex, List.of("DispatchedCoroutine", "BlockingCoroutine"), held, Thread.currentThread()); + ``` diff --git a/docs/diagrams/codekarta/class-diagram.svg b/docs/diagrams/codekarta/class-diagram.svg index f69b3fcff..90d1889a9 100644 --- a/docs/diagrams/codekarta/class-diagram.svg +++ b/docs/diagrams/codekarta/class-diagram.svg @@ -1,5 +1,5 @@ - + - - - + + + se.deversity.asynctest se.deversity.asynctest.benchmark - + se.deversity.asynctest.diagnostics se.deversity.asynctest.extension @@ -76,16 +76,16 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe se.deversity.asynctest.spi se.deversity.asynctest.telemetry - -implements - -violations - -failOn - -minTrust - -enabledDetectors + +implements + +violations + +failOn + +minTrust + +enabledDetectors CURRENT @@ -94,56 +94,56 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe registry falseSharingDetector - -wakeupDetector + +wakeupDetector constructorSafetyValidator - -abaProblemDetector - -lockOrderValidator - -synchronizerMonitor - -threadPoolMonitor + +abaProblemDetector + +lockOrderValidator + +synchronizerMonitor + +threadPoolMonitor memoryOrderingMonitor pipelineMonitor - -readWriteLockMonitor - -semaphoreMisuseDetector - -completableFutureExceptionDetector - -completableFutureCompletionLeakDetector + +readWriteLockMonitor + +semaphoreMisuseDetector + +completableFutureExceptionDetector + +completableFutureCompletionLeakDetector virtualThreadPinningDetector - -threadPoolDeadlockDetector - -concurrentModificationDetector - -lockLeakDetector - -sharedRandomDetector - -blockingQueueDetector - -conditionVariableDetector - -simpleDateFormatDetector + +threadPoolDeadlockDetector + +concurrentModificationDetector + +lockLeakDetector + +sharedRandomDetector + +blockingQueueDetector + +conditionVariableDetector + +simpleDateFormatDetector parallelStreamDetector - -resourceLeakDetector + +resourceLeakDetector countDownLatchDetector cyclicBarrierDetector - -reentrantLockDetector + +reentrantLockDetector volatileArrayDetector @@ -172,22 +172,22 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe threadFactoryDetector threadLeakDetector - -sleepInLockDetector - -unboundedQueueDetector - -threadStarvationDetector - -calendarDetector - -sharedCollectionDetector - -timerDetector - -copyOnWriteCollectionDetector - -stringBuilderDetector + +sleepInLockDetector + +unboundedQueueDetector + +threadStarvationDetector + +calendarDetector + +sharedCollectionDetector + +timerDetector + +copyOnWriteCollectionDetector + +stringBuilderDetector structuredConcurrencyMisuseDetector @@ -198,102 +198,102 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe virtualThreadCpuBoundTaskDetector virtualThreadCarrierExhaustionDetector - -httpClientConcurrencyDetector + +httpClientConcurrencyDetector streamClosingDetector - -cacheConcurrencyDetector - -completableFutureChainDetector - -executorShutdownDetector + +cacheConcurrencyDetector + +completableFutureChainDetector + +executorShutdownDetector mutableMapKeyDetector nestedMonitorLockoutDetector - -lockDowngradeDetector - -inheritableThreadLocalMisuseDetector - -threadLocalContaminationDetector - -atomicNonAtomicUpdateDetector - -synchronizedCollectionIterationDetector - -sharedFormatterDetector - -concurrentMapComputeRecursionDetector - -synchronizedOnLiteralDetector - -publicLockExposureDetector + +lockDowngradeDetector + +inheritableThreadLocalMisuseDetector + +threadLocalContaminationDetector + +atomicNonAtomicUpdateDetector + +synchronizedCollectionIterationDetector + +sharedFormatterDetector + +concurrentMapComputeRecursionDetector + +synchronizedOnLiteralDetector + +publicLockExposureDetector forkJoinTaskBlockingDetector optimisticReadValidationDetector - -cfCommonPoolBlockingDetector - -sharedMatcherDetector - -sharedDecimalFormatDetector - -weakReferenceRaceDetector - -statefulLambdaDetector - -sharedMessageDigestDetector + +cfCommonPoolBlockingDetector + +sharedMatcherDetector + +sharedDecimalFormatDetector + +weakReferenceRaceDetector + +statefulLambdaDetector + +sharedMessageDigestDetector interruptSwallowingDetector mdcContextLeakDetector systemPropertyMutationDetector - -futureIgnoredDetector + +futureIgnoredDetector explicitGcDetector deprecatedThreadApiDetector - -sharedXmlParserDetector + +sharedXmlParserDetector boxedPrimitiveLockDetector - -sharedTimeZoneDetector + +sharedTimeZoneDetector uncaughtExceptionHandlerDetector daemonThreadHygieneDetector notifyWithoutMonitorDetector - -sharedSecureRandomDetector - -weakHashMapSharedDetector - -jdbcConnectionSharedDetector + +sharedSecureRandomDetector + +weakHashMapSharedDetector + +jdbcConnectionSharedDetector sharedStatefulCryptoDetector nonAtomicConcurrentMapUpdateDetector - -sharedDeflaterDetector - -thisEscapeDetector - -threadLocalRandomMisuseDetector - -completableFutureObtrudeDetector - -spuriousWakeupHazardDetector - -lockUpgradeDeadlockDetector - -tryLockMisuseDetector + +sharedDeflaterDetector + +thisEscapeDetector + +threadLocalRandomMisuseDetector + +completableFutureObtrudeDetector + +spuriousWakeupHazardDetector + +lockUpgradeDeadlockDetector + +tryLockMisuseDetector cfBlockingCallbackDetector @@ -302,148 +302,150 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe structuredTaskScopeMisuseDetector gathererConcurrencyMisuseDetector - -sharedByteBufferDetector - -sharedCharsetCoderDetector - -sharedChecksumDetector - -fileChannelPositionRaceDetector - -sharedIteratorDetector - -highContentionAtomicDetector - -sharedJsonMapperReconfigDetector + +sharedByteBufferDetector + +sharedCharsetCoderDetector + +sharedChecksumDetector + +fileChannelPositionRaceDetector + +sharedIteratorDetector + +highContentionAtomicDetector + +sharedJsonMapperReconfigDetector lazyConstantMisuseDetector finalFieldMutationDetector - -sharedKdfDetector + +sharedKdfDetector latchMisuseDetector - -executorDeadlockDetector - -futureBlockingDetector - -flowPublisherConcurrencyDetector - -confinedArenaThreadEscapeDetector - -sharedMemorySegmentRaceDetector - -varHandleNonAtomicUpdateDetector - -recordMutableComponentLeakDetector + +executorDeadlockDetector + +futureBlockingDetector + +flowPublisherConcurrencyDetector + +confinedArenaThreadEscapeDetector + +sharedMemorySegmentRaceDetector + +varHandleNonAtomicUpdateDetector + +recordMutableComponentLeakDetector staticInitDeadlockDetector - -virtualThreadPoolingDetector - -platformThreadPerTaskDetector - -sharedSplittableRandomDetector - -completableFutureCompletionRaceDetector + +virtualThreadPoolingDetector + +platformThreadPerTaskDetector + +sharedSplittableRandomDetector + +completableFutureCompletionRaceDetector completableFutureCancellationPropagationDetector - -completableFutureCombinatorMisuseDetector - -lambdaLostUpdateDetector + +completableFutureCombinatorMisuseDetector + +lambdaLostUpdateDetector virtualThreadResourceSaturationDetector - -virtualThreadMonitorSerializationDetector + +virtualThreadMonitorSerializationDetector threadLocalCacheDegradationDetector scopeJoinerMisuseDetector scopeConfigurationMisuseDetector - -scopeResultEscapeDetector + +scopeResultEscapeDetector lazyCollectionMisuseDetector processStreamStarvationDetector blockingOnNonBlockingThreadDetector - -atomicityValidator - -GLOBAL + +kotlinMutexReentrancyDetector + +atomicityValidator + +GLOBAL currentResult baselineResult - -config + +config comparator comparisonResult deadlockDetector - -visibilityMonitor - -livelockDetector + +visibilityMonitor + +livelockDetector falseSharingDetector - -wakeupDetector + +wakeupDetector constructorSafetyValidator - -abaProblemDetector - -lockOrderValidator - -synchronizerMonitor - -threadPoolMonitor + +abaProblemDetector + +lockOrderValidator + +synchronizerMonitor + +threadPoolMonitor memoryOrderingMonitor pipelineMonitor - -readWriteLockMonitor - -semaphoreMisuseDetector - -completableFutureExceptionDetector - -completableFutureCompletionLeakDetector + +readWriteLockMonitor + +semaphoreMisuseDetector + +completableFutureExceptionDetector + +completableFutureCompletionLeakDetector virtualThreadPinningDetector - -threadPoolDeadlockDetector - -concurrentModificationDetector - -lockLeakDetector - -sharedRandomDetector - -blockingQueueDetector - -conditionVariableDetector - -simpleDateFormatDetector + +threadPoolDeadlockDetector + +concurrentModificationDetector + +lockLeakDetector + +sharedRandomDetector + +blockingQueueDetector + +conditionVariableDetector + +simpleDateFormatDetector parallelStreamDetector - -resourceLeakDetector + +resourceLeakDetector countDownLatchDetector cyclicBarrierDetector - -reentrantLockDetector + +reentrantLockDetector volatileArrayDetector @@ -470,34 +472,34 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe forkJoinPoolDetector threadFactoryDetector - -raceConditionDetector - -threadLocalMonitor + +raceConditionDetector + +threadLocalMonitor busyWaitDetector - -atomicityValidator - -interruptMonitor + +atomicityValidator + +interruptMonitor threadLeakDetector - -sleepInLockDetector - -unboundedQueueDetector - -threadStarvationDetector - -calendarDetector - -sharedCollectionDetector - -timerDetector - -copyOnWriteCollectionDetector - -stringBuilderDetector + +sleepInLockDetector + +unboundedQueueDetector + +threadStarvationDetector + +calendarDetector + +sharedCollectionDetector + +timerDetector + +copyOnWriteCollectionDetector + +stringBuilderDetector structuredConcurrencyMisuseDetector @@ -508,102 +510,102 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe virtualThreadCpuBoundTaskDetector virtualThreadCarrierExhaustionDetector - -httpClientConcurrencyDetector + +httpClientConcurrencyDetector streamClosingDetector - -cacheConcurrencyDetector - -completableFutureChainDetector - -executorShutdownDetector + +cacheConcurrencyDetector + +completableFutureChainDetector + +executorShutdownDetector mutableMapKeyDetector nestedMonitorLockoutDetector - -lockDowngradeDetector - -inheritableThreadLocalMisuseDetector - -threadLocalContaminationDetector - -atomicNonAtomicUpdateDetector - -synchronizedCollectionIterationDetector - -sharedFormatterDetector - -concurrentMapComputeRecursionDetector - -synchronizedOnLiteralDetector - -publicLockExposureDetector + +lockDowngradeDetector + +inheritableThreadLocalMisuseDetector + +threadLocalContaminationDetector + +atomicNonAtomicUpdateDetector + +synchronizedCollectionIterationDetector + +sharedFormatterDetector + +concurrentMapComputeRecursionDetector + +synchronizedOnLiteralDetector + +publicLockExposureDetector forkJoinTaskBlockingDetector optimisticReadValidationDetector - -cfCommonPoolBlockingDetector - -sharedMatcherDetector - -sharedDecimalFormatDetector - -weakReferenceRaceDetector - -statefulLambdaDetector - -sharedMessageDigestDetector + +cfCommonPoolBlockingDetector + +sharedMatcherDetector + +sharedDecimalFormatDetector + +weakReferenceRaceDetector + +statefulLambdaDetector + +sharedMessageDigestDetector interruptSwallowingDetector mdcContextLeakDetector systemPropertyMutationDetector - -futureIgnoredDetector + +futureIgnoredDetector explicitGcDetector deprecatedThreadApiDetector - -sharedXmlParserDetector + +sharedXmlParserDetector boxedPrimitiveLockDetector - -sharedTimeZoneDetector + +sharedTimeZoneDetector uncaughtExceptionHandlerDetector daemonThreadHygieneDetector notifyWithoutMonitorDetector - -sharedSecureRandomDetector - -weakHashMapSharedDetector - -jdbcConnectionSharedDetector + +sharedSecureRandomDetector + +weakHashMapSharedDetector + +jdbcConnectionSharedDetector sharedStatefulCryptoDetector nonAtomicConcurrentMapUpdateDetector - -sharedDeflaterDetector - -thisEscapeDetector - -threadLocalRandomMisuseDetector - -completableFutureObtrudeDetector - -spuriousWakeupHazardDetector - -lockUpgradeDeadlockDetector - -tryLockMisuseDetector + +sharedDeflaterDetector + +thisEscapeDetector + +threadLocalRandomMisuseDetector + +completableFutureObtrudeDetector + +spuriousWakeupHazardDetector + +lockUpgradeDeadlockDetector + +tryLockMisuseDetector cfBlockingCallbackDetector @@ -612,316 +614,320 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe structuredTaskScopeMisuseDetector gathererConcurrencyMisuseDetector - -sharedByteBufferDetector - -sharedCharsetCoderDetector - -sharedChecksumDetector - -fileChannelPositionRaceDetector - -sharedIteratorDetector - -highContentionAtomicDetector - -sharedJsonMapperReconfigDetector + +sharedByteBufferDetector + +sharedCharsetCoderDetector + +sharedChecksumDetector + +fileChannelPositionRaceDetector + +sharedIteratorDetector + +highContentionAtomicDetector + +sharedJsonMapperReconfigDetector lazyConstantMisuseDetector finalFieldMutationDetector - -sharedKdfDetector + +sharedKdfDetector latchMisuseDetector - -executorDeadlockDetector - -futureBlockingDetector - -flowPublisherConcurrencyDetector - -confinedArenaThreadEscapeDetector - -sharedMemorySegmentRaceDetector - -varHandleNonAtomicUpdateDetector - -recordMutableComponentLeakDetector + +executorDeadlockDetector + +futureBlockingDetector + +flowPublisherConcurrencyDetector + +confinedArenaThreadEscapeDetector + +sharedMemorySegmentRaceDetector + +varHandleNonAtomicUpdateDetector + +recordMutableComponentLeakDetector staticInitDeadlockDetector - -virtualThreadPoolingDetector - -platformThreadPerTaskDetector - -sharedSplittableRandomDetector - -completableFutureCompletionRaceDetector + +virtualThreadPoolingDetector + +platformThreadPerTaskDetector + +sharedSplittableRandomDetector + +completableFutureCompletionRaceDetector completableFutureCancellationPropagationDetector - -completableFutureCombinatorMisuseDetector - -lambdaLostUpdateDetector + +completableFutureCombinatorMisuseDetector + +lambdaLostUpdateDetector virtualThreadResourceSaturationDetector - -virtualThreadMonitorSerializationDetector + +virtualThreadMonitorSerializationDetector threadLocalCacheDegradationDetector scopeJoinerMisuseDetector scopeConfigurationMisuseDetector - -scopeResultEscapeDetector + +scopeResultEscapeDetector lazyCollectionMisuseDetector processStreamStarvationDetector blockingOnNonBlockingThreadDetector - -enabled - -unnamedLabels - -unnamedLabels - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -unnamedLabels - -extends - -extends - -extends - -unnamedLabels - -extends - -extends - -unnamedLabels - -extends + +kotlinMutexReentrancyDetector + +enabled + +unnamedLabels + +unnamedLabels + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +unnamedLabels + +extends + +extends + +extends + +unnamedLabels + +extends + +extends + +unnamedLabels + +extends DECLARED - -AGENT_FED - -ZERO_CONFIG_FED + +AGENT_FED + +ZERO_CONFIG_FED FEEDS HARNESS - -extends - -unnamedLabels - -extends - -extends - -extends - -extends - -extends - -extends + +extends + +unnamedLabels + +extends + +extends + +extends + +extends + +extends + +extends LOOKUP - -extends - -extends - -unnamedLabels - -extends - -extends - -extends - -upgradeReporter - -unnamedLabels - -unnamedLabels - -extends - -unnamedLabels - -unnamedLabels - -extends - -unnamedLabels - -visibility - -livelock - -race - -threadLocal - -busyWait - -atomicity - -interrupt - -extends - -extends - -extends - -unnamedLabels - -deduplicator - -extends - -extends - -unnamedLabels - -leakReporter - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -unnamedLabels - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -unnamedLabels - -unnamedLabels - -extends - -extends - -extends - -extends - -extends - -extends - -extends - -unnamedLabels - -extends - -extends - -extends - -extends - -extends + +extends + +extends + +extends + +unnamedLabels + +extends + +extends + +extends + +upgradeReporter + +unnamedLabels + +unnamedLabels + +extends + +unnamedLabels + +unnamedLabels + +extends + +unnamedLabels + +visibility + +livelock + +race + +threadLocal + +busyWait + +atomicity + +interrupt + +extends + +extends + +extends + +unnamedLabels + +deduplicator + +extends + +extends + +unnamedLabels + +leakReporter + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +unnamedLabels + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +unnamedLabels + +unnamedLabels + +extends + +extends + +extends + +extends + +extends + +extends + +extends + +unnamedLabels + +extends + +extends + +extends + +extends + +extends asyncTest severities - -listeners - -implements + +listeners + +implements EMPTY severity implements - -implements + +implements sink - -implements + +implements sink @@ -930,12 +936,12 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe findings implements - -implements + +implements byId - -atomicityValidator + +atomicityValidator BUFFER @@ -968,9 +974,9 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe COMMON_POOL_TASK: ThreadLo… STACK: StackWalker UNCONFIGURABLE: Map<Execut… - RUNNING_HANDED: ThreadLoca… - SINGLE_THREAD_WRAPPERS: Se… - …(+2 more) + PIPELINES: Map<Stream<?>,L… + RUNNING_HANDED: ThreadLoca… + …(+6 more) abaSlot(Object): ABAProble… abaSlot(Object, Object): A… @@ -978,7 +984,7 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe acquire(Semaphore): void tryAcquire(Semaphore): boo… release(Semaphore): void - …(+202 more) + …(+235 more) AgentConstructionHooks [CLASS] @@ -1103,33 +1109,33 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe AsyncFindings [CLASS] - - AsyncFindings - - violations: List<Violation> - closed: boolean - - collect(): AsyncFindings - onViolation(Violation): vo… - violations(): List<Violati… - violationsFrom(String): Li… - assertReported(String): vo… - assertReported(String, Iss… - …(+7 more) + + AsyncFindings + + violations: List<Violation> + closed: boolean + + collect(): AsyncFindings + onViolation(Violation): vo… + violations(): List<Violati… + violationsFrom(String): Li… + assertReported(String): vo… + assertReported(String, Iss… + …(+7 more) AsyncTestListener [INTERFACE] - - «interface» - AsyncTestListener - - onInvocationStarted(int, i… - onInvocationCompleted(int,… - onTestFailed(Throwable): v… - onDetectorReport(String, S… - onTimeout(long): void - onStructuredReport(String,… - …(+1 more) + + «interface» + AsyncTestListener + + onInvocationStarted(int, i… + onInvocationCompleted(int,… + onTestFailed(Throwable): v… + onDetectorReport(String, S… + onTimeout(long): void + onStructuredReport(String,… + …(+1 more) Violation [CLASS] @@ -1143,29 +1149,29 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe AsyncTestConfig [CLASS] - - AsyncTestConfig - - threads: int - invocations: int - useVirtualThreads: boolean - timeoutMs: long - virtualThreadStressMode: S… - detectAll: boolean - …(+164 more) - - enabledDetectors(): Set<De… - isEnabled(DetectorType): b… - isEnabled(String): boolean - excludedIds(): Set<String> - from(AsyncTest): AsyncTest… - from(AsyncTest, int): Asyn… - …(+1 more) + + AsyncTestConfig + + threads: int + invocations: int + useVirtualThreads: boolean + timeoutMs: long + virtualThreadStressMode: S… + detectAll: boolean + …(+165 more) + + enabledDetectors(): Set<De… + isEnabled(DetectorType): b… + isEnabled(String): boolean + excludedIds(): Set<String> + from(AsyncTest): AsyncTest… + from(AsyncTest, int): Asyn… + …(+1 more) FailOn [CLASS] - - FailOn + + FailOn TrustTier [CLASS] @@ -1174,8 +1180,8 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe DetectorType [CLASS] - - DetectorType + + DetectorType AsyncTestContext [CLASS] @@ -1188,7 +1194,7 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe LENT: ThreadLocal<AsyncTes… registry: DetectorRegistry sharingScope: SelfGuard.Sc… - …(+153 more) + …(+154 more) sharedVisibilityMonitor():… sharedLivelockDetector(): … @@ -1196,7 +1202,7 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe sharedThreadLocalMonitor()… sharedBusyWaitDetector(): … sharedAtomicityValidator()… - …(+234 more) + …(+236 more) DetectorRegistry [CLASS] @@ -1235,18 +1241,18 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe WakeupDetector [CLASS] - - WakeupDetector - - enabled: boolean - - newState(Object, String): … - recordWaitEnter(Object): v… - recordWaitExit(Object, boo… - recordGaveUp(Object): void - recordNotify(Object, boole… - markInvocationStart(): void - …(+6 more) + + WakeupDetector + + enabled: boolean + + newState(Object, String): … + recordWaitEnter(Object): v… + recordWaitExit(Object, boo… + recordGaveUp(Object): void + recordNotify(Object, boole… + markInvocationStart(): void + …(+6 more) ConstructorSafetyValidator [CLASS] @@ -1271,73 +1277,73 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe ABAProblemDetector [CLASS] - - ABAProblemDetector - - unnamedLabels: UnnamedLabe… - sequence: AtomicLong - roundStarts: long - trackedVariables: Map<Stri… - agentSlots: Map<Object,Age… - enabled: boolean - …(+3 more) - - recordValueChange(String, … - recordRead(String, Object)… - recordCASAttempt(String, O… - detectCycles(AtomicValueHi… - abaReturn(List<ValueChange… - firstAfter(List<ValueChang… - …(+16 more) + + ABAProblemDetector + + unnamedLabels: UnnamedLabe… + sequence: AtomicLong + roundStarts: long + trackedVariables: Map<Stri… + agentSlots: Map<Object,Age… + enabled: boolean + …(+3 more) + + recordValueChange(String, … + recordRead(String, Object)… + recordCASAttempt(String, O… + detectCycles(AtomicValueHi… + abaReturn(List<ValueChange… + firstAfter(List<ValueChang… + …(+16 more) LockOrderValidator [CLASS] - - LockOrderValidator - - unnamedLabels: UnnamedLabe… - labels: Map<IdentityKey,St… - threadLockOrders: Map<Long… - enabled: boolean - - label(IdentityKey): String - recordLockAcquisition(Obje… - recordLockRelease(Object):… - validateLockOrder(): LockO… - detectDeadlockCycles(Colle… - hasCycle(IdentityKey, Map<… - …(+3 more) + + LockOrderValidator + + unnamedLabels: UnnamedLabe… + labels: Map<IdentityKey,St… + threadLockOrders: Map<Long… + enabled: boolean + + label(IdentityKey): String + recordLockAcquisition(Obje… + recordLockRelease(Object):… + validateLockOrder(): LockO… + detectDeadlockCycles(Colle… + hasCycle(IdentityKey, Map<… + …(+3 more) SynchronizerMonitor [CLASS] - - SynchronizerMonitor - - enabled: boolean - - registerSynchronizer(Objec… - recordBarrierArrival(Objec… - recordBarrierAdvance(Objec… - recordBarrierReset(Object)… - analyzeSynchronizers(): Sy… - analyze(): SynchronizerRep… - …(+3 more) + + SynchronizerMonitor + + enabled: boolean + + registerSynchronizer(Objec… + recordBarrierArrival(Objec… + recordBarrierAdvance(Objec… + recordBarrierReset(Object)… + analyzeSynchronizers(): Sy… + analyze(): SynchronizerRep… + …(+3 more) ThreadPoolMonitor [CLASS] - - ThreadPoolMonitor - - LONG_TASK_THRESHOLD_MS: lo… - enabled: boolean - - registerPool(Object, Strin… - recordTaskSubmitted(Object… - recordTaskStarted(Object):… - recordTaskCompleted(Object… - recordTaskRejected(Object,… - recordRejectedExecution(Ob… - …(+5 more) + + ThreadPoolMonitor + + LONG_TASK_THRESHOLD_MS: lo… + enabled: boolean + + registerPool(Object, Strin… + recordTaskSubmitted(Object… + recordTaskStarted(Object):… + recordTaskCompleted(Object… + recordTaskRejected(Object,… + recordRejectedExecution(Ob… + …(+5 more) MemoryOrderingMonitor [CLASS] @@ -1373,71 +1379,71 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe ReadWriteLockMonitor [CLASS] - - ReadWriteLockMonitor - - WRITER_STARVATION_WAIT_THR… - READER_DOMINANCE_RATIO_THR… - LONG_WRITE_WAIT_THRESHOLD_… - enabled: boolean - - newState(Object, String): … - registerLock(Object, Strin… - recordReadLockAcquired(Obj… - recordReadLockReleased(Obj… - recordWriteLockAcquired(Ob… - recordWriteLockReleased(Ob… - …(+6 more) + + ReadWriteLockMonitor + + WRITER_STARVATION_WAIT_THR… + READER_DOMINANCE_RATIO_THR… + LONG_WRITE_WAIT_THRESHOLD_… + enabled: boolean + + newState(Object, String): … + registerLock(Object, Strin… + recordReadLockAcquired(Obj… + recordReadLockReleased(Obj… + recordWriteLockAcquired(Ob… + recordWriteLockReleased(Ob… + …(+6 more) SemaphoreMisuseDetector [CLASS] - - SemaphoreMisuseDetector - - enabled: boolean - - newState(Object, String): … - registerSemaphore(Semaphor… - recordAcquire(Semaphore, S… - recordRelease(Semaphore, S… - analyze(): SemaphoreMisuse… + + SemaphoreMisuseDetector + + enabled: boolean + + newState(Object, String): … + registerSemaphore(Semaphor… + recordAcquire(Semaphore, S… + recordRelease(Semaphore, S… + analyze(): SemaphoreMisuse… CompletableFutureExceptionDetector [CLASS] - - CompletableFutureExceptionDetect… - - MISSING_HANDLER_AGE_THRESH… - enabled: boolean - MAX_DISCARDED: int - discarded: Queue<Discarded> - discardedCount: AtomicInte… - - newState(Object, String): … - recordDiscarded(Future<?>,… - failureOf(Future<?>): Thro… - recordFutureCreated(Comple… - recordExceptionHandled(Com… - recordFutureCompleted(Comp… - …(+2 more) + + CompletableFutureExceptionDetect… + + MISSING_HANDLER_AGE_THRESH… + enabled: boolean + MAX_DISCARDED: int + discarded: Queue<Discarded> + discardedCount: AtomicInte… + + newState(Object, String): … + recordDiscarded(Future<?>,… + failureOf(Future<?>): Thro… + recordFutureCreated(Comple… + recordExceptionHandled(Com… + recordFutureCompleted(Comp… + …(+2 more) CompletableFutureCompletionLeakDetector [CLASS] - - CompletableFutureCompletionLeakD… - - unnamedLabels: UnnamedLabe… - futures: Map<IdentityKey,F… - leakCount: AtomicInteger - enabled: boolean - - recordFutureCreated(Comple… - recordFutureCompleted(Comp… - recordFutureCompleted(Comp… - analyze(): CompletionLeakR… - hasLeaks(): boolean - getLeakCount(): int - …(+2 more) + + CompletableFutureCompletionLeakD… + + unnamedLabels: UnnamedLabe… + futures: Map<IdentityKey,F… + leakCount: AtomicInteger + enabled: boolean + + recordFutureCreated(Comple… + recordFutureCompleted(Comp… + recordFutureCompleted(Comp… + analyze(): CompletionLeakR… + hasLeaks(): boolean + getLeakCount(): int + …(+2 more) VirtualThreadPinningDetector [CLASS] @@ -1460,114 +1466,114 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe ThreadPoolDeadlockDetector [CLASS] - - ThreadPoolDeadlockDetector - - deadlockRiskCount: AtomicI… - enabled: boolean - - registerPool(ExecutorServi… - recordNestedSubmission(Exe… - recordTaskCompleted(Execut… - analyze(): ThreadPoolDeadl… - hasDeadlockRisk(): boolean - getDeadlockRiskCount(): int - …(+3 more) + + ThreadPoolDeadlockDetector + + deadlockRiskCount: AtomicI… + enabled: boolean + + registerPool(ExecutorServi… + recordNestedSubmission(Exe… + recordTaskCompleted(Execut… + analyze(): ThreadPoolDeadl… + hasDeadlockRisk(): boolean + getDeadlockRiskCount(): int + …(+3 more) ConcurrentModificationDetector [CLASS] - - ConcurrentModificationDetector - - enabled: boolean - - newState(Object, String): … - registerCollection(Collect… - recordIterationStarted(Col… - recordIterationEnded(Colle… - recordModification(Collect… - recordModificationDuringIt… - …(+1 more) + + ConcurrentModificationDetector + + enabled: boolean + + newState(Object, String): … + registerCollection(Collect… + recordIterationStarted(Col… + recordIterationEnded(Colle… + recordModification(Collect… + recordModificationDuringIt… + …(+1 more) LockLeakDetector [CLASS] - - LockLeakDetector - - unnamedLabels: UnnamedLabe… - locks: Map<IdentityKey,Loc… - enabled: boolean - - registerLock(Lock, String)… - recordLockAcquired(Lock, S… - recordLockReleased(Lock, S… - analyze(): LockLeakReport - confirmedHold(ReentrantLoc… + + LockLeakDetector + + unnamedLabels: UnnamedLabe… + locks: Map<IdentityKey,Loc… + enabled: boolean + + registerLock(Lock, String)… + recordLockAcquired(Lock, S… + recordLockReleased(Lock, S… + analyze(): LockLeakReport + confirmedHold(ReentrantLoc… SharedRandomDetector [CLASS] - - SharedRandomDetector - - CONTENTION_ACCESS_THRESHOL… - CONTENTION_RATE_THRESHOLD:… - enabled: boolean - - newState(Object, String): … - registerRandom(Random, Str… - recordRandomAccess(Random,… - analyze(): SharedRandomRep… + + SharedRandomDetector + + CONTENTION_ACCESS_THRESHOL… + CONTENTION_RATE_THRESHOLD:… + enabled: boolean + + newState(Object, String): … + registerRandom(Random, Str… + recordRandomAccess(Random,… + analyze(): SharedRandomRep… BlockingQueueDetector [CLASS] - - BlockingQueueDetector - - UNBOUNDED: int - enabled: boolean - lastOffer: ThreadLocal<Que… - COHERENT_READ_ATTEMPTS: int - - registerQueue(BlockingQueu… - observeQueue(BlockingQueue… - observedCapacityOf(Blockin… - widerBound(int, int): int - recordOffer(BlockingQueue<… - recordOfferResultDiscarded… - …(+5 more) + + BlockingQueueDetector + + UNBOUNDED: int + enabled: boolean + lastOffer: ThreadLocal<Que… + COHERENT_READ_ATTEMPTS: int + + registerQueue(BlockingQueu… + observeQueue(BlockingQueue… + observedCapacityOf(Blockin… + widerBound(int, int): int + recordOffer(BlockingQueue<… + recordOfferResultDiscarded… + …(+5 more) ConditionVariableDetector [CLASS] - - ConditionVariableDetector - - LOCK_HELD: int - NOT_OWNED: int - invocationEpoch: AtomicLong - enabled: boolean - - newState(Object, String): … - registerCondition(Conditio… - registerCondition(Reentran… - registerCondition(Reentran… - registerCondition(Reentran… - registerCondition(Reentran… - …(+10 more) + + ConditionVariableDetector + + LOCK_HELD: int + NOT_OWNED: int + invocationEpoch: AtomicLong + enabled: boolean + + newState(Object, String): … + registerCondition(Conditio… + registerCondition(Reentran… + registerCondition(Reentran… + registerCondition(Reentran… + registerCondition(Reentran… + …(+10 more) SimpleDateFormatDetector [CLASS] - - SimpleDateFormatDetector - - enabled: boolean - - newState(Object, String): … - registerFormatter(SimpleDa… - recordFormat(SimpleDateFor… - recordParse(SimpleDateForm… - recordError(SimpleDateForm… - recordAccess(SimpleDateFor… - …(+1 more) + + SimpleDateFormatDetector + + enabled: boolean + + newState(Object, String): … + registerFormatter(SimpleDa… + recordFormat(SimpleDateFor… + recordParse(SimpleDateForm… + recordError(SimpleDateForm… + recordAccess(SimpleDateFor… + …(+1 more) ParallelStreamDetector [CLASS] @@ -1587,15 +1593,15 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe ResourceLeakDetector [CLASS] - - ResourceLeakDetector - - enabled: boolean - - registerResource(Object, S… - recordResourceOpened(Objec… - recordResourceClosed(Objec… - analyze(): ResourceLeakRep… + + ResourceLeakDetector + + enabled: boolean + + registerResource(Object, S… + recordResourceOpened(Objec… + recordResourceClosed(Objec… + analyze(): ResourceLeakRep… CountDownLatchDetector [CLASS] @@ -1636,24 +1642,24 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe ReentrantLockDetector [CLASS] - - ReentrantLockDetector - - unnamedLabels: UnnamedLabe… - lockRegistry: Map<Reentran… - timeouts: Map<ReentrantLoc… - observed: Map<ReentrantLoc… - observedStarvation: Set<St… - recordedWaits: Set<String> - …(+3 more) - - deferLeakReportingTo(LockL… - nameOf(ReentrantLock): Str… - observedFor(ReentrantLock)… - registerLock(ReentrantLock… - recordLockAcquired(Reentra… - recordLockReleased(Reentra… - …(+13 more) + + ReentrantLockDetector + + unnamedLabels: UnnamedLabe… + lockRegistry: Map<Reentran… + timeouts: Map<ReentrantLoc… + observed: Map<ReentrantLoc… + observedStarvation: Set<St… + recordedWaits: Set<String> + …(+3 more) + + deferLeakReportingTo(LockL… + nameOf(ReentrantLock): Str… + observedFor(ReentrantLock)… + registerLock(ReentrantLock… + recordLockAcquired(Reentra… + recordLockReleased(Reentra… + …(+13 more) VolatileArrayDetector [CLASS] @@ -1891,127 +1897,127 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe SleepInLockDetector [CLASS] - - SleepInLockDetector - - unnamedLabels: UnnamedLabe… - events: List<SleepInLockEv… - eventCount: AtomicInteger - enabled: boolean - monitoring: boolean - - startMonitoring(): void - stopMonitoring(): void - recordSleep(long): void - recordSleep(long, Object):… - recordSleepUnderHeldLocks(… - recordHolding(long, Object… - …(+6 more) + + SleepInLockDetector + + unnamedLabels: UnnamedLabe… + events: List<SleepInLockEv… + eventCount: AtomicInteger + enabled: boolean + monitoring: boolean + + startMonitoring(): void + stopMonitoring(): void + recordSleep(long): void + recordSleep(long, Object):… + recordSleepUnderHeldLocks(… + recordHolding(long, Object… + …(+6 more) UnboundedQueueDetector [CLASS] - - UnboundedQueueDetector - - events: List<UnboundedQueu… - enabled: boolean - warningThreshold: int - - recordQueueCreation(Blocki… - recordEnqueue(BlockingQueu… - recordDequeue(BlockingQueu… - analyze(): UnboundedQueueR… - clear(): void - disable(): void - …(+1 more) + + UnboundedQueueDetector + + events: List<UnboundedQueu… + enabled: boolean + warningThreshold: int + + recordQueueCreation(Blocki… + recordEnqueue(BlockingQueu… + recordDequeue(BlockingQueu… + analyze(): UnboundedQueueR… + clear(): void + disable(): void + …(+1 more) ThreadStarvationDetector [CLASS] - - ThreadStarvationDetector - - starvationEvents: List<Tas… - enabled: boolean - starvationThresholdMs: long - - registerExecutor(ExecutorS… - recordTaskSubmission(Execu… - recordTaskStart(String, lo… - recordTaskEnd(String): void - analyze(): ThreadStarvatio… - clear(): void - …(+2 more) + + ThreadStarvationDetector + + starvationEvents: List<Tas… + enabled: boolean + starvationThresholdMs: long + + registerExecutor(ExecutorS… + recordTaskSubmission(Execu… + recordTaskStart(String, lo… + recordTaskEnd(String): void + analyze(): ThreadStarvatio… + clear(): void + …(+2 more) CalendarDetector [CLASS] - - CalendarDetector - - newState(Object, String): … - registerCalendar(Calendar,… - recordGet(Calendar, String… - recordSet(Calendar, String… - recordSetTime(Calendar, St… - recordAdd(Calendar, String… - …(+4 more) + + CalendarDetector + + newState(Object, String): … + registerCalendar(Calendar,… + recordGet(Calendar, String… + recordSet(Calendar, String… + recordSetTime(Calendar, St… + recordAdd(Calendar, String… + …(+4 more) SharedCollectionDetector [CLASS] - - SharedCollectionDetector - - newState(Object, String): … - registerCollection(Object,… - recordRead(Object, String,… - recordWrite(Object, String… - resolveState(Object, Strin… - markInvocationStart(): void - …(+1 more) + + SharedCollectionDetector + + newState(Object, String): … + registerCollection(Object,… + recordRead(Object, String,… + recordWrite(Object, String… + resolveState(Object, Strin… + markInvocationStart(): void + …(+1 more) TimerDetector [CLASS] - - TimerDetector - - TIMER_THREAD_CLASS: String - DEATH_WAIT_MS: long - QUOTED_STARVATIONS: int - - newState(Object, String): … - registerTimer(java.util.Ti… - recordTaskSchedule(java.ut… - recordTaskRun(java.util.Ti… - recordTaskRun(java.util.Ti… - recordFixedDelayTaskRun(ja… - …(+10 more) + + TimerDetector + + TIMER_THREAD_CLASS: String + DEATH_WAIT_MS: long + QUOTED_STARVATIONS: int + + newState(Object, String): … + registerTimer(java.util.Ti… + recordTaskSchedule(java.ut… + recordTaskRun(java.util.Ti… + recordTaskRun(java.util.Ti… + recordFixedDelayTaskRun(ja… + …(+10 more) CopyOnWriteCollectionDetector [CLASS] - - CopyOnWriteCollectionDetector - - WRITE_RATIO_THRESHOLD: dou… - MIN_WRITE_COUNT_FOR_RATIO_… - - newState(Object, String): … - registerCollection(Object,… - recordRead(Object, String)… - recordWrite(Object, String… - resolve(Object, String): C… - analyze(): CopyOnWriteRepo… + + CopyOnWriteCollectionDetector + + WRITE_RATIO_THRESHOLD: dou… + MIN_WRITE_COUNT_FOR_RATIO_… + + newState(Object, String): … + registerCollection(Object,… + recordRead(Object, String)… + recordWrite(Object, String… + resolve(Object, String): C… + analyze(): CopyOnWriteRepo… StringBuilderDetector [CLASS] - - StringBuilderDetector - - newState(Object, String): … - registerBuilder(StringBuil… - recordAppend(StringBuilder… - recordInsert(StringBuilder… - recordDelete(StringBuilder… - recordReplace(StringBuilde… - …(+8 more) + + StringBuilderDetector + + newState(Object, String): … + registerBuilder(StringBuil… + recordAppend(StringBuilder… + recordInsert(StringBuilder… + recordDelete(StringBuilder… + recordReplace(StringBuilde… + …(+8 more) StructuredConcurrencyMisuseDetector [CLASS] @@ -2110,21 +2116,21 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe HttpClientConcurrencyDetector [CLASS] - - HttpClientConcurrencyDetector - - POOL_EXHAUSTION_REQUESTS_T… - UNATTRIBUTED_CLIENT: String - unattributed: ClientState - enabled: boolean - - newState(Object, String): … - disable(): void - enable(): void - recordClientCreated(Object… - recordRequestSent(Object, … - recordRequestSent(Object, … - …(+4 more) + + HttpClientConcurrencyDetector + + POOL_EXHAUSTION_REQUESTS_T… + UNATTRIBUTED_CLIENT: String + unattributed: ClientState + enabled: boolean + + newState(Object, String): … + disable(): void + enable(): void + recordClientCreated(Object… + recordRequestSent(Object, … + recordRequestSent(Object, … + …(+4 more) StreamClosingDetector [CLASS] @@ -2149,56 +2155,56 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe CacheConcurrencyDetector [CLASS] - - CacheConcurrencyDetector - - MAX_TRACKED_KEYS: int - enabled: boolean - - newState(Object, String): … - typedState(Object, String)… - cacheState(Map<?,?>, Strin… - disable(): void - enable(): void - registerCache(Map<?,?>, St… - …(+5 more) + + CacheConcurrencyDetector + + MAX_TRACKED_KEYS: int + enabled: boolean + + newState(Object, String): … + typedState(Object, String)… + cacheState(Map<?,?>, Strin… + disable(): void + enable(): void + registerCache(Map<?,?>, St… + …(+5 more) CompletableFutureChainDetector [CLASS] - - CompletableFutureChainDetector - - ARROW: java.util.regex.Pat… - totalCreated: AtomicInteger - totalJoined: AtomicInteger - totalChained: AtomicInteger - enabled: boolean - - newState(Object, String): … - disable(): void - enable(): void - recordFutureCreated(Comple… - recordChainOperation(Compl… - recordExceptionally(Comple… - …(+3 more) + + CompletableFutureChainDetector + + ARROW: java.util.regex.Pat… + totalCreated: AtomicInteger + totalJoined: AtomicInteger + totalChained: AtomicInteger + enabled: boolean + + newState(Object, String): … + disable(): void + enable(): void + recordFutureCreated(Comple… + recordChainOperation(Compl… + recordExceptionally(Comple… + …(+3 more) ExecutorShutdownDetector [CLASS] - - ExecutorShutdownDetector - - unnamedLabels: UnnamedLabe… - executors: Map<ExecutorSer… - heldUntilTeardown: List<Ex… - holdUntilTeardown: boolean - - recordExecutorCreated(Exec… - recordTaskSubmitted(Execut… - recordShutdownCalled(Execu… - recordAwaitTerminationCall… - holdUnclosedUntilTeardown(… - analyzeAfterTeardown(): Ex… - …(+2 more) + + ExecutorShutdownDetector + + unnamedLabels: UnnamedLabe… + executors: Map<ExecutorSer… + heldUntilTeardown: List<Ex… + holdUntilTeardown: boolean + + recordExecutorCreated(Exec… + recordTaskSubmitted(Execut… + recordShutdownCalled(Execu… + recordAwaitTerminationCall… + holdUnclosedUntilTeardown(… + analyzeAfterTeardown(): Ex… + …(+2 more) MutableMapKeyDetector [CLASS] @@ -2232,124 +2238,124 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe LockDowngradeDetector [CLASS] - - LockDowngradeDetector - - invocationEpoch: AtomicLong - upgradeReporter: LockUpgra… - - newState(Object, String): … - deferUpgradeReportingTo(Lo… - forward(ReadWriteLock, jav… - stateFor(ReadWriteLock, St… - recordReadLockAcquired(Rea… - recordReadLockReleased(Rea… - …(+5 more) + + LockDowngradeDetector + + invocationEpoch: AtomicLong + upgradeReporter: LockUpgra… + + newState(Object, String): … + deferUpgradeReportingTo(Lo… + forward(ReadWriteLock, jav… + stateFor(ReadWriteLock, St… + recordReadLockAcquired(Rea… + recordReadLockReleased(Rea… + …(+5 more) InheritableThreadLocalMisuseDetector [CLASS] - - InheritableThreadLocalMisuseDete… - - knownPoolThreadIds: Set<Lo… - pooledGetIssues: List<Stri… - pooledSetIssues: List<Stri… - - newState(Object, String): … - registerPoolThread(Thread)… - recordGet(InheritableThrea… - recordSet(InheritableThrea… - analyze(): InheritableThre… + + InheritableThreadLocalMisuseDete… + + knownPoolThreadIds: Set<Lo… + pooledGetIssues: List<Stri… + pooledSetIssues: List<Stri… + + newState(Object, String): … + registerPoolThread(Thread)… + recordGet(InheritableThrea… + recordSet(InheritableThrea… + analyze(): InheritableThre… ThreadLocalContaminationDetector [CLASS] - - ThreadLocalContaminationDetect… - - unnamedLabels: UnnamedLabe… - threadStates: Map<Long,Thr… - contaminations: List<Strin… - - recordNewTask(Thread, Stri… - recordSet(Thread, Object, … - recordGet(Thread, Object, … - analyze(): ThreadLocalCont… + + ThreadLocalContaminationDetect… + + unnamedLabels: UnnamedLabe… + threadStates: Map<Long,Thr… + contaminations: List<Strin… + + recordNewTask(Thread, Stri… + recordSet(Thread, Object, … + recordGet(Thread, Object, … + analyze(): ThreadLocalCont… AtomicNonAtomicUpdateDetector [CLASS] - - AtomicNonAtomicUpdateDetector - - MAX_WOVEN_DETAILS: int - - newState(Object, String): … - recordGet(Object, String, … - recordSet(Object, String, … - recordCas(Object, String, … - agentRead(Object): void - agentStore(Object): void - …(+4 more) + + AtomicNonAtomicUpdateDetector + + MAX_WOVEN_DETAILS: int + + newState(Object, String): … + recordGet(Object, String, … + recordSet(Object, String, … + recordCas(Object, String, … + agentRead(Object): void + agentStore(Object): void + …(+4 more) SynchronizedCollectionIterationDetector [CLASS] - - SynchronizedCollectionIterationD… - - MAX_DETAILS: int - viewOwners: Map<IdentityKe… - - newState(Object, String): … - recordWrapperCreated(Objec… - recordIterationStarted(Obj… - recordView(Object, Object)… - agentIteration(Object, Thr… - agentContains(Object, Obje… - …(+3 more) + + SynchronizedCollectionIterationD… + + MAX_DETAILS: int + viewOwners: Map<IdentityKe… + + newState(Object, String): … + recordWrapperCreated(Objec… + recordIterationStarted(Obj… + recordView(Object, Object)… + agentIteration(Object, Thr… + agentContains(Object, Obje… + …(+3 more) SharedFormatterDetector [CLASS] - - SharedFormatterDetector - - newState(Object, String): … - recordAccess(Object, Strin… - analyze(): SharedFormatter… + + SharedFormatterDetector + + newState(Object, String): … + recordAccess(Object, Strin… + analyze(): SharedFormatter… ConcurrentMapComputeRecursionDetector [CLASS] - - ConcurrentMapComputeRecursionDet… - - unnamedLabels: UnnamedLabe… - activeByScope: Map<Scope,M… - recursions: List<String> - crossKeyRecursions: List<S… - - scope(Object, Thread): Sco… - recordComputeStart(Map<?,?… - recordComputeEnd(Map<?,?>,… - markInvocationStart(): void - analyze(): ConcurrentMapCo… + + ConcurrentMapComputeRecursionDet… + + unnamedLabels: UnnamedLabe… + activeByScope: Map<Scope,M… + recursions: List<String> + crossKeyRecursions: List<S… + + scope(Object, Thread): Sco… + recordComputeStart(Map<?,?… + recordComputeEnd(Map<?,?>,… + markInvocationStart(): void + analyze(): ConcurrentMapCo… SynchronizedOnLiteralDetector [CLASS] - - SynchronizedOnLiteralDetector - - newState(Object, String): … - recordMonitorAcquired(Obje… - describeIfLiteral(Object):… - analyze(): SynchronizedOnL… + + SynchronizedOnLiteralDetector + + newState(Object, String): … + recordMonitorAcquired(Obje… + describeIfLiteral(Object):… + analyze(): SynchronizedOnL… PublicLockExposureDetector [CLASS] - - PublicLockExposureDetector - - newState(Object, String): … - recordSynchronizedOnThis(O… - recordObjectPublished(Obje… - analyze(): PublicLockExpos… + + PublicLockExposureDetector + + newState(Object, String): … + recordSynchronizedOnThis(O… + recordObjectPublished(Obje… + analyze(): PublicLockExpos… ForkJoinTaskBlockingDetector [CLASS] @@ -2384,68 +2390,68 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe CompletableFutureCommonPoolBlockingDetector [CLASS] - - CompletableFutureCommonPoolBlock… - - MAX_DISTINCT_FINDINGS: int - occurrences: Map<String,At… - droppedDistinctFindings: A… - - newState(Object, String): … - recordCommonPoolSubmission… - recordBlockingCall(Object,… - analyze(): CompletableFutu… + + CompletableFutureCommonPoolBlock… + + MAX_DISTINCT_FINDINGS: int + occurrences: Map<String,At… + droppedDistinctFindings: A… + + newState(Object, String): … + recordCommonPoolSubmission… + recordBlockingCall(Object,… + analyze(): CompletableFutu… SharedMatcherDetector [CLASS] - - SharedMatcherDetector - - newState(Object, String): … - recordAccess(Object, Strin… - analyze(): SharedMatcherRe… + + SharedMatcherDetector + + newState(Object, String): … + recordAccess(Object, Strin… + analyze(): SharedMatcherRe… SharedDecimalFormatDetector [CLASS] - - SharedDecimalFormatDetector - - newState(Object, String): … - recordAccess(Object, Strin… - analyze(): SharedDecimalFo… + + SharedDecimalFormatDetector + + newState(Object, String): … + recordAccess(Object, Strin… + analyze(): SharedDecimalFo… WeakReferenceRaceDetector [CLASS] - - WeakReferenceRaceDetector - - newState(Object, String): … - recordGet(Object, String, … - recordNullDereference(Obje… - analyze(): WeakReferenceRa… + + WeakReferenceRaceDetector + + newState(Object, String): … + recordGet(Object, String, … + recordNullDereference(Obje… + analyze(): WeakReferenceRa… StatefulLambdaDetector [CLASS] - - StatefulLambdaDetector - - newState(Object, String): … - recordExecution(Object, St… - recordCapturedMutation(Obj… - recordCapturedMutation(Obj… - recordCapturedRead(Object,… - noteCaptureAccess(Object, … - …(+2 more) + + StatefulLambdaDetector + + newState(Object, String): … + recordExecution(Object, St… + recordCapturedMutation(Obj… + recordCapturedMutation(Obj… + recordCapturedRead(Object,… + noteCaptureAccess(Object, … + …(+2 more) SharedMessageDigestDetector [CLASS] - - SharedMessageDigestDetector - - newState(Object, String): … - typeOf(Object): String - recordAccess(Object, Strin… - analyze(): SharedMessageDi… + + SharedMessageDigestDetector + + newState(Object, String): … + typeOf(Object): String + recordAccess(Object, Strin… + analyze(): SharedMessageDi… InterruptSwallowingDetector [CLASS] @@ -2486,19 +2492,19 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe FutureIgnoredDetector [CLASS] - - FutureIgnoredDetector - - MAX_DISCARDED: int - discarded: Queue<Discarded> - discardedCount: AtomicInte… - discardedDropped: LongAdder - - recordSubmit(Object, Strin… - recordInspect(Object, Thre… - recordDiscarded(Future<?>,… - failureOf(Future<?>): Thro… - analyze(): FutureIgnoredRe… + + FutureIgnoredDetector + + MAX_DISCARDED: int + discarded: Queue<Discarded> + discardedCount: AtomicInte… + discardedDropped: LongAdder + + recordSubmit(Object, Strin… + recordInspect(Object, Thre… + recordDiscarded(Future<?>,… + failureOf(Future<?>): Thro… + analyze(): FutureIgnoredRe… ExplicitGcDetector [CLASS] @@ -2523,12 +2529,12 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe SharedXmlParserDetector [CLASS] - - SharedXmlParserDetector - - newState(Object, String): … - recordAccess(Object, Strin… - analyze(): SharedXmlParser… + + SharedXmlParserDetector + + newState(Object, String): … + recordAccess(Object, Strin… + analyze(): SharedXmlParser… BoxedPrimitiveLockDetector [CLASS] @@ -2545,12 +2551,12 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe SharedTimeZoneDetector [CLASS] - - SharedTimeZoneDetector - - newState(Object, String): … - recordMutation(Object, Str… - analyze(): SharedTimeZoneR… + + SharedTimeZoneDetector + + newState(Object, String): … + recordMutation(Object, Str… + analyze(): SharedTimeZoneR… UncaughtExceptionHandlerDetector [CLASS] @@ -2589,43 +2595,43 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe SharedSecureRandomDetector [CLASS] - - SharedSecureRandomDetector - - invocationEpoch: AtomicLong - - newState(Object, String): … - describe(SecureRandom, Str… - markInvocationStart(): void - recordAccess(SecureRandom,… - analyze(): Report - safeString(java.util.concu… + + SharedSecureRandomDetector + + invocationEpoch: AtomicLong + + newState(Object, String): … + describe(SecureRandom, Str… + markInvocationStart(): void + recordAccess(SecureRandom,… + analyze(): Report + safeString(java.util.concu… WeakHashMapSharedDetector [CLASS] - - WeakHashMapSharedDetector - - newState(Object, String): … - typeOf(Object): String - recordAccess(Map<?,?>, Str… - recordRead(Map<?,?>, Strin… - record(Map<?,?>, String, b… - analyze(): Report + + WeakHashMapSharedDetector + + newState(Object, String): … + typeOf(Object): String + recordAccess(Map<?,?>, Str… + recordRead(Map<?,?>, Strin… + record(Map<?,?>, String, b… + analyze(): Report JdbcConnectionSharedDetector [CLASS] - - JdbcConnectionSharedDetector - - PERSISTENCE_HANDLES: Map<S… - - newState(Object, String): … - typeOf(Object): String - persistenceType(Class<?>):… - recordAccess(Object, Strin… - recordRelease(Object, Thre… - analyze(): Report + + JdbcConnectionSharedDetector + + PERSISTENCE_HANDLES: Map<S… + + newState(Object, String): … + typeOf(Object): String + persistenceType(Class<?>):… + recordAccess(Object, Strin… + recordRelease(Object, Thre… + analyze(): Report SharedStatefulCryptoDetector [CLASS] @@ -2659,73 +2665,73 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe SharedDeflaterDetector [CLASS] - - SharedDeflaterDetector - - newState(Object, String): … - recordAccess(Deflater, Str… - recordAccess(Inflater, Str… - record(Object, String, Str… - analyze(): Report + + SharedDeflaterDetector + + newState(Object, String): … + recordAccess(Deflater, Str… + recordAccess(Inflater, Str… + record(Object, String, Str… + analyze(): Report ThisEscapeDetector [CLASS] - - ThisEscapeDetector - - recordConstructorEscape(Ob… - recordExternalAccess(Objec… - recordConstructionComplete… - analyze(): Report + + ThisEscapeDetector + + recordConstructorEscape(Ob… + recordExternalAccess(Objec… + recordConstructionComplete… + analyze(): Report ThreadLocalRandomMisuseDetector [CLASS] - - ThreadLocalRandomMisuseDetect… - - recordObtain(ThreadLocalRa… - recordUse(ThreadLocalRando… - analyze(): Report + + ThreadLocalRandomMisuseDetect… + + recordObtain(ThreadLocalRa… + recordUse(ThreadLocalRando… + analyze(): Report CompletableFutureObtrudeDetector [CLASS] - - CompletableFutureObtrudeDetect… - - newState(Object, String): … - recordObtrude(CompletableF… - analyze(): Report + + CompletableFutureObtrudeDetect… + + newState(Object, String): … + recordObtrude(CompletableF… + analyze(): Report SpuriousWakeupDetector [CLASS] - - SpuriousWakeupDetector - - newState(Object, String): … - recordWait(Object, String,… - analyze(): Report + + SpuriousWakeupDetector + + newState(Object, String): … + recordWait(Object, String,… + analyze(): Report LockUpgradeDeadlockDetector [CLASS] - - LockUpgradeDeadlockDetector - - newState(Object, String): … - recordReadLockAcquired(Ree… - recordReadLockReleased(Ree… - recordWriteLockAcquisition… - analyze(): Report + + LockUpgradeDeadlockDetector + + newState(Object, String): … + recordReadLockAcquired(Ree… + recordReadLockReleased(Ree… + recordWriteLockAcquisition… + analyze(): Report TryLockMisuseDetector [CLASS] - - TryLockMisuseDetector - - newState(Object, String): … - recordTryLockResult(Object… - recordLockAcquired(Object,… - recordUnlock(Object, Strin… - analyze(): Report + + TryLockMisuseDetector + + newState(Object, String): … + recordTryLockResult(Object… + recordLockAcquired(Object,… + recordUnlock(Object, Strin… + analyze(): Report CompletableFutureBlockingCallbackDetector [CLASS] @@ -2806,96 +2812,96 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe SharedByteBufferDetector [CLASS] - - SharedByteBufferDetector - - newState(Object, String): … - recordAccess(Object, Strin… - recordPositionalAccess(Obj… - recordAbsoluteAccess(Objec… - resolve(Object): State - analyze(): Report + + SharedByteBufferDetector + + newState(Object, String): … + recordAccess(Object, Strin… + recordPositionalAccess(Obj… + recordAbsoluteAccess(Objec… + resolve(Object): State + analyze(): Report SharedCharsetCoderDetector [CLASS] - - SharedCharsetCoderDetector - - newState(Object, String): … - recordAccess(CharsetEncode… - recordAccess(CharsetDecode… - record(Object, String, Str… - analyze(): Report + + SharedCharsetCoderDetector + + newState(Object, String): … + recordAccess(CharsetEncode… + recordAccess(CharsetDecode… + record(Object, String, Str… + analyze(): Report SharedChecksumDetector [CLASS] - - SharedChecksumDetector - - newState(Object, String): … - recordAccess(Checksum, Str… - analyze(): Report + + SharedChecksumDetector + + newState(Object, String): … + recordAccess(Checksum, Str… + analyze(): Report FileChannelPositionRaceDetector [CLASS] - - FileChannelPositionRaceDetect… - - SEEK_SLOTS: int - NEUTRAL_OPERATIONS: String - seeks: ThreadLocal<Seeks> - openSeeks: AtomicReference… - - newState(Object, String): … - recordImplicitPositionAcce… - neutral(String): boolean - openSeek(Object): void - seekReliedOn(Object): Seek - markInvocationStart(): void - …(+3 more) + + FileChannelPositionRaceDetect… + + SEEK_SLOTS: int + NEUTRAL_OPERATIONS: String + seeks: ThreadLocal<Seeks> + openSeeks: AtomicReference… + + newState(Object, String): … + recordImplicitPositionAcce… + neutral(String): boolean + openSeek(Object): void + seekReliedOn(Object): Seek + markInvocationStart(): void + …(+3 more) SharedIteratorDetector [CLASS] - - SharedIteratorDetector - - newState(Object, String): … - recordAccess(Object, Strin… - kindOf(Object): String - analyze(): Report + + SharedIteratorDetector + + newState(Object, String): … + recordAccess(Object, Strin… + kindOf(Object): String + analyze(): Report HighContentionAtomicDetector [CLASS] - - HighContentionAtomicDetector - - DEFAULT_ATTEMPT_THRESHOLD:… - FAILURE_RATIO_THRESHOLD: d… - invocationEpoch: AtomicLong - attemptThreshold: long - - newState(Object, String): … - recordCasAttempt(Object, b… - recordUpdate(Object): void - stateFor(Object): State - track(State, Thread): void - markInvocationStart(): void - …(+1 more) + + HighContentionAtomicDetector + + DEFAULT_ATTEMPT_THRESHOLD:… + FAILURE_RATIO_THRESHOLD: d… + invocationEpoch: AtomicLong + attemptThreshold: long + + newState(Object, String): … + recordCasAttempt(Object, b… + recordUpdate(Object): void + stateFor(Object): State + track(State, Thread): void + markInvocationStart(): void + …(+1 more) SharedJsonMapperReconfigDetector [CLASS] - - SharedJsonMapperReconfigDetect… - - MAX_REPORTED_MUTATIONS: int - - busier(SelfGuard.RoundThre… - newState(Object, String): … - recordUse(Object): void - recordConfigMutation(Objec… - retainedMutationRecords():… - stateFor(Object): State - …(+1 more) + + SharedJsonMapperReconfigDetect… + + MAX_REPORTED_MUTATIONS: int + + busier(SelfGuard.RoundThre… + newState(Object, String): … + recordUse(Object): void + recordConfigMutation(Objec… + retainedMutationRecords():… + stateFor(Object): State + …(+1 more) LazyConstantMisuseDetector [CLASS] @@ -2934,11 +2940,11 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe SharedKdfDetector [CLASS] - - SharedKdfDetector - - recordAccess(Object, Strin… - analyze(): Report + + SharedKdfDetector + + recordAccess(Object, Strin… + analyze(): Report LatchMisuseDetector [CLASS] @@ -2955,119 +2961,119 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe ExecutorDeadlockDetector [CLASS] - - ExecutorDeadlockDetector - - registerExecutor(Object, S… - recordTaskSubmitted(Object… - recordTaskStarted(Object):… - recordWaitingOnSibling(Obj… - agentSiblingWait(Object, i… - recordSiblingWaitEnded(Obj… - …(+3 more) + + ExecutorDeadlockDetector + + registerExecutor(Object, S… + recordTaskSubmitted(Object… + recordTaskStarted(Object):… + recordWaitingOnSibling(Obj… + agentSiblingWait(Object, i… + recordSiblingWaitEnded(Obj… + …(+3 more) FutureBlockingDetector [CLASS] - - FutureBlockingDetector - - enabled: boolean - - disable(): void - enable(): void - registerExecutor(Object, S… - recordTaskSubmitted(Object… - recordTaskStarted(Object):… - recordBlockingWait(Object)… - …(+4 more) + + FutureBlockingDetector + + enabled: boolean + + disable(): void + enable(): void + registerExecutor(Object, S… + recordTaskSubmitted(Object… + recordTaskStarted(Object):… + recordBlockingWait(Object)… + …(+4 more) FlowPublisherConcurrencyDetector [CLASS] - - FlowPublisherConcurrencyDetect… - - newState(Object, String): … - recordSubscribe(Object, St… - recordRequest(Object, long… - recordNextStart(Object, Th… - recordNextEnd(Object): void - recordComplete(Object, Thr… - …(+5 more) + + FlowPublisherConcurrencyDetect… + + newState(Object, String): … + recordSubscribe(Object, St… + recordRequest(Object, long… + recordNextStart(Object, Th… + recordNextEnd(Object): void + recordComplete(Object, Thr… + …(+5 more) ConfinedArenaThreadEscapeDetector [CLASS] - - ConfinedArenaThreadEscapeDetector - - unnamedLabels: UnnamedLabe… - PROBE: Thread - SEGMENT: String - IS_ACCESSIBLE_BY: Method - SCOPE: Method - IS_ALIVE: Method - …(+2 more) - - lookup(String, String, Cla… - recordArena(Object, String… - recordAllocation(Object, O… - recordAccess(Object, Strin… - recordClose(Object, Thread… - isClosed(IdentityKey): boo… - …(+7 more) + + ConfinedArenaThreadEscapeDetector + + unnamedLabels: UnnamedLabe… + PROBE: Thread + SEGMENT: String + IS_ACCESSIBLE_BY: Method + SCOPE: Method + IS_ALIVE: Method + …(+2 more) + + lookup(String, String, Cla… + recordArena(Object, String… + recordAllocation(Object, O… + recordAccess(Object, Strin… + recordClose(Object, Thread… + isClosed(IdentityKey): boo… + …(+7 more) SharedMemorySegmentRaceDetector [CLASS] - - SharedMemorySegmentRaceDetect… - - MAX_TRACKED_ACCESSES: int - MAX_REPORTED_PAIRS: int - invocationEpoch: java.util… - - newState(Object, String): … - markInvocationStart(): void - recordAccess(Object, Strin… - recordAccess(Object, Strin… - recordClose(Object, String… - analyze(): Report - …(+3 more) + + SharedMemorySegmentRaceDetect… + + MAX_TRACKED_ACCESSES: int + MAX_REPORTED_PAIRS: int + invocationEpoch: java.util… + + newState(Object, String): … + markInvocationStart(): void + recordAccess(Object, Strin… + recordAccess(Object, Strin… + recordClose(Object, String… + analyze(): Report + …(+3 more) VarHandleNonAtomicUpdateDetector [CLASS] - - VarHandleNonAtomicUpdateDetect… - - unnamedLabels: UnnamedLabe… - MAX_DETAILS: int - locations: Map<Location,St… - - recordGet(Object, Object, … - recordSet(Object, Object, … - recordAtomicUpdate(Object,… - markInvocationStart(): void - guardOf(Object, Object): O… - note(State, Object, Mode, … - …(+3 more) + + VarHandleNonAtomicUpdateDetect… + + unnamedLabels: UnnamedLabe… + MAX_DETAILS: int + locations: Map<Location,St… + + recordGet(Object, Object, … + recordSet(Object, Object, … + recordAtomicUpdate(Object,… + markInvocationStart(): void + guardOf(Object, Object): O… + note(State, Object, Mode, … + …(+3 more) RecordMutableComponentLeakDetector [CLASS] - - RecordMutableComponentLeakDetect… - - MAX_INSTANCES: int - CONCURRENT_PREFIX: String - IMMUTABLE_VIEWS: Set<Strin… - KNOWN_MUTABLE: Set<String> - dropped: LongAdder - invocationEpoch: AtomicLong - - newState(Object, String): … - markInvocationStart(): void - recordShared(Object, Strin… - snapshotted(State): State - snapshot(State): void - read(Object, RecordCompone… - …(+6 more) + + RecordMutableComponentLeakDetect… + + MAX_INSTANCES: int + CONCURRENT_PREFIX: String + IMMUTABLE_VIEWS: Set<Strin… + KNOWN_MUTABLE: Set<String> + dropped: LongAdder + invocationEpoch: AtomicLong + + newState(Object, String): … + markInvocationStart(): void + recordShared(Object, Strin… + snapshotted(State): State + snapshot(State): void + read(Object, RecordCompone… + …(+6 more) StaticInitDeadlockDetector [CLASS] @@ -3092,62 +3098,62 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe VirtualThreadPoolingDetector [CLASS] - - VirtualThreadPoolingDetector - - POOLED_TASKS_THRESHOLD: int - tasksPerVirtualThread: Map… - - registerExecutor(ExecutorS… - manufacturesVirtualThreads… - recordTaskExecution(String… - recordTaskExecution(String… - analyze(): Report + + VirtualThreadPoolingDetector + + POOLED_TASKS_THRESHOLD: int + tasksPerVirtualThread: Map… + + registerExecutor(ExecutorS… + manufacturesVirtualThreads… + recordTaskExecution(String… + recordTaskExecution(String… + analyze(): Report PlatformThreadPerTaskDetector [CLASS] - - PlatformThreadPerTaskDetector - - DEFAULT_CHURN_THRESHOLD: i… - THREAD_PER_TASK_EXECUTOR: … - PROBE_TIMEOUT_MS: long - churnThreshold: int - platformThreadsCreated: Qu… - virtualThreadsCreated: Ato… - - newState(Object, String): … - setChurnThreshold(int): vo… - recordThreadCreated(Thread… - registerExecutor(ExecutorS… - analyze(): Report + + PlatformThreadPerTaskDetector + + DEFAULT_CHURN_THRESHOLD: i… + THREAD_PER_TASK_EXECUTOR: … + PROBE_TIMEOUT_MS: long + churnThreshold: int + platformThreadsCreated: Qu… + virtualThreadsCreated: Ato… + + newState(Object, String): … + setChurnThreshold(int): vo… + recordThreadCreated(Thread… + registerExecutor(ExecutorS… + analyze(): Report SharedSplittableRandomDetector [CLASS] - - SharedSplittableRandomDetector - - newState(Object, String): … - registerGenerator(RandomGe… - recordAccess(RandomGenerat… - tracked(RandomGenerator): … - analyze(): Report + + SharedSplittableRandomDetector + + newState(Object, String): … + registerGenerator(RandomGe… + recordAccess(RandomGenerat… + tracked(RandomGenerator): … + analyze(): Report CompletableFutureCompletionRaceDetector [CLASS] - - CompletableFutureCompletionRaceD… - - sequence: AtomicInteger - enabled: boolean - - newState(Object, String): … - complete(CompletableFuture… - completeExceptionally(Comp… - recordCompletionAttempt(Co… - recordExceptionalCompletio… - record(CompletableFuture<?… - …(+4 more) + + CompletableFutureCompletionRaceD… + + sequence: AtomicInteger + enabled: boolean + + newState(Object, String): … + complete(CompletableFuture… + completeExceptionally(Comp… + recordCompletionAttempt(Co… + recordExceptionalCompletio… + record(CompletableFuture<?… + …(+4 more) CompletableFutureCancellationPropagationDetector [CLASS] @@ -3171,38 +3177,38 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe CompletableFutureCombinatorMisuseDetector [CLASS] - - CompletableFutureCombinatorMisus… - - NON_BLOCKING_READS: Set<St… - sequence: AtomicLong - enabled: boolean - - sameIgnoringCase(String, S… - isNonBlockingRead(String):… - recordCombinator(Completab… - recordConstituentCompleted… - recordAwait(CompletableFut… - disable(): void - …(+2 more) + + CompletableFutureCombinatorMisus… + + NON_BLOCKING_READS: Set<St… + sequence: AtomicLong + enabled: boolean + + sameIgnoringCase(String, S… + isNonBlockingRead(String):… + recordCombinator(Completab… + recordConstituentCompleted… + recordAwait(CompletableFut… + disable(): void + …(+2 more) LambdaLostUpdateDetector [CLASS] - - LambdaLostUpdateDetector - - unnamedLabels: UnnamedLabe… - captures: Map<CaptureKey,C… - enabled: boolean - invocationEpoch: AtomicLong - - markInvocationStart(): void - recordReadModifyWrite(Obje… - recordReadModifyWrite(Obje… - render(Object): String - disable(): void - enable(): void - …(+4 more) + + LambdaLostUpdateDetector + + unnamedLabels: UnnamedLabe… + captures: Map<CaptureKey,C… + enabled: boolean + invocationEpoch: AtomicLong + + markInvocationStart(): void + recordReadModifyWrite(Obje… + recordReadModifyWrite(Obje… + render(Object): String + disable(): void + enable(): void + …(+4 more) VirtualThreadResourceSaturationDetector [CLASS] @@ -3222,21 +3228,21 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe VirtualThreadMonitorSerializationDetector [CLASS] - - VirtualThreadMonitorSerializatio… - - DEFAULT_CONTENTION_THRESHO… - contentionThreshold: int - jdkFeatureVersion: int - enabled: boolean - - newState(Object, String): … - recordMonitorEnter(Object,… - recordMonitorAcquired(Obje… - state(Object, Thread): Mon… - raise(AtomicInteger, int):… - disable(): void - …(+2 more) + + VirtualThreadMonitorSerializatio… + + DEFAULT_CONTENTION_THRESHO… + contentionThreshold: int + jdkFeatureVersion: int + enabled: boolean + + newState(Object, String): … + recordMonitorEnter(Object,… + recordMonitorAcquired(Obje… + state(Object, Thread): Mon… + raise(AtomicInteger, int):… + disable(): void + …(+2 more) ThreadLocalCacheDegradationDetector [CLASS] @@ -3291,20 +3297,20 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe ScopeResultEscapeDetector [CLASS] - - ScopeResultEscapeDetector - - scopes: Map<String,ScopeSt… - sequence: AtomicLong - enabled: boolean - - recordScopeOpened(String, … - recordJoinCompleted(String… - recordResultHandle(Object,… - recordHandleRead(Object, T… - recordHandlePublished(Obje… - recordHandleMutation(Objec… - …(+10 more) + + ScopeResultEscapeDetector + + scopes: Map<String,ScopeSt… + sequence: AtomicLong + enabled: boolean + + recordScopeOpened(String, … + recordJoinCompleted(String… + recordResultHandle(Object,… + recordHandleRead(Object, T… + recordHandlePublished(Obje… + recordHandleMutation(Objec… + …(+10 more) LazyCollectionMisuseDetector [CLASS] @@ -3366,59 +3372,74 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe implementsNamed(Class<?>, … …(+4 more) + + KotlinMutexReentrancyDetector [CLASS] + + KotlinMutexReentrancyDetector + + REMEDY: String + + newState(Object, String): … + recordAcquired(Object, Obj… + recordHolderUnknown(Object… + holderAmong(Object, List<?… + recordReentry(Object, List… + describe(List<String>, int… + …(+2 more) + AtomicityValidator [CLASS] - - AtomicityValidator - - instances: Map<IdentityKey… - collectedInstances: java.l… - lastInstance: java.util.co… - receiverStates: Map<Intege… - generationTakers: Map<Inte… - offers: Map<Integer,Offer> - …(+13 more) - - guardKey(String, int): Str… - instanceOf(Object): int - recordTaker(int, int, long… - ownershipTakes(): int - verdictCounts(String): Map… - takerOf(int, int): Long - …(+56 more) + + AtomicityValidator + + instances: Map<IdentityKey… + collectedInstances: java.l… + lastInstance: java.util.co… + receiverStates: Map<Intege… + generationTakers: Map<Inte… + offers: Map<Integer,Offer> + …(+13 more) + + guardKey(String, int): Str… + instanceOf(Object): int + recordTaker(int, int, long… + ownershipTakes(): int + verdictCounts(String): Map… + takerOf(int, int): Long + …(+56 more) AsyncTestListenerRegistry [CLASS] - - AsyncTestListenerRegistry - - GLOBAL: ListenerRegistryCo… - - register(AsyncTestListener… - unregister(AsyncTestListen… - fireInvocationStarted(int,… - fireInvocationCompleted(in… - fireTestFailed(Throwable):… - fireDetectorReport(String,… - …(+9 more) + + AsyncTestListenerRegistry + + GLOBAL: ListenerRegistryCo… + + register(AsyncTestListener… + unregister(AsyncTestListen… + fireInvocationStarted(int,… + fireInvocationCompleted(in… + fireTestFailed(Throwable):… + fireDetectorReport(String,… + …(+9 more) ListenerRegistryCore [CLASS] - - ListenerRegistryCore - - log: Logger - ANSI: Pattern - writeLock: Object - listeners: List<AsyncTestL… - - register(AsyncTestListener… - unregister(AsyncTestListen… - clearAll(): void - snapshot(): List<AsyncTest… - restore(List<AsyncTestList… - listenerCount(): int - …(+13 more) + + ListenerRegistryCore + + log: Logger + ANSI: Pattern + writeLock: Object + listeners: List<AsyncTestL… + + register(AsyncTestListener… + unregister(AsyncTestListen… + clearAll(): void + snapshot(): List<AsyncTest… + restore(List<AsyncTestList… + listenerCount(): int + …(+13 more) AsyncTestRunner [CLASS] @@ -3568,81 +3589,81 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe VisibilityMonitor [CLASS] - - VisibilityMonitor - - fieldSnapshots: Map<String… - invocationCounter: AtomicL… - enabled: boolean - NULL_VALUE: Object - - recordFieldAccess(String, … - markInvocationStart(): void - analyzeVisibility(): Visib… - analyze(): VisibilityReport - reset(): void - disable(): void - …(+1 more) + + VisibilityMonitor + + fieldSnapshots: Map<String… + invocationCounter: AtomicL… + enabled: boolean + NULL_VALUE: Object + + recordFieldAccess(String, … + markInvocationStart(): void + analyzeVisibility(): Visib… + analyze(): VisibilityReport + reset(): void + disable(): void + …(+1 more) LivelockDetector [CLASS] - - LivelockDetector - - STARVATION_SNAPSHOT_THRESH… - TIMEOUT_SAMPLES: int - TIMEOUT_SAMPLE_GAP_MS: long - BLOCKED_OR_WAITING: Set<Th… - threadHistory: Map<Long,Li… - observedThreads: Set<Long> - …(+6 more) - - workerEnteredBody(Thread):… - workerLeftBody(Thread): vo… - roundTimedOut(): void - captureSnapshot(): void - analyzeLivelocks(): Livelo… - analyze(): LivelockReport - …(+5 more) + + LivelockDetector + + STARVATION_SNAPSHOT_THRESH… + TIMEOUT_SAMPLES: int + TIMEOUT_SAMPLE_GAP_MS: long + BLOCKED_OR_WAITING: Set<Th… + threadHistory: Map<Long,Li… + observedThreads: Set<Long> + …(+6 more) + + workerEnteredBody(Thread):… + workerLeftBody(Thread): vo… + roundTimedOut(): void + captureSnapshot(): void + analyzeLivelocks(): Livelo… + analyze(): LivelockReport + …(+5 more) RaceConditionDetector [CLASS] - - RaceConditionDetector - - unnamedLabels: UnnamedLabe… - VOLATILE_FIELDS: ClassValu… - deduplicator: IssueDedupli… - invocationEpoch: AtomicLong - enabled: boolean - - intersection(int[], int[])… - isVolatile(Class<?>, Strin… - newState(Object, String): … - markInvocationStart(): void - recordFieldRead(Object, St… - recordFieldWrite(Object, S… - …(+10 more) + + RaceConditionDetector + + unnamedLabels: UnnamedLabe… + VOLATILE_FIELDS: ClassValu… + deduplicator: IssueDedupli… + invocationEpoch: AtomicLong + enabled: boolean + + intersection(int[], int[])… + isVolatile(Class<?>, Strin… + newState(Object, String): … + markInvocationStart(): void + recordFieldRead(Object, St… + recordFieldWrite(Object, S… + …(+10 more) ThreadLocalMonitor [CLASS] - - ThreadLocalMonitor - - unnamedLabels: UnnamedLabe… - RETAINED_VALUES_THRESHOLD:… - threadLocals: Map<ThreadLo… - threadLocalsByThread: Map<… - enabled: boolean - taskUses: Map<ThreadLocal<… - - recordThreadLocalInit(Thre… - recordThreadLocalAccess(Th… - recordThreadLocalCleanup(T… - taskUseOf(ThreadLocal<?>):… - agentTaskSet(ThreadLocal<?… - agentTaskRead(ThreadLocal<… - …(+9 more) + + ThreadLocalMonitor + + unnamedLabels: UnnamedLabe… + RETAINED_VALUES_THRESHOLD:… + threadLocals: Map<ThreadLo… + threadLocalsByThread: Map<… + enabled: boolean + taskUses: Map<ThreadLocal<… + + recordThreadLocalInit(Thre… + recordThreadLocalAccess(Th… + recordThreadLocalCleanup(T… + taskUseOf(ThreadLocal<?>):… + agentTaskSet(ThreadLocal<?… + agentTaskRead(ThreadLocal<… + …(+9 more) BusyWaitDetector [CLASS] @@ -3663,52 +3684,52 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe InterruptMonitor [CLASS] - - InterruptMonitor - - interruptEvents: List<Inte… - ignoredDescriptions: Set<S… - blockingWithoutHandling: S… - enabled: boolean - wovenLocations: Set<String> - - recordInterruptException(I… - recordInterruptRestored():… - recordIgnoredException(Str… - recordSwallowingHandlers(S… - recordBlockingOperationWit… - inferCallSite(): String - …(+5 more) + + InterruptMonitor + + interruptEvents: List<Inte… + ignoredDescriptions: Set<S… + blockingWithoutHandling: S… + enabled: boolean + wovenLocations: Set<String> + + recordInterruptException(I… + recordInterruptRestored():… + recordIgnoredException(Str… + recordSwallowingHandlers(S… + recordBlockingOperationWit… + inferCallSite(): String + …(+5 more) UnnamedLabels [CLASS] - - UnnamedLabels - - counters: ConcurrentMap<St… - byObject: ConcurrentMap<Ob… - - next(String): String - of(Object, String): String - of(IdentityKey, String): S… - counters(): ConcurrentMap<… - byObject(): ConcurrentMap<… + + UnnamedLabels + + counters: ConcurrentMap<St… + byObject: ConcurrentMap<Ob… + + next(String): String + of(Object, String): String + of(IdentityKey, String): S… + counters(): ConcurrentMap<… + byObject(): ConcurrentMap<… AbstractInstanceDetector [CLASS] - - AbstractInstanceDetector - - unnamedLabels: UnnamedLabe… - states: ConcurrentMap<Obje… - - stateFor(Object, String): S - stateFor(Object, String, S… - stateFor(Object, String, S… - trackedState(Object): S - clearStates(): void - register(Object, String, S… - …(+3 more) + + AbstractInstanceDetector + + unnamedLabels: UnnamedLabe… + states: ConcurrentMap<Obje… + + stateFor(Object, String): S + stateFor(Object, String, S… + stateFor(Object, String, S… + trackedState(Object): S + clearStates(): void + register(Object, String, S… + …(+3 more) AutoFix [CLASS] @@ -3818,8 +3839,8 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe FIELD_CLOCK_CACHE: int CLOCKS: ThreadLocal<Thread… THREADS: Map<Thread,Thread… - FORKS: Map<Thread,Stamp> - …(+3 more) + RUNNING: Map<Long,ThreadRe… + …(+5 more) release(Object): void releaseInto(ThreadClock, C… @@ -3827,7 +3848,7 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe releaseVolatile(Object, St… releaseVolatileReference(O… releaseVolatile(Object, St… - …(+23 more) + …(+24 more) HeldLocks [CLASS] @@ -3865,20 +3886,20 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe IssueDeduplicator [CLASS] - - IssueDeduplicator - - groups: Map<String,IssueGr… - totalCount: AtomicInteger - MAX_DETAILED_THREADS: int - - record(T): void - getGroups(): List<IssueGro… - getTotalCount(): int - getUniqueCount(): int - hasIssues(): boolean - clear(): void - …(+1 more) + + IssueDeduplicator + + groups: Map<String,IssueGr… + totalCount: AtomicInteger + MAX_DETAILED_THREADS: int + + record(T): void + getGroups(): List<IssueGro… + getTotalCount(): int + getUniqueCount(): int + hasIssues(): boolean + clear(): void + …(+1 more) JfrPinningStream [CLASS] @@ -4004,24 +4025,24 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe Phase1DetectorSet [CLASS] - - Phase1DetectorSet - - visibility: VisibilityMoni… - livelock: LivelockDetector - race: RaceConditionDetector - threadLocal: ThreadLocalMo… - busyWait: BusyWaitDetector - atomicity: AtomicityValida… - …(+2 more) - - from(AsyncTestConfig): Pha… - from(AsyncTestConfig, Asyn… - sharedOrNew(T, Supplier<T>… - printReports(): void - printReport(String, Object… - collectReports(): Map<Stri… - …(+1 more) + + Phase1DetectorSet + + visibility: VisibilityMoni… + livelock: LivelockDetector + race: RaceConditionDetector + threadLocal: ThreadLocalMo… + busyWait: BusyWaitDetector + atomicity: AtomicityValida… + …(+2 more) + + from(AsyncTestConfig): Pha… + from(AsyncTestConfig, Asyn… + sharedOrNew(T, Supplier<T>… + printReports(): void + printReport(String, Object… + collectReports(): Map<Stri… + …(+1 more) PipeSinks [CLASS] @@ -4204,57 +4225,78 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe grades(): Map<String,List<… …(+3 more) + + KotlinMutexes [CLASS] + + KotlinMutexes + + MUTEX: String + CONTINUATION: String + CONTEXT: String + KEY: String + ELEMENT: String + JOB: String + …(+4 more) + + of(Object): Binding + names(List<Object>): List<… + suspended(Object): boolean + rethrow(Throwable): Assert… + bind(Class<?>): Binding + jobReader(ClassLoader, Cla… + …(+2 more) + LinearizabilityChecker [CLASS] - - LinearizabilityChecker - - MAX_OPERATIONS: int - DEFAULT_BUDGET: long - NO_RESPONSE: long - - check(List<Op>, Sequential… - shortestViolatingCut(List<… - prefix(List<Op>, long): Li… + + LinearizabilityChecker + + MAX_OPERATIONS: int + DEFAULT_BUDGET: long + NO_RESPONSE: long + + check(List<Op>, Sequential… + shortestViolatingCut(List<… + prefix(List<Op>, long): Li… NoopAsyncTestListener [CLASS] - - NoopAsyncTestListener - - onInvocationStarted(int, i… - onInvocationCompleted(int,… - onTestFailed(Throwable): v… - onDetectorReport(String, S… - onTimeout(long): void + + NoopAsyncTestListener + + onInvocationStarted(int, i… + onInvocationCompleted(int,… + onTestFailed(Throwable): v… + onDetectorReport(String, S… + onTimeout(long): void OperationHistory [CLASS] - - OperationHistory - - TICKETS: AtomicLong - MAX_OPERATIONS_PER_ROUND: … - NO_ROUND: Object - fresh: Supplier<? extends … - subjects: Map<Object,S> - rounds: Map<Object,RoundLo… - …(+9 more) - - of(Supplier<? extends S>):… - subject(): S - call(String, Object, Suppl… - run(String, Object, Runnab… - operation(String, Function… - generate(int): void - …(+22 more) + + OperationHistory + + TICKETS: AtomicLong + MAX_OPERATIONS_PER_ROUND: … + NO_ROUND: Object + fresh: Supplier<? extends … + subjects: Map<Object,S> + rounds: Map<Object,RoundLo… + …(+9 more) + + of(Supplier<? extends S>):… + subject(): S + call(String, Object, Suppl… + run(String, Object, Runnab… + operation(String, Function… + generate(int): void + …(+22 more) Preset [CLASS] - - Preset - - enabled: Set<DetectorType> + + Preset + + enabled: Set<DetectorType> Baseline [CLASS] @@ -4500,32 +4542,32 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe RunOutcomes [CLASS] - - RunOutcomes - - THREADS_NAMED: int - DUPLICATES_LISTED: int - events: ConcurrentMap<Stri… - values: ConcurrentMap<Obje… - - record(String): void - recordValue(Object): void - count(String): long - assertExactlyOnce(String):… - assertAtMostOnce(String): … - assertCount(String, long):… - …(+3 more) + + RunOutcomes + + THREADS_NAMED: int + DUPLICATES_LISTED: int + events: ConcurrentMap<Stri… + values: ConcurrentMap<Obje… + + record(String): void + recordValue(Object): void + count(String): long + assertExactlyOnce(String):… + assertAtMostOnce(String): … + assertCount(String, long):… + …(+3 more) SequentialSpec [INTERFACE] - - «interface» - SequentialSpec - - initial(): M - copy(M): M - apply(M, String, Object): … - of(Supplier<M>, UnaryOpera… + + «interface» + SequentialSpec + + initial(): M + copy(M): M + apply(M, String, Object): … + of(Supplier<M>, UnaryOpera… Detector [INTERFACE] @@ -4670,14 +4712,14 @@ text { font-family: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe recordAccess(Object, Objec… …(+207 more) - -Legend - -implements - -has - -extends + +Legend + +implements + +has + +extends - Created with https://github.com/PIsberg/codekarta + Created with https://github.com/PIsberg/codekarta diff --git a/docs/quality-gates/ci-coverage.md b/docs/quality-gates/ci-coverage.md index 0f32fd396..980e639b7 100644 --- a/docs/quality-gates/ci-coverage.md +++ b/docs/quality-gates/ci-coverage.md @@ -15,21 +15,21 @@ Underneath, which legs run depends on the event: |---|---|---| | Consumer Fixture (JDK 21, 25) | every PR and push | Resolves the built artifact from a local repo and drives it through the public API only, one `@AsyncTest` fixture per `DetectorType` | | Examples Shard (PR) | PRs that change `examples/**` **or** library sources | See below | -| Examples Reactor | push to `main`/`develop`, and nightly | All 150 example projects, four shards | +| Examples Reactor | push to `main`/`develop`, and nightly | All 151 example projects, four shards | | Examples on JDK 25 | every PR and push, and nightly | The examples that carry a JDK 24+ profile, which the JDK 21 legs above never activate: example 116's real-`Gatherer` test (#893). Fails if that test did not run | **The PR filter used to ask the wrong question.** It watched `examples/**` only, so it answered "did you edit an example?" when what matters is "could you have broken the examples?", and the -150 examples all consume the built artifact. A library-only PR therefore ran zero of them and went +151 examples all consume the built artifact. A library-only PR therefore ran zero of them and went green, with any breakage surfacing after merge or overnight. `examples-detect` now also watches `async-test-*/src/main/**` and the root build files. A library -change runs a deterministic every-4th sample, 38 of the 150 examples, rather than the full +change runs a deterministic every-4th sample, 38 of the 151 examples, rather than the full reactor: enough to catch a systemic break at PR time, cheap enough to afford on every library PR. A PR that changes both gets the union, deduplicated. `gradle-tests.yml` mirrors this exactly. The sample is a sample, not coverage. The full reactor on push and nightly is still what proves -all 150 examples build; this only moves discovery of the common failure earlier. +all 151 examples build; this only moves discovery of the common failure earlier. ## What a docs-only change runs diff --git a/docs/quality-gates/static-analysis.md b/docs/quality-gates/static-analysis.md index 0917ea15d..af157190a 100644 --- a/docs/quality-gates/static-analysis.md +++ b/docs/quality-gates/static-analysis.md @@ -72,7 +72,7 @@ same sources throughout, so this closed a duplicate-coverage hole rather than an ### NullAway Nullness is the one defect class the other analysers do not check, and this codebase is built out -of nullable references: every one of the 148 detectors is built by +of nullable references: every one of the 149 detectors is built by `create(DetectorType.X, XDetector::new)`, which returns `null` for a type the run does not enable, so a `Phase1DetectorSet` field, a `DetectorRegistry` field and every accessor that reaches one is null whenever its detector is off. Whether each read site guards for that was, until now, enforced by diff --git a/docs/usage/getting-started.md b/docs/usage/getting-started.md index 0832102e1..7b143d741 100644 --- a/docs/usage/getting-started.md +++ b/docs/usage/getting-started.md @@ -73,7 +73,7 @@ public class MyAsyncTests { detectAll = true ) void testConcurrentAccess() { - // All 148 detectors are enabled! + // All 149 detectors are enabled! } } ``` diff --git a/examples/152-kotlin-mutex-reentrancy/build.gradle.kts b/examples/152-kotlin-mutex-reentrancy/build.gradle.kts new file mode 100644 index 000000000..0798ba32e --- /dev/null +++ b/examples/152-kotlin-mutex-reentrancy/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + alias(libs.plugins.kotlin.jvm) +} +group = "se.deversity.async-test-lib" +version = "1.0.0" +kotlin { + jvmToolchain(21) +} +repositories { + mavenLocal() + mavenCentral() +} +val asyncTestVersion = libs.versions.async.test.version.get() +val kotlinxVersion = libs.versions.kotlinx.coroutines.version.get() +val junitVersion = libs.versions.junit.jupiter.version.get() +val junitPlatformVersion = libs.versions.junit.platform.version.get() +dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:$kotlinxVersion") + testImplementation("se.deversity.async-test-lib:async-test-lib:$asyncTestVersion") + testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion") + testRuntimeOnly("org.junit.platform:junit-platform-launcher:$junitPlatformVersion") +} +tasks.test { + useJUnitPlatform() + systemProperty("license.mock.mode", "true") +} diff --git a/examples/152-kotlin-mutex-reentrancy/pom.xml b/examples/152-kotlin-mutex-reentrancy/pom.xml new file mode 100644 index 000000000..ae2a12566 --- /dev/null +++ b/examples/152-kotlin-mutex-reentrancy/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + se.deversity.async-test-lib + async-examples-aggregator + 1.0.0 + + + se.deversity.async-test-lib + async-example-kotlin-mutex-reentrancy + 1.0.0 + + Async Test Lib - Kotlin Mutex reentrancy + A kotlinx Mutex locked again from a withContext block its holder waits for, which never resumes. + + + 21 + 21 + UTF-8 + + + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + org.jetbrains.kotlinx + kotlinx-coroutines-core-jvm + ${kotlinx-coroutines.version} + + + se.deversity.async-test-lib + async-test-lib + ${async-test.version} + test + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + + + src/main/kotlin + src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + 21 + + + + compile + compile + compile + + + test-compile + test-compile + test-compile + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + + true + + + + + + diff --git a/examples/152-kotlin-mutex-reentrancy/settings.gradle.kts b/examples/152-kotlin-mutex-reentrancy/settings.gradle.kts new file mode 100644 index 000000000..7a561022f --- /dev/null +++ b/examples/152-kotlin-mutex-reentrancy/settings.gradle.kts @@ -0,0 +1,4 @@ +rootProject.name = "async-example-kotlin-mutex-reentrancy" + +// Every version comes from versions/pom.xml (libs.versions.*). +apply(from = "../../versions/versions.settings.gradle.kts") diff --git a/examples/152-kotlin-mutex-reentrancy/src/main/kotlin/se/deversity/asynctest/example/PriceCache.kt b/examples/152-kotlin-mutex-reentrancy/src/main/kotlin/se/deversity/asynctest/example/PriceCache.kt new file mode 100644 index 000000000..0897ca209 --- /dev/null +++ b/examples/152-kotlin-mutex-reentrancy/src/main/kotlin/se/deversity/asynctest/example/PriceCache.kt @@ -0,0 +1,46 @@ +package se.deversity.asynctest.example + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext + +/** + * A price cache refreshed from a slow source. + * + * [refresh] is the shipped version. It holds the lock across the load and then calls [update], + * which takes the same lock again. A kotlinx `Mutex` is not reentrant: the inner `withLock` waits + * for the outer one to end, and the outer one waits for the block that holds the inner one, so the + * coroutine never resumes. Nothing throws; the refresh just never finishes. + * + * [refreshFixed] loads with nothing locked and holds the lock only to store the result, through + * [updateLocked], which assumes its caller holds it. + */ +class PriceCache(private val source: suspend (String) -> Int) { + + private val mutex = Mutex() + private var prices: Map = emptyMap() + + /** The lock this cache guards its prices with, for a test that watches it. */ + val lock: Mutex get() = mutex + + suspend fun refresh(symbol: String) = mutex.withLock { + val fresh = withContext(Dispatchers.IO) { source(symbol) } + update(symbol, fresh) // locks mutex again: waits for this withLock, which waits for it + } + + suspend fun update(symbol: String, price: Int) = mutex.withLock { + prices = prices + (symbol to price) + } + + suspend fun refreshFixed(symbol: String) { + val fresh = withContext(Dispatchers.IO) { source(symbol) } // nothing locked while loading + mutex.withLock { updateLocked(symbol, fresh) } + } + + private fun updateLocked(symbol: String, price: Int) { + prices = prices + (symbol to price) + } + + fun price(symbol: String): Int? = prices[symbol] +} diff --git a/examples/152-kotlin-mutex-reentrancy/src/test/kotlin/se/deversity/asynctest/example/PriceCacheTest.kt b/examples/152-kotlin-mutex-reentrancy/src/test/kotlin/se/deversity/asynctest/example/PriceCacheTest.kt new file mode 100644 index 000000000..38a49a949 --- /dev/null +++ b/examples/152-kotlin-mutex-reentrancy/src/test/kotlin/se/deversity/asynctest/example/PriceCacheTest.kt @@ -0,0 +1,100 @@ +package se.deversity.asynctest.example + +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeoutOrNull +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import se.deversity.asynctest.diagnostics.IssueSeverity +import se.deversity.asynctest.diagnostics.KotlinMutexReentrancyDetector + +/** + * Test for PriceCache. + * + * ======================================================================== + * DETECTOR: KotlinMutexReentrancyDetector + * (DetectorType.KOTLIN_MUTEX_REENTRANCY) + * ======================================================================== + * + * A kotlinx Mutex is not reentrant. A coroutine that holds one and locks it + * again waits for an unlock only it can make. The usual shape hides the + * second lock behind a scope: a withLock inside the withContext block of the + * same withLock. The block runs as a child coroutine its caller is + * suspended for, so each waits for the other and neither resumes. + * + * THE BUG: + * - PriceCache.refresh holds the lock across a withContext load and then + * calls update, which locks it again + * + * THE FIX: + * - load with nothing locked, and hold the lock only to store the result + * (PriceCache.refreshFixed) + * + * With the agent attached (collections=true, the calling package and + * kotlinx.coroutines in includes=) every woven lock, unlock and tryLock + * feeds the detector, and the holder is the coroutine's Job read from the + * continuation. These tests record by hand so that they run without it. + */ +class PriceCacheTest { + + private lateinit var detector: KotlinMutexReentrancyDetector + + @BeforeEach + fun setUp() { + detector = KotlinMutexReentrancyDetector() + } + + // ----------------------------------------------------------------------- + // Part 1: the shipped version hangs. Nothing throws: the refresh just + // never returns, so a timeout is the only thing that ends it. + // ----------------------------------------------------------------------- + + @Test + fun refreshNeverFinishes() = runBlocking { + val cache = PriceCache { 400 } + assertNull(withTimeoutOrNull(500) { cache.refresh("ACME") }, "the refresh finished") + assertNull(cache.price("ACME")) + } + + // ----------------------------------------------------------------------- + // Part 2: the same calls, recorded as the agent would see them. The + // outer withLock took the mutex without waiting; the inner lock waits, + // and the coroutine holding the mutex is suspended for the caller's scope. + // ----------------------------------------------------------------------- + + @Test + fun relockingFromTheWithContextBlock_isDetected() { + val mutex = PriceCache { 400 }.lock + val refresh = Any() // the refresh coroutine's Job + val block = Any() // the withContext block's Job + + detector.recordAcquired(mutex, refresh) + val held = detector.holderAmong(mutex, listOf(block, refresh)) + detector.recordReentry(mutex, listOf("DispatchedCoroutine", "BlockingCoroutine"), held, Thread.currentThread()) + + val report = detector.analyze() + assertTrue(report.hasIssues()) { "the mutex was locked again by its holder:\n$report" } + assertEquals(IssueSeverity.HIGH, report.structuredViolations[0].severity()) + } + + // ----------------------------------------------------------------------- + // Part 3: the fix. The load runs with nothing locked, so the one lock is + // taken with nothing holding it, and the refresh finishes. + // ----------------------------------------------------------------------- + + @Test + fun lockingOnlyToStore_isClean() = runBlocking { + val cache = PriceCache { 400 } + val refresh = Any() + + detector.recordAcquired(cache.lock, refresh) + detector.recordHolderUnknown(cache.lock) + assertFalse(detector.analyze().hasIssues()) { detector.analyze().toString() } + + cache.refreshFixed("ACME") + assertEquals(400, cache.price("ACME")) + } +} diff --git a/examples/README.md b/examples/README.md index 26ae38720..149220d76 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,7 +6,7 @@ Real-world examples demonstrating common Java concurrency bugs that `@AsyncTest` Most examples ship the buggy service, a sequential `@Test` that passes on it, and an `@AsyncTest` that exposes the bug. **Those `@AsyncTest` demonstrations are `@Disabled`**: 96 of -the 150 examples have one. That is deliberate: they demonstrate code that fails, so enabling +the 151 examples have one. That is deliberate: they demonstrate code that fails, so enabling them would make the examples pipeline permanently red. Each carries a reason saying so, and removing the annotation is the intended way to watch the bug surface. @@ -18,7 +18,7 @@ rather than only that the example compiles. Forty-one examples are written this example from 136 onwards is. The distinction matters when reading the pipeline's green tick. For the disabled majority, the -examples pipeline builds all 150 and runs their enabled tests, so it proves those examples +examples pipeline builds all 151 and runs their enabled tests, so it proves those examples **compile and keep working against the current library** — it does not prove any detector fires. The check that does that for the library itself is `DetectionCoverageTest` in `async-test-lib`, which runs real buggy code through a real `@AsyncTest` and asserts on the @@ -189,6 +189,7 @@ JavaBean accessors and feeds the detectors for you, see [../docs/AGENT.md](../do | 149 | [Lazy Collection Misuse](149-lazy-collection-misuse/) | `LazyCollectionMisuseDetector` | `List.ofLazy` elements compute on whichever thread asks first, so a mapping function reading its own collection deadlocks two threads the JDK's cycle check never sees | 🔴 High | | 150 | [Process Stream Starvation](150-process-stream-starvation/) | `ProcessStreamStarvationDetector` | `Process.waitFor()` before anyone reads the child's output returns on a quiet command and hangs forever once a verbose one fills its pipe | | 151 | [Blocking On A Non-Blocking Thread](151-blocking-on-non-blocking-thread/) | `BlockingOnNonBlockingThreadDetector` | a slow lookup on an event-loop thread answers one quote fine and stalls every quote queued behind it under load | 🟡 Medium | +| 152 | [Kotlin Mutex Reentrancy](152-kotlin-mutex-reentrancy/) | `KotlinMutexReentrancyDetector` | a `withLock` inside the `withContext` block of the same `withLock` waits for the outer lock, which waits for the block - kotlinx `Mutex` is not reentrant, so the refresh never returns and nothing throws | > Examples 114–119 target JDK 24–26 concurrency features. The detectors work off recorded > `String`-key + `Thread` events, so they compile and run on the Java 21 baseline while diff --git a/examples/pom.xml b/examples/pom.xml index 9d6c0e7a5..10a5e3cfc 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -166,5 +166,6 @@ 149-lazy-collection-misuse 150-process-stream-starvation 151-blocking-on-non-blocking-thread + 152-kotlin-mutex-reentrancy diff --git a/examples/settings.gradle.kts b/examples/settings.gradle.kts index 79fdee910..c1d532325 100644 --- a/examples/settings.gradle.kts +++ b/examples/settings.gradle.kts @@ -154,3 +154,4 @@ include(":148-scope-result-escape") include(":149-lazy-collection-misuse") include(":150-process-stream-starvation") include(":151-blocking-on-non-blocking-thread") +include(":152-kotlin-mutex-reentrancy")