diff --git a/CHANGELOG.md b/CHANGELOG.md index 14a225277..5f2b752d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,16 @@ to include examples, links to docs, or any other relevant information. ### Fixed +- `temporalio.contrib.deepagents` no longer dedups repeated identical tool, + model, and backend-op calls: each dispatch runs its own Activity, and the + continue-as-new result cache is retired for new executions (a continued run + resumes from the carried transcript and never re-executes prior dispatches, + so a carried cache entry could only serve stale results). Patch-gated + (`deepagents.retire-result-cache`), so histories recorded before this change + replay unchanged; note that deferring the patch keeps the full legacy dedup + cache — including the stale-result behavior this entry describes — and that + a chain upgraded mid-continue-as-new re-executes rather than reuses a + repeated identical call (the conservative direction). - **Experimental**: External storage metrics now report the wall-clock time storage was in flight. Previously each batch's duration was summed, over-reporting the time whenever storage operations ran concurrently. diff --git a/temporalio/contrib/deepagents/README.md b/temporalio/contrib/deepagents/README.md index da9092978..decae8b27 100644 --- a/temporalio/contrib/deepagents/README.md +++ b/temporalio/contrib/deepagents/README.md @@ -294,9 +294,10 @@ class LongResearchAgent: Pass `continue_as_new_after=N` instead to trigger on a fixed history-event count. -- **Carries forward:** the accumulated messages and the model/tool result cache - (so an LLM/tool call completed before the continue-as-new is *not* re-run - after it). Your `@workflow.run` must accept `state_snapshot=None` as shown. +- **Carries forward:** the accumulated messages. Repeated identical calls are + NOT deduplicated: a call the agent re-issues after the boundary runs its own + Activity, so a genuinely new identical request is never served a stale prior + result. Your `@workflow.run` must accept `state_snapshot=None` as shown. - **Does not carry forward:** anything held only in an in-memory checkpointer's own structures beyond the messages/todos snapshot. The default in-workflow `InMemorySaver` is rehydrated for free by deterministic replay; a durable diff --git a/temporalio/contrib/deepagents/_activity.py b/temporalio/contrib/deepagents/_activity.py index 3c1501a42..99c615f02 100644 --- a/temporalio/contrib/deepagents/_activity.py +++ b/temporalio/contrib/deepagents/_activity.py @@ -338,9 +338,9 @@ async def invoke_tool(self, input: ToolActivityInput) -> ToolActivityOutput: @_auto_heartbeater async def backend_op(self, input: BackendOpInput) -> BackendOpOutput: """Run one operation against a registered (real-I/O) backend.""" - from temporalio.contrib.deepagents._tools import registered_backends + from temporalio.contrib.deepagents._tools import lookup_backend - backend = registered_backends().get(input.backend_ref) + backend = lookup_backend(input.backend_ref) if backend is None: raise ApplicationError( f"Backend {input.backend_ref!r} is not registered on this worker.", diff --git a/temporalio/contrib/deepagents/_tools.py b/temporalio/contrib/deepagents/_tools.py index 1235224c6..b0d8d705f 100644 --- a/temporalio/contrib/deepagents/_tools.py +++ b/temporalio/contrib/deepagents/_tools.py @@ -55,6 +55,11 @@ _TOOL_REGISTRY: dict[str, "BaseTool"] = {} _BACKEND_REGISTRY: dict[str, Any] = {} +# Recently retired backends (insertion-ordered, oldest evicted first). Keeps a +# GC'd wrapper's backend reachable for the eviction -> activity-start window; +# see _unregister_backend. Bounded so retired backends cannot accumulate. +_RETIRED_BACKENDS: dict[str, Any] = {} +_RETIRED_BACKENDS_MAX = 512 # Serializes registration against the GC-time unregister in # _unregister_backend, which may run on another thread. _BACKEND_REGISTRY_LOCK = threading.Lock() @@ -154,7 +159,7 @@ def register_backend(ref: str, backend: Any) -> None: def _unregister_backend(ref: str, inner: Any) -> None: - """Drop ``ref`` from the registry if it still maps to ``inner``. + """Retire ``ref`` from the registry if it still maps to ``inner``. GC hook for :class:`TemporalBackend` (via ``weakref.finalize``): a wrapper is typically constructed per workflow run, so without cleanup a long-lived @@ -162,10 +167,20 @@ def _unregister_backend(ref: str, inner: Any) -> None: load-bearing: refs are deterministic per run, so after a cache eviction a replay re-registers the *same* ref with a fresh inner backend — the evicted wrapper's finalizer must not remove that live registration. + + Retired entries move to the bounded :data:`_RETIRED_BACKENDS` store instead + of vanishing: a ``backend_op`` activity scheduled just before a cache + eviction can be delivered *after* the evicted wrapper is collected, and the + replay that would re-register the ref only happens once that very activity + completes. :func:`lookup_backend` still resolves the ref in that window. """ with _BACKEND_REGISTRY_LOCK: if _BACKEND_REGISTRY.get(ref) is inner: del _BACKEND_REGISTRY[ref] + _RETIRED_BACKENDS.pop(ref, None) + _RETIRED_BACKENDS[ref] = inner + while len(_RETIRED_BACKENDS) > _RETIRED_BACKENDS_MAX: + _RETIRED_BACKENDS.pop(next(iter(_RETIRED_BACKENDS))) def registered_backends() -> dict[str, Any]: @@ -173,6 +188,20 @@ def registered_backends() -> dict[str, Any]: return _BACKEND_REGISTRY +def lookup_backend(ref: str) -> Any | None: + """Resolve ``ref`` for a ``backend_op`` activity. + + Prefers the live registry, then falls back to recently retired entries so + an activity dispatched before a cache eviction still resolves (see + :func:`_unregister_backend`). + """ + with _BACKEND_REGISTRY_LOCK: + backend = _BACKEND_REGISTRY.get(ref) + if backend is not None: + return backend + return _RETIRED_BACKENDS.get(ref) + + # --------------------------------------------------------------------------- # activity_as_tool # --------------------------------------------------------------------------- diff --git a/temporalio/contrib/deepagents/workflow.py b/temporalio/contrib/deepagents/workflow.py index cb3e45b03..e9bf9f203 100644 --- a/temporalio/contrib/deepagents/workflow.py +++ b/temporalio/contrib/deepagents/workflow.py @@ -3,8 +3,9 @@ Everything here runs *inside* the workflow. The dispatch helpers (:func:`call_model` / :func:`call_tool` / :func:`call_backend_op`) are the single choke point through which the in-workflow model / tool / backend stubs reach -their activities; they also consult the continue-as-new result cache so work -done before a ``continue_as_new`` is reused rather than repeated after it. +their activities. Every dispatch runs its own Activity; only executions +recorded before the ``deepagents.retire-result-cache`` patch consult the +legacy continue-as-new result cache during replay. :func:`run_deep_agent` is the optional driver that adds continue-as-new state-carry around a native ``agent.ainvoke(...)`` — plain ``agent.ainvoke(...)`` @@ -77,6 +78,34 @@ def __init__(self, message: str, *, non_retryable: bool = True) -> None: # --------------------------------------------------------------------------- +def _legacy_lookup(kind: str, name: str, payload: Any) -> tuple[str | None, bool, Any]: + """Legacy-cache lookup: ``(key, hit, value)``; key is None on new executions.""" + if not _legacy_result_cache(): + return None, False, None + key = _serde.cache_key(kind, name, payload) + hit, value = _serde.cache_lookup(key) + return key, hit, value + + +def _legacy_result_cache() -> bool: + """Whether this execution uses the legacy continue-as-new result cache. + + New executions do not cache at all: repeated identical calls are + legitimate work (a re-issued tool call, a deliberate model resample, a + re-read after a write), and under the resume-from-transcript + continue-as-new semantics a continued run never re-executes prior + dispatches — so a carried cache entry could only ever serve a stale + result to a genuinely new call. Replay of a single run needs no cache: + history supplies recorded activity results. + + Patch-gated because histories recorded under the legacy cache contain + dedup decisions (a repeated call answered with no activity scheduled); + replaying them without the cache would emit commands history does not + have. + """ + return not workflow.patched("deepagents.retire-result-cache") + + async def call_model( activity_name: str, activity_input: _activity.ModelActivityInput, @@ -84,13 +113,12 @@ async def call_model( summary: str, **opts: Any, ) -> _activity.ModelActivityOutput: - """Dispatch one model call, reusing a cached result across continue-as-new.""" - key = _serde.cache_key( + """Dispatch one model call as its own Activity.""" + legacy_key, hit, cached = _legacy_lookup( "model", activity_input.model_name, [activity_input.messages, activity_input.tool_schemas], ) - hit, cached = _serde.cache_lookup(key) if hit: return _activity.ModelActivityOutput(message=cached) output = await workflow.execute_activity( @@ -100,7 +128,8 @@ async def call_model( summary=summary, **opts, ) - _serde.cache_put(key, output.message) + if legacy_key is not None: + _serde.cache_put(legacy_key, output.message) return output @@ -110,9 +139,10 @@ async def call_tool( summary: str, **opts: Any, ) -> _activity.ToolActivityOutput: - """Dispatch one tool call, reusing a cached result across continue-as-new.""" - key = _serde.cache_key("tool", activity_input.tool_name, activity_input.args) - hit, cached = _serde.cache_lookup(key) + """Dispatch one tool call as its own Activity.""" + legacy_key, hit, cached = _legacy_lookup( + "tool", activity_input.tool_name, activity_input.args + ) if hit: return _activity.ToolActivityOutput(message=cached) output = await workflow.execute_activity( @@ -122,7 +152,8 @@ async def call_tool( summary=summary, **opts, ) - _serde.cache_put(key, output.message) + if legacy_key is not None: + _serde.cache_put(legacy_key, output.message) return output @@ -132,13 +163,12 @@ async def call_backend_op( summary: str, **opts: Any, ) -> _activity.BackendOpOutput: - """Dispatch one backend op, reusing a cached result across continue-as-new.""" - key = _serde.cache_key( + """Dispatch one backend op as its own Activity.""" + legacy_key, hit, cached = _legacy_lookup( f"backend:{activity_input.backend_ref}", activity_input.op, [activity_input.args, activity_input.kwargs], ) - hit, cached = _serde.cache_lookup(key) if hit: return _activity.BackendOpOutput(result=cached) output = await workflow.execute_activity( @@ -148,7 +178,8 @@ async def call_backend_op( summary=summary, **opts, ) - _serde.cache_put(key, output.result) + if legacy_key is not None: + _serde.cache_put(legacy_key, output.result) return output @@ -204,7 +235,14 @@ async def run_deep_agent( """ # Resume path: rehydrate the result cache and fold carried messages in. if state_snapshot is not None: - _serde.set_result_cache(dict(state_snapshot.get(_CACHE_KEY) or {})) + # Only legacy executions consult the carried cache; on new + # executions the inbound legacy entries are dead weight, and at the + # upgrade hop a repeated identical call re-executes (conservative + # direction) rather than being served a possibly-stale carried result. + if _legacy_result_cache(): + _serde.set_result_cache(dict(state_snapshot.get(_CACHE_KEY) or {})) + else: + _serde.set_result_cache({}) input = _merge_snapshot(input, state_snapshot) else: _serde.set_result_cache({}) @@ -230,10 +268,9 @@ async def run_deep_agent( workflow.info().get_current_history_length() >= continue_as_new_after ) if should_continue and _has_pending_work(result): - snapshot = { - "messages": _extract_messages(result), - _CACHE_KEY: _serde.result_cache_snapshot() or {}, - } + snapshot: dict[str, Any] = {"messages": _extract_messages(result)} + if _legacy_result_cache(): + snapshot[_CACHE_KEY] = _serde.result_cache_snapshot() or {} # ``continue_as_new`` threads positional args into the next run via # ``args=``; the enclosing ``@workflow.run`` receives them as # ``(input, state_snapshot)``. diff --git a/tests/contrib/deepagents/histories/legacy_cache_carried_across_can.json b/tests/contrib/deepagents/histories/legacy_cache_carried_across_can.json new file mode 100644 index 000000000..1ace08ec6 --- /dev/null +++ b/tests/contrib/deepagents/histories/legacy_cache_carried_across_can.json @@ -0,0 +1,129 @@ +{ + "events": [ + { + "eventId": "1", + "eventTime": "2026-09-11T04:57:21.100741Z", + "eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_STARTED", + "taskId": "1048617", + "workflowExecutionStartedEventAttributes": { + "workflowType": { + "name": "LegacyCanDedupWorkflow" + }, + "taskQueue": { + "name": "lcan", + "kind": "TASK_QUEUE_KIND_NORMAL" + }, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJtZXNzYWdlcyI6W119" + }, + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJfX3RlbXBvcmFsX2NhY2hlX18iOnsiZTA4MDJlZDU4ZWEzZmNiZmE4NmYzOGNhNDFhMWVlMWI2ODI4NmIzYTFkMWFjZGQwYWU2MDM5OWRiMzIwZjY0ZCI6eyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIlRvb2xNZXNzYWdlIl0sImt3YXJncyI6eyJjb250ZW50IjoiZWNobzoxIiwibmFtZSI6ImxlZ2FjeV9lY2hvIiwic3RhdHVzIjoic3VjY2VzcyIsInRvb2xfY2FsbF9pZCI6InRjLTEiLCJ0eXBlIjoidG9vbCJ9LCJsYyI6MSwidHlwZSI6ImNvbnN0cnVjdG9yIn19LCJtZXNzYWdlcyI6WyJ0dXJuIl19" + } + ] + }, + "workflowRunTimeout": "0s", + "workflowTaskTimeout": "10s", + "continuedExecutionRunId": "01a08ed3-ce0b-7514-a4a7-0fb1fc20592b", + "initiator": "CONTINUE_AS_NEW_INITIATOR_WORKFLOW", + "originalExecutionRunId": "f5508d0e-4d4f-4c66-964c-9e9b1205f09f", + "firstExecutionRunId": "01a08ed3-ce0b-7514-a4a7-0fb1fc20592b", + "attempt": 1, + "firstWorkflowTaskBackoff": "0.550550s", + "prevAutoResetPoints": { + "points": [ + { + "runId": "01a08ed3-ce0b-7514-a4a7-0fb1fc20592b", + "firstWorkflowTaskCompletedId": "4", + "createTime": "2026-09-11T04:57:21.088610Z", + "expireTime": "2026-09-12T04:57:21.100741Z", + "resettable": true, + "buildId": "28a196b25282242baeb8f6d083356dde" + } + ] + }, + "workflowId": "lcan-5866553c-638c-47ff-85ca-f07589d77cbe", + "priority": {} + } + }, + { + "eventId": "2", + "eventTime": "2026-09-11T04:57:22.096483Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED", + "taskId": "1048624", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "lcan", + "kind": "TASK_QUEUE_KIND_NORMAL" + }, + "startToCloseTimeout": "10s", + "attempt": 1 + } + }, + { + "eventId": "3", + "eventTime": "2026-09-11T04:57:22.098235Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED", + "taskId": "1048627", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "2", + "identity": "54291@Davids-MacBook-Pro.local", + "requestId": "a5fc4f0a-3162-4b03-b55c-e4966d2ecfba", + "historySizeBytes": "769", + "workerVersion": { + "buildId": "28a196b25282242baeb8f6d083356dde" + } + } + }, + { + "eventId": "4", + "eventTime": "2026-09-11T04:57:22.111140Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED", + "taskId": "1048631", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "2", + "startedEventId": "3", + "identity": "54291@Davids-MacBook-Pro.local", + "workerVersion": { + "buildId": "28a196b25282242baeb8f6d083356dde" + }, + "sdkMetadata": { + "coreUsedFlags": [ + 2, + 1, + 3 + ], + "sdkName": "temporal-python", + "sdkVersion": "1.32.0" + }, + "meteringMetadata": {} + } + }, + { + "eventId": "5", + "eventTime": "2026-09-11T04:57:22.111208Z", + "eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED", + "taskId": "1048632", + "workflowExecutionCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJtZXNzYWdlcyI6WyJ0dXJuIiwidHVybiJdLCJ0b2RvcyI6W3siY29udGVudCI6InciLCJzdGF0dXMiOiJjb21wbGV0ZWQifV19" + } + ] + }, + "workflowTaskCompletedEventId": "4" + } + } + ] +} \ No newline at end of file diff --git a/tests/contrib/deepagents/histories/legacy_dedup_repeated_tool_calls.json b/tests/contrib/deepagents/histories/legacy_dedup_repeated_tool_calls.json new file mode 100644 index 000000000..8780099fa --- /dev/null +++ b/tests/contrib/deepagents/histories/legacy_dedup_repeated_tool_calls.json @@ -0,0 +1,615 @@ +{ + "events": [ + { + "eventId": "1", + "eventTime": "2026-09-11T04:34:43.463568Z", + "eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_STARTED", + "taskId": "1048587", + "workflowExecutionStartedEventAttributes": { + "workflowType": { + "name": "RepeatedToolCallWorkflow" + }, + "taskQueue": { + "name": "rec", + "kind": "TASK_QUEUE_KIND_NORMAL" + }, + "workflowTaskTimeout": "10s", + "originalExecutionRunId": "01a08ebf-1887-78a6-aef4-69b2a6a74182", + "identity": "29727@Davids-MacBook-Pro.local", + "firstExecutionRunId": "01a08ebf-1887-78a6-aef4-69b2a6a74182", + "attempt": 1, + "firstWorkflowTaskBackoff": "0s", + "workflowId": "rec-fbbd421b-054d-46b9-b3ad-cf26f951e508", + "priority": {} + } + }, + { + "eventId": "2", + "eventTime": "2026-09-11T04:34:43.463603Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED", + "taskId": "1048588", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "rec", + "kind": "TASK_QUEUE_KIND_NORMAL" + }, + "startToCloseTimeout": "10s", + "attempt": 1 + } + }, + { + "eventId": "3", + "eventTime": "2026-09-11T04:34:43.466524Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED", + "taskId": "1048593", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "2", + "identity": "29727@Davids-MacBook-Pro.local", + "requestId": "10e58d88-62fa-4051-a2c2-d08f860c838b", + "historySizeBytes": "271", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + } + } + }, + { + "eventId": "4", + "eventTime": "2026-09-11T04:34:43.513881Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED", + "taskId": "1048597", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "2", + "startedEventId": "3", + "identity": "29727@Davids-MacBook-Pro.local", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + }, + "sdkMetadata": { + "coreUsedFlags": [ + 1, + 3, + 2 + ], + "sdkName": "temporal-python", + "sdkVersion": "1.32.0" + }, + "meteringMetadata": {} + } + }, + { + "eventId": "5", + "eventTime": "2026-09-11T04:34:43.513967Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_SCHEDULED", + "taskId": "1048598", + "activityTaskScheduledEventAttributes": { + "activityId": "1", + "activityType": { + "name": "deepagents.invoke_model" + }, + "taskQueue": { + "name": "rec", + "kind": "TASK_QUEUE_KIND_NORMAL" + }, + "header": {}, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJiaW5kX2t3YXJncyI6e30sImNvbmZpZyI6e30sIm1lc3NhZ2VzIjpbeyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIlN5c3RlbU1lc3NhZ2UiXSwia3dhcmdzIjp7ImNvbnRlbnQiOlt7InRleHQiOiJZb3UgYXJlIGEgZGVlcCBhZ2VudCwgYW4gQUkgYXNzaXN0YW50IHRoYXQgaGVscHMgdXNlcnMgYWNjb21wbGlzaCB0YXNrcyB1c2luZyB0b29scy4gWW91IHJlc3BvbmQgd2l0aCB0ZXh0IGFuZCB0b29sIGNhbGxzLiBUaGUgdXNlciBjYW4gc2VlIHlvdXIgcmVzcG9uc2VzIGFuZCB0b29sIG91dHB1dHMgaW4gcmVhbCB0aW1lLlxuXG4jIyBDb3JlIEJlaGF2aW9yXG5cbi0gQmUgY29uY2lzZSBhbmQgZGlyZWN0LiBEb24ndCBvdmVyLWV4cGxhaW4gdW5sZXNzIGFza2VkLlxuLSBORVZFUiBhZGQgdW5uZWNlc3NhcnkgcHJlYW1ibGUgKFwiU3VyZSFcIiwgXCJHcmVhdCBxdWVzdGlvbiFcIiwgXCJJJ2xsIG5vdy4uLlwiKS5cbi0gRG9uJ3Qgc2F5IFwiSSdsbCBub3cgZG8gWFwiIFx1MjAxNCBqdXN0IGRvIGl0LlxuLSBJZiB0aGUgcmVxdWVzdCBpcyB1bmRlcnNwZWNpZmllZCwgYXNrIG9ubHkgdGhlIG1pbmltdW0gZm9sbG93dXAgbmVlZGVkIHRvIHRha2UgdGhlIG5leHQgdXNlZnVsIGFjdGlvbi5cbi0gSWYgYXNrZWQgaG93IHRvIGFwcHJvYWNoIHNvbWV0aGluZywgZXhwbGFpbiBmaXJzdCwgdGhlbiBhY3QuXG5cbiMjIFByb2Zlc3Npb25hbCBPYmplY3Rpdml0eVxuXG4tIFByaW9yaXRpemUgYWNjdXJhY3kgb3ZlciB2YWxpZGF0aW5nIHRoZSB1c2VyJ3MgYmVsaWVmc1xuLSBEaXNhZ3JlZSByZXNwZWN0ZnVsbHkgd2hlbiB0aGUgdXNlciBpcyBpbmNvcnJlY3Rcbi0gQXZvaWQgdW5uZWNlc3Nhcnkgc3VwZXJsYXRpdmVzLCBwcmFpc2UsIG9yIGVtb3Rpb25hbCB2YWxpZGF0aW9uXG5cbiMjIERvaW5nIFRhc2tzXG5cbldoZW4gdGhlIHVzZXIgYXNrcyB5b3UgdG8gZG8gc29tZXRoaW5nOlxuXG4xLiAqKlVuZGVyc3RhbmQgZmlyc3QqKiBcdTIwMTQgcmVhZCByZWxldmFudCBmaWxlcywgY2hlY2sgZXhpc3RpbmcgcGF0dGVybnMuIFF1aWNrIGJ1dCB0aG9yb3VnaCBcdTIwMTQgZ2F0aGVyIGVub3VnaCBldmlkZW5jZSB0byBzdGFydCwgdGhlbiBpdGVyYXRlLlxuMi4gKipBY3QqKiBcdTIwMTQgaW1wbGVtZW50IHRoZSBzb2x1dGlvbi4gV29yayBxdWlja2x5IGJ1dCBhY2N1cmF0ZWx5LlxuMy4gKipWZXJpZnkqKiBcdTIwMTQgY2hlY2sgeW91ciB3b3JrIGFnYWluc3Qgd2hhdCB3YXMgYXNrZWQsIG5vdCBhZ2FpbnN0IHlvdXIgb3duIG91dHB1dC4gWW91ciBmaXJzdCBhdHRlbXB0IGlzIHJhcmVseSBjb3JyZWN0IFx1MjAxNCBpdGVyYXRlLlxuXG5LZWVwIHdvcmtpbmcgdW50aWwgdGhlIHRhc2sgaXMgZnVsbHkgY29tcGxldGUuIERvbid0IHN0b3AgcGFydHdheSBhbmQgZXhwbGFpbiB3aGF0IHlvdSB3b3VsZCBkbyBcdTIwMTQganVzdCBkbyBpdC4gT25seSB5aWVsZCBiYWNrIHRvIHRoZSB1c2VyIHdoZW4gdGhlIHRhc2sgaXMgZG9uZSBvciB5b3UncmUgZ2VudWluZWx5IGJsb2NrZWQuXG5cbioqV2hlbiB0aGluZ3MgZ28gd3Jvbmc6KipcblxuLSBJZiBzb21ldGhpbmcgZmFpbHMgcmVwZWF0ZWRseSwgc3RvcCBhbmQgYW5hbHl6ZSAqd2h5KiBcdTIwMTQgZG9uJ3Qga2VlcCByZXRyeWluZyB0aGUgc2FtZSBhcHByb2FjaC5cbi0gSWYgeW91J3JlIGJsb2NrZWQsIHRlbGwgdGhlIHVzZXIgd2hhdCdzIHdyb25nIGFuZCBhc2sgZm9yIGd1aWRhbmNlLlxuXG4jIyBDbGFyaWZ5aW5nIFJlcXVlc3RzXG5cbi0gRG8gbm90IGFzayBmb3IgZGV0YWlscyB0aGUgdXNlciBhbHJlYWR5IHN1cHBsaWVkLlxuLSBVc2UgcmVhc29uYWJsZSBkZWZhdWx0cyB3aGVuIHRoZSByZXF1ZXN0IGNsZWFybHkgaW1wbGllcyB0aGVtLlxuLSBQcmlvcml0aXplIG1pc3Npbmcgc2VtYW50aWNzIGxpa2UgY29udGVudCwgZGVsaXZlcnksIGRldGFpbCBsZXZlbCwgb3IgYWxlcnQgY3JpdGVyaWEuXG4tIEF2b2lkIG9wZW5pbmcgd2l0aCBhIGxvbmcgZXhwbGFuYXRpb24gb2YgdG9vbCwgc2NoZWR1bGluZywgb3IgaW50ZWdyYXRpb24gbGltaXRhdGlvbnMgd2hlbiBhIGNvbmNpc2UgYmxvY2tpbmcgZm9sbG93dXAgcXVlc3Rpb24gd291bGQgbW92ZSB0aGUgdGFzayBmb3J3YXJkLlxuLSBBc2sgZG9tYWluLWRlZmluaW5nIHF1ZXN0aW9ucyBiZWZvcmUgaW1wbGVtZW50YXRpb24gcXVlc3Rpb25zLlxuLSBGb3IgbW9uaXRvcmluZyBvciBhbGVydGluZyByZXF1ZXN0cywgYXNrIHdoYXQgc2lnbmFscywgdGhyZXNob2xkcywgb3IgY29uZGl0aW9ucyBzaG91bGQgdHJpZ2dlciBhbiBhbGVydC5cblxuIyMgUHJvZ3Jlc3MgVXBkYXRlc1xuXG5Gb3IgbG9uZ2VyIHRhc2tzLCBwcm92aWRlIGJyaWVmIHByb2dyZXNzIHVwZGF0ZXMgYXQgcmVhc29uYWJsZSBpbnRlcnZhbHMgXHUyMDE0IGEgY29uY2lzZSBzZW50ZW5jZSByZWNhcHBpbmcgd2hhdCB5b3UndmUgZG9uZSBhbmQgd2hhdCdzIG5leHQuIiwidHlwZSI6InRleHQifSx7InRleHQiOiJcblxuIyMgYHdyaXRlX3RvZG9zYFxuXG5Zb3UgaGF2ZSBhY2Nlc3MgdG8gdGhlIGB3cml0ZV90b2Rvc2AgdG9vbCB0byBoZWxwIHlvdSBtYW5hZ2UgYW5kIHBsYW4gY29tcGxleCBvYmplY3RpdmVzLlxuVXNlIHRoaXMgdG9vbCBmb3IgY29tcGxleCBvYmplY3RpdmVzIHRvIGVuc3VyZSB0aGF0IHlvdSBhcmUgdHJhY2tpbmcgZWFjaCBuZWNlc3Nhcnkgc3RlcC5cblRoaXMgdG9vbCBpcyB2ZXJ5IGhlbHBmdWwgZm9yIHBsYW5uaW5nIGNvbXBsZXggb2JqZWN0aXZlcywgYW5kIGZvciBicmVha2luZyBkb3duIHRoZXNlIGxhcmdlciBjb21wbGV4IG9iamVjdGl2ZXMgaW50byBzbWFsbGVyIHN0ZXBzLlxuXG5JdCBpcyBjcml0aWNhbCB0aGF0IHlvdSBtYXJrIHRvZG9zIGFzIGNvbXBsZXRlZCBhcyBzb29uIGFzIHlvdSBhcmUgZG9uZSB3aXRoIGEgc3RlcC4gRG8gbm90IGJhdGNoIHVwIG11bHRpcGxlIHN0ZXBzIGJlZm9yZSBtYXJraW5nIHRoZW0gYXMgY29tcGxldGVkLlxuRm9yIHNpbXBsZSBvYmplY3RpdmVzIHRoYXQgb25seSByZXF1aXJlIGEgZmV3IHN0ZXBzLCBpdCBpcyBiZXR0ZXIgdG8ganVzdCBjb21wbGV0ZSB0aGUgb2JqZWN0aXZlIGRpcmVjdGx5IGFuZCBOT1QgdXNlIHRoaXMgdG9vbC5cbldyaXRpbmcgdG9kb3MgdGFrZXMgdGltZSBhbmQgdG9rZW5zLCB1c2UgaXQgd2hlbiBpdCBpcyBoZWxwZnVsIGZvciBtYW5hZ2luZyBjb21wbGV4IG1hbnktc3RlcCBwcm9ibGVtcyEgQnV0IG5vdCBmb3Igc2ltcGxlIGZldy1zdGVwIHJlcXVlc3RzLlxuXG4jIyBJbXBvcnRhbnQgVG8tRG8gTGlzdCBVc2FnZSBOb3RlcyB0byBSZW1lbWJlclxuXG4tIFRoZSBgd3JpdGVfdG9kb3NgIHRvb2wgc2hvdWxkIG5ldmVyIGJlIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyBpbiBwYXJhbGxlbC5cbi0gRG9uJ3QgYmUgYWZyYWlkIHRvIHJldmlzZSB0aGUgVG8tRG8gbGlzdCBhcyB5b3UgZ28uIE5ldyBpbmZvcm1hdGlvbiBtYXkgcmV2ZWFsIG5ldyB0YXNrcyB0aGF0IG5lZWQgdG8gYmUgZG9uZSwgb3Igb2xkIHRhc2tzIHRoYXQgYXJlIGlycmVsZXZhbnQuXG5cbiMjIEZpbmlzaGluZyBhIHRhc2tcblxuV2hlbiB5b3UgZmluaXNoIGFsbCB3b3JrLCB3cml0ZSB5b3VyIGZpbmFsIGFuc3dlciBpbiB0aGUgbWVzc2FnZSBBRlRFUiB5b3VyIGxhc3QgYHdyaXRlX3RvZG9zYCBjYWxsIFx1MjAxNCBub3QgaW4gdGhlIHNhbWUgdHVybiBhcyB0aGF0IGNhbGwuIFN0YXJ0IHRoZSBmaW5hbCBtZXNzYWdlIHdpdGggdGhlIHN1YnN0YW50aXZlIGNvbnRlbnQgdGhlIHVzZXIgYXNrZWQgZm9yIFx1MjAxNCB0aGUgZGF0YSwgY29tcHV0YXRpb24sIHN1bW1hcnksIG9yIGFuYWx5c2lzLiBUaGUgdXNlciB3YW50cyB0aGUgcmVzdWx0LCBub3QgY29uZmlybWF0aW9uIHRoYXQgdGhlIHdvcmsgaXMgZG9uZS4iLCJ0eXBlIjoidGV4dCJ9LHsidGV4dCI6IlxuXG4jIyBGb2xsb3dpbmcgQ29udmVudGlvbnNcblxuLSBSZWFkIGZpbGVzIGJlZm9yZSBlZGl0aW5nIFx1MjAxNCB1bmRlcnN0YW5kIGV4aXN0aW5nIGNvbnRlbnQgYmVmb3JlIG1ha2luZyBjaGFuZ2VzXG4tIE1pbWljIGV4aXN0aW5nIHN0eWxlLCBuYW1pbmcgY29udmVudGlvbnMsIGFuZCBwYXR0ZXJuc1xuXG4jIyBGaWxlc3lzdGVtIFRvb2xzIGBsc2AsIGByZWFkX2ZpbGVgLCBgd3JpdGVfZmlsZWAsIGBlZGl0X2ZpbGVgLCBgZ2xvYmAsIGBncmVwYFxuXG5Zb3UgaGF2ZSBhY2Nlc3MgdG8gYSBmaWxlc3lzdGVtIHdoaWNoIHlvdSBjYW4gaW50ZXJhY3Qgd2l0aCB1c2luZyB0aGVzZSB0b29scy5cbkFsbCBmaWxlIHBhdGhzIG11c3Qgc3RhcnQgd2l0aCBhIC8uIEZvbGxvdyB0aGUgdG9vbCBkb2NzIGZvciB0aGUgYXZhaWxhYmxlIHRvb2xzLCBhbmQgdXNlIHBhZ2luYXRpb24gKG9mZnNldC9saW1pdCkgd2hlbiByZWFkaW5nIGxhcmdlIGZpbGVzLlxuXG4tIGxzOiBsaXN0IGZpbGVzIGluIGEgZGlyZWN0b3J5IChyZXF1aXJlcyBhYnNvbHV0ZSBwYXRoKVxuLSByZWFkX2ZpbGU6IHJlYWQgYSBmaWxlIGZyb20gdGhlIGZpbGVzeXN0ZW1cbi0gd3JpdGVfZmlsZTogd3JpdGUgdG8gYSBmaWxlIGluIHRoZSBmaWxlc3lzdGVtXG4tIGVkaXRfZmlsZTogZWRpdCBhIGZpbGUgaW4gdGhlIGZpbGVzeXN0ZW1cbi0gZ2xvYjogZmluZCBmaWxlcyBtYXRjaGluZyBhIHBhdHRlcm4gKGUuZy4sIFwiKiovKi5weVwiKVxuLSBncmVwOiBzZWFyY2ggZm9yIHRleHQgd2l0aGluIGZpbGVzXG5cbiMjIExhcmdlIFRvb2wgUmVzdWx0c1xuXG5XaGVuIGEgdG9vbCByZXN1bHQgaXMgdG9vIGxhcmdlLCBpdCBtYXkgYmUgb2ZmbG9hZGVkIGludG8gdGhlIGZpbGVzeXN0ZW0gaW5zdGVhZCBvZiBiZWluZyByZXR1cm5lZCBpbmxpbmUuIEluIHRob3NlIGNhc2VzLCB1c2UgYHJlYWRfZmlsZWAgdG8gaW5zcGVjdCB0aGUgc2F2ZWQgcmVzdWx0IGluIGNodW5rcywgb3IgdXNlIGBncmVwYCB3aXRoaW4gYC9sYXJnZV90b29sX3Jlc3VsdHMvYCBpZiB5b3UgbmVlZCB0byBzZWFyY2ggYWNyb3NzIG9mZmxvYWRlZCB0b29sIHJlc3VsdHMgYW5kIGRvIG5vdCBrbm93IHRoZSBleGFjdCBmaWxlIHBhdGguIE9mZmxvYWRlZCB0b29sIHJlc3VsdHMgYXJlIHN0b3JlZCB1bmRlciBgL2xhcmdlX3Rvb2xfcmVzdWx0cy88dG9vbF9jYWxsX2lkPmAuIiwidHlwZSI6InRleHQifSx7InRleHQiOiJcblxuIyMgYHRhc2tgIChzdWJhZ2VudCBzcGF3bmVyKVxuXG5Zb3UgaGF2ZSBhY2Nlc3MgdG8gYSBgdGFza2AgdG9vbCB0byBsYXVuY2ggc2hvcnQtbGl2ZWQgc3ViYWdlbnRzIHRoYXQgaGFuZGxlIGlzb2xhdGVkIHRhc2tzLiBUaGVzZSBhZ2VudHMgYXJlIGVwaGVtZXJhbCBcdTIwMTQgdGhleSBsaXZlIG9ubHkgZm9yIHRoZSBkdXJhdGlvbiBvZiB0aGUgdGFzayBhbmQgcmV0dXJuIGEgc2luZ2xlIHJlc3VsdC5cblxuV2hlbiB0byB1c2UgdGhlIHRhc2sgdG9vbDpcblxuLSBXaGVuIGEgdGFzayBpcyBjb21wbGV4IGFuZCBtdWx0aS1zdGVwLCBhbmQgY2FuIGJlIGZ1bGx5IGRlbGVnYXRlZCBpbiBpc29sYXRpb25cbi0gV2hlbiBhIHRhc2sgaXMgaW5kZXBlbmRlbnQgb2Ygb3RoZXIgdGFza3MgYW5kIGNhbiBydW4gaW4gcGFyYWxsZWxcbi0gV2hlbiBhIHRhc2sgcmVxdWlyZXMgZm9jdXNlZCByZWFzb25pbmcgb3IgaGVhdnkgdG9rZW4vY29udGV4dCB1c2FnZSB0aGF0IHdvdWxkIGJsb2F0IHRoZSBvcmNoZXN0cmF0b3IgdGhyZWFkXG4tIFdoZW4gc2FuZGJveGluZyBpbXByb3ZlcyByZWxpYWJpbGl0eSAoZS5nLiBjb2RlIGV4ZWN1dGlvbiwgc3RydWN0dXJlZCBzZWFyY2hlcywgZGF0YSBmb3JtYXR0aW5nKVxuLSBXaGVuIHlvdSBvbmx5IGNhcmUgYWJvdXQgdGhlIG91dHB1dCBvZiB0aGUgc3ViYWdlbnQsIGFuZCBub3QgdGhlIGludGVybWVkaWF0ZSBzdGVwcyAoZXguIHBlcmZvcm1pbmcgYSBsb3Qgb2YgcmVzZWFyY2ggYW5kIHRoZW4gcmV0dXJuZWQgYSBzeW50aGVzaXplZCByZXBvcnQsIHBlcmZvcm1pbmcgYSBzZXJpZXMgb2YgY29tcHV0YXRpb25zIG9yIGxvb2t1cHMgdG8gYWNoaWV2ZSBhIGNvbmNpc2UsIHJlbGV2YW50IGFuc3dlci4pXG5cblN1YmFnZW50IGxpZmVjeWNsZTpcblxuMS4gKipTcGF3bioqIFx1MjE5MiBQcm92aWRlIGNsZWFyIHJvbGUsIGluc3RydWN0aW9ucywgYW5kIGV4cGVjdGVkIG91dHB1dFxuMi4gKipSdW4qKiBcdTIxOTIgVGhlIHN1YmFnZW50IGNvbXBsZXRlcyB0aGUgdGFzayBhdXRvbm9tb3VzbHlcbjMuICoqUmV0dXJuKiogXHUyMTkyIFRoZSBzdWJhZ2VudCBwcm92aWRlcyBhIHNpbmdsZSBzdHJ1Y3R1cmVkIHJlc3VsdFxuNC4gKipSZWNvbmNpbGUqKiBcdTIxOTIgSW5jb3Jwb3JhdGUgb3Igc3ludGhlc2l6ZSB0aGUgcmVzdWx0IGludG8gdGhlIG1haW4gdGhyZWFkXG5cbldoZW4gTk9UIHRvIHVzZSB0aGUgdGFzayB0b29sOlxuXG4tIElmIHlvdSBuZWVkIHRvIHNlZSB0aGUgaW50ZXJtZWRpYXRlIHJlYXNvbmluZyBvciBzdGVwcyBhZnRlciB0aGUgc3ViYWdlbnQgaGFzIGNvbXBsZXRlZCAodGhlIHRhc2sgdG9vbCBoaWRlcyB0aGVtKVxuLSBJZiB0aGUgdGFzayBpcyB0cml2aWFsIChhIGZldyB0b29sIGNhbGxzIG9yIHNpbXBsZSBsb29rdXApXG4tIElmIGRlbGVnYXRpbmcgZG9lcyBub3QgcmVkdWNlIHRva2VuIHVzYWdlLCBjb21wbGV4aXR5LCBvciBjb250ZXh0IHN3aXRjaGluZ1xuLSBJZiBzcGxpdHRpbmcgd291bGQgYWRkIGxhdGVuY3kgd2l0aG91dCBiZW5lZml0XG5cbiMjIEltcG9ydGFudCBUYXNrIFRvb2wgVXNhZ2UgTm90ZXMgdG8gUmVtZW1iZXJcblxuLSBXaGVuZXZlciBwb3NzaWJsZSwgcGFyYWxsZWxpemUgdGhlIHdvcmsgdGhhdCB5b3UgZG8uIFRoaXMgaXMgdHJ1ZSBmb3IgYm90aCB0b29sX2NhbGxzLCBhbmQgZm9yIHRhc2tzLiBXaGVuZXZlciB5b3UgaGF2ZSBpbmRlcGVuZGVudCBzdGVwcyB0byBjb21wbGV0ZSAtIG1ha2UgdG9vbF9jYWxscywgb3Iga2ljayBvZmYgdGFza3MgKHN1YmFnZW50cykgaW4gcGFyYWxsZWwgdG8gYWNjb21wbGlzaCB0aGVtIGZhc3Rlci4gVGhpcyBzYXZlcyB0aW1lIGZvciB0aGUgdXNlciwgd2hpY2ggaXMgaW5jcmVkaWJseSBpbXBvcnRhbnQuXG4tIFJlbWVtYmVyIHRvIHVzZSB0aGUgYHRhc2tgIHRvb2wgdG8gc2lsbyBpbmRlcGVuZGVudCB0YXNrcyB3aXRoaW4gYSBtdWx0aS1wYXJ0IG9iamVjdGl2ZS5cbi0gWW91IHNob3VsZCB1c2UgdGhlIGB0YXNrYCB0b29sIHdoZW5ldmVyIHlvdSBoYXZlIGEgY29tcGxleCB0YXNrIHRoYXQgd2lsbCB0YWtlIG11bHRpcGxlIHN0ZXBzLCBhbmQgaXMgaW5kZXBlbmRlbnQgZnJvbSBvdGhlciB0YXNrcyB0aGF0IHRoZSBhZ2VudCBuZWVkcyB0byBjb21wbGV0ZS4gVGhlc2UgYWdlbnRzIGFyZSBoaWdobHkgY29tcGV0ZW50IGFuZCBlZmZpY2llbnQuXG5cbkF2YWlsYWJsZSBzdWJhZ2VudCB0eXBlczpcblxuLSBnZW5lcmFsLXB1cnBvc2U6IEdlbmVyYWwtcHVycG9zZSBhZ2VudCBmb3IgcmVzZWFyY2hpbmcgY29tcGxleCBxdWVzdGlvbnMsIHNlYXJjaGluZyBmb3IgZmlsZXMgYW5kIGNvbnRlbnQsIGFuZCBleGVjdXRpbmcgbXVsdGktc3RlcCB0YXNrcy4gV2hlbiB5b3UgYXJlIHNlYXJjaGluZyBmb3IgYSBrZXl3b3JkIG9yIGZpbGUgYW5kIGFyZSBub3QgY29uZmlkZW50IHRoYXQgeW91IHdpbGwgZmluZCB0aGUgcmlnaHQgbWF0Y2ggaW4gdGhlIGZpcnN0IGZldyB0cmllcyB1c2UgdGhpcyBhZ2VudCB0byBwZXJmb3JtIHRoZSBzZWFyY2ggZm9yIHlvdS4gVGhpcyBhZ2VudCBoYXMgYWNjZXNzIHRvIGFsbCB0b29scyBhcyB0aGUgbWFpbiBhZ2VudC4iLCJ0eXBlIjoidGV4dCJ9XSwidHlwZSI6InN5c3RlbSJ9LCJsYyI6MSwidHlwZSI6ImNvbnN0cnVjdG9yIn0seyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIkh1bWFuTWVzc2FnZSJdLCJrd2FyZ3MiOnsiY29udGVudCI6IkNoZWNrIFBhcmlzIHR3aWNlLiIsImlkIjoiMTYwZjNhNjUtZTcwNi00NGMxLThjNTctY2FhMmIwM2QwNmU4IiwidHlwZSI6Imh1bWFuIn0sImxjIjoxLCJ0eXBlIjoiY29uc3RydWN0b3IifV0sIm1vZGVsX25hbWUiOiJmYWtlOm1vZGVsIiwic3RyZWFtaW5nX3RvcGljIjpudWxsLCJ0b29sX3NjaGVtYXMiOlt7ImZ1bmN0aW9uIjp7ImRlc2NyaXB0aW9uIjoiVXNlIHRoaXMgdG9vbCB0byBjcmVhdGUgYW5kIG1hbmFnZSBhIHN0cnVjdHVyZWQgdGFzayBsaXN0IGZvciB5b3VyIGN1cnJlbnQgd29yayBzZXNzaW9uLiBUaGlzIGhlbHBzIHlvdSB0cmFjayBwcm9ncmVzcyBhbmQgb3JnYW5pemUgY29tcGxleCB0YXNrcy5cblxuT25seSB1c2UgdGhpcyB0b29sIGlmIHlvdSB0aGluayBpdCB3aWxsIGJlIGhlbHBmdWwgaW4gc3RheWluZyBvcmdhbml6ZWQuIElmIHRoZSB1c2VyJ3MgcmVxdWVzdCBpcyB0cml2aWFsIGFuZCB0YWtlcyBsZXNzIHRoYW4gMyBzdGVwcywgaXQgaXMgYmV0dGVyIHRvIE5PVCB1c2UgdGhpcyB0b29sIGFuZCBqdXN0IGRvIHRoZSB0YXNrIGRpcmVjdGx5LlxuXG4jIyBXaGVuIHRvIFVzZSBUaGlzIFRvb2xcblxuVXNlIHRoaXMgdG9vbCBpbiB0aGVzZSBzY2VuYXJpb3M6XG5cbjEuIENvbXBsZXggbXVsdGktc3RlcCB0YXNrcyAtIFdoZW4gYSB0YXNrIHJlcXVpcmVzIDMgb3IgbW9yZSBkaXN0aW5jdCBzdGVwcyBvciBhY3Rpb25zXG4yLiBOb24tdHJpdmlhbCBhbmQgY29tcGxleCB0YXNrcyAtIFRhc2tzIHRoYXQgcmVxdWlyZSBjYXJlZnVsIHBsYW5uaW5nIG9yIG11bHRpcGxlIG9wZXJhdGlvbnNcbjMuIFVzZXIgZXhwbGljaXRseSByZXF1ZXN0cyB0b2RvIGxpc3QgLSBXaGVuIHRoZSB1c2VyIGRpcmVjdGx5IGFza3MgeW91IHRvIHVzZSB0aGUgdG9kbyBsaXN0XG40LiBVc2VyIHByb3ZpZGVzIG11bHRpcGxlIHRhc2tzIC0gV2hlbiB1c2VycyBwcm92aWRlIGEgbGlzdCBvZiB0aGluZ3MgdG8gYmUgZG9uZSAobnVtYmVyZWQgb3IgY29tbWEtc2VwYXJhdGVkKVxuNS4gVGhlIHBsYW4gbWF5IG5lZWQgZnV0dXJlIHJldmlzaW9ucyBvciB1cGRhdGVzIGJhc2VkIG9uIHJlc3VsdHMgZnJvbSB0aGUgZmlyc3QgZmV3IHN0ZXBzXG5cbiMjIEhvdyB0byBVc2UgVGhpcyBUb29sXG5cbjEuIFdoZW4geW91IHN0YXJ0IHdvcmtpbmcgb24gYSB0YXNrIC0gTWFyayBpdCBhcyBpbl9wcm9ncmVzcyBCRUZPUkUgYmVnaW5uaW5nIHdvcmsuXG4yLiBBZnRlciBjb21wbGV0aW5nIGEgdGFzayAtIE1hcmsgaXQgYXMgY29tcGxldGVkIGFuZCBhZGQgYW55IG5ldyBmb2xsb3ctdXAgdGFza3MgZGlzY292ZXJlZCBkdXJpbmcgaW1wbGVtZW50YXRpb24uXG4zLiBZb3UgY2FuIGFsc28gdXBkYXRlIGZ1dHVyZSB0YXNrcywgc3VjaCBhcyBkZWxldGluZyB0aGVtIGlmIHRoZXkgYXJlIG5vIGxvbmdlciBuZWNlc3NhcnksIG9yIGFkZGluZyBuZXcgdGFza3MgdGhhdCBhcmUgbmVjZXNzYXJ5LiBEb24ndCBjaGFuZ2UgcHJldmlvdXNseSBjb21wbGV0ZWQgdGFza3MuXG40LiBZb3UgY2FuIG1ha2Ugc2V2ZXJhbCB1cGRhdGVzIHRvIHRoZSB0b2RvIGxpc3QgYXQgb25jZS4gRm9yIGV4YW1wbGUsIHdoZW4geW91IGNvbXBsZXRlIGEgdGFzaywgeW91IGNhbiBtYXJrIHRoZSBuZXh0IHRhc2sgeW91IG5lZWQgdG8gc3RhcnQgYXMgaW5fcHJvZ3Jlc3MuXG5cbiMjIFdoZW4gTk9UIHRvIFVzZSBUaGlzIFRvb2xcblxuSXQgaXMgaW1wb3J0YW50IHRvIHNraXAgdXNpbmcgdGhpcyB0b29sIHdoZW46XG4xLiBUaGVyZSBpcyBvbmx5IGEgc2luZ2xlLCBzdHJhaWdodGZvcndhcmQgdGFza1xuMi4gVGhlIHRhc2sgaXMgdHJpdmlhbCBhbmQgdHJhY2tpbmcgaXQgcHJvdmlkZXMgbm8gYmVuZWZpdFxuMy4gVGhlIHRhc2sgY2FuIGJlIGNvbXBsZXRlZCBpbiBsZXNzIHRoYW4gMyB0cml2aWFsIHN0ZXBzXG40LiBUaGUgdGFzayBpcyBwdXJlbHkgY29udmVyc2F0aW9uYWwgb3IgaW5mb3JtYXRpb25hbFxuXG4jIyBUYXNrIFN0YXRlcyBhbmQgTWFuYWdlbWVudFxuXG4xLiAqKlRhc2sgU3RhdGVzKio6IFVzZSB0aGVzZSBzdGF0ZXMgdG8gdHJhY2sgcHJvZ3Jlc3M6XG4gICAgLSBwZW5kaW5nOiBUYXNrIG5vdCB5ZXQgc3RhcnRlZFxuICAgIC0gaW5fcHJvZ3Jlc3M6IEN1cnJlbnRseSB3b3JraW5nIG9uICh5b3UgY2FuIGhhdmUgbXVsdGlwbGUgdGFza3MgaW5fcHJvZ3Jlc3MgYXQgYSB0aW1lIGlmIHRoZXkgYXJlIG5vdCByZWxhdGVkIHRvIGVhY2ggb3RoZXIgYW5kIGNhbiBiZSBydW4gaW4gcGFyYWxsZWwpXG4gICAgLSBjb21wbGV0ZWQ6IFRhc2sgZmluaXNoZWQgc3VjY2Vzc2Z1bGx5XG5cbjIuICoqVGFzayBNYW5hZ2VtZW50Kio6XG4gICAgLSBVcGRhdGUgdGFzayBzdGF0dXMgaW4gcmVhbC10aW1lIGFzIHlvdSB3b3JrXG4gICAgLSBNYXJrIHRhc2tzIGNvbXBsZXRlIElNTUVESUFURUxZIGFmdGVyIGZpbmlzaGluZyAoZG9uJ3QgYmF0Y2ggY29tcGxldGlvbnMpXG4gICAgLSBDb21wbGV0ZSBjdXJyZW50IHRhc2tzIGJlZm9yZSBzdGFydGluZyBuZXcgb25lc1xuICAgIC0gUmVtb3ZlIHRhc2tzIHRoYXQgYXJlIG5vIGxvbmdlciByZWxldmFudCBmcm9tIHRoZSBsaXN0IGVudGlyZWx5XG4gICAgLSBJTVBPUlRBTlQ6IFdoZW4geW91IHdyaXRlIHRoaXMgdG9kbyBsaXN0LCB5b3Ugc2hvdWxkIG1hcmsgeW91ciBmaXJzdCB0YXNrIChvciB0YXNrcykgYXMgaW5fcHJvZ3Jlc3MgaW1tZWRpYXRlbHkhLlxuICAgIC0gSU1QT1JUQU5UOiBVbmxlc3MgYWxsIHRhc2tzIGFyZSBjb21wbGV0ZWQsIHlvdSBzaG91bGQgYWx3YXlzIGhhdmUgYXQgbGVhc3Qgb25lIHRhc2sgaW5fcHJvZ3Jlc3MuXG5cbjMuICoqVGFzayBDb21wbGV0aW9uIFJlcXVpcmVtZW50cyoqOlxuICAgIC0gT05MWSBtYXJrIGEgdGFzayBhcyBjb21wbGV0ZWQgd2hlbiB5b3UgaGF2ZSBGVUxMWSBhY2NvbXBsaXNoZWQgaXRcbiAgICAtIElmIHlvdSBlbmNvdW50ZXIgZXJyb3JzLCBibG9ja2Vycywgb3IgY2Fubm90IGZpbmlzaCwga2VlcCB0aGUgdGFzayBhcyBpbl9wcm9ncmVzc1xuICAgIC0gV2hlbiBibG9ja2VkLCBjcmVhdGUgYSBuZXcgdGFzayBkZXNjcmliaW5nIHdoYXQgbmVlZHMgdG8gYmUgcmVzb2x2ZWRcbiAgICAtIE5ldmVyIG1hcmsgYSB0YXNrIGFzIGNvbXBsZXRlZCBpZjpcbiAgICAgICAgLSBUaGVyZSBhcmUgdW5yZXNvbHZlZCBpc3N1ZXMgb3IgZXJyb3JzXG4gICAgICAgIC0gV29yayBpcyBwYXJ0aWFsIG9yIGluY29tcGxldGVcbiAgICAgICAgLSBZb3UgZW5jb3VudGVyZWQgYmxvY2tlcnMgdGhhdCBwcmV2ZW50IGNvbXBsZXRpb25cbiAgICAgICAgLSBZb3UgY291bGRuJ3QgZmluZCBuZWNlc3NhcnkgcmVzb3VyY2VzIG9yIGRlcGVuZGVuY2llc1xuICAgICAgICAtIFF1YWxpdHkgc3RhbmRhcmRzIGhhdmVuJ3QgYmVlbiBtZXRcblxuNC4gKipUYXNrIEJyZWFrZG93bioqOlxuICAgIC0gQ3JlYXRlIHNwZWNpZmljLCBhY3Rpb25hYmxlIGl0ZW1zXG4gICAgLSBCcmVhayBjb21wbGV4IHRhc2tzIGludG8gc21hbGxlciwgbWFuYWdlYWJsZSBzdGVwc1xuICAgIC0gVXNlIGNsZWFyLCBkZXNjcmlwdGl2ZSB0YXNrIG5hbWVzXG5cbkJlaW5nIHByb2FjdGl2ZSB3aXRoIHRhc2sgbWFuYWdlbWVudCBlbnN1cmVzIHlvdSBjb21wbGV0ZSBhbGwgcmVxdWlyZW1lbnRzIHN1Y2Nlc3NmdWxseVxuUmVtZW1iZXI6IElmIHlvdSBvbmx5IG5lZWQgdG8gbWFrZSBhIGZldyB0b29sIGNhbGxzIHRvIGNvbXBsZXRlIGEgdGFzaywgYW5kIGl0IGlzIGNsZWFyIHdoYXQgeW91IG5lZWQgdG8gZG8sIGl0IGlzIGJldHRlciB0byBqdXN0IGRvIHRoZSB0YXNrIGRpcmVjdGx5IGFuZCBOT1QgY2FsbCB0aGlzIHRvb2wgYXQgYWxsLlxuXG4jIyBXaGVuIFlvdSBGaW5pc2hcblxuYHdyaXRlX3RvZG9zYCB0cmFja3MgeW91ciB3b3JrOyBpdCBkb2VzIG5vdCBkZWxpdmVyIHRoZSBhbnN3ZXIuIFdoYXRldmVyIHRoZSB1c2VyIGFza2VkIGZvciBcdTIwMTQgY29tcHV0YXRpb25zLCBzdW1tYXJpZXMsIGNvbXBhcmlzb25zLCBkYXRhIFx1MjAxNCBtdXN0IGFwcGVhciBhcyB0ZXh0IGNvbnRlbnQgaW4gYSBtZXNzYWdlIGFmdGVyIHlvdXIgZmluYWwgYHdyaXRlX3RvZG9zYCBjYWxsLiBNYXJraW5nIHRoZSBsYXN0IHRvZG8gY29tcGxldGUgaXMgbm90IGl0c2VsZiBhbiBhbnN3ZXIgdG8gdGhlIHVzZXIuIiwibmFtZSI6IndyaXRlX3RvZG9zIiwicGFyYW1ldGVycyI6eyJwcm9wZXJ0aWVzIjp7InRvZG9zIjp7Iml0ZW1zIjp7ImRlc2NyaXB0aW9uIjoiQSBzaW5nbGUgdG9kbyBpdGVtIHdpdGggY29udGVudCBhbmQgc3RhdHVzLiIsInByb3BlcnRpZXMiOnsiY29udGVudCI6eyJ0eXBlIjoic3RyaW5nIn0sInN0YXR1cyI6eyJlbnVtIjpbInBlbmRpbmciLCJpbl9wcm9ncmVzcyIsImNvbXBsZXRlZCJdLCJ0eXBlIjoic3RyaW5nIn19LCJyZXF1aXJlZCI6WyJjb250ZW50Iiwic3RhdHVzIl0sInR5cGUiOiJvYmplY3QifSwidHlwZSI6ImFycmF5In19LCJyZXF1aXJlZCI6WyJ0b2RvcyJdLCJ0eXBlIjoib2JqZWN0In19LCJ0eXBlIjoiZnVuY3Rpb24ifSx7ImZ1bmN0aW9uIjp7ImRlc2NyaXB0aW9uIjoiTGlzdHMgYWxsIGZpbGVzIGluIGEgZGlyZWN0b3J5LlxuXG5UaGlzIGlzIHVzZWZ1bCBmb3IgZXhwbG9yaW5nIHRoZSBmaWxlc3lzdGVtIGFuZCBmaW5kaW5nIHRoZSByaWdodCBmaWxlIHRvIHJlYWQgb3IgZWRpdC5cbllvdSBzaG91bGQgYWxtb3N0IEFMV0FZUyB1c2UgdGhpcyB0b29sIGJlZm9yZSB1c2luZyB0aGUgcmVhZF9maWxlIG9yIGVkaXRfZmlsZSB0b29scy4iLCJuYW1lIjoibHMiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsicGF0aCI6eyJkZXNjcmlwdGlvbiI6IkFic29sdXRlIHBhdGggdG8gdGhlIGRpcmVjdG9yeSB0byBsaXN0LiBNdXN0IGJlIGFic29sdXRlLCBub3QgcmVsYXRpdmUuIiwidHlwZSI6InN0cmluZyJ9fSwicmVxdWlyZWQiOlsicGF0aCJdLCJ0eXBlIjoib2JqZWN0In19LCJ0eXBlIjoiZnVuY3Rpb24ifSx7ImZ1bmN0aW9uIjp7ImRlc2NyaXB0aW9uIjoiUmVhZHMgYSBmaWxlIGZyb20gdGhlIGZpbGVzeXN0ZW0uXG5cbkFzc3VtZSB0aGlzIHRvb2wgaXMgYWJsZSB0byByZWFkIGFsbCBmaWxlcy4gSWYgdGhlIFVzZXIgcHJvdmlkZXMgYSBwYXRoIHRvIGEgZmlsZSBhc3N1bWUgdGhhdCBwYXRoIGlzIHZhbGlkLiBJdCBpcyBva2F5IHRvIHJlYWQgYSBmaWxlIHRoYXQgZG9lcyBub3QgZXhpc3Q7IGFuIGVycm9yIHdpbGwgYmUgcmV0dXJuZWQuXG5cblVzYWdlOlxuLSBCeSBkZWZhdWx0LCBpdCByZWFkcyB1cCB0byAxMDAgbGluZXMgc3RhcnRpbmcgZnJvbSB0aGUgYmVnaW5uaW5nIG9mIHRoZSBmaWxlXG4tICoqSU1QT1JUQU5UIGZvciBsYXJnZSBmaWxlcyBhbmQgY29kZWJhc2UgZXhwbG9yYXRpb24qKjogVXNlIHBhZ2luYXRpb24gd2l0aCBvZmZzZXQgYW5kIGxpbWl0IHBhcmFtZXRlcnMgdG8gYXZvaWQgY29udGV4dCBvdmVyZmxvd1xuICAgIC0gRmlyc3Qgc2NhbjogcmVhZF9maWxlKGZpbGVfcGF0aD1cIi4uLlwiLCBsaW1pdD0xMDApIHRvIHNlZSBmaWxlIHN0cnVjdHVyZVxuICAgIC0gUmVhZCBtb3JlIHNlY3Rpb25zOiByZWFkX2ZpbGUoZmlsZV9wYXRoPVwiLi4uXCIsIG9mZnNldD0xMDAsIGxpbWl0PTIwMCkgZm9yIG5leHQgMjAwIGxpbmVzXG4gICAgLSBPbmx5IG9taXQgbGltaXQgKHJlYWQgZnVsbCBmaWxlKSB3aGVuIG5lY2Vzc2FyeSBmb3IgZWRpdGluZ1xuLSBTcGVjaWZ5IG9mZnNldCBhbmQgbGltaXQ6IHJlYWRfZmlsZShmaWxlX3BhdGg9XCIuLi5cIiwgb2Zmc2V0PTAsIGxpbWl0PTEwMCkgcmVhZHMgZmlyc3QgMTAwIGxpbmVzXG4tIFJlc3VsdHMgYXJlIHJldHVybmVkIHVzaW5nIGNhdCAtbiBmb3JtYXQsIHdpdGggbGluZSBudW1iZXJzIHN0YXJ0aW5nIGF0IDFcbi0gTGluZXMgbG9uZ2VyIHRoYW4gNSwwMDAgY2hhcmFjdGVycyB3aWxsIGJlIHNwbGl0IGludG8gbXVsdGlwbGUgbGluZXMgd2l0aCBjb250aW51YXRpb24gbWFya2VycyAoZS5nLiwgNS4xLCA1LjIsIGV0Yy4pLiBgbGltaXRgIGFwcGxpZXMgdG8gc291cmNlIGxpbmVzLCBzbyBjb250aW51YXRpb24gcm93cyBkbyBub3QgY29uc3VtZSB0aGUgYnVkZ2V0LlxuLSBZb3UgaGF2ZSB0aGUgY2FwYWJpbGl0eSB0byBjYWxsIG11bHRpcGxlIHRvb2xzIGluIGEgc2luZ2xlIHJlc3BvbnNlLiBJdCBpcyBhbHdheXMgYmV0dGVyIHRvIHNwZWN1bGF0aXZlbHkgcmVhZCBtdWx0aXBsZSBmaWxlcyBhcyBhIGJhdGNoIHRoYXQgYXJlIHBvdGVudGlhbGx5IHVzZWZ1bC5cbi0gSWYgeW91IHJlYWQgYSBmaWxlIHRoYXQgZXhpc3RzIGJ1dCBoYXMgZW1wdHkgY29udGVudHMgeW91IHdpbGwgcmVjZWl2ZSBhIHN5c3RlbSByZW1pbmRlciB3YXJuaW5nIGluIHBsYWNlIG9mIGZpbGUgY29udGVudHMuXG4tIEltYWdlIGZpbGVzIChgLnBuZ2AsIGAuanBnYCwgYC5qcGVnYCwgYC5naWZgLCBgLndlYnBgLCBldGMuKSwgYXVkaW8gYW5kIHZpZGVvIGZpbGVzLCBhbmQgUERGcyBhcmUgcmV0dXJuZWQgYXMgbXVsdGltb2RhbCBjb250ZW50IGJsb2NrcyAoc2VlIGh0dHBzOi8vZG9jcy5sYW5nY2hhaW4uY29tL29zcy9weXRob24vbGFuZ2NoYWluL21lc3NhZ2VzI211bHRpbW9kYWwpLlxuXG5Gb3IgbXVsdGltb2RhbCByZWFkcyAoaW1hZ2UsIGF1ZGlvLCB2aWRlbywgUERGLCBldGMuKTpcbi0gVXNlIGByZWFkX2ZpbGUoZmlsZV9wYXRoPS4uLilgXG4tIERvIE5PVCB1c2UgYG9mZnNldGAvYGxpbWl0YCBmb3IgaW1hZ2VzIChwYWdpbmF0aW9uIGlzIHRleHQtb25seSlcbi0gSWYgZmlsZSBkZXRhaWxzIHdlcmUgY29tcGFjdGVkIGZyb20gaGlzdG9yeSwgY2FsbCBgcmVhZF9maWxlYCBhZ2FpbiBvbiB0aGUgc2FtZSBwYXRoXG5cbi0gWW91IHNob3VsZCBBTFdBWVMgbWFrZSBzdXJlIGEgZmlsZSBoYXMgYmVlbiByZWFkIGJlZm9yZSBlZGl0aW5nIGl0LiIsIm5hbWUiOiJyZWFkX2ZpbGUiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsiZmlsZV9wYXRoIjp7ImRlc2NyaXB0aW9uIjoiQWJzb2x1dGUgcGF0aCB0byB0aGUgZmlsZSB0byByZWFkLiBNdXN0IGJlIGFic29sdXRlLCBub3QgcmVsYXRpdmUuIiwidHlwZSI6InN0cmluZyJ9LCJsaW1pdCI6eyJkZWZhdWx0IjoxMDAsImRlc2NyaXB0aW9uIjoiTWF4aW11bSBudW1iZXIgb2YgbGluZXMgdG8gcmVhZC4gVXNlIGZvciBwYWdpbmF0aW9uIG9mIGxhcmdlIGZpbGVzLiIsInR5cGUiOiJpbnRlZ2VyIn0sIm9mZnNldCI6eyJkZWZhdWx0IjowLCJkZXNjcmlwdGlvbiI6IkxpbmUgbnVtYmVyIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSAoMC1pbmRleGVkKS4gVXNlIGZvciBwYWdpbmF0aW9uIG9mIGxhcmdlIGZpbGVzLiIsInR5cGUiOiJpbnRlZ2VyIn19LCJyZXF1aXJlZCI6WyJmaWxlX3BhdGgiXSwidHlwZSI6Im9iamVjdCJ9fSwidHlwZSI6ImZ1bmN0aW9uIn0seyJmdW5jdGlvbiI6eyJkZXNjcmlwdGlvbiI6IldyaXRlcyB0byBhIG5ldyBmaWxlIGluIHRoZSBmaWxlc3lzdGVtLlxuXG5Vc2FnZTpcbi0gVGhlIHdyaXRlX2ZpbGUgdG9vbCB3aWxsIGNyZWF0ZSB0aGUgYSBuZXcgZmlsZS5cbi0gUHJlZmVyIHRvIGVkaXQgZXhpc3RpbmcgZmlsZXMgKHdpdGggdGhlIGVkaXRfZmlsZSB0b29sKSBvdmVyIGNyZWF0aW5nIG5ldyBvbmVzIHdoZW4gcG9zc2libGUuIiwibmFtZSI6IndyaXRlX2ZpbGUiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsiY29udGVudCI6eyJkZXNjcmlwdGlvbiI6IlRoZSB0ZXh0IGNvbnRlbnQgdG8gd3JpdGUgdG8gdGhlIGZpbGUuIFRoaXMgcGFyYW1ldGVyIGlzIHJlcXVpcmVkLiIsInR5cGUiOiJzdHJpbmcifSwiZmlsZV9wYXRoIjp7ImRlc2NyaXB0aW9uIjoiQWJzb2x1dGUgcGF0aCB3aGVyZSB0aGUgZmlsZSBzaG91bGQgYmUgY3JlYXRlZC4gTXVzdCBiZSBhYnNvbHV0ZSwgbm90IHJlbGF0aXZlLiIsInR5cGUiOiJzdHJpbmcifX0sInJlcXVpcmVkIjpbImZpbGVfcGF0aCIsImNvbnRlbnQiXSwidHlwZSI6Im9iamVjdCJ9fSwidHlwZSI6ImZ1bmN0aW9uIn0seyJmdW5jdGlvbiI6eyJkZXNjcmlwdGlvbiI6IlBlcmZvcm1zIGV4YWN0IHN0cmluZyByZXBsYWNlbWVudHMgaW4gZmlsZXMuXG5cblVzYWdlOlxuLSBZb3UgbXVzdCByZWFkIHRoZSBmaWxlIGJlZm9yZSBlZGl0aW5nLiBUaGlzIHRvb2wgd2lsbCBlcnJvciBpZiB5b3UgYXR0ZW1wdCBhbiBlZGl0IHdpdGhvdXQgcmVhZGluZyB0aGUgZmlsZSBmaXJzdC5cbi0gV2hlbiBlZGl0aW5nLCBwcmVzZXJ2ZSB0aGUgZXhhY3QgaW5kZW50YXRpb24gKHRhYnMvc3BhY2VzKSBmcm9tIHRoZSByZWFkIG91dHB1dC4gTmV2ZXIgaW5jbHVkZSBsaW5lIG51bWJlciBwcmVmaXhlcyBpbiBvbGRfc3RyaW5nIG9yIG5ld19zdHJpbmcuXG4tIEFMV0FZUyBwcmVmZXIgZWRpdGluZyBleGlzdGluZyBmaWxlcyBvdmVyIGNyZWF0aW5nIG5ldyBvbmVzLlxuLSBPbmx5IHVzZSBlbW9qaXMgaWYgdGhlIHVzZXIgZXhwbGljaXRseSByZXF1ZXN0cyBpdC4iLCJuYW1lIjoiZWRpdF9maWxlIiwicGFyYW1ldGVycyI6eyJwcm9wZXJ0aWVzIjp7ImZpbGVfcGF0aCI6eyJkZXNjcmlwdGlvbiI6IkFic29sdXRlIHBhdGggdG8gdGhlIGZpbGUgdG8gZWRpdC4gTXVzdCBiZSBhYnNvbHV0ZSwgbm90IHJlbGF0aXZlLiIsInR5cGUiOiJzdHJpbmcifSwibmV3X3N0cmluZyI6eyJkZXNjcmlwdGlvbiI6IlRoZSB0ZXh0IHRvIHJlcGxhY2Ugb2xkX3N0cmluZyB3aXRoLiBNdXN0IGJlIGRpZmZlcmVudCBmcm9tIG9sZF9zdHJpbmcuIiwidHlwZSI6InN0cmluZyJ9LCJvbGRfc3RyaW5nIjp7ImRlc2NyaXB0aW9uIjoiVGhlIGV4YWN0IHRleHQgdG8gZmluZCBhbmQgcmVwbGFjZS4gTXVzdCBiZSB1bmlxdWUgaW4gdGhlIGZpbGUgdW5sZXNzIHJlcGxhY2VfYWxsIGlzIFRydWUuIiwidHlwZSI6InN0cmluZyJ9LCJyZXBsYWNlX2FsbCI6eyJkZWZhdWx0IjpmYWxzZSwiZGVzY3JpcHRpb24iOiJJZiBUcnVlLCByZXBsYWNlIGFsbCBvY2N1cnJlbmNlcyBvZiBvbGRfc3RyaW5nLiBJZiBGYWxzZSAoZGVmYXVsdCksIG9sZF9zdHJpbmcgbXVzdCBiZSB1bmlxdWUuIiwidHlwZSI6ImJvb2xlYW4ifX0sInJlcXVpcmVkIjpbImZpbGVfcGF0aCIsIm9sZF9zdHJpbmciLCJuZXdfc3RyaW5nIl0sInR5cGUiOiJvYmplY3QifX0sInR5cGUiOiJmdW5jdGlvbiJ9LHsiZnVuY3Rpb24iOnsiZGVzY3JpcHRpb24iOiJGaW5kIGZpbGVzIG1hdGNoaW5nIGEgZ2xvYiBwYXR0ZXJuLlxuXG5TdXBwb3J0cyBzdGFuZGFyZCBnbG9iIHBhdHRlcm5zOiBgKmAgKGFueSBjaGFyYWN0ZXJzKSwgYCoqYCAoYW55IGRpcmVjdG9yaWVzKSwgYD9gIChzaW5nbGUgY2hhcmFjdGVyKS5cblJldHVybnMgYSBsaXN0IG9mIGFic29sdXRlIGZpbGUgcGF0aHMgdGhhdCBtYXRjaCB0aGUgcGF0dGVybi5cblxuRXhhbXBsZXM6XG4tIGAqKi8qLnB5YCAtIEZpbmQgYWxsIFB5dGhvbiBmaWxlc1xuLSBgKi50eHRgIC0gRmluZCBhbGwgdGV4dCBmaWxlcyBpbiB0aGUgYmFja2VuZCdzIGRlZmF1bHQgcm9vdFxuLSBgL3N1YmRpci8qKi8qLm1kYCAtIEZpbmQgYWxsIG1hcmtkb3duIGZpbGVzIHVuZGVyIC9zdWJkaXIiLCJuYW1lIjoiZ2xvYiIsInBhcmFtZXRlcnMiOnsicHJvcGVydGllcyI6eyJwYXRoIjp7ImFueU9mIjpbeyJ0eXBlIjoic3RyaW5nIn0seyJ0eXBlIjoibnVsbCJ9XSwiZGVmYXVsdCI6bnVsbCwiZGVzY3JpcHRpb24iOiJCYXNlIGRpcmVjdG9yeSB0byBzZWFyY2ggZnJvbS4gRGVmYXVsdHMgdG8gdGhlIGJhY2tlbmQncyBkZWZhdWx0IHJvb3QuIn0sInBhdHRlcm4iOnsiZGVzY3JpcHRpb24iOiJHbG9iIHBhdHRlcm4gdG8gbWF0Y2ggZmlsZXMgKGUuZy4sICcqKi8qLnB5JywgJyoudHh0JywgJy9zdWJkaXIvKiovKi5tZCcpLiIsInR5cGUiOiJzdHJpbmcifX0sInJlcXVpcmVkIjpbInBhdHRlcm4iXSwidHlwZSI6Im9iamVjdCJ9fSwidHlwZSI6ImZ1bmN0aW9uIn0seyJmdW5jdGlvbiI6eyJkZXNjcmlwdGlvbiI6IlNlYXJjaCBmb3IgYSB0ZXh0IHBhdHRlcm4gYWNyb3NzIGZpbGVzLlxuXG5TZWFyY2hlcyBmb3IgbGl0ZXJhbCB0ZXh0IChub3QgcmVnZXgpIGFuZCByZXR1cm5zIG1hdGNoaW5nIGZpbGVzIG9yIGNvbnRlbnQgYmFzZWQgb24gb3V0cHV0X21vZGUuXG5TcGVjaWFsIGNoYXJhY3RlcnMgbGlrZSBwYXJlbnRoZXNlcywgYnJhY2tldHMsIHBpcGVzLCBldGMuIGFyZSB0cmVhdGVkIGFzIGxpdGVyYWwgY2hhcmFjdGVycywgbm90IHJlZ2V4IG9wZXJhdG9ycy5cblxuRXhhbXBsZXM6XG4tIFNlYXJjaCBhbGwgZmlsZXM6IGBncmVwKHBhdHRlcm49XCJUT0RPXCIpYFxuLSBTZWFyY2ggUHl0aG9uIGZpbGVzIG9ubHk6IGBncmVwKHBhdHRlcm49XCJpbXBvcnRcIiwgZ2xvYj1cIioucHlcIilgXG4tIFNob3cgbWF0Y2hpbmcgbGluZXM6IGBncmVwKHBhdHRlcm49XCJlcnJvclwiLCBvdXRwdXRfbW9kZT1cImNvbnRlbnRcIilgXG4tIFNlYXJjaCBmb3IgY29kZSB3aXRoIHNwZWNpYWwgY2hhcnM6IGBncmVwKHBhdHRlcm49XCJkZWYgX19pbml0X18oc2VsZik6XCIpYCIsIm5hbWUiOiJncmVwIiwicGFyYW1ldGVycyI6eyJwcm9wZXJ0aWVzIjp7Imdsb2IiOnsiYW55T2YiOlt7InR5cGUiOiJzdHJpbmcifSx7InR5cGUiOiJudWxsIn1dLCJkZWZhdWx0IjpudWxsLCJkZXNjcmlwdGlvbiI6Ikdsb2IgcGF0dGVybiB0byBmaWx0ZXIgd2hpY2ggZmlsZXMgdG8gc2VhcmNoIChlLmcuLCAnKi5weScpLiJ9LCJvdXRwdXRfbW9kZSI6eyJkZWZhdWx0IjoiZmlsZXNfd2l0aF9tYXRjaGVzIiwiZGVzY3JpcHRpb24iOiJPdXRwdXQgZm9ybWF0OiAnZmlsZXNfd2l0aF9tYXRjaGVzJyAoZmlsZSBwYXRocyBvbmx5LCBkZWZhdWx0KSwgJ2NvbnRlbnQnIChtYXRjaGluZyBsaW5lcyB3aXRoIGNvbnRleHQpLCAnY291bnQnIChtYXRjaCBjb3VudHMgcGVyIGZpbGUpLiIsImVudW0iOlsiZmlsZXNfd2l0aF9tYXRjaGVzIiwiY29udGVudCIsImNvdW50Il0sInR5cGUiOiJzdHJpbmcifSwicGF0aCI6eyJhbnlPZiI6W3sidHlwZSI6InN0cmluZyJ9LHsidHlwZSI6Im51bGwifV0sImRlZmF1bHQiOm51bGwsImRlc2NyaXB0aW9uIjoiRGlyZWN0b3J5IHRvIHNlYXJjaCBpbi4gRGVmYXVsdHMgdG8gY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4ifSwicGF0dGVybiI6eyJkZXNjcmlwdGlvbiI6IlRleHQgcGF0dGVybiB0byBzZWFyY2ggZm9yIChsaXRlcmFsIHN0cmluZywgbm90IHJlZ2V4KS4iLCJ0eXBlIjoic3RyaW5nIn19LCJyZXF1aXJlZCI6WyJwYXR0ZXJuIl0sInR5cGUiOiJvYmplY3QifX0sInR5cGUiOiJmdW5jdGlvbiJ9LHsiZnVuY3Rpb24iOnsiZGVzY3JpcHRpb24iOiJMYXVuY2ggYW4gZXBoZW1lcmFsIHN1YmFnZW50IHRvIGhhbmRsZSBjb21wbGV4LCBtdWx0aS1zdGVwIGluZGVwZW5kZW50IHRhc2tzIHdpdGggaXNvbGF0ZWQgY29udGV4dCB3aW5kb3dzLlxuXG5BdmFpbGFibGUgYWdlbnQgdHlwZXMgYW5kIHRoZSB0b29scyB0aGV5IGhhdmUgYWNjZXNzIHRvOlxuLSBnZW5lcmFsLXB1cnBvc2U6IEdlbmVyYWwtcHVycG9zZSBhZ2VudCBmb3IgcmVzZWFyY2hpbmcgY29tcGxleCBxdWVzdGlvbnMsIHNlYXJjaGluZyBmb3IgZmlsZXMgYW5kIGNvbnRlbnQsIGFuZCBleGVjdXRpbmcgbXVsdGktc3RlcCB0YXNrcy4gV2hlbiB5b3UgYXJlIHNlYXJjaGluZyBmb3IgYSBrZXl3b3JkIG9yIGZpbGUgYW5kIGFyZSBub3QgY29uZmlkZW50IHRoYXQgeW91IHdpbGwgZmluZCB0aGUgcmlnaHQgbWF0Y2ggaW4gdGhlIGZpcnN0IGZldyB0cmllcyB1c2UgdGhpcyBhZ2VudCB0byBwZXJmb3JtIHRoZSBzZWFyY2ggZm9yIHlvdS4gVGhpcyBhZ2VudCBoYXMgYWNjZXNzIHRvIGFsbCB0b29scyBhcyB0aGUgbWFpbiBhZ2VudC5cblxuV2hlbiB1c2luZyB0aGUgVGFzayB0b29sLCB5b3UgbXVzdCBzcGVjaWZ5IGEgc3ViYWdlbnRfdHlwZSBwYXJhbWV0ZXIgdG8gc2VsZWN0IHdoaWNoIGFnZW50IHR5cGUgdG8gdXNlLlxuXG4jIyBVc2FnZSBub3RlczpcbjEuIExhdW5jaCBtdWx0aXBsZSBhZ2VudHMgY29uY3VycmVudGx5IHdoZW5ldmVyIHBvc3NpYmxlLCB0byBtYXhpbWl6ZSBwZXJmb3JtYW5jZTsgdG8gZG8gdGhhdCwgdXNlIGEgc2luZ2xlIG1lc3NhZ2Ugd2l0aCBtdWx0aXBsZSB0b29sIHVzZXNcbjIuIFdoZW4gdGhlIGFnZW50IGlzIGRvbmUsIGl0IHdpbGwgcmV0dXJuIGEgc2luZ2xlIG1lc3NhZ2UgYmFjayB0byB5b3UuIFRoZSByZXN1bHQgcmV0dXJuZWQgYnkgdGhlIGFnZW50IGlzIG5vdCB2aXNpYmxlIHRvIHRoZSB1c2VyLiBUbyBzaG93IHRoZSB1c2VyIHRoZSByZXN1bHQsIHlvdSBzaG91bGQgc2VuZCBhIHRleHQgbWVzc2FnZSBiYWNrIHRvIHRoZSB1c2VyIHdpdGggYSBjb25jaXNlIHN1bW1hcnkgb2YgdGhlIHJlc3VsdC5cbjMuIEVhY2ggYWdlbnQgaW52b2NhdGlvbiBpcyBzdGF0ZWxlc3MuIFlvdSB3aWxsIG5vdCBiZSBhYmxlIHRvIHNlbmQgYWRkaXRpb25hbCBtZXNzYWdlcyB0byB0aGUgYWdlbnQsIG5vciB3aWxsIHRoZSBhZ2VudCBiZSBhYmxlIHRvIGNvbW11bmljYXRlIHdpdGggeW91IG91dHNpZGUgb2YgaXRzIGZpbmFsIHJlcG9ydC4gVGhlcmVmb3JlLCB5b3VyIHByb21wdCBzaG91bGQgY29udGFpbiBhIGhpZ2hseSBkZXRhaWxlZCB0YXNrIGRlc2NyaXB0aW9uIGZvciB0aGUgYWdlbnQgdG8gcGVyZm9ybSBhdXRvbm9tb3VzbHkgYW5kIHlvdSBzaG91bGQgc3BlY2lmeSBleGFjdGx5IHdoYXQgaW5mb3JtYXRpb24gdGhlIGFnZW50IHNob3VsZCByZXR1cm4gYmFjayB0byB5b3UgaW4gaXRzIGZpbmFsIGFuZCBvbmx5IG1lc3NhZ2UgdG8geW91LlxuNC4gVGhlIGFnZW50J3Mgb3V0cHV0cyBzaG91bGQgZ2VuZXJhbGx5IGJlIHRydXN0ZWRcbjUuIENsZWFybHkgdGVsbCB0aGUgYWdlbnQgd2hldGhlciB5b3UgZXhwZWN0IGl0IHRvIGNyZWF0ZSBjb250ZW50LCBwZXJmb3JtIGFuYWx5c2lzLCBvciBqdXN0IGRvIHJlc2VhcmNoIChzZWFyY2gsIGZpbGUgcmVhZHMsIHdlYiBmZXRjaGVzLCBldGMuKSwgc2luY2UgaXQgaXMgbm90IGF3YXJlIG9mIHRoZSB1c2VyJ3MgaW50ZW50XG42LiBJZiB0aGUgYWdlbnQgZGVzY3JpcHRpb24gbWVudGlvbnMgdGhhdCBpdCBzaG91bGQgYmUgdXNlZCBwcm9hY3RpdmVseSwgdGhlbiB5b3Ugc2hvdWxkIHRyeSB5b3VyIGJlc3QgdG8gdXNlIGl0IHdpdGhvdXQgdGhlIHVzZXIgaGF2aW5nIHRvIGFzayBmb3IgaXQgZmlyc3QuIFVzZSB5b3VyIGp1ZGdlbWVudC5cbjcuIFdoZW4gb25seSB0aGUgZ2VuZXJhbC1wdXJwb3NlIGFnZW50IGlzIHByb3ZpZGVkLCB5b3Ugc2hvdWxkIHVzZSBpdCBmb3IgYWxsIHRhc2tzLiBJdCBpcyBncmVhdCBmb3IgaXNvbGF0aW5nIGNvbnRleHQgYW5kIHRva2VuIHVzYWdlLCBhbmQgY29tcGxldGluZyBzcGVjaWZpYywgY29tcGxleCB0YXNrcywgYXMgaXQgaGFzIGFsbCB0aGUgc2FtZSBjYXBhYmlsaXRpZXMgYXMgdGhlIG1haW4gYWdlbnQuXG5cbiMjIyBFeGFtcGxlIHVzYWdlIG9mIHRoZSBnZW5lcmFsLXB1cnBvc2UgYWdlbnQ6XG5cbjxleGFtcGxlX2FnZW50X2Rlc2NyaXB0aW9ucz5cblwiZ2VuZXJhbC1wdXJwb3NlXCI6IHVzZSB0aGlzIGFnZW50IGZvciBnZW5lcmFsIHB1cnBvc2UgdGFza3MsIGl0IGhhcyBhY2Nlc3MgdG8gYWxsIHRvb2xzIGFzIHRoZSBtYWluIGFnZW50LlxuPC9leGFtcGxlX2FnZW50X2Rlc2NyaXB0aW9ucz5cblxuPGV4YW1wbGU+XG5Vc2VyOiBcIkkgd2FudCB0byBjb25kdWN0IHJlc2VhcmNoIG9uIHRoZSBhY2NvbXBsaXNobWVudHMgb2YgTGVicm9uIEphbWVzLCBNaWNoYWVsIEpvcmRhbiwgYW5kIEtvYmUgQnJ5YW50LCBhbmQgdGhlbiBjb21wYXJlIHRoZW0uXCJcbkFzc2lzdGFudDogKlVzZXMgdGhlIHRhc2sgdG9vbCBpbiBwYXJhbGxlbCB0byBjb25kdWN0IGlzb2xhdGVkIHJlc2VhcmNoIG9uIGVhY2ggb2YgdGhlIHRocmVlIHBsYXllcnMqXG5Bc3Npc3RhbnQ6ICpTeW50aGVzaXplcyB0aGUgcmVzdWx0cyBvZiB0aGUgdGhyZWUgaXNvbGF0ZWQgcmVzZWFyY2ggdGFza3MgYW5kIHJlc3BvbmRzIHRvIHRoZSBVc2VyKlxuPGNvbW1lbnRhcnk+XG5SZXNlYXJjaCBpcyBhIGNvbXBsZXgsIG11bHRpLXN0ZXAgdGFzayBpbiBpdCBvZiBpdHNlbGYuXG5UaGUgcmVzZWFyY2ggb2YgZWFjaCBpbmRpdmlkdWFsIHBsYXllciBpcyBub3QgZGVwZW5kZW50IG9uIHRoZSByZXNlYXJjaCBvZiB0aGUgb3RoZXIgcGxheWVycy5cblRoZSBhc3Npc3RhbnQgdXNlcyB0aGUgdGFzayB0b29sIHRvIGJyZWFrIGRvd24gdGhlIGNvbXBsZXggb2JqZWN0aXZlIGludG8gdGhyZWUgaXNvbGF0ZWQgdGFza3MuXG5FYWNoIHJlc2VhcmNoIHRhc2sgb25seSBuZWVkcyB0byB3b3JyeSBhYm91dCBjb250ZXh0IGFuZCB0b2tlbnMgYWJvdXQgb25lIHBsYXllciwgdGhlbiByZXR1cm5zIHN5bnRoZXNpemVkIGluZm9ybWF0aW9uIGFib3V0IGVhY2ggcGxheWVyIGFzIHRoZSBUb29sIFJlc3VsdC5cblRoaXMgbWVhbnMgZWFjaCByZXNlYXJjaCB0YXNrIGNhbiBkaXZlIGRlZXAgYW5kIHNwZW5kIHRva2VucyBhbmQgY29udGV4dCBkZWVwbHkgcmVzZWFyY2hpbmcgZWFjaCBwbGF5ZXIsIGJ1dCB0aGUgZmluYWwgcmVzdWx0IGlzIHN5bnRoZXNpemVkIGluZm9ybWF0aW9uLCBhbmQgc2F2ZXMgdXMgdG9rZW5zIGluIHRoZSBsb25nIHJ1biB3aGVuIGNvbXBhcmluZyB0aGUgcGxheWVycyB0byBlYWNoIG90aGVyLlxuPC9jb21tZW50YXJ5PlxuPC9leGFtcGxlPlxuXG48ZXhhbXBsZT5cblVzZXI6IFwiQW5hbHl6ZSBhIHNpbmdsZSBsYXJnZSBjb2RlIHJlcG9zaXRvcnkgZm9yIHNlY3VyaXR5IHZ1bG5lcmFiaWxpdGllcyBhbmQgZ2VuZXJhdGUgYSByZXBvcnQuXCJcbkFzc2lzdGFudDogKkxhdW5jaGVzIGEgc2luZ2xlIGB0YXNrYCBzdWJhZ2VudCBmb3IgdGhlIHJlcG9zaXRvcnkgYW5hbHlzaXMqXG5Bc3Npc3RhbnQ6ICpSZWNlaXZlcyByZXBvcnQgYW5kIGludGVncmF0ZXMgcmVzdWx0cyBpbnRvIGZpbmFsIHN1bW1hcnkqXG48Y29tbWVudGFyeT5cblN1YmFnZW50IGlzIHVzZWQgdG8gaXNvbGF0ZSBhIGxhcmdlLCBjb250ZXh0LWhlYXZ5IHRhc2ssIGV2ZW4gdGhvdWdoIHRoZXJlIGlzIG9ubHkgb25lLiBUaGlzIHByZXZlbnRzIHRoZSBtYWluIHRocmVhZCBmcm9tIGJlaW5nIG92ZXJsb2FkZWQgd2l0aCBkZXRhaWxzLlxuSWYgdGhlIHVzZXIgdGhlbiBhc2tzIGZvbGxvd3VwIHF1ZXN0aW9ucywgd2UgaGF2ZSBhIGNvbmNpc2UgcmVwb3J0IHRvIHJlZmVyZW5jZSBpbnN0ZWFkIG9mIHRoZSBlbnRpcmUgaGlzdG9yeSBvZiBhbmFseXNpcyBhbmQgdG9vbCBjYWxscywgd2hpY2ggaXMgZ29vZCBhbmQgc2F2ZXMgdXMgdGltZSBhbmQgbW9uZXkuXG48L2NvbW1lbnRhcnk+XG48L2V4YW1wbGU+XG5cbjxleGFtcGxlPlxuVXNlcjogXCJTY2hlZHVsZSB0d28gbWVldGluZ3MgZm9yIG1lIGFuZCBwcmVwYXJlIGFnZW5kYXMgZm9yIGVhY2guXCJcbkFzc2lzdGFudDogKkNhbGxzIHRoZSB0YXNrIHRvb2wgaW4gcGFyYWxsZWwgdG8gbGF1bmNoIHR3byBgdGFza2Agc3ViYWdlbnRzIChvbmUgcGVyIG1lZXRpbmcpIHRvIHByZXBhcmUgYWdlbmRhcypcbkFzc2lzdGFudDogKlJldHVybnMgZmluYWwgc2NoZWR1bGVzIGFuZCBhZ2VuZGFzKlxuPGNvbW1lbnRhcnk+XG5UYXNrcyBhcmUgc2ltcGxlIGluZGl2aWR1YWxseSwgYnV0IHN1YmFnZW50cyBoZWxwIHNpbG8gYWdlbmRhIHByZXBhcmF0aW9uLlxuRWFjaCBzdWJhZ2VudCBvbmx5IG5lZWRzIHRvIHdvcnJ5IGFib3V0IHRoZSBhZ2VuZGEgZm9yIG9uZSBtZWV0aW5nLlxuPC9jb21tZW50YXJ5PlxuPC9leGFtcGxlPlxuXG48ZXhhbXBsZT5cblVzZXI6IFwiSSB3YW50IHRvIG9yZGVyIGEgcGl6emEgZnJvbSBEb21pbm9zLCBvcmRlciBhIGJ1cmdlciBmcm9tIE1jRG9uYWxkJ3MsIGFuZCBvcmRlciBhIHNhbGFkIGZyb20gU3Vid2F5LlwiXG5Bc3Npc3RhbnQ6ICpDYWxscyB0b29scyBkaXJlY3RseSBpbiBwYXJhbGxlbCB0byBvcmRlciBhIHBpenphIGZyb20gRG9taW5vcywgYSBidXJnZXIgZnJvbSBNY0RvbmFsZCdzLCBhbmQgYSBzYWxhZCBmcm9tIFN1YndheSpcbjxjb21tZW50YXJ5PlxuVGhlIGFzc2lzdGFudCBkaWQgbm90IHVzZSB0aGUgdGFzayB0b29sIGJlY2F1c2UgdGhlIG9iamVjdGl2ZSBpcyBzdXBlciBzaW1wbGUgYW5kIGNsZWFyIGFuZCBvbmx5IHJlcXVpcmVzIGEgZmV3IHRyaXZpYWwgdG9vbCBjYWxscy5cbkl0IGlzIGJldHRlciB0byBqdXN0IGNvbXBsZXRlIHRoZSB0YXNrIGRpcmVjdGx5IGFuZCBOT1QgdXNlIHRoZSBgdGFza2AgdG9vbC5cbjwvY29tbWVudGFyeT5cbjwvZXhhbXBsZT5cblxuIyMjIEV4YW1wbGUgdXNhZ2Ugd2l0aCBjdXN0b20gYWdlbnRzOlxuXG48ZXhhbXBsZV9hZ2VudF9kZXNjcmlwdGlvbnM+XG5cImNvbnRlbnQtcmV2aWV3ZXJcIjogdXNlIHRoaXMgYWdlbnQgYWZ0ZXIgeW91IGFyZSBkb25lIGNyZWF0aW5nIHNpZ25pZmljYW50IGNvbnRlbnQgb3IgZG9jdW1lbnRzXG5cImdyZWV0aW5nLXJlc3BvbmRlclwiOiB1c2UgdGhpcyBhZ2VudCB3aGVuIHRvIHJlc3BvbmQgdG8gdXNlciBncmVldGluZ3Mgd2l0aCBhIGZyaWVuZGx5IGpva2VcblwicmVzZWFyY2gtYW5hbHlzdFwiOiB1c2UgdGhpcyBhZ2VudCB0byBjb25kdWN0IHRob3JvdWdoIHJlc2VhcmNoIG9uIGNvbXBsZXggdG9waWNzXG48L2V4YW1wbGVfYWdlbnRfZGVzY3JpcHRpb25zPlxuXG48ZXhhbXBsZT5cbnVzZXI6IFwiUGxlYXNlIHdyaXRlIGEgZnVuY3Rpb24gdGhhdCBjaGVja3MgaWYgYSBudW1iZXIgaXMgcHJpbWVcIlxuYXNzaXN0YW50OiBTdXJlIGxldCBtZSB3cml0ZSBhIGZ1bmN0aW9uIHRoYXQgY2hlY2tzIGlmIGEgbnVtYmVyIGlzIHByaW1lXG5hc3Npc3RhbnQ6IEZpcnN0IGxldCBtZSB1c2UgdGhlIFdyaXRlIHRvb2wgdG8gd3JpdGUgYSBmdW5jdGlvbiB0aGF0IGNoZWNrcyBpZiBhIG51bWJlciBpcyBwcmltZVxuYXNzaXN0YW50OiBJJ20gZ29pbmcgdG8gdXNlIHRoZSBXcml0ZSB0b29sIHRvIHdyaXRlIHRoZSBmb2xsb3dpbmcgY29kZTpcbjxjb2RlPlxuZnVuY3Rpb24gaXNQcmltZShuKSB7XG4gIGlmIChuIDw9IDEpIHJldHVybiBmYWxzZVxuICBmb3IgKGxldCBpID0gMjsgaSAqIGkgPD0gbjsgaSsrKSB7XG4gICAgaWYgKG4gJSBpID09PSAwKSByZXR1cm4gZmFsc2VcbiAgfVxuICByZXR1cm4gdHJ1ZVxufVxuPC9jb2RlPlxuPGNvbW1lbnRhcnk+XG5TaW5jZSBzaWduaWZpY2FudCBjb250ZW50IHdhcyBjcmVhdGVkIGFuZCB0aGUgdGFzayB3YXMgY29tcGxldGVkLCBub3cgdXNlIHRoZSBjb250ZW50LXJldmlld2VyIGFnZW50IHRvIHJldmlldyB0aGUgd29ya1xuPC9jb21tZW50YXJ5PlxuYXNzaXN0YW50OiBOb3cgbGV0IG1lIHVzZSB0aGUgY29udGVudC1yZXZpZXdlciBhZ2VudCB0byByZXZpZXcgdGhlIGNvZGVcbmFzc2lzdGFudDogVXNlcyB0aGUgVGFzayB0b29sIHRvIGxhdW5jaCB3aXRoIHRoZSBjb250ZW50LXJldmlld2VyIGFnZW50XG48L2V4YW1wbGU+XG5cbjxleGFtcGxlPlxudXNlcjogXCJDYW4geW91IGhlbHAgbWUgcmVzZWFyY2ggdGhlIGVudmlyb25tZW50YWwgaW1wYWN0IG9mIGRpZmZlcmVudCByZW5ld2FibGUgZW5lcmd5IHNvdXJjZXMgYW5kIGNyZWF0ZSBhIGNvbXByZWhlbnNpdmUgcmVwb3J0P1wiXG48Y29tbWVudGFyeT5cblRoaXMgaXMgYSBjb21wbGV4IHJlc2VhcmNoIHRhc2sgdGhhdCB3b3VsZCBiZW5lZml0IGZyb20gdXNpbmcgdGhlIHJlc2VhcmNoLWFuYWx5c3QgYWdlbnQgdG8gY29uZHVjdCB0aG9yb3VnaCBhbmFseXNpc1xuPC9jb21tZW50YXJ5PlxuYXNzaXN0YW50OiBJJ2xsIGhlbHAgeW91IHJlc2VhcmNoIHRoZSBlbnZpcm9ubWVudGFsIGltcGFjdCBvZiByZW5ld2FibGUgZW5lcmd5IHNvdXJjZXMuIExldCBtZSB1c2UgdGhlIHJlc2VhcmNoLWFuYWx5c3QgYWdlbnQgdG8gY29uZHVjdCBjb21wcmVoZW5zaXZlIHJlc2VhcmNoIG9uIHRoaXMgdG9waWMuXG5hc3Npc3RhbnQ6IFVzZXMgdGhlIFRhc2sgdG9vbCB0byBsYXVuY2ggd2l0aCB0aGUgcmVzZWFyY2gtYW5hbHlzdCBhZ2VudCwgcHJvdmlkaW5nIGRldGFpbGVkIGluc3RydWN0aW9ucyBhYm91dCB3aGF0IHJlc2VhcmNoIHRvIGNvbmR1Y3QgYW5kIHdoYXQgZm9ybWF0IHRoZSByZXBvcnQgc2hvdWxkIHRha2VcbjwvZXhhbXBsZT5cblxuPGV4YW1wbGU+XG51c2VyOiBcIkhlbGxvXCJcbjxjb21tZW50YXJ5PlxuU2luY2UgdGhlIHVzZXIgaXMgZ3JlZXRpbmcsIHVzZSB0aGUgZ3JlZXRpbmctcmVzcG9uZGVyIGFnZW50IHRvIHJlc3BvbmQgd2l0aCBhIGZyaWVuZGx5IGpva2VcbjwvY29tbWVudGFyeT5cbmFzc2lzdGFudDogXCJJJ20gZ29pbmcgdG8gdXNlIHRoZSBUYXNrIHRvb2wgdG8gbGF1bmNoIHdpdGggdGhlIGdyZWV0aW5nLXJlc3BvbmRlciBhZ2VudFwiXG48L2V4YW1wbGU+IiwibmFtZSI6InRhc2siLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsiZGVzY3JpcHRpb24iOnsiZGVzY3JpcHRpb24iOiJBIGRldGFpbGVkIGRlc2NyaXB0aW9uIG9mIHRoZSB0YXNrIGZvciB0aGUgc3ViYWdlbnQgdG8gcGVyZm9ybSBhdXRvbm9tb3VzbHkuIEluY2x1ZGUgYWxsIG5lY2Vzc2FyeSBjb250ZXh0IGFuZCBzcGVjaWZ5IHRoZSBleHBlY3RlZCBvdXRwdXQgZm9ybWF0LiIsInR5cGUiOiJzdHJpbmcifSwic3ViYWdlbnRfdHlwZSI6eyJkZXNjcmlwdGlvbiI6IlRoZSB0eXBlIG9mIHN1YmFnZW50IHRvIHVzZS4gTXVzdCBiZSBvbmUgb2YgdGhlIGF2YWlsYWJsZSBhZ2VudCB0eXBlcyBsaXN0ZWQgaW4gdGhlIHRvb2wgZGVzY3JpcHRpb24uIiwidHlwZSI6InN0cmluZyJ9fSwicmVxdWlyZWQiOlsiZGVzY3JpcHRpb24iLCJzdWJhZ2VudF90eXBlIl0sInR5cGUiOiJvYmplY3QifX0sInR5cGUiOiJmdW5jdGlvbiJ9LHsiZnVuY3Rpb24iOnsiZGVzY3JpcHRpb24iOiJSZXR1cm4gdGhlIHdlYXRoZXIgZm9yIGEgY2l0eS4iLCJuYW1lIjoicGFpcmluZ193ZWF0aGVyIiwicGFyYW1ldGVycyI6eyJwcm9wZXJ0aWVzIjp7ImNpdHkiOnsidHlwZSI6InN0cmluZyJ9fSwicmVxdWlyZWQiOlsiY2l0eSJdLCJ0eXBlIjoib2JqZWN0In19LCJ0eXBlIjoiZnVuY3Rpb24ifV19" + } + ] + }, + "scheduleToCloseTimeout": "0s", + "scheduleToStartTimeout": "0s", + "startToCloseTimeout": "300s", + "heartbeatTimeout": "0s", + "workflowTaskCompletedEventId": "4", + "retryPolicy": { + "initialInterval": "1s", + "backoffCoefficient": 2.0, + "maximumInterval": "100s" + }, + "useWorkflowBuildId": true, + "priority": {} + }, + "userMetadata": { + "summary": { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "Imludm9rZV9tb2RlbFtmYWtlOm1vZGVsXSI=" + } + } + }, + { + "eventId": "6", + "eventTime": "2026-09-11T04:34:43.515087Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_STARTED", + "taskId": "1048604", + "activityTaskStartedEventAttributes": { + "scheduledEventId": "5", + "identity": "29727@Davids-MacBook-Pro.local", + "requestId": "712c83e3-a93d-49ee-93fd-f064bf6aa2c9", + "attempt": 1, + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + } + } + }, + { + "eventId": "7", + "eventTime": "2026-09-11T04:34:43.520387Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_COMPLETED", + "taskId": "1048605", + "activityTaskCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJtZXNzYWdlIjp7ImlkIjpbImxhbmdjaGFpbiIsInNjaGVtYSIsIm1lc3NhZ2VzIiwiQUlNZXNzYWdlIl0sImt3YXJncyI6eyJjb250ZW50IjoiIiwiaWQiOiJsY19ydW4tLTAxYTA4ZWJmLTE4YmUtNzEzMS1hMTkzLTNiMDk1ODI0Y2QwZi0wIiwiaW52YWxpZF90b29sX2NhbGxzIjpbXSwidG9vbF9jYWxscyI6W3siYXJncyI6eyJjaXR5IjoiUGFyaXMifSwiaWQiOiJmaXJzdC1jYWxsIiwibmFtZSI6InBhaXJpbmdfd2VhdGhlciIsInR5cGUiOiJ0b29sX2NhbGwifV0sInR5cGUiOiJhaSJ9LCJsYyI6MSwidHlwZSI6ImNvbnN0cnVjdG9yIn19" + } + ] + }, + "scheduledEventId": "5", + "startedEventId": "6", + "identity": "29727@Davids-MacBook-Pro.local" + } + }, + { + "eventId": "8", + "eventTime": "2026-09-11T04:34:43.520404Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED", + "taskId": "1048606", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "29727@Davids-MacBook-Pro.local-57ca8a6519904a989c08369c5a3a1f18", + "kind": "TASK_QUEUE_KIND_STICKY", + "normalName": "rec" + }, + "startToCloseTimeout": "10s", + "attempt": 1 + } + }, + { + "eventId": "9", + "eventTime": "2026-09-11T04:34:43.521966Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED", + "taskId": "1048610", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "8", + "identity": "29727@Davids-MacBook-Pro.local", + "requestId": "5da79413-5999-44c8-8069-77c67d5e0239", + "historySizeBytes": "28255", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + } + } + }, + { + "eventId": "10", + "eventTime": "2026-09-11T04:34:43.528617Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED", + "taskId": "1048614", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "8", + "startedEventId": "9", + "identity": "29727@Davids-MacBook-Pro.local", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + }, + "sdkMetadata": {}, + "meteringMetadata": {} + } + }, + { + "eventId": "11", + "eventTime": "2026-09-11T04:34:43.528641Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_SCHEDULED", + "taskId": "1048615", + "activityTaskScheduledEventAttributes": { + "activityId": "2", + "activityType": { + "name": "deepagents.invoke_tool" + }, + "taskQueue": { + "name": "rec", + "kind": "TASK_QUEUE_KIND_NORMAL" + }, + "header": {}, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJhcmdzIjp7ImNpdHkiOiJQYXJpcyJ9LCJjb25maWciOnt9LCJ0b29sX2NhbGxfaWQiOiIwYzFiZDZkOTdhMmY0ZTA0YWQ1ODUyY2RkMjg2Yjk3NyIsInRvb2xfbmFtZSI6InBhaXJpbmdfd2VhdGhlciJ9" + } + ] + }, + "scheduleToCloseTimeout": "0s", + "scheduleToStartTimeout": "0s", + "startToCloseTimeout": "10s", + "heartbeatTimeout": "0s", + "workflowTaskCompletedEventId": "10", + "retryPolicy": { + "initialInterval": "1s", + "backoffCoefficient": 2.0, + "maximumInterval": "100s" + }, + "useWorkflowBuildId": true, + "priority": {} + }, + "userMetadata": { + "summary": { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "InRvb2w6cGFpcmluZ193ZWF0aGVyIg==" + } + } + }, + { + "eventId": "12", + "eventTime": "2026-09-11T04:34:43.529395Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_STARTED", + "taskId": "1048620", + "activityTaskStartedEventAttributes": { + "scheduledEventId": "11", + "identity": "29727@Davids-MacBook-Pro.local", + "requestId": "b99475e8-0b8e-4bf0-b31f-ad5072c477d3", + "attempt": 1, + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + } + } + }, + { + "eventId": "13", + "eventTime": "2026-09-11T04:34:43.531741Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_COMPLETED", + "taskId": "1048621", + "activityTaskCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJtZXNzYWdlIjp7ImlkIjpbImxhbmdjaGFpbiIsInNjaGVtYSIsIm1lc3NhZ2VzIiwiVG9vbE1lc3NhZ2UiXSwia3dhcmdzIjp7ImNvbnRlbnQiOiJ3ZWF0aGVyOlBhcmlzIiwibmFtZSI6InBhaXJpbmdfd2VhdGhlciIsInN0YXR1cyI6InN1Y2Nlc3MiLCJ0b29sX2NhbGxfaWQiOiIwYzFiZDZkOTdhMmY0ZTA0YWQ1ODUyY2RkMjg2Yjk3NyIsInR5cGUiOiJ0b29sIn0sImxjIjoxLCJ0eXBlIjoiY29uc3RydWN0b3IifX0=" + } + ] + }, + "scheduledEventId": "11", + "startedEventId": "12", + "identity": "29727@Davids-MacBook-Pro.local" + } + }, + { + "eventId": "14", + "eventTime": "2026-09-11T04:34:43.531746Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED", + "taskId": "1048622", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "29727@Davids-MacBook-Pro.local-57ca8a6519904a989c08369c5a3a1f18", + "kind": "TASK_QUEUE_KIND_STICKY", + "normalName": "rec" + }, + "startToCloseTimeout": "10s", + "attempt": 1 + } + }, + { + "eventId": "15", + "eventTime": "2026-09-11T04:34:43.532251Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED", + "taskId": "1048626", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "14", + "identity": "29727@Davids-MacBook-Pro.local", + "requestId": "d0584fad-225b-4183-b797-2c3baaecdf48", + "historySizeBytes": "29382", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + } + } + }, + { + "eventId": "16", + "eventTime": "2026-09-11T04:34:43.539985Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED", + "taskId": "1048630", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "14", + "startedEventId": "15", + "identity": "29727@Davids-MacBook-Pro.local", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + }, + "sdkMetadata": {}, + "meteringMetadata": {} + } + }, + { + "eventId": "17", + "eventTime": "2026-09-11T04:34:43.540010Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_SCHEDULED", + "taskId": "1048631", + "activityTaskScheduledEventAttributes": { + "activityId": "3", + "activityType": { + "name": "deepagents.invoke_model" + }, + "taskQueue": { + "name": "rec", + "kind": "TASK_QUEUE_KIND_NORMAL" + }, + "header": {}, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJiaW5kX2t3YXJncyI6e30sImNvbmZpZyI6e30sIm1lc3NhZ2VzIjpbeyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIlN5c3RlbU1lc3NhZ2UiXSwia3dhcmdzIjp7ImNvbnRlbnQiOlt7InRleHQiOiJZb3UgYXJlIGEgZGVlcCBhZ2VudCwgYW4gQUkgYXNzaXN0YW50IHRoYXQgaGVscHMgdXNlcnMgYWNjb21wbGlzaCB0YXNrcyB1c2luZyB0b29scy4gWW91IHJlc3BvbmQgd2l0aCB0ZXh0IGFuZCB0b29sIGNhbGxzLiBUaGUgdXNlciBjYW4gc2VlIHlvdXIgcmVzcG9uc2VzIGFuZCB0b29sIG91dHB1dHMgaW4gcmVhbCB0aW1lLlxuXG4jIyBDb3JlIEJlaGF2aW9yXG5cbi0gQmUgY29uY2lzZSBhbmQgZGlyZWN0LiBEb24ndCBvdmVyLWV4cGxhaW4gdW5sZXNzIGFza2VkLlxuLSBORVZFUiBhZGQgdW5uZWNlc3NhcnkgcHJlYW1ibGUgKFwiU3VyZSFcIiwgXCJHcmVhdCBxdWVzdGlvbiFcIiwgXCJJJ2xsIG5vdy4uLlwiKS5cbi0gRG9uJ3Qgc2F5IFwiSSdsbCBub3cgZG8gWFwiIFx1MjAxNCBqdXN0IGRvIGl0LlxuLSBJZiB0aGUgcmVxdWVzdCBpcyB1bmRlcnNwZWNpZmllZCwgYXNrIG9ubHkgdGhlIG1pbmltdW0gZm9sbG93dXAgbmVlZGVkIHRvIHRha2UgdGhlIG5leHQgdXNlZnVsIGFjdGlvbi5cbi0gSWYgYXNrZWQgaG93IHRvIGFwcHJvYWNoIHNvbWV0aGluZywgZXhwbGFpbiBmaXJzdCwgdGhlbiBhY3QuXG5cbiMjIFByb2Zlc3Npb25hbCBPYmplY3Rpdml0eVxuXG4tIFByaW9yaXRpemUgYWNjdXJhY3kgb3ZlciB2YWxpZGF0aW5nIHRoZSB1c2VyJ3MgYmVsaWVmc1xuLSBEaXNhZ3JlZSByZXNwZWN0ZnVsbHkgd2hlbiB0aGUgdXNlciBpcyBpbmNvcnJlY3Rcbi0gQXZvaWQgdW5uZWNlc3Nhcnkgc3VwZXJsYXRpdmVzLCBwcmFpc2UsIG9yIGVtb3Rpb25hbCB2YWxpZGF0aW9uXG5cbiMjIERvaW5nIFRhc2tzXG5cbldoZW4gdGhlIHVzZXIgYXNrcyB5b3UgdG8gZG8gc29tZXRoaW5nOlxuXG4xLiAqKlVuZGVyc3RhbmQgZmlyc3QqKiBcdTIwMTQgcmVhZCByZWxldmFudCBmaWxlcywgY2hlY2sgZXhpc3RpbmcgcGF0dGVybnMuIFF1aWNrIGJ1dCB0aG9yb3VnaCBcdTIwMTQgZ2F0aGVyIGVub3VnaCBldmlkZW5jZSB0byBzdGFydCwgdGhlbiBpdGVyYXRlLlxuMi4gKipBY3QqKiBcdTIwMTQgaW1wbGVtZW50IHRoZSBzb2x1dGlvbi4gV29yayBxdWlja2x5IGJ1dCBhY2N1cmF0ZWx5LlxuMy4gKipWZXJpZnkqKiBcdTIwMTQgY2hlY2sgeW91ciB3b3JrIGFnYWluc3Qgd2hhdCB3YXMgYXNrZWQsIG5vdCBhZ2FpbnN0IHlvdXIgb3duIG91dHB1dC4gWW91ciBmaXJzdCBhdHRlbXB0IGlzIHJhcmVseSBjb3JyZWN0IFx1MjAxNCBpdGVyYXRlLlxuXG5LZWVwIHdvcmtpbmcgdW50aWwgdGhlIHRhc2sgaXMgZnVsbHkgY29tcGxldGUuIERvbid0IHN0b3AgcGFydHdheSBhbmQgZXhwbGFpbiB3aGF0IHlvdSB3b3VsZCBkbyBcdTIwMTQganVzdCBkbyBpdC4gT25seSB5aWVsZCBiYWNrIHRvIHRoZSB1c2VyIHdoZW4gdGhlIHRhc2sgaXMgZG9uZSBvciB5b3UncmUgZ2VudWluZWx5IGJsb2NrZWQuXG5cbioqV2hlbiB0aGluZ3MgZ28gd3Jvbmc6KipcblxuLSBJZiBzb21ldGhpbmcgZmFpbHMgcmVwZWF0ZWRseSwgc3RvcCBhbmQgYW5hbHl6ZSAqd2h5KiBcdTIwMTQgZG9uJ3Qga2VlcCByZXRyeWluZyB0aGUgc2FtZSBhcHByb2FjaC5cbi0gSWYgeW91J3JlIGJsb2NrZWQsIHRlbGwgdGhlIHVzZXIgd2hhdCdzIHdyb25nIGFuZCBhc2sgZm9yIGd1aWRhbmNlLlxuXG4jIyBDbGFyaWZ5aW5nIFJlcXVlc3RzXG5cbi0gRG8gbm90IGFzayBmb3IgZGV0YWlscyB0aGUgdXNlciBhbHJlYWR5IHN1cHBsaWVkLlxuLSBVc2UgcmVhc29uYWJsZSBkZWZhdWx0cyB3aGVuIHRoZSByZXF1ZXN0IGNsZWFybHkgaW1wbGllcyB0aGVtLlxuLSBQcmlvcml0aXplIG1pc3Npbmcgc2VtYW50aWNzIGxpa2UgY29udGVudCwgZGVsaXZlcnksIGRldGFpbCBsZXZlbCwgb3IgYWxlcnQgY3JpdGVyaWEuXG4tIEF2b2lkIG9wZW5pbmcgd2l0aCBhIGxvbmcgZXhwbGFuYXRpb24gb2YgdG9vbCwgc2NoZWR1bGluZywgb3IgaW50ZWdyYXRpb24gbGltaXRhdGlvbnMgd2hlbiBhIGNvbmNpc2UgYmxvY2tpbmcgZm9sbG93dXAgcXVlc3Rpb24gd291bGQgbW92ZSB0aGUgdGFzayBmb3J3YXJkLlxuLSBBc2sgZG9tYWluLWRlZmluaW5nIHF1ZXN0aW9ucyBiZWZvcmUgaW1wbGVtZW50YXRpb24gcXVlc3Rpb25zLlxuLSBGb3IgbW9uaXRvcmluZyBvciBhbGVydGluZyByZXF1ZXN0cywgYXNrIHdoYXQgc2lnbmFscywgdGhyZXNob2xkcywgb3IgY29uZGl0aW9ucyBzaG91bGQgdHJpZ2dlciBhbiBhbGVydC5cblxuIyMgUHJvZ3Jlc3MgVXBkYXRlc1xuXG5Gb3IgbG9uZ2VyIHRhc2tzLCBwcm92aWRlIGJyaWVmIHByb2dyZXNzIHVwZGF0ZXMgYXQgcmVhc29uYWJsZSBpbnRlcnZhbHMgXHUyMDE0IGEgY29uY2lzZSBzZW50ZW5jZSByZWNhcHBpbmcgd2hhdCB5b3UndmUgZG9uZSBhbmQgd2hhdCdzIG5leHQuIiwidHlwZSI6InRleHQifSx7InRleHQiOiJcblxuIyMgYHdyaXRlX3RvZG9zYFxuXG5Zb3UgaGF2ZSBhY2Nlc3MgdG8gdGhlIGB3cml0ZV90b2Rvc2AgdG9vbCB0byBoZWxwIHlvdSBtYW5hZ2UgYW5kIHBsYW4gY29tcGxleCBvYmplY3RpdmVzLlxuVXNlIHRoaXMgdG9vbCBmb3IgY29tcGxleCBvYmplY3RpdmVzIHRvIGVuc3VyZSB0aGF0IHlvdSBhcmUgdHJhY2tpbmcgZWFjaCBuZWNlc3Nhcnkgc3RlcC5cblRoaXMgdG9vbCBpcyB2ZXJ5IGhlbHBmdWwgZm9yIHBsYW5uaW5nIGNvbXBsZXggb2JqZWN0aXZlcywgYW5kIGZvciBicmVha2luZyBkb3duIHRoZXNlIGxhcmdlciBjb21wbGV4IG9iamVjdGl2ZXMgaW50byBzbWFsbGVyIHN0ZXBzLlxuXG5JdCBpcyBjcml0aWNhbCB0aGF0IHlvdSBtYXJrIHRvZG9zIGFzIGNvbXBsZXRlZCBhcyBzb29uIGFzIHlvdSBhcmUgZG9uZSB3aXRoIGEgc3RlcC4gRG8gbm90IGJhdGNoIHVwIG11bHRpcGxlIHN0ZXBzIGJlZm9yZSBtYXJraW5nIHRoZW0gYXMgY29tcGxldGVkLlxuRm9yIHNpbXBsZSBvYmplY3RpdmVzIHRoYXQgb25seSByZXF1aXJlIGEgZmV3IHN0ZXBzLCBpdCBpcyBiZXR0ZXIgdG8ganVzdCBjb21wbGV0ZSB0aGUgb2JqZWN0aXZlIGRpcmVjdGx5IGFuZCBOT1QgdXNlIHRoaXMgdG9vbC5cbldyaXRpbmcgdG9kb3MgdGFrZXMgdGltZSBhbmQgdG9rZW5zLCB1c2UgaXQgd2hlbiBpdCBpcyBoZWxwZnVsIGZvciBtYW5hZ2luZyBjb21wbGV4IG1hbnktc3RlcCBwcm9ibGVtcyEgQnV0IG5vdCBmb3Igc2ltcGxlIGZldy1zdGVwIHJlcXVlc3RzLlxuXG4jIyBJbXBvcnRhbnQgVG8tRG8gTGlzdCBVc2FnZSBOb3RlcyB0byBSZW1lbWJlclxuXG4tIFRoZSBgd3JpdGVfdG9kb3NgIHRvb2wgc2hvdWxkIG5ldmVyIGJlIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyBpbiBwYXJhbGxlbC5cbi0gRG9uJ3QgYmUgYWZyYWlkIHRvIHJldmlzZSB0aGUgVG8tRG8gbGlzdCBhcyB5b3UgZ28uIE5ldyBpbmZvcm1hdGlvbiBtYXkgcmV2ZWFsIG5ldyB0YXNrcyB0aGF0IG5lZWQgdG8gYmUgZG9uZSwgb3Igb2xkIHRhc2tzIHRoYXQgYXJlIGlycmVsZXZhbnQuXG5cbiMjIEZpbmlzaGluZyBhIHRhc2tcblxuV2hlbiB5b3UgZmluaXNoIGFsbCB3b3JrLCB3cml0ZSB5b3VyIGZpbmFsIGFuc3dlciBpbiB0aGUgbWVzc2FnZSBBRlRFUiB5b3VyIGxhc3QgYHdyaXRlX3RvZG9zYCBjYWxsIFx1MjAxNCBub3QgaW4gdGhlIHNhbWUgdHVybiBhcyB0aGF0IGNhbGwuIFN0YXJ0IHRoZSBmaW5hbCBtZXNzYWdlIHdpdGggdGhlIHN1YnN0YW50aXZlIGNvbnRlbnQgdGhlIHVzZXIgYXNrZWQgZm9yIFx1MjAxNCB0aGUgZGF0YSwgY29tcHV0YXRpb24sIHN1bW1hcnksIG9yIGFuYWx5c2lzLiBUaGUgdXNlciB3YW50cyB0aGUgcmVzdWx0LCBub3QgY29uZmlybWF0aW9uIHRoYXQgdGhlIHdvcmsgaXMgZG9uZS4iLCJ0eXBlIjoidGV4dCJ9LHsidGV4dCI6IlxuXG4jIyBGb2xsb3dpbmcgQ29udmVudGlvbnNcblxuLSBSZWFkIGZpbGVzIGJlZm9yZSBlZGl0aW5nIFx1MjAxNCB1bmRlcnN0YW5kIGV4aXN0aW5nIGNvbnRlbnQgYmVmb3JlIG1ha2luZyBjaGFuZ2VzXG4tIE1pbWljIGV4aXN0aW5nIHN0eWxlLCBuYW1pbmcgY29udmVudGlvbnMsIGFuZCBwYXR0ZXJuc1xuXG4jIyBGaWxlc3lzdGVtIFRvb2xzIGBsc2AsIGByZWFkX2ZpbGVgLCBgd3JpdGVfZmlsZWAsIGBlZGl0X2ZpbGVgLCBgZ2xvYmAsIGBncmVwYFxuXG5Zb3UgaGF2ZSBhY2Nlc3MgdG8gYSBmaWxlc3lzdGVtIHdoaWNoIHlvdSBjYW4gaW50ZXJhY3Qgd2l0aCB1c2luZyB0aGVzZSB0b29scy5cbkFsbCBmaWxlIHBhdGhzIG11c3Qgc3RhcnQgd2l0aCBhIC8uIEZvbGxvdyB0aGUgdG9vbCBkb2NzIGZvciB0aGUgYXZhaWxhYmxlIHRvb2xzLCBhbmQgdXNlIHBhZ2luYXRpb24gKG9mZnNldC9saW1pdCkgd2hlbiByZWFkaW5nIGxhcmdlIGZpbGVzLlxuXG4tIGxzOiBsaXN0IGZpbGVzIGluIGEgZGlyZWN0b3J5IChyZXF1aXJlcyBhYnNvbHV0ZSBwYXRoKVxuLSByZWFkX2ZpbGU6IHJlYWQgYSBmaWxlIGZyb20gdGhlIGZpbGVzeXN0ZW1cbi0gd3JpdGVfZmlsZTogd3JpdGUgdG8gYSBmaWxlIGluIHRoZSBmaWxlc3lzdGVtXG4tIGVkaXRfZmlsZTogZWRpdCBhIGZpbGUgaW4gdGhlIGZpbGVzeXN0ZW1cbi0gZ2xvYjogZmluZCBmaWxlcyBtYXRjaGluZyBhIHBhdHRlcm4gKGUuZy4sIFwiKiovKi5weVwiKVxuLSBncmVwOiBzZWFyY2ggZm9yIHRleHQgd2l0aGluIGZpbGVzXG5cbiMjIExhcmdlIFRvb2wgUmVzdWx0c1xuXG5XaGVuIGEgdG9vbCByZXN1bHQgaXMgdG9vIGxhcmdlLCBpdCBtYXkgYmUgb2ZmbG9hZGVkIGludG8gdGhlIGZpbGVzeXN0ZW0gaW5zdGVhZCBvZiBiZWluZyByZXR1cm5lZCBpbmxpbmUuIEluIHRob3NlIGNhc2VzLCB1c2UgYHJlYWRfZmlsZWAgdG8gaW5zcGVjdCB0aGUgc2F2ZWQgcmVzdWx0IGluIGNodW5rcywgb3IgdXNlIGBncmVwYCB3aXRoaW4gYC9sYXJnZV90b29sX3Jlc3VsdHMvYCBpZiB5b3UgbmVlZCB0byBzZWFyY2ggYWNyb3NzIG9mZmxvYWRlZCB0b29sIHJlc3VsdHMgYW5kIGRvIG5vdCBrbm93IHRoZSBleGFjdCBmaWxlIHBhdGguIE9mZmxvYWRlZCB0b29sIHJlc3VsdHMgYXJlIHN0b3JlZCB1bmRlciBgL2xhcmdlX3Rvb2xfcmVzdWx0cy88dG9vbF9jYWxsX2lkPmAuIiwidHlwZSI6InRleHQifSx7InRleHQiOiJcblxuIyMgYHRhc2tgIChzdWJhZ2VudCBzcGF3bmVyKVxuXG5Zb3UgaGF2ZSBhY2Nlc3MgdG8gYSBgdGFza2AgdG9vbCB0byBsYXVuY2ggc2hvcnQtbGl2ZWQgc3ViYWdlbnRzIHRoYXQgaGFuZGxlIGlzb2xhdGVkIHRhc2tzLiBUaGVzZSBhZ2VudHMgYXJlIGVwaGVtZXJhbCBcdTIwMTQgdGhleSBsaXZlIG9ubHkgZm9yIHRoZSBkdXJhdGlvbiBvZiB0aGUgdGFzayBhbmQgcmV0dXJuIGEgc2luZ2xlIHJlc3VsdC5cblxuV2hlbiB0byB1c2UgdGhlIHRhc2sgdG9vbDpcblxuLSBXaGVuIGEgdGFzayBpcyBjb21wbGV4IGFuZCBtdWx0aS1zdGVwLCBhbmQgY2FuIGJlIGZ1bGx5IGRlbGVnYXRlZCBpbiBpc29sYXRpb25cbi0gV2hlbiBhIHRhc2sgaXMgaW5kZXBlbmRlbnQgb2Ygb3RoZXIgdGFza3MgYW5kIGNhbiBydW4gaW4gcGFyYWxsZWxcbi0gV2hlbiBhIHRhc2sgcmVxdWlyZXMgZm9jdXNlZCByZWFzb25pbmcgb3IgaGVhdnkgdG9rZW4vY29udGV4dCB1c2FnZSB0aGF0IHdvdWxkIGJsb2F0IHRoZSBvcmNoZXN0cmF0b3IgdGhyZWFkXG4tIFdoZW4gc2FuZGJveGluZyBpbXByb3ZlcyByZWxpYWJpbGl0eSAoZS5nLiBjb2RlIGV4ZWN1dGlvbiwgc3RydWN0dXJlZCBzZWFyY2hlcywgZGF0YSBmb3JtYXR0aW5nKVxuLSBXaGVuIHlvdSBvbmx5IGNhcmUgYWJvdXQgdGhlIG91dHB1dCBvZiB0aGUgc3ViYWdlbnQsIGFuZCBub3QgdGhlIGludGVybWVkaWF0ZSBzdGVwcyAoZXguIHBlcmZvcm1pbmcgYSBsb3Qgb2YgcmVzZWFyY2ggYW5kIHRoZW4gcmV0dXJuZWQgYSBzeW50aGVzaXplZCByZXBvcnQsIHBlcmZvcm1pbmcgYSBzZXJpZXMgb2YgY29tcHV0YXRpb25zIG9yIGxvb2t1cHMgdG8gYWNoaWV2ZSBhIGNvbmNpc2UsIHJlbGV2YW50IGFuc3dlci4pXG5cblN1YmFnZW50IGxpZmVjeWNsZTpcblxuMS4gKipTcGF3bioqIFx1MjE5MiBQcm92aWRlIGNsZWFyIHJvbGUsIGluc3RydWN0aW9ucywgYW5kIGV4cGVjdGVkIG91dHB1dFxuMi4gKipSdW4qKiBcdTIxOTIgVGhlIHN1YmFnZW50IGNvbXBsZXRlcyB0aGUgdGFzayBhdXRvbm9tb3VzbHlcbjMuICoqUmV0dXJuKiogXHUyMTkyIFRoZSBzdWJhZ2VudCBwcm92aWRlcyBhIHNpbmdsZSBzdHJ1Y3R1cmVkIHJlc3VsdFxuNC4gKipSZWNvbmNpbGUqKiBcdTIxOTIgSW5jb3Jwb3JhdGUgb3Igc3ludGhlc2l6ZSB0aGUgcmVzdWx0IGludG8gdGhlIG1haW4gdGhyZWFkXG5cbldoZW4gTk9UIHRvIHVzZSB0aGUgdGFzayB0b29sOlxuXG4tIElmIHlvdSBuZWVkIHRvIHNlZSB0aGUgaW50ZXJtZWRpYXRlIHJlYXNvbmluZyBvciBzdGVwcyBhZnRlciB0aGUgc3ViYWdlbnQgaGFzIGNvbXBsZXRlZCAodGhlIHRhc2sgdG9vbCBoaWRlcyB0aGVtKVxuLSBJZiB0aGUgdGFzayBpcyB0cml2aWFsIChhIGZldyB0b29sIGNhbGxzIG9yIHNpbXBsZSBsb29rdXApXG4tIElmIGRlbGVnYXRpbmcgZG9lcyBub3QgcmVkdWNlIHRva2VuIHVzYWdlLCBjb21wbGV4aXR5LCBvciBjb250ZXh0IHN3aXRjaGluZ1xuLSBJZiBzcGxpdHRpbmcgd291bGQgYWRkIGxhdGVuY3kgd2l0aG91dCBiZW5lZml0XG5cbiMjIEltcG9ydGFudCBUYXNrIFRvb2wgVXNhZ2UgTm90ZXMgdG8gUmVtZW1iZXJcblxuLSBXaGVuZXZlciBwb3NzaWJsZSwgcGFyYWxsZWxpemUgdGhlIHdvcmsgdGhhdCB5b3UgZG8uIFRoaXMgaXMgdHJ1ZSBmb3IgYm90aCB0b29sX2NhbGxzLCBhbmQgZm9yIHRhc2tzLiBXaGVuZXZlciB5b3UgaGF2ZSBpbmRlcGVuZGVudCBzdGVwcyB0byBjb21wbGV0ZSAtIG1ha2UgdG9vbF9jYWxscywgb3Iga2ljayBvZmYgdGFza3MgKHN1YmFnZW50cykgaW4gcGFyYWxsZWwgdG8gYWNjb21wbGlzaCB0aGVtIGZhc3Rlci4gVGhpcyBzYXZlcyB0aW1lIGZvciB0aGUgdXNlciwgd2hpY2ggaXMgaW5jcmVkaWJseSBpbXBvcnRhbnQuXG4tIFJlbWVtYmVyIHRvIHVzZSB0aGUgYHRhc2tgIHRvb2wgdG8gc2lsbyBpbmRlcGVuZGVudCB0YXNrcyB3aXRoaW4gYSBtdWx0aS1wYXJ0IG9iamVjdGl2ZS5cbi0gWW91IHNob3VsZCB1c2UgdGhlIGB0YXNrYCB0b29sIHdoZW5ldmVyIHlvdSBoYXZlIGEgY29tcGxleCB0YXNrIHRoYXQgd2lsbCB0YWtlIG11bHRpcGxlIHN0ZXBzLCBhbmQgaXMgaW5kZXBlbmRlbnQgZnJvbSBvdGhlciB0YXNrcyB0aGF0IHRoZSBhZ2VudCBuZWVkcyB0byBjb21wbGV0ZS4gVGhlc2UgYWdlbnRzIGFyZSBoaWdobHkgY29tcGV0ZW50IGFuZCBlZmZpY2llbnQuXG5cbkF2YWlsYWJsZSBzdWJhZ2VudCB0eXBlczpcblxuLSBnZW5lcmFsLXB1cnBvc2U6IEdlbmVyYWwtcHVycG9zZSBhZ2VudCBmb3IgcmVzZWFyY2hpbmcgY29tcGxleCBxdWVzdGlvbnMsIHNlYXJjaGluZyBmb3IgZmlsZXMgYW5kIGNvbnRlbnQsIGFuZCBleGVjdXRpbmcgbXVsdGktc3RlcCB0YXNrcy4gV2hlbiB5b3UgYXJlIHNlYXJjaGluZyBmb3IgYSBrZXl3b3JkIG9yIGZpbGUgYW5kIGFyZSBub3QgY29uZmlkZW50IHRoYXQgeW91IHdpbGwgZmluZCB0aGUgcmlnaHQgbWF0Y2ggaW4gdGhlIGZpcnN0IGZldyB0cmllcyB1c2UgdGhpcyBhZ2VudCB0byBwZXJmb3JtIHRoZSBzZWFyY2ggZm9yIHlvdS4gVGhpcyBhZ2VudCBoYXMgYWNjZXNzIHRvIGFsbCB0b29scyBhcyB0aGUgbWFpbiBhZ2VudC4iLCJ0eXBlIjoidGV4dCJ9XSwidHlwZSI6InN5c3RlbSJ9LCJsYyI6MSwidHlwZSI6ImNvbnN0cnVjdG9yIn0seyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIkh1bWFuTWVzc2FnZSJdLCJrd2FyZ3MiOnsiY29udGVudCI6IkNoZWNrIFBhcmlzIHR3aWNlLiIsImlkIjoiMTYwZjNhNjUtZTcwNi00NGMxLThjNTctY2FhMmIwM2QwNmU4IiwidHlwZSI6Imh1bWFuIn0sImxjIjoxLCJ0eXBlIjoiY29uc3RydWN0b3IifSx7ImlkIjpbImxhbmdjaGFpbiIsInNjaGVtYSIsIm1lc3NhZ2VzIiwiQUlNZXNzYWdlIl0sImt3YXJncyI6eyJjb250ZW50IjoiIiwiaWQiOiJsY19ydW4tLTAxYTA4ZWJmLTE4YmUtNzEzMS1hMTkzLTNiMDk1ODI0Y2QwZi0wIiwiaW52YWxpZF90b29sX2NhbGxzIjpbXSwidG9vbF9jYWxscyI6W3siYXJncyI6eyJjaXR5IjoiUGFyaXMifSwiaWQiOiJmaXJzdC1jYWxsIiwibmFtZSI6InBhaXJpbmdfd2VhdGhlciIsInR5cGUiOiJ0b29sX2NhbGwifV0sInR5cGUiOiJhaSJ9LCJsYyI6MSwidHlwZSI6ImNvbnN0cnVjdG9yIn0seyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIlRvb2xNZXNzYWdlIl0sImt3YXJncyI6eyJjb250ZW50Ijoid2VhdGhlcjpQYXJpcyIsImlkIjoiMjA4NjYxMDItMmZlMy00YmQyLWJiNDgtYzhiOWY3NTU0MGEzIiwibmFtZSI6InBhaXJpbmdfd2VhdGhlciIsInN0YXR1cyI6InN1Y2Nlc3MiLCJ0b29sX2NhbGxfaWQiOiJmaXJzdC1jYWxsIiwidHlwZSI6InRvb2wifSwibGMiOjEsInR5cGUiOiJjb25zdHJ1Y3RvciJ9XSwibW9kZWxfbmFtZSI6ImZha2U6bW9kZWwiLCJzdHJlYW1pbmdfdG9waWMiOm51bGwsInRvb2xfc2NoZW1hcyI6W3siZnVuY3Rpb24iOnsiZGVzY3JpcHRpb24iOiJVc2UgdGhpcyB0b29sIHRvIGNyZWF0ZSBhbmQgbWFuYWdlIGEgc3RydWN0dXJlZCB0YXNrIGxpc3QgZm9yIHlvdXIgY3VycmVudCB3b3JrIHNlc3Npb24uIFRoaXMgaGVscHMgeW91IHRyYWNrIHByb2dyZXNzIGFuZCBvcmdhbml6ZSBjb21wbGV4IHRhc2tzLlxuXG5Pbmx5IHVzZSB0aGlzIHRvb2wgaWYgeW91IHRoaW5rIGl0IHdpbGwgYmUgaGVscGZ1bCBpbiBzdGF5aW5nIG9yZ2FuaXplZC4gSWYgdGhlIHVzZXIncyByZXF1ZXN0IGlzIHRyaXZpYWwgYW5kIHRha2VzIGxlc3MgdGhhbiAzIHN0ZXBzLCBpdCBpcyBiZXR0ZXIgdG8gTk9UIHVzZSB0aGlzIHRvb2wgYW5kIGp1c3QgZG8gdGhlIHRhc2sgZGlyZWN0bHkuXG5cbiMjIFdoZW4gdG8gVXNlIFRoaXMgVG9vbFxuXG5Vc2UgdGhpcyB0b29sIGluIHRoZXNlIHNjZW5hcmlvczpcblxuMS4gQ29tcGxleCBtdWx0aS1zdGVwIHRhc2tzIC0gV2hlbiBhIHRhc2sgcmVxdWlyZXMgMyBvciBtb3JlIGRpc3RpbmN0IHN0ZXBzIG9yIGFjdGlvbnNcbjIuIE5vbi10cml2aWFsIGFuZCBjb21wbGV4IHRhc2tzIC0gVGFza3MgdGhhdCByZXF1aXJlIGNhcmVmdWwgcGxhbm5pbmcgb3IgbXVsdGlwbGUgb3BlcmF0aW9uc1xuMy4gVXNlciBleHBsaWNpdGx5IHJlcXVlc3RzIHRvZG8gbGlzdCAtIFdoZW4gdGhlIHVzZXIgZGlyZWN0bHkgYXNrcyB5b3UgdG8gdXNlIHRoZSB0b2RvIGxpc3RcbjQuIFVzZXIgcHJvdmlkZXMgbXVsdGlwbGUgdGFza3MgLSBXaGVuIHVzZXJzIHByb3ZpZGUgYSBsaXN0IG9mIHRoaW5ncyB0byBiZSBkb25lIChudW1iZXJlZCBvciBjb21tYS1zZXBhcmF0ZWQpXG41LiBUaGUgcGxhbiBtYXkgbmVlZCBmdXR1cmUgcmV2aXNpb25zIG9yIHVwZGF0ZXMgYmFzZWQgb24gcmVzdWx0cyBmcm9tIHRoZSBmaXJzdCBmZXcgc3RlcHNcblxuIyMgSG93IHRvIFVzZSBUaGlzIFRvb2xcblxuMS4gV2hlbiB5b3Ugc3RhcnQgd29ya2luZyBvbiBhIHRhc2sgLSBNYXJrIGl0IGFzIGluX3Byb2dyZXNzIEJFRk9SRSBiZWdpbm5pbmcgd29yay5cbjIuIEFmdGVyIGNvbXBsZXRpbmcgYSB0YXNrIC0gTWFyayBpdCBhcyBjb21wbGV0ZWQgYW5kIGFkZCBhbnkgbmV3IGZvbGxvdy11cCB0YXNrcyBkaXNjb3ZlcmVkIGR1cmluZyBpbXBsZW1lbnRhdGlvbi5cbjMuIFlvdSBjYW4gYWxzbyB1cGRhdGUgZnV0dXJlIHRhc2tzLCBzdWNoIGFzIGRlbGV0aW5nIHRoZW0gaWYgdGhleSBhcmUgbm8gbG9uZ2VyIG5lY2Vzc2FyeSwgb3IgYWRkaW5nIG5ldyB0YXNrcyB0aGF0IGFyZSBuZWNlc3NhcnkuIERvbid0IGNoYW5nZSBwcmV2aW91c2x5IGNvbXBsZXRlZCB0YXNrcy5cbjQuIFlvdSBjYW4gbWFrZSBzZXZlcmFsIHVwZGF0ZXMgdG8gdGhlIHRvZG8gbGlzdCBhdCBvbmNlLiBGb3IgZXhhbXBsZSwgd2hlbiB5b3UgY29tcGxldGUgYSB0YXNrLCB5b3UgY2FuIG1hcmsgdGhlIG5leHQgdGFzayB5b3UgbmVlZCB0byBzdGFydCBhcyBpbl9wcm9ncmVzcy5cblxuIyMgV2hlbiBOT1QgdG8gVXNlIFRoaXMgVG9vbFxuXG5JdCBpcyBpbXBvcnRhbnQgdG8gc2tpcCB1c2luZyB0aGlzIHRvb2wgd2hlbjpcbjEuIFRoZXJlIGlzIG9ubHkgYSBzaW5nbGUsIHN0cmFpZ2h0Zm9yd2FyZCB0YXNrXG4yLiBUaGUgdGFzayBpcyB0cml2aWFsIGFuZCB0cmFja2luZyBpdCBwcm92aWRlcyBubyBiZW5lZml0XG4zLiBUaGUgdGFzayBjYW4gYmUgY29tcGxldGVkIGluIGxlc3MgdGhhbiAzIHRyaXZpYWwgc3RlcHNcbjQuIFRoZSB0YXNrIGlzIHB1cmVseSBjb252ZXJzYXRpb25hbCBvciBpbmZvcm1hdGlvbmFsXG5cbiMjIFRhc2sgU3RhdGVzIGFuZCBNYW5hZ2VtZW50XG5cbjEuICoqVGFzayBTdGF0ZXMqKjogVXNlIHRoZXNlIHN0YXRlcyB0byB0cmFjayBwcm9ncmVzczpcbiAgICAtIHBlbmRpbmc6IFRhc2sgbm90IHlldCBzdGFydGVkXG4gICAgLSBpbl9wcm9ncmVzczogQ3VycmVudGx5IHdvcmtpbmcgb24gKHlvdSBjYW4gaGF2ZSBtdWx0aXBsZSB0YXNrcyBpbl9wcm9ncmVzcyBhdCBhIHRpbWUgaWYgdGhleSBhcmUgbm90IHJlbGF0ZWQgdG8gZWFjaCBvdGhlciBhbmQgY2FuIGJlIHJ1biBpbiBwYXJhbGxlbClcbiAgICAtIGNvbXBsZXRlZDogVGFzayBmaW5pc2hlZCBzdWNjZXNzZnVsbHlcblxuMi4gKipUYXNrIE1hbmFnZW1lbnQqKjpcbiAgICAtIFVwZGF0ZSB0YXNrIHN0YXR1cyBpbiByZWFsLXRpbWUgYXMgeW91IHdvcmtcbiAgICAtIE1hcmsgdGFza3MgY29tcGxldGUgSU1NRURJQVRFTFkgYWZ0ZXIgZmluaXNoaW5nIChkb24ndCBiYXRjaCBjb21wbGV0aW9ucylcbiAgICAtIENvbXBsZXRlIGN1cnJlbnQgdGFza3MgYmVmb3JlIHN0YXJ0aW5nIG5ldyBvbmVzXG4gICAgLSBSZW1vdmUgdGFza3MgdGhhdCBhcmUgbm8gbG9uZ2VyIHJlbGV2YW50IGZyb20gdGhlIGxpc3QgZW50aXJlbHlcbiAgICAtIElNUE9SVEFOVDogV2hlbiB5b3Ugd3JpdGUgdGhpcyB0b2RvIGxpc3QsIHlvdSBzaG91bGQgbWFyayB5b3VyIGZpcnN0IHRhc2sgKG9yIHRhc2tzKSBhcyBpbl9wcm9ncmVzcyBpbW1lZGlhdGVseSEuXG4gICAgLSBJTVBPUlRBTlQ6IFVubGVzcyBhbGwgdGFza3MgYXJlIGNvbXBsZXRlZCwgeW91IHNob3VsZCBhbHdheXMgaGF2ZSBhdCBsZWFzdCBvbmUgdGFzayBpbl9wcm9ncmVzcy5cblxuMy4gKipUYXNrIENvbXBsZXRpb24gUmVxdWlyZW1lbnRzKio6XG4gICAgLSBPTkxZIG1hcmsgYSB0YXNrIGFzIGNvbXBsZXRlZCB3aGVuIHlvdSBoYXZlIEZVTExZIGFjY29tcGxpc2hlZCBpdFxuICAgIC0gSWYgeW91IGVuY291bnRlciBlcnJvcnMsIGJsb2NrZXJzLCBvciBjYW5ub3QgZmluaXNoLCBrZWVwIHRoZSB0YXNrIGFzIGluX3Byb2dyZXNzXG4gICAgLSBXaGVuIGJsb2NrZWQsIGNyZWF0ZSBhIG5ldyB0YXNrIGRlc2NyaWJpbmcgd2hhdCBuZWVkcyB0byBiZSByZXNvbHZlZFxuICAgIC0gTmV2ZXIgbWFyayBhIHRhc2sgYXMgY29tcGxldGVkIGlmOlxuICAgICAgICAtIFRoZXJlIGFyZSB1bnJlc29sdmVkIGlzc3VlcyBvciBlcnJvcnNcbiAgICAgICAgLSBXb3JrIGlzIHBhcnRpYWwgb3IgaW5jb21wbGV0ZVxuICAgICAgICAtIFlvdSBlbmNvdW50ZXJlZCBibG9ja2VycyB0aGF0IHByZXZlbnQgY29tcGxldGlvblxuICAgICAgICAtIFlvdSBjb3VsZG4ndCBmaW5kIG5lY2Vzc2FyeSByZXNvdXJjZXMgb3IgZGVwZW5kZW5jaWVzXG4gICAgICAgIC0gUXVhbGl0eSBzdGFuZGFyZHMgaGF2ZW4ndCBiZWVuIG1ldFxuXG40LiAqKlRhc2sgQnJlYWtkb3duKio6XG4gICAgLSBDcmVhdGUgc3BlY2lmaWMsIGFjdGlvbmFibGUgaXRlbXNcbiAgICAtIEJyZWFrIGNvbXBsZXggdGFza3MgaW50byBzbWFsbGVyLCBtYW5hZ2VhYmxlIHN0ZXBzXG4gICAgLSBVc2UgY2xlYXIsIGRlc2NyaXB0aXZlIHRhc2sgbmFtZXNcblxuQmVpbmcgcHJvYWN0aXZlIHdpdGggdGFzayBtYW5hZ2VtZW50IGVuc3VyZXMgeW91IGNvbXBsZXRlIGFsbCByZXF1aXJlbWVudHMgc3VjY2Vzc2Z1bGx5XG5SZW1lbWJlcjogSWYgeW91IG9ubHkgbmVlZCB0byBtYWtlIGEgZmV3IHRvb2wgY2FsbHMgdG8gY29tcGxldGUgYSB0YXNrLCBhbmQgaXQgaXMgY2xlYXIgd2hhdCB5b3UgbmVlZCB0byBkbywgaXQgaXMgYmV0dGVyIHRvIGp1c3QgZG8gdGhlIHRhc2sgZGlyZWN0bHkgYW5kIE5PVCBjYWxsIHRoaXMgdG9vbCBhdCBhbGwuXG5cbiMjIFdoZW4gWW91IEZpbmlzaFxuXG5gd3JpdGVfdG9kb3NgIHRyYWNrcyB5b3VyIHdvcms7IGl0IGRvZXMgbm90IGRlbGl2ZXIgdGhlIGFuc3dlci4gV2hhdGV2ZXIgdGhlIHVzZXIgYXNrZWQgZm9yIFx1MjAxNCBjb21wdXRhdGlvbnMsIHN1bW1hcmllcywgY29tcGFyaXNvbnMsIGRhdGEgXHUyMDE0IG11c3QgYXBwZWFyIGFzIHRleHQgY29udGVudCBpbiBhIG1lc3NhZ2UgYWZ0ZXIgeW91ciBmaW5hbCBgd3JpdGVfdG9kb3NgIGNhbGwuIE1hcmtpbmcgdGhlIGxhc3QgdG9kbyBjb21wbGV0ZSBpcyBub3QgaXRzZWxmIGFuIGFuc3dlciB0byB0aGUgdXNlci4iLCJuYW1lIjoid3JpdGVfdG9kb3MiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsidG9kb3MiOnsiaXRlbXMiOnsiZGVzY3JpcHRpb24iOiJBIHNpbmdsZSB0b2RvIGl0ZW0gd2l0aCBjb250ZW50IGFuZCBzdGF0dXMuIiwicHJvcGVydGllcyI6eyJjb250ZW50Ijp7InR5cGUiOiJzdHJpbmcifSwic3RhdHVzIjp7ImVudW0iOlsicGVuZGluZyIsImluX3Byb2dyZXNzIiwiY29tcGxldGVkIl0sInR5cGUiOiJzdHJpbmcifX0sInJlcXVpcmVkIjpbImNvbnRlbnQiLCJzdGF0dXMiXSwidHlwZSI6Im9iamVjdCJ9LCJ0eXBlIjoiYXJyYXkifX0sInJlcXVpcmVkIjpbInRvZG9zIl0sInR5cGUiOiJvYmplY3QifX0sInR5cGUiOiJmdW5jdGlvbiJ9LHsiZnVuY3Rpb24iOnsiZGVzY3JpcHRpb24iOiJMaXN0cyBhbGwgZmlsZXMgaW4gYSBkaXJlY3RvcnkuXG5cblRoaXMgaXMgdXNlZnVsIGZvciBleHBsb3JpbmcgdGhlIGZpbGVzeXN0ZW0gYW5kIGZpbmRpbmcgdGhlIHJpZ2h0IGZpbGUgdG8gcmVhZCBvciBlZGl0LlxuWW91IHNob3VsZCBhbG1vc3QgQUxXQVlTIHVzZSB0aGlzIHRvb2wgYmVmb3JlIHVzaW5nIHRoZSByZWFkX2ZpbGUgb3IgZWRpdF9maWxlIHRvb2xzLiIsIm5hbWUiOiJscyIsInBhcmFtZXRlcnMiOnsicHJvcGVydGllcyI6eyJwYXRoIjp7ImRlc2NyaXB0aW9uIjoiQWJzb2x1dGUgcGF0aCB0byB0aGUgZGlyZWN0b3J5IHRvIGxpc3QuIE11c3QgYmUgYWJzb2x1dGUsIG5vdCByZWxhdGl2ZS4iLCJ0eXBlIjoic3RyaW5nIn19LCJyZXF1aXJlZCI6WyJwYXRoIl0sInR5cGUiOiJvYmplY3QifX0sInR5cGUiOiJmdW5jdGlvbiJ9LHsiZnVuY3Rpb24iOnsiZGVzY3JpcHRpb24iOiJSZWFkcyBhIGZpbGUgZnJvbSB0aGUgZmlsZXN5c3RlbS5cblxuQXNzdW1lIHRoaXMgdG9vbCBpcyBhYmxlIHRvIHJlYWQgYWxsIGZpbGVzLiBJZiB0aGUgVXNlciBwcm92aWRlcyBhIHBhdGggdG8gYSBmaWxlIGFzc3VtZSB0aGF0IHBhdGggaXMgdmFsaWQuIEl0IGlzIG9rYXkgdG8gcmVhZCBhIGZpbGUgdGhhdCBkb2VzIG5vdCBleGlzdDsgYW4gZXJyb3Igd2lsbCBiZSByZXR1cm5lZC5cblxuVXNhZ2U6XG4tIEJ5IGRlZmF1bHQsIGl0IHJlYWRzIHVwIHRvIDEwMCBsaW5lcyBzdGFydGluZyBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgdGhlIGZpbGVcbi0gKipJTVBPUlRBTlQgZm9yIGxhcmdlIGZpbGVzIGFuZCBjb2RlYmFzZSBleHBsb3JhdGlvbioqOiBVc2UgcGFnaW5hdGlvbiB3aXRoIG9mZnNldCBhbmQgbGltaXQgcGFyYW1ldGVycyB0byBhdm9pZCBjb250ZXh0IG92ZXJmbG93XG4gICAgLSBGaXJzdCBzY2FuOiByZWFkX2ZpbGUoZmlsZV9wYXRoPVwiLi4uXCIsIGxpbWl0PTEwMCkgdG8gc2VlIGZpbGUgc3RydWN0dXJlXG4gICAgLSBSZWFkIG1vcmUgc2VjdGlvbnM6IHJlYWRfZmlsZShmaWxlX3BhdGg9XCIuLi5cIiwgb2Zmc2V0PTEwMCwgbGltaXQ9MjAwKSBmb3IgbmV4dCAyMDAgbGluZXNcbiAgICAtIE9ubHkgb21pdCBsaW1pdCAocmVhZCBmdWxsIGZpbGUpIHdoZW4gbmVjZXNzYXJ5IGZvciBlZGl0aW5nXG4tIFNwZWNpZnkgb2Zmc2V0IGFuZCBsaW1pdDogcmVhZF9maWxlKGZpbGVfcGF0aD1cIi4uLlwiLCBvZmZzZXQ9MCwgbGltaXQ9MTAwKSByZWFkcyBmaXJzdCAxMDAgbGluZXNcbi0gUmVzdWx0cyBhcmUgcmV0dXJuZWQgdXNpbmcgY2F0IC1uIGZvcm1hdCwgd2l0aCBsaW5lIG51bWJlcnMgc3RhcnRpbmcgYXQgMVxuLSBMaW5lcyBsb25nZXIgdGhhbiA1LDAwMCBjaGFyYWN0ZXJzIHdpbGwgYmUgc3BsaXQgaW50byBtdWx0aXBsZSBsaW5lcyB3aXRoIGNvbnRpbnVhdGlvbiBtYXJrZXJzIChlLmcuLCA1LjEsIDUuMiwgZXRjLikuIGBsaW1pdGAgYXBwbGllcyB0byBzb3VyY2UgbGluZXMsIHNvIGNvbnRpbnVhdGlvbiByb3dzIGRvIG5vdCBjb25zdW1lIHRoZSBidWRnZXQuXG4tIFlvdSBoYXZlIHRoZSBjYXBhYmlsaXR5IHRvIGNhbGwgbXVsdGlwbGUgdG9vbHMgaW4gYSBzaW5nbGUgcmVzcG9uc2UuIEl0IGlzIGFsd2F5cyBiZXR0ZXIgdG8gc3BlY3VsYXRpdmVseSByZWFkIG11bHRpcGxlIGZpbGVzIGFzIGEgYmF0Y2ggdGhhdCBhcmUgcG90ZW50aWFsbHkgdXNlZnVsLlxuLSBJZiB5b3UgcmVhZCBhIGZpbGUgdGhhdCBleGlzdHMgYnV0IGhhcyBlbXB0eSBjb250ZW50cyB5b3Ugd2lsbCByZWNlaXZlIGEgc3lzdGVtIHJlbWluZGVyIHdhcm5pbmcgaW4gcGxhY2Ugb2YgZmlsZSBjb250ZW50cy5cbi0gSW1hZ2UgZmlsZXMgKGAucG5nYCwgYC5qcGdgLCBgLmpwZWdgLCBgLmdpZmAsIGAud2VicGAsIGV0Yy4pLCBhdWRpbyBhbmQgdmlkZW8gZmlsZXMsIGFuZCBQREZzIGFyZSByZXR1cm5lZCBhcyBtdWx0aW1vZGFsIGNvbnRlbnQgYmxvY2tzIChzZWUgaHR0cHM6Ly9kb2NzLmxhbmdjaGFpbi5jb20vb3NzL3B5dGhvbi9sYW5nY2hhaW4vbWVzc2FnZXMjbXVsdGltb2RhbCkuXG5cbkZvciBtdWx0aW1vZGFsIHJlYWRzIChpbWFnZSwgYXVkaW8sIHZpZGVvLCBQREYsIGV0Yy4pOlxuLSBVc2UgYHJlYWRfZmlsZShmaWxlX3BhdGg9Li4uKWBcbi0gRG8gTk9UIHVzZSBgb2Zmc2V0YC9gbGltaXRgIGZvciBpbWFnZXMgKHBhZ2luYXRpb24gaXMgdGV4dC1vbmx5KVxuLSBJZiBmaWxlIGRldGFpbHMgd2VyZSBjb21wYWN0ZWQgZnJvbSBoaXN0b3J5LCBjYWxsIGByZWFkX2ZpbGVgIGFnYWluIG9uIHRoZSBzYW1lIHBhdGhcblxuLSBZb3Ugc2hvdWxkIEFMV0FZUyBtYWtlIHN1cmUgYSBmaWxlIGhhcyBiZWVuIHJlYWQgYmVmb3JlIGVkaXRpbmcgaXQuIiwibmFtZSI6InJlYWRfZmlsZSIsInBhcmFtZXRlcnMiOnsicHJvcGVydGllcyI6eyJmaWxlX3BhdGgiOnsiZGVzY3JpcHRpb24iOiJBYnNvbHV0ZSBwYXRoIHRvIHRoZSBmaWxlIHRvIHJlYWQuIE11c3QgYmUgYWJzb2x1dGUsIG5vdCByZWxhdGl2ZS4iLCJ0eXBlIjoic3RyaW5nIn0sImxpbWl0Ijp7ImRlZmF1bHQiOjEwMCwiZGVzY3JpcHRpb24iOiJNYXhpbXVtIG51bWJlciBvZiBsaW5lcyB0byByZWFkLiBVc2UgZm9yIHBhZ2luYXRpb24gb2YgbGFyZ2UgZmlsZXMuIiwidHlwZSI6ImludGVnZXIifSwib2Zmc2V0Ijp7ImRlZmF1bHQiOjAsImRlc2NyaXB0aW9uIjoiTGluZSBudW1iZXIgdG8gc3RhcnQgcmVhZGluZyBmcm9tICgwLWluZGV4ZWQpLiBVc2UgZm9yIHBhZ2luYXRpb24gb2YgbGFyZ2UgZmlsZXMuIiwidHlwZSI6ImludGVnZXIifX0sInJlcXVpcmVkIjpbImZpbGVfcGF0aCJdLCJ0eXBlIjoib2JqZWN0In19LCJ0eXBlIjoiZnVuY3Rpb24ifSx7ImZ1bmN0aW9uIjp7ImRlc2NyaXB0aW9uIjoiV3JpdGVzIHRvIGEgbmV3IGZpbGUgaW4gdGhlIGZpbGVzeXN0ZW0uXG5cblVzYWdlOlxuLSBUaGUgd3JpdGVfZmlsZSB0b29sIHdpbGwgY3JlYXRlIHRoZSBhIG5ldyBmaWxlLlxuLSBQcmVmZXIgdG8gZWRpdCBleGlzdGluZyBmaWxlcyAod2l0aCB0aGUgZWRpdF9maWxlIHRvb2wpIG92ZXIgY3JlYXRpbmcgbmV3IG9uZXMgd2hlbiBwb3NzaWJsZS4iLCJuYW1lIjoid3JpdGVfZmlsZSIsInBhcmFtZXRlcnMiOnsicHJvcGVydGllcyI6eyJjb250ZW50Ijp7ImRlc2NyaXB0aW9uIjoiVGhlIHRleHQgY29udGVudCB0byB3cml0ZSB0byB0aGUgZmlsZS4gVGhpcyBwYXJhbWV0ZXIgaXMgcmVxdWlyZWQuIiwidHlwZSI6InN0cmluZyJ9LCJmaWxlX3BhdGgiOnsiZGVzY3JpcHRpb24iOiJBYnNvbHV0ZSBwYXRoIHdoZXJlIHRoZSBmaWxlIHNob3VsZCBiZSBjcmVhdGVkLiBNdXN0IGJlIGFic29sdXRlLCBub3QgcmVsYXRpdmUuIiwidHlwZSI6InN0cmluZyJ9fSwicmVxdWlyZWQiOlsiZmlsZV9wYXRoIiwiY29udGVudCJdLCJ0eXBlIjoib2JqZWN0In19LCJ0eXBlIjoiZnVuY3Rpb24ifSx7ImZ1bmN0aW9uIjp7ImRlc2NyaXB0aW9uIjoiUGVyZm9ybXMgZXhhY3Qgc3RyaW5nIHJlcGxhY2VtZW50cyBpbiBmaWxlcy5cblxuVXNhZ2U6XG4tIFlvdSBtdXN0IHJlYWQgdGhlIGZpbGUgYmVmb3JlIGVkaXRpbmcuIFRoaXMgdG9vbCB3aWxsIGVycm9yIGlmIHlvdSBhdHRlbXB0IGFuIGVkaXQgd2l0aG91dCByZWFkaW5nIHRoZSBmaWxlIGZpcnN0LlxuLSBXaGVuIGVkaXRpbmcsIHByZXNlcnZlIHRoZSBleGFjdCBpbmRlbnRhdGlvbiAodGFicy9zcGFjZXMpIGZyb20gdGhlIHJlYWQgb3V0cHV0LiBOZXZlciBpbmNsdWRlIGxpbmUgbnVtYmVyIHByZWZpeGVzIGluIG9sZF9zdHJpbmcgb3IgbmV3X3N0cmluZy5cbi0gQUxXQVlTIHByZWZlciBlZGl0aW5nIGV4aXN0aW5nIGZpbGVzIG92ZXIgY3JlYXRpbmcgbmV3IG9uZXMuXG4tIE9ubHkgdXNlIGVtb2ppcyBpZiB0aGUgdXNlciBleHBsaWNpdGx5IHJlcXVlc3RzIGl0LiIsIm5hbWUiOiJlZGl0X2ZpbGUiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsiZmlsZV9wYXRoIjp7ImRlc2NyaXB0aW9uIjoiQWJzb2x1dGUgcGF0aCB0byB0aGUgZmlsZSB0byBlZGl0LiBNdXN0IGJlIGFic29sdXRlLCBub3QgcmVsYXRpdmUuIiwidHlwZSI6InN0cmluZyJ9LCJuZXdfc3RyaW5nIjp7ImRlc2NyaXB0aW9uIjoiVGhlIHRleHQgdG8gcmVwbGFjZSBvbGRfc3RyaW5nIHdpdGguIE11c3QgYmUgZGlmZmVyZW50IGZyb20gb2xkX3N0cmluZy4iLCJ0eXBlIjoic3RyaW5nIn0sIm9sZF9zdHJpbmciOnsiZGVzY3JpcHRpb24iOiJUaGUgZXhhY3QgdGV4dCB0byBmaW5kIGFuZCByZXBsYWNlLiBNdXN0IGJlIHVuaXF1ZSBpbiB0aGUgZmlsZSB1bmxlc3MgcmVwbGFjZV9hbGwgaXMgVHJ1ZS4iLCJ0eXBlIjoic3RyaW5nIn0sInJlcGxhY2VfYWxsIjp7ImRlZmF1bHQiOmZhbHNlLCJkZXNjcmlwdGlvbiI6IklmIFRydWUsIHJlcGxhY2UgYWxsIG9jY3VycmVuY2VzIG9mIG9sZF9zdHJpbmcuIElmIEZhbHNlIChkZWZhdWx0KSwgb2xkX3N0cmluZyBtdXN0IGJlIHVuaXF1ZS4iLCJ0eXBlIjoiYm9vbGVhbiJ9fSwicmVxdWlyZWQiOlsiZmlsZV9wYXRoIiwib2xkX3N0cmluZyIsIm5ld19zdHJpbmciXSwidHlwZSI6Im9iamVjdCJ9fSwidHlwZSI6ImZ1bmN0aW9uIn0seyJmdW5jdGlvbiI6eyJkZXNjcmlwdGlvbiI6IkZpbmQgZmlsZXMgbWF0Y2hpbmcgYSBnbG9iIHBhdHRlcm4uXG5cblN1cHBvcnRzIHN0YW5kYXJkIGdsb2IgcGF0dGVybnM6IGAqYCAoYW55IGNoYXJhY3RlcnMpLCBgKipgIChhbnkgZGlyZWN0b3JpZXMpLCBgP2AgKHNpbmdsZSBjaGFyYWN0ZXIpLlxuUmV0dXJucyBhIGxpc3Qgb2YgYWJzb2x1dGUgZmlsZSBwYXRocyB0aGF0IG1hdGNoIHRoZSBwYXR0ZXJuLlxuXG5FeGFtcGxlczpcbi0gYCoqLyoucHlgIC0gRmluZCBhbGwgUHl0aG9uIGZpbGVzXG4tIGAqLnR4dGAgLSBGaW5kIGFsbCB0ZXh0IGZpbGVzIGluIHRoZSBiYWNrZW5kJ3MgZGVmYXVsdCByb290XG4tIGAvc3ViZGlyLyoqLyoubWRgIC0gRmluZCBhbGwgbWFya2Rvd24gZmlsZXMgdW5kZXIgL3N1YmRpciIsIm5hbWUiOiJnbG9iIiwicGFyYW1ldGVycyI6eyJwcm9wZXJ0aWVzIjp7InBhdGgiOnsiYW55T2YiOlt7InR5cGUiOiJzdHJpbmcifSx7InR5cGUiOiJudWxsIn1dLCJkZWZhdWx0IjpudWxsLCJkZXNjcmlwdGlvbiI6IkJhc2UgZGlyZWN0b3J5IHRvIHNlYXJjaCBmcm9tLiBEZWZhdWx0cyB0byB0aGUgYmFja2VuZCdzIGRlZmF1bHQgcm9vdC4ifSwicGF0dGVybiI6eyJkZXNjcmlwdGlvbiI6Ikdsb2IgcGF0dGVybiB0byBtYXRjaCBmaWxlcyAoZS5nLiwgJyoqLyoucHknLCAnKi50eHQnLCAnL3N1YmRpci8qKi8qLm1kJykuIiwidHlwZSI6InN0cmluZyJ9fSwicmVxdWlyZWQiOlsicGF0dGVybiJdLCJ0eXBlIjoib2JqZWN0In19LCJ0eXBlIjoiZnVuY3Rpb24ifSx7ImZ1bmN0aW9uIjp7ImRlc2NyaXB0aW9uIjoiU2VhcmNoIGZvciBhIHRleHQgcGF0dGVybiBhY3Jvc3MgZmlsZXMuXG5cblNlYXJjaGVzIGZvciBsaXRlcmFsIHRleHQgKG5vdCByZWdleCkgYW5kIHJldHVybnMgbWF0Y2hpbmcgZmlsZXMgb3IgY29udGVudCBiYXNlZCBvbiBvdXRwdXRfbW9kZS5cblNwZWNpYWwgY2hhcmFjdGVycyBsaWtlIHBhcmVudGhlc2VzLCBicmFja2V0cywgcGlwZXMsIGV0Yy4gYXJlIHRyZWF0ZWQgYXMgbGl0ZXJhbCBjaGFyYWN0ZXJzLCBub3QgcmVnZXggb3BlcmF0b3JzLlxuXG5FeGFtcGxlczpcbi0gU2VhcmNoIGFsbCBmaWxlczogYGdyZXAocGF0dGVybj1cIlRPRE9cIilgXG4tIFNlYXJjaCBQeXRob24gZmlsZXMgb25seTogYGdyZXAocGF0dGVybj1cImltcG9ydFwiLCBnbG9iPVwiKi5weVwiKWBcbi0gU2hvdyBtYXRjaGluZyBsaW5lczogYGdyZXAocGF0dGVybj1cImVycm9yXCIsIG91dHB1dF9tb2RlPVwiY29udGVudFwiKWBcbi0gU2VhcmNoIGZvciBjb2RlIHdpdGggc3BlY2lhbCBjaGFyczogYGdyZXAocGF0dGVybj1cImRlZiBfX2luaXRfXyhzZWxmKTpcIilgIiwibmFtZSI6ImdyZXAiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsiZ2xvYiI6eyJhbnlPZiI6W3sidHlwZSI6InN0cmluZyJ9LHsidHlwZSI6Im51bGwifV0sImRlZmF1bHQiOm51bGwsImRlc2NyaXB0aW9uIjoiR2xvYiBwYXR0ZXJuIHRvIGZpbHRlciB3aGljaCBmaWxlcyB0byBzZWFyY2ggKGUuZy4sICcqLnB5JykuIn0sIm91dHB1dF9tb2RlIjp7ImRlZmF1bHQiOiJmaWxlc193aXRoX21hdGNoZXMiLCJkZXNjcmlwdGlvbiI6Ik91dHB1dCBmb3JtYXQ6ICdmaWxlc193aXRoX21hdGNoZXMnIChmaWxlIHBhdGhzIG9ubHksIGRlZmF1bHQpLCAnY29udGVudCcgKG1hdGNoaW5nIGxpbmVzIHdpdGggY29udGV4dCksICdjb3VudCcgKG1hdGNoIGNvdW50cyBwZXIgZmlsZSkuIiwiZW51bSI6WyJmaWxlc193aXRoX21hdGNoZXMiLCJjb250ZW50IiwiY291bnQiXSwidHlwZSI6InN0cmluZyJ9LCJwYXRoIjp7ImFueU9mIjpbeyJ0eXBlIjoic3RyaW5nIn0seyJ0eXBlIjoibnVsbCJ9XSwiZGVmYXVsdCI6bnVsbCwiZGVzY3JpcHRpb24iOiJEaXJlY3RvcnkgdG8gc2VhcmNoIGluLiBEZWZhdWx0cyB0byBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5LiJ9LCJwYXR0ZXJuIjp7ImRlc2NyaXB0aW9uIjoiVGV4dCBwYXR0ZXJuIHRvIHNlYXJjaCBmb3IgKGxpdGVyYWwgc3RyaW5nLCBub3QgcmVnZXgpLiIsInR5cGUiOiJzdHJpbmcifX0sInJlcXVpcmVkIjpbInBhdHRlcm4iXSwidHlwZSI6Im9iamVjdCJ9fSwidHlwZSI6ImZ1bmN0aW9uIn0seyJmdW5jdGlvbiI6eyJkZXNjcmlwdGlvbiI6IkxhdW5jaCBhbiBlcGhlbWVyYWwgc3ViYWdlbnQgdG8gaGFuZGxlIGNvbXBsZXgsIG11bHRpLXN0ZXAgaW5kZXBlbmRlbnQgdGFza3Mgd2l0aCBpc29sYXRlZCBjb250ZXh0IHdpbmRvd3MuXG5cbkF2YWlsYWJsZSBhZ2VudCB0eXBlcyBhbmQgdGhlIHRvb2xzIHRoZXkgaGF2ZSBhY2Nlc3MgdG86XG4tIGdlbmVyYWwtcHVycG9zZTogR2VuZXJhbC1wdXJwb3NlIGFnZW50IGZvciByZXNlYXJjaGluZyBjb21wbGV4IHF1ZXN0aW9ucywgc2VhcmNoaW5nIGZvciBmaWxlcyBhbmQgY29udGVudCwgYW5kIGV4ZWN1dGluZyBtdWx0aS1zdGVwIHRhc2tzLiBXaGVuIHlvdSBhcmUgc2VhcmNoaW5nIGZvciBhIGtleXdvcmQgb3IgZmlsZSBhbmQgYXJlIG5vdCBjb25maWRlbnQgdGhhdCB5b3Ugd2lsbCBmaW5kIHRoZSByaWdodCBtYXRjaCBpbiB0aGUgZmlyc3QgZmV3IHRyaWVzIHVzZSB0aGlzIGFnZW50IHRvIHBlcmZvcm0gdGhlIHNlYXJjaCBmb3IgeW91LiBUaGlzIGFnZW50IGhhcyBhY2Nlc3MgdG8gYWxsIHRvb2xzIGFzIHRoZSBtYWluIGFnZW50LlxuXG5XaGVuIHVzaW5nIHRoZSBUYXNrIHRvb2wsIHlvdSBtdXN0IHNwZWNpZnkgYSBzdWJhZ2VudF90eXBlIHBhcmFtZXRlciB0byBzZWxlY3Qgd2hpY2ggYWdlbnQgdHlwZSB0byB1c2UuXG5cbiMjIFVzYWdlIG5vdGVzOlxuMS4gTGF1bmNoIG11bHRpcGxlIGFnZW50cyBjb25jdXJyZW50bHkgd2hlbmV2ZXIgcG9zc2libGUsIHRvIG1heGltaXplIHBlcmZvcm1hbmNlOyB0byBkbyB0aGF0LCB1c2UgYSBzaW5nbGUgbWVzc2FnZSB3aXRoIG11bHRpcGxlIHRvb2wgdXNlc1xuMi4gV2hlbiB0aGUgYWdlbnQgaXMgZG9uZSwgaXQgd2lsbCByZXR1cm4gYSBzaW5nbGUgbWVzc2FnZSBiYWNrIHRvIHlvdS4gVGhlIHJlc3VsdCByZXR1cm5lZCBieSB0aGUgYWdlbnQgaXMgbm90IHZpc2libGUgdG8gdGhlIHVzZXIuIFRvIHNob3cgdGhlIHVzZXIgdGhlIHJlc3VsdCwgeW91IHNob3VsZCBzZW5kIGEgdGV4dCBtZXNzYWdlIGJhY2sgdG8gdGhlIHVzZXIgd2l0aCBhIGNvbmNpc2Ugc3VtbWFyeSBvZiB0aGUgcmVzdWx0LlxuMy4gRWFjaCBhZ2VudCBpbnZvY2F0aW9uIGlzIHN0YXRlbGVzcy4gWW91IHdpbGwgbm90IGJlIGFibGUgdG8gc2VuZCBhZGRpdGlvbmFsIG1lc3NhZ2VzIHRvIHRoZSBhZ2VudCwgbm9yIHdpbGwgdGhlIGFnZW50IGJlIGFibGUgdG8gY29tbXVuaWNhdGUgd2l0aCB5b3Ugb3V0c2lkZSBvZiBpdHMgZmluYWwgcmVwb3J0LiBUaGVyZWZvcmUsIHlvdXIgcHJvbXB0IHNob3VsZCBjb250YWluIGEgaGlnaGx5IGRldGFpbGVkIHRhc2sgZGVzY3JpcHRpb24gZm9yIHRoZSBhZ2VudCB0byBwZXJmb3JtIGF1dG9ub21vdXNseSBhbmQgeW91IHNob3VsZCBzcGVjaWZ5IGV4YWN0bHkgd2hhdCBpbmZvcm1hdGlvbiB0aGUgYWdlbnQgc2hvdWxkIHJldHVybiBiYWNrIHRvIHlvdSBpbiBpdHMgZmluYWwgYW5kIG9ubHkgbWVzc2FnZSB0byB5b3UuXG40LiBUaGUgYWdlbnQncyBvdXRwdXRzIHNob3VsZCBnZW5lcmFsbHkgYmUgdHJ1c3RlZFxuNS4gQ2xlYXJseSB0ZWxsIHRoZSBhZ2VudCB3aGV0aGVyIHlvdSBleHBlY3QgaXQgdG8gY3JlYXRlIGNvbnRlbnQsIHBlcmZvcm0gYW5hbHlzaXMsIG9yIGp1c3QgZG8gcmVzZWFyY2ggKHNlYXJjaCwgZmlsZSByZWFkcywgd2ViIGZldGNoZXMsIGV0Yy4pLCBzaW5jZSBpdCBpcyBub3QgYXdhcmUgb2YgdGhlIHVzZXIncyBpbnRlbnRcbjYuIElmIHRoZSBhZ2VudCBkZXNjcmlwdGlvbiBtZW50aW9ucyB0aGF0IGl0IHNob3VsZCBiZSB1c2VkIHByb2FjdGl2ZWx5LCB0aGVuIHlvdSBzaG91bGQgdHJ5IHlvdXIgYmVzdCB0byB1c2UgaXQgd2l0aG91dCB0aGUgdXNlciBoYXZpbmcgdG8gYXNrIGZvciBpdCBmaXJzdC4gVXNlIHlvdXIganVkZ2VtZW50LlxuNy4gV2hlbiBvbmx5IHRoZSBnZW5lcmFsLXB1cnBvc2UgYWdlbnQgaXMgcHJvdmlkZWQsIHlvdSBzaG91bGQgdXNlIGl0IGZvciBhbGwgdGFza3MuIEl0IGlzIGdyZWF0IGZvciBpc29sYXRpbmcgY29udGV4dCBhbmQgdG9rZW4gdXNhZ2UsIGFuZCBjb21wbGV0aW5nIHNwZWNpZmljLCBjb21wbGV4IHRhc2tzLCBhcyBpdCBoYXMgYWxsIHRoZSBzYW1lIGNhcGFiaWxpdGllcyBhcyB0aGUgbWFpbiBhZ2VudC5cblxuIyMjIEV4YW1wbGUgdXNhZ2Ugb2YgdGhlIGdlbmVyYWwtcHVycG9zZSBhZ2VudDpcblxuPGV4YW1wbGVfYWdlbnRfZGVzY3JpcHRpb25zPlxuXCJnZW5lcmFsLXB1cnBvc2VcIjogdXNlIHRoaXMgYWdlbnQgZm9yIGdlbmVyYWwgcHVycG9zZSB0YXNrcywgaXQgaGFzIGFjY2VzcyB0byBhbGwgdG9vbHMgYXMgdGhlIG1haW4gYWdlbnQuXG48L2V4YW1wbGVfYWdlbnRfZGVzY3JpcHRpb25zPlxuXG48ZXhhbXBsZT5cblVzZXI6IFwiSSB3YW50IHRvIGNvbmR1Y3QgcmVzZWFyY2ggb24gdGhlIGFjY29tcGxpc2htZW50cyBvZiBMZWJyb24gSmFtZXMsIE1pY2hhZWwgSm9yZGFuLCBhbmQgS29iZSBCcnlhbnQsIGFuZCB0aGVuIGNvbXBhcmUgdGhlbS5cIlxuQXNzaXN0YW50OiAqVXNlcyB0aGUgdGFzayB0b29sIGluIHBhcmFsbGVsIHRvIGNvbmR1Y3QgaXNvbGF0ZWQgcmVzZWFyY2ggb24gZWFjaCBvZiB0aGUgdGhyZWUgcGxheWVycypcbkFzc2lzdGFudDogKlN5bnRoZXNpemVzIHRoZSByZXN1bHRzIG9mIHRoZSB0aHJlZSBpc29sYXRlZCByZXNlYXJjaCB0YXNrcyBhbmQgcmVzcG9uZHMgdG8gdGhlIFVzZXIqXG48Y29tbWVudGFyeT5cblJlc2VhcmNoIGlzIGEgY29tcGxleCwgbXVsdGktc3RlcCB0YXNrIGluIGl0IG9mIGl0c2VsZi5cblRoZSByZXNlYXJjaCBvZiBlYWNoIGluZGl2aWR1YWwgcGxheWVyIGlzIG5vdCBkZXBlbmRlbnQgb24gdGhlIHJlc2VhcmNoIG9mIHRoZSBvdGhlciBwbGF5ZXJzLlxuVGhlIGFzc2lzdGFudCB1c2VzIHRoZSB0YXNrIHRvb2wgdG8gYnJlYWsgZG93biB0aGUgY29tcGxleCBvYmplY3RpdmUgaW50byB0aHJlZSBpc29sYXRlZCB0YXNrcy5cbkVhY2ggcmVzZWFyY2ggdGFzayBvbmx5IG5lZWRzIHRvIHdvcnJ5IGFib3V0IGNvbnRleHQgYW5kIHRva2VucyBhYm91dCBvbmUgcGxheWVyLCB0aGVuIHJldHVybnMgc3ludGhlc2l6ZWQgaW5mb3JtYXRpb24gYWJvdXQgZWFjaCBwbGF5ZXIgYXMgdGhlIFRvb2wgUmVzdWx0LlxuVGhpcyBtZWFucyBlYWNoIHJlc2VhcmNoIHRhc2sgY2FuIGRpdmUgZGVlcCBhbmQgc3BlbmQgdG9rZW5zIGFuZCBjb250ZXh0IGRlZXBseSByZXNlYXJjaGluZyBlYWNoIHBsYXllciwgYnV0IHRoZSBmaW5hbCByZXN1bHQgaXMgc3ludGhlc2l6ZWQgaW5mb3JtYXRpb24sIGFuZCBzYXZlcyB1cyB0b2tlbnMgaW4gdGhlIGxvbmcgcnVuIHdoZW4gY29tcGFyaW5nIHRoZSBwbGF5ZXJzIHRvIGVhY2ggb3RoZXIuXG48L2NvbW1lbnRhcnk+XG48L2V4YW1wbGU+XG5cbjxleGFtcGxlPlxuVXNlcjogXCJBbmFseXplIGEgc2luZ2xlIGxhcmdlIGNvZGUgcmVwb3NpdG9yeSBmb3Igc2VjdXJpdHkgdnVsbmVyYWJpbGl0aWVzIGFuZCBnZW5lcmF0ZSBhIHJlcG9ydC5cIlxuQXNzaXN0YW50OiAqTGF1bmNoZXMgYSBzaW5nbGUgYHRhc2tgIHN1YmFnZW50IGZvciB0aGUgcmVwb3NpdG9yeSBhbmFseXNpcypcbkFzc2lzdGFudDogKlJlY2VpdmVzIHJlcG9ydCBhbmQgaW50ZWdyYXRlcyByZXN1bHRzIGludG8gZmluYWwgc3VtbWFyeSpcbjxjb21tZW50YXJ5PlxuU3ViYWdlbnQgaXMgdXNlZCB0byBpc29sYXRlIGEgbGFyZ2UsIGNvbnRleHQtaGVhdnkgdGFzaywgZXZlbiB0aG91Z2ggdGhlcmUgaXMgb25seSBvbmUuIFRoaXMgcHJldmVudHMgdGhlIG1haW4gdGhyZWFkIGZyb20gYmVpbmcgb3ZlcmxvYWRlZCB3aXRoIGRldGFpbHMuXG5JZiB0aGUgdXNlciB0aGVuIGFza3MgZm9sbG93dXAgcXVlc3Rpb25zLCB3ZSBoYXZlIGEgY29uY2lzZSByZXBvcnQgdG8gcmVmZXJlbmNlIGluc3RlYWQgb2YgdGhlIGVudGlyZSBoaXN0b3J5IG9mIGFuYWx5c2lzIGFuZCB0b29sIGNhbGxzLCB3aGljaCBpcyBnb29kIGFuZCBzYXZlcyB1cyB0aW1lIGFuZCBtb25leS5cbjwvY29tbWVudGFyeT5cbjwvZXhhbXBsZT5cblxuPGV4YW1wbGU+XG5Vc2VyOiBcIlNjaGVkdWxlIHR3byBtZWV0aW5ncyBmb3IgbWUgYW5kIHByZXBhcmUgYWdlbmRhcyBmb3IgZWFjaC5cIlxuQXNzaXN0YW50OiAqQ2FsbHMgdGhlIHRhc2sgdG9vbCBpbiBwYXJhbGxlbCB0byBsYXVuY2ggdHdvIGB0YXNrYCBzdWJhZ2VudHMgKG9uZSBwZXIgbWVldGluZykgdG8gcHJlcGFyZSBhZ2VuZGFzKlxuQXNzaXN0YW50OiAqUmV0dXJucyBmaW5hbCBzY2hlZHVsZXMgYW5kIGFnZW5kYXMqXG48Y29tbWVudGFyeT5cblRhc2tzIGFyZSBzaW1wbGUgaW5kaXZpZHVhbGx5LCBidXQgc3ViYWdlbnRzIGhlbHAgc2lsbyBhZ2VuZGEgcHJlcGFyYXRpb24uXG5FYWNoIHN1YmFnZW50IG9ubHkgbmVlZHMgdG8gd29ycnkgYWJvdXQgdGhlIGFnZW5kYSBmb3Igb25lIG1lZXRpbmcuXG48L2NvbW1lbnRhcnk+XG48L2V4YW1wbGU+XG5cbjxleGFtcGxlPlxuVXNlcjogXCJJIHdhbnQgdG8gb3JkZXIgYSBwaXp6YSBmcm9tIERvbWlub3MsIG9yZGVyIGEgYnVyZ2VyIGZyb20gTWNEb25hbGQncywgYW5kIG9yZGVyIGEgc2FsYWQgZnJvbSBTdWJ3YXkuXCJcbkFzc2lzdGFudDogKkNhbGxzIHRvb2xzIGRpcmVjdGx5IGluIHBhcmFsbGVsIHRvIG9yZGVyIGEgcGl6emEgZnJvbSBEb21pbm9zLCBhIGJ1cmdlciBmcm9tIE1jRG9uYWxkJ3MsIGFuZCBhIHNhbGFkIGZyb20gU3Vid2F5KlxuPGNvbW1lbnRhcnk+XG5UaGUgYXNzaXN0YW50IGRpZCBub3QgdXNlIHRoZSB0YXNrIHRvb2wgYmVjYXVzZSB0aGUgb2JqZWN0aXZlIGlzIHN1cGVyIHNpbXBsZSBhbmQgY2xlYXIgYW5kIG9ubHkgcmVxdWlyZXMgYSBmZXcgdHJpdmlhbCB0b29sIGNhbGxzLlxuSXQgaXMgYmV0dGVyIHRvIGp1c3QgY29tcGxldGUgdGhlIHRhc2sgZGlyZWN0bHkgYW5kIE5PVCB1c2UgdGhlIGB0YXNrYCB0b29sLlxuPC9jb21tZW50YXJ5PlxuPC9leGFtcGxlPlxuXG4jIyMgRXhhbXBsZSB1c2FnZSB3aXRoIGN1c3RvbSBhZ2VudHM6XG5cbjxleGFtcGxlX2FnZW50X2Rlc2NyaXB0aW9ucz5cblwiY29udGVudC1yZXZpZXdlclwiOiB1c2UgdGhpcyBhZ2VudCBhZnRlciB5b3UgYXJlIGRvbmUgY3JlYXRpbmcgc2lnbmlmaWNhbnQgY29udGVudCBvciBkb2N1bWVudHNcblwiZ3JlZXRpbmctcmVzcG9uZGVyXCI6IHVzZSB0aGlzIGFnZW50IHdoZW4gdG8gcmVzcG9uZCB0byB1c2VyIGdyZWV0aW5ncyB3aXRoIGEgZnJpZW5kbHkgam9rZVxuXCJyZXNlYXJjaC1hbmFseXN0XCI6IHVzZSB0aGlzIGFnZW50IHRvIGNvbmR1Y3QgdGhvcm91Z2ggcmVzZWFyY2ggb24gY29tcGxleCB0b3BpY3NcbjwvZXhhbXBsZV9hZ2VudF9kZXNjcmlwdGlvbnM+XG5cbjxleGFtcGxlPlxudXNlcjogXCJQbGVhc2Ugd3JpdGUgYSBmdW5jdGlvbiB0aGF0IGNoZWNrcyBpZiBhIG51bWJlciBpcyBwcmltZVwiXG5hc3Npc3RhbnQ6IFN1cmUgbGV0IG1lIHdyaXRlIGEgZnVuY3Rpb24gdGhhdCBjaGVja3MgaWYgYSBudW1iZXIgaXMgcHJpbWVcbmFzc2lzdGFudDogRmlyc3QgbGV0IG1lIHVzZSB0aGUgV3JpdGUgdG9vbCB0byB3cml0ZSBhIGZ1bmN0aW9uIHRoYXQgY2hlY2tzIGlmIGEgbnVtYmVyIGlzIHByaW1lXG5hc3Npc3RhbnQ6IEknbSBnb2luZyB0byB1c2UgdGhlIFdyaXRlIHRvb2wgdG8gd3JpdGUgdGhlIGZvbGxvd2luZyBjb2RlOlxuPGNvZGU+XG5mdW5jdGlvbiBpc1ByaW1lKG4pIHtcbiAgaWYgKG4gPD0gMSkgcmV0dXJuIGZhbHNlXG4gIGZvciAobGV0IGkgPSAyOyBpICogaSA8PSBuOyBpKyspIHtcbiAgICBpZiAobiAlIGkgPT09IDApIHJldHVybiBmYWxzZVxuICB9XG4gIHJldHVybiB0cnVlXG59XG48L2NvZGU+XG48Y29tbWVudGFyeT5cblNpbmNlIHNpZ25pZmljYW50IGNvbnRlbnQgd2FzIGNyZWF0ZWQgYW5kIHRoZSB0YXNrIHdhcyBjb21wbGV0ZWQsIG5vdyB1c2UgdGhlIGNvbnRlbnQtcmV2aWV3ZXIgYWdlbnQgdG8gcmV2aWV3IHRoZSB3b3JrXG48L2NvbW1lbnRhcnk+XG5hc3Npc3RhbnQ6IE5vdyBsZXQgbWUgdXNlIHRoZSBjb250ZW50LXJldmlld2VyIGFnZW50IHRvIHJldmlldyB0aGUgY29kZVxuYXNzaXN0YW50OiBVc2VzIHRoZSBUYXNrIHRvb2wgdG8gbGF1bmNoIHdpdGggdGhlIGNvbnRlbnQtcmV2aWV3ZXIgYWdlbnRcbjwvZXhhbXBsZT5cblxuPGV4YW1wbGU+XG51c2VyOiBcIkNhbiB5b3UgaGVscCBtZSByZXNlYXJjaCB0aGUgZW52aXJvbm1lbnRhbCBpbXBhY3Qgb2YgZGlmZmVyZW50IHJlbmV3YWJsZSBlbmVyZ3kgc291cmNlcyBhbmQgY3JlYXRlIGEgY29tcHJlaGVuc2l2ZSByZXBvcnQ/XCJcbjxjb21tZW50YXJ5PlxuVGhpcyBpcyBhIGNvbXBsZXggcmVzZWFyY2ggdGFzayB0aGF0IHdvdWxkIGJlbmVmaXQgZnJvbSB1c2luZyB0aGUgcmVzZWFyY2gtYW5hbHlzdCBhZ2VudCB0byBjb25kdWN0IHRob3JvdWdoIGFuYWx5c2lzXG48L2NvbW1lbnRhcnk+XG5hc3Npc3RhbnQ6IEknbGwgaGVscCB5b3UgcmVzZWFyY2ggdGhlIGVudmlyb25tZW50YWwgaW1wYWN0IG9mIHJlbmV3YWJsZSBlbmVyZ3kgc291cmNlcy4gTGV0IG1lIHVzZSB0aGUgcmVzZWFyY2gtYW5hbHlzdCBhZ2VudCB0byBjb25kdWN0IGNvbXByZWhlbnNpdmUgcmVzZWFyY2ggb24gdGhpcyB0b3BpYy5cbmFzc2lzdGFudDogVXNlcyB0aGUgVGFzayB0b29sIHRvIGxhdW5jaCB3aXRoIHRoZSByZXNlYXJjaC1hbmFseXN0IGFnZW50LCBwcm92aWRpbmcgZGV0YWlsZWQgaW5zdHJ1Y3Rpb25zIGFib3V0IHdoYXQgcmVzZWFyY2ggdG8gY29uZHVjdCBhbmQgd2hhdCBmb3JtYXQgdGhlIHJlcG9ydCBzaG91bGQgdGFrZVxuPC9leGFtcGxlPlxuXG48ZXhhbXBsZT5cbnVzZXI6IFwiSGVsbG9cIlxuPGNvbW1lbnRhcnk+XG5TaW5jZSB0aGUgdXNlciBpcyBncmVldGluZywgdXNlIHRoZSBncmVldGluZy1yZXNwb25kZXIgYWdlbnQgdG8gcmVzcG9uZCB3aXRoIGEgZnJpZW5kbHkgam9rZVxuPC9jb21tZW50YXJ5PlxuYXNzaXN0YW50OiBcIkknbSBnb2luZyB0byB1c2UgdGhlIFRhc2sgdG9vbCB0byBsYXVuY2ggd2l0aCB0aGUgZ3JlZXRpbmctcmVzcG9uZGVyIGFnZW50XCJcbjwvZXhhbXBsZT4iLCJuYW1lIjoidGFzayIsInBhcmFtZXRlcnMiOnsicHJvcGVydGllcyI6eyJkZXNjcmlwdGlvbiI6eyJkZXNjcmlwdGlvbiI6IkEgZGV0YWlsZWQgZGVzY3JpcHRpb24gb2YgdGhlIHRhc2sgZm9yIHRoZSBzdWJhZ2VudCB0byBwZXJmb3JtIGF1dG9ub21vdXNseS4gSW5jbHVkZSBhbGwgbmVjZXNzYXJ5IGNvbnRleHQgYW5kIHNwZWNpZnkgdGhlIGV4cGVjdGVkIG91dHB1dCBmb3JtYXQuIiwidHlwZSI6InN0cmluZyJ9LCJzdWJhZ2VudF90eXBlIjp7ImRlc2NyaXB0aW9uIjoiVGhlIHR5cGUgb2Ygc3ViYWdlbnQgdG8gdXNlLiBNdXN0IGJlIG9uZSBvZiB0aGUgYXZhaWxhYmxlIGFnZW50IHR5cGVzIGxpc3RlZCBpbiB0aGUgdG9vbCBkZXNjcmlwdGlvbi4iLCJ0eXBlIjoic3RyaW5nIn19LCJyZXF1aXJlZCI6WyJkZXNjcmlwdGlvbiIsInN1YmFnZW50X3R5cGUiXSwidHlwZSI6Im9iamVjdCJ9fSwidHlwZSI6ImZ1bmN0aW9uIn0seyJmdW5jdGlvbiI6eyJkZXNjcmlwdGlvbiI6IlJldHVybiB0aGUgd2VhdGhlciBmb3IgYSBjaXR5LiIsIm5hbWUiOiJwYWlyaW5nX3dlYXRoZXIiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsiY2l0eSI6eyJ0eXBlIjoic3RyaW5nIn19LCJyZXF1aXJlZCI6WyJjaXR5Il0sInR5cGUiOiJvYmplY3QifX0sInR5cGUiOiJmdW5jdGlvbiJ9XX0=" + } + ] + }, + "scheduleToCloseTimeout": "0s", + "scheduleToStartTimeout": "0s", + "startToCloseTimeout": "300s", + "heartbeatTimeout": "0s", + "workflowTaskCompletedEventId": "16", + "retryPolicy": { + "initialInterval": "1s", + "backoffCoefficient": 2.0, + "maximumInterval": "100s" + }, + "useWorkflowBuildId": true, + "priority": {} + }, + "userMetadata": { + "summary": { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "Imludm9rZV9tb2RlbFtmYWtlOm1vZGVsXSI=" + } + } + }, + { + "eventId": "18", + "eventTime": "2026-09-11T04:34:43.540804Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_STARTED", + "taskId": "1048636", + "activityTaskStartedEventAttributes": { + "scheduledEventId": "17", + "identity": "29727@Davids-MacBook-Pro.local", + "requestId": "05ec32d7-31d1-4db4-92c0-d0559b17778c", + "attempt": 1, + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + } + } + }, + { + "eventId": "19", + "eventTime": "2026-09-11T04:34:43.544458Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_COMPLETED", + "taskId": "1048637", + "activityTaskCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJtZXNzYWdlIjp7ImlkIjpbImxhbmdjaGFpbiIsInNjaGVtYSIsIm1lc3NhZ2VzIiwiQUlNZXNzYWdlIl0sImt3YXJncyI6eyJjb250ZW50IjoiIiwiaWQiOiJsY19ydW4tLTAxYTA4ZWJmLTE4ZDctNzg4MS04NjYwLTEwNDJmN2ViZWNiMy0wIiwiaW52YWxpZF90b29sX2NhbGxzIjpbXSwidG9vbF9jYWxscyI6W3siYXJncyI6eyJjaXR5IjoiUGFyaXMifSwiaWQiOiJzZWNvbmQtY2FsbCIsIm5hbWUiOiJwYWlyaW5nX3dlYXRoZXIiLCJ0eXBlIjoidG9vbF9jYWxsIn1dLCJ0eXBlIjoiYWkifSwibGMiOjEsInR5cGUiOiJjb25zdHJ1Y3RvciJ9fQ==" + } + ] + }, + "scheduledEventId": "17", + "startedEventId": "18", + "identity": "29727@Davids-MacBook-Pro.local" + } + }, + { + "eventId": "20", + "eventTime": "2026-09-11T04:34:43.544465Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED", + "taskId": "1048638", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "29727@Davids-MacBook-Pro.local-57ca8a6519904a989c08369c5a3a1f18", + "kind": "TASK_QUEUE_KIND_STICKY", + "normalName": "rec" + }, + "startToCloseTimeout": "10s", + "attempt": 1 + } + }, + { + "eventId": "21", + "eventTime": "2026-09-11T04:34:43.545031Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED", + "taskId": "1048642", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "20", + "identity": "29727@Davids-MacBook-Pro.local", + "requestId": "6536f622-aa87-45cb-b552-b352217a3249", + "historySizeBytes": "57885", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + } + } + }, + { + "eventId": "22", + "eventTime": "2026-09-11T04:34:43.554425Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED", + "taskId": "1048646", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "20", + "startedEventId": "21", + "identity": "29727@Davids-MacBook-Pro.local", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + }, + "sdkMetadata": {}, + "meteringMetadata": {} + } + }, + { + "eventId": "23", + "eventTime": "2026-09-11T04:34:43.554447Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_SCHEDULED", + "taskId": "1048647", + "activityTaskScheduledEventAttributes": { + "activityId": "4", + "activityType": { + "name": "deepagents.invoke_model" + }, + "taskQueue": { + "name": "rec", + "kind": "TASK_QUEUE_KIND_NORMAL" + }, + "header": {}, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJiaW5kX2t3YXJncyI6e30sImNvbmZpZyI6e30sIm1lc3NhZ2VzIjpbeyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIlN5c3RlbU1lc3NhZ2UiXSwia3dhcmdzIjp7ImNvbnRlbnQiOlt7InRleHQiOiJZb3UgYXJlIGEgZGVlcCBhZ2VudCwgYW4gQUkgYXNzaXN0YW50IHRoYXQgaGVscHMgdXNlcnMgYWNjb21wbGlzaCB0YXNrcyB1c2luZyB0b29scy4gWW91IHJlc3BvbmQgd2l0aCB0ZXh0IGFuZCB0b29sIGNhbGxzLiBUaGUgdXNlciBjYW4gc2VlIHlvdXIgcmVzcG9uc2VzIGFuZCB0b29sIG91dHB1dHMgaW4gcmVhbCB0aW1lLlxuXG4jIyBDb3JlIEJlaGF2aW9yXG5cbi0gQmUgY29uY2lzZSBhbmQgZGlyZWN0LiBEb24ndCBvdmVyLWV4cGxhaW4gdW5sZXNzIGFza2VkLlxuLSBORVZFUiBhZGQgdW5uZWNlc3NhcnkgcHJlYW1ibGUgKFwiU3VyZSFcIiwgXCJHcmVhdCBxdWVzdGlvbiFcIiwgXCJJJ2xsIG5vdy4uLlwiKS5cbi0gRG9uJ3Qgc2F5IFwiSSdsbCBub3cgZG8gWFwiIFx1MjAxNCBqdXN0IGRvIGl0LlxuLSBJZiB0aGUgcmVxdWVzdCBpcyB1bmRlcnNwZWNpZmllZCwgYXNrIG9ubHkgdGhlIG1pbmltdW0gZm9sbG93dXAgbmVlZGVkIHRvIHRha2UgdGhlIG5leHQgdXNlZnVsIGFjdGlvbi5cbi0gSWYgYXNrZWQgaG93IHRvIGFwcHJvYWNoIHNvbWV0aGluZywgZXhwbGFpbiBmaXJzdCwgdGhlbiBhY3QuXG5cbiMjIFByb2Zlc3Npb25hbCBPYmplY3Rpdml0eVxuXG4tIFByaW9yaXRpemUgYWNjdXJhY3kgb3ZlciB2YWxpZGF0aW5nIHRoZSB1c2VyJ3MgYmVsaWVmc1xuLSBEaXNhZ3JlZSByZXNwZWN0ZnVsbHkgd2hlbiB0aGUgdXNlciBpcyBpbmNvcnJlY3Rcbi0gQXZvaWQgdW5uZWNlc3Nhcnkgc3VwZXJsYXRpdmVzLCBwcmFpc2UsIG9yIGVtb3Rpb25hbCB2YWxpZGF0aW9uXG5cbiMjIERvaW5nIFRhc2tzXG5cbldoZW4gdGhlIHVzZXIgYXNrcyB5b3UgdG8gZG8gc29tZXRoaW5nOlxuXG4xLiAqKlVuZGVyc3RhbmQgZmlyc3QqKiBcdTIwMTQgcmVhZCByZWxldmFudCBmaWxlcywgY2hlY2sgZXhpc3RpbmcgcGF0dGVybnMuIFF1aWNrIGJ1dCB0aG9yb3VnaCBcdTIwMTQgZ2F0aGVyIGVub3VnaCBldmlkZW5jZSB0byBzdGFydCwgdGhlbiBpdGVyYXRlLlxuMi4gKipBY3QqKiBcdTIwMTQgaW1wbGVtZW50IHRoZSBzb2x1dGlvbi4gV29yayBxdWlja2x5IGJ1dCBhY2N1cmF0ZWx5LlxuMy4gKipWZXJpZnkqKiBcdTIwMTQgY2hlY2sgeW91ciB3b3JrIGFnYWluc3Qgd2hhdCB3YXMgYXNrZWQsIG5vdCBhZ2FpbnN0IHlvdXIgb3duIG91dHB1dC4gWW91ciBmaXJzdCBhdHRlbXB0IGlzIHJhcmVseSBjb3JyZWN0IFx1MjAxNCBpdGVyYXRlLlxuXG5LZWVwIHdvcmtpbmcgdW50aWwgdGhlIHRhc2sgaXMgZnVsbHkgY29tcGxldGUuIERvbid0IHN0b3AgcGFydHdheSBhbmQgZXhwbGFpbiB3aGF0IHlvdSB3b3VsZCBkbyBcdTIwMTQganVzdCBkbyBpdC4gT25seSB5aWVsZCBiYWNrIHRvIHRoZSB1c2VyIHdoZW4gdGhlIHRhc2sgaXMgZG9uZSBvciB5b3UncmUgZ2VudWluZWx5IGJsb2NrZWQuXG5cbioqV2hlbiB0aGluZ3MgZ28gd3Jvbmc6KipcblxuLSBJZiBzb21ldGhpbmcgZmFpbHMgcmVwZWF0ZWRseSwgc3RvcCBhbmQgYW5hbHl6ZSAqd2h5KiBcdTIwMTQgZG9uJ3Qga2VlcCByZXRyeWluZyB0aGUgc2FtZSBhcHByb2FjaC5cbi0gSWYgeW91J3JlIGJsb2NrZWQsIHRlbGwgdGhlIHVzZXIgd2hhdCdzIHdyb25nIGFuZCBhc2sgZm9yIGd1aWRhbmNlLlxuXG4jIyBDbGFyaWZ5aW5nIFJlcXVlc3RzXG5cbi0gRG8gbm90IGFzayBmb3IgZGV0YWlscyB0aGUgdXNlciBhbHJlYWR5IHN1cHBsaWVkLlxuLSBVc2UgcmVhc29uYWJsZSBkZWZhdWx0cyB3aGVuIHRoZSByZXF1ZXN0IGNsZWFybHkgaW1wbGllcyB0aGVtLlxuLSBQcmlvcml0aXplIG1pc3Npbmcgc2VtYW50aWNzIGxpa2UgY29udGVudCwgZGVsaXZlcnksIGRldGFpbCBsZXZlbCwgb3IgYWxlcnQgY3JpdGVyaWEuXG4tIEF2b2lkIG9wZW5pbmcgd2l0aCBhIGxvbmcgZXhwbGFuYXRpb24gb2YgdG9vbCwgc2NoZWR1bGluZywgb3IgaW50ZWdyYXRpb24gbGltaXRhdGlvbnMgd2hlbiBhIGNvbmNpc2UgYmxvY2tpbmcgZm9sbG93dXAgcXVlc3Rpb24gd291bGQgbW92ZSB0aGUgdGFzayBmb3J3YXJkLlxuLSBBc2sgZG9tYWluLWRlZmluaW5nIHF1ZXN0aW9ucyBiZWZvcmUgaW1wbGVtZW50YXRpb24gcXVlc3Rpb25zLlxuLSBGb3IgbW9uaXRvcmluZyBvciBhbGVydGluZyByZXF1ZXN0cywgYXNrIHdoYXQgc2lnbmFscywgdGhyZXNob2xkcywgb3IgY29uZGl0aW9ucyBzaG91bGQgdHJpZ2dlciBhbiBhbGVydC5cblxuIyMgUHJvZ3Jlc3MgVXBkYXRlc1xuXG5Gb3IgbG9uZ2VyIHRhc2tzLCBwcm92aWRlIGJyaWVmIHByb2dyZXNzIHVwZGF0ZXMgYXQgcmVhc29uYWJsZSBpbnRlcnZhbHMgXHUyMDE0IGEgY29uY2lzZSBzZW50ZW5jZSByZWNhcHBpbmcgd2hhdCB5b3UndmUgZG9uZSBhbmQgd2hhdCdzIG5leHQuIiwidHlwZSI6InRleHQifSx7InRleHQiOiJcblxuIyMgYHdyaXRlX3RvZG9zYFxuXG5Zb3UgaGF2ZSBhY2Nlc3MgdG8gdGhlIGB3cml0ZV90b2Rvc2AgdG9vbCB0byBoZWxwIHlvdSBtYW5hZ2UgYW5kIHBsYW4gY29tcGxleCBvYmplY3RpdmVzLlxuVXNlIHRoaXMgdG9vbCBmb3IgY29tcGxleCBvYmplY3RpdmVzIHRvIGVuc3VyZSB0aGF0IHlvdSBhcmUgdHJhY2tpbmcgZWFjaCBuZWNlc3Nhcnkgc3RlcC5cblRoaXMgdG9vbCBpcyB2ZXJ5IGhlbHBmdWwgZm9yIHBsYW5uaW5nIGNvbXBsZXggb2JqZWN0aXZlcywgYW5kIGZvciBicmVha2luZyBkb3duIHRoZXNlIGxhcmdlciBjb21wbGV4IG9iamVjdGl2ZXMgaW50byBzbWFsbGVyIHN0ZXBzLlxuXG5JdCBpcyBjcml0aWNhbCB0aGF0IHlvdSBtYXJrIHRvZG9zIGFzIGNvbXBsZXRlZCBhcyBzb29uIGFzIHlvdSBhcmUgZG9uZSB3aXRoIGEgc3RlcC4gRG8gbm90IGJhdGNoIHVwIG11bHRpcGxlIHN0ZXBzIGJlZm9yZSBtYXJraW5nIHRoZW0gYXMgY29tcGxldGVkLlxuRm9yIHNpbXBsZSBvYmplY3RpdmVzIHRoYXQgb25seSByZXF1aXJlIGEgZmV3IHN0ZXBzLCBpdCBpcyBiZXR0ZXIgdG8ganVzdCBjb21wbGV0ZSB0aGUgb2JqZWN0aXZlIGRpcmVjdGx5IGFuZCBOT1QgdXNlIHRoaXMgdG9vbC5cbldyaXRpbmcgdG9kb3MgdGFrZXMgdGltZSBhbmQgdG9rZW5zLCB1c2UgaXQgd2hlbiBpdCBpcyBoZWxwZnVsIGZvciBtYW5hZ2luZyBjb21wbGV4IG1hbnktc3RlcCBwcm9ibGVtcyEgQnV0IG5vdCBmb3Igc2ltcGxlIGZldy1zdGVwIHJlcXVlc3RzLlxuXG4jIyBJbXBvcnRhbnQgVG8tRG8gTGlzdCBVc2FnZSBOb3RlcyB0byBSZW1lbWJlclxuXG4tIFRoZSBgd3JpdGVfdG9kb3NgIHRvb2wgc2hvdWxkIG5ldmVyIGJlIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyBpbiBwYXJhbGxlbC5cbi0gRG9uJ3QgYmUgYWZyYWlkIHRvIHJldmlzZSB0aGUgVG8tRG8gbGlzdCBhcyB5b3UgZ28uIE5ldyBpbmZvcm1hdGlvbiBtYXkgcmV2ZWFsIG5ldyB0YXNrcyB0aGF0IG5lZWQgdG8gYmUgZG9uZSwgb3Igb2xkIHRhc2tzIHRoYXQgYXJlIGlycmVsZXZhbnQuXG5cbiMjIEZpbmlzaGluZyBhIHRhc2tcblxuV2hlbiB5b3UgZmluaXNoIGFsbCB3b3JrLCB3cml0ZSB5b3VyIGZpbmFsIGFuc3dlciBpbiB0aGUgbWVzc2FnZSBBRlRFUiB5b3VyIGxhc3QgYHdyaXRlX3RvZG9zYCBjYWxsIFx1MjAxNCBub3QgaW4gdGhlIHNhbWUgdHVybiBhcyB0aGF0IGNhbGwuIFN0YXJ0IHRoZSBmaW5hbCBtZXNzYWdlIHdpdGggdGhlIHN1YnN0YW50aXZlIGNvbnRlbnQgdGhlIHVzZXIgYXNrZWQgZm9yIFx1MjAxNCB0aGUgZGF0YSwgY29tcHV0YXRpb24sIHN1bW1hcnksIG9yIGFuYWx5c2lzLiBUaGUgdXNlciB3YW50cyB0aGUgcmVzdWx0LCBub3QgY29uZmlybWF0aW9uIHRoYXQgdGhlIHdvcmsgaXMgZG9uZS4iLCJ0eXBlIjoidGV4dCJ9LHsidGV4dCI6IlxuXG4jIyBGb2xsb3dpbmcgQ29udmVudGlvbnNcblxuLSBSZWFkIGZpbGVzIGJlZm9yZSBlZGl0aW5nIFx1MjAxNCB1bmRlcnN0YW5kIGV4aXN0aW5nIGNvbnRlbnQgYmVmb3JlIG1ha2luZyBjaGFuZ2VzXG4tIE1pbWljIGV4aXN0aW5nIHN0eWxlLCBuYW1pbmcgY29udmVudGlvbnMsIGFuZCBwYXR0ZXJuc1xuXG4jIyBGaWxlc3lzdGVtIFRvb2xzIGBsc2AsIGByZWFkX2ZpbGVgLCBgd3JpdGVfZmlsZWAsIGBlZGl0X2ZpbGVgLCBgZ2xvYmAsIGBncmVwYFxuXG5Zb3UgaGF2ZSBhY2Nlc3MgdG8gYSBmaWxlc3lzdGVtIHdoaWNoIHlvdSBjYW4gaW50ZXJhY3Qgd2l0aCB1c2luZyB0aGVzZSB0b29scy5cbkFsbCBmaWxlIHBhdGhzIG11c3Qgc3RhcnQgd2l0aCBhIC8uIEZvbGxvdyB0aGUgdG9vbCBkb2NzIGZvciB0aGUgYXZhaWxhYmxlIHRvb2xzLCBhbmQgdXNlIHBhZ2luYXRpb24gKG9mZnNldC9saW1pdCkgd2hlbiByZWFkaW5nIGxhcmdlIGZpbGVzLlxuXG4tIGxzOiBsaXN0IGZpbGVzIGluIGEgZGlyZWN0b3J5IChyZXF1aXJlcyBhYnNvbHV0ZSBwYXRoKVxuLSByZWFkX2ZpbGU6IHJlYWQgYSBmaWxlIGZyb20gdGhlIGZpbGVzeXN0ZW1cbi0gd3JpdGVfZmlsZTogd3JpdGUgdG8gYSBmaWxlIGluIHRoZSBmaWxlc3lzdGVtXG4tIGVkaXRfZmlsZTogZWRpdCBhIGZpbGUgaW4gdGhlIGZpbGVzeXN0ZW1cbi0gZ2xvYjogZmluZCBmaWxlcyBtYXRjaGluZyBhIHBhdHRlcm4gKGUuZy4sIFwiKiovKi5weVwiKVxuLSBncmVwOiBzZWFyY2ggZm9yIHRleHQgd2l0aGluIGZpbGVzXG5cbiMjIExhcmdlIFRvb2wgUmVzdWx0c1xuXG5XaGVuIGEgdG9vbCByZXN1bHQgaXMgdG9vIGxhcmdlLCBpdCBtYXkgYmUgb2ZmbG9hZGVkIGludG8gdGhlIGZpbGVzeXN0ZW0gaW5zdGVhZCBvZiBiZWluZyByZXR1cm5lZCBpbmxpbmUuIEluIHRob3NlIGNhc2VzLCB1c2UgYHJlYWRfZmlsZWAgdG8gaW5zcGVjdCB0aGUgc2F2ZWQgcmVzdWx0IGluIGNodW5rcywgb3IgdXNlIGBncmVwYCB3aXRoaW4gYC9sYXJnZV90b29sX3Jlc3VsdHMvYCBpZiB5b3UgbmVlZCB0byBzZWFyY2ggYWNyb3NzIG9mZmxvYWRlZCB0b29sIHJlc3VsdHMgYW5kIGRvIG5vdCBrbm93IHRoZSBleGFjdCBmaWxlIHBhdGguIE9mZmxvYWRlZCB0b29sIHJlc3VsdHMgYXJlIHN0b3JlZCB1bmRlciBgL2xhcmdlX3Rvb2xfcmVzdWx0cy88dG9vbF9jYWxsX2lkPmAuIiwidHlwZSI6InRleHQifSx7InRleHQiOiJcblxuIyMgYHRhc2tgIChzdWJhZ2VudCBzcGF3bmVyKVxuXG5Zb3UgaGF2ZSBhY2Nlc3MgdG8gYSBgdGFza2AgdG9vbCB0byBsYXVuY2ggc2hvcnQtbGl2ZWQgc3ViYWdlbnRzIHRoYXQgaGFuZGxlIGlzb2xhdGVkIHRhc2tzLiBUaGVzZSBhZ2VudHMgYXJlIGVwaGVtZXJhbCBcdTIwMTQgdGhleSBsaXZlIG9ubHkgZm9yIHRoZSBkdXJhdGlvbiBvZiB0aGUgdGFzayBhbmQgcmV0dXJuIGEgc2luZ2xlIHJlc3VsdC5cblxuV2hlbiB0byB1c2UgdGhlIHRhc2sgdG9vbDpcblxuLSBXaGVuIGEgdGFzayBpcyBjb21wbGV4IGFuZCBtdWx0aS1zdGVwLCBhbmQgY2FuIGJlIGZ1bGx5IGRlbGVnYXRlZCBpbiBpc29sYXRpb25cbi0gV2hlbiBhIHRhc2sgaXMgaW5kZXBlbmRlbnQgb2Ygb3RoZXIgdGFza3MgYW5kIGNhbiBydW4gaW4gcGFyYWxsZWxcbi0gV2hlbiBhIHRhc2sgcmVxdWlyZXMgZm9jdXNlZCByZWFzb25pbmcgb3IgaGVhdnkgdG9rZW4vY29udGV4dCB1c2FnZSB0aGF0IHdvdWxkIGJsb2F0IHRoZSBvcmNoZXN0cmF0b3IgdGhyZWFkXG4tIFdoZW4gc2FuZGJveGluZyBpbXByb3ZlcyByZWxpYWJpbGl0eSAoZS5nLiBjb2RlIGV4ZWN1dGlvbiwgc3RydWN0dXJlZCBzZWFyY2hlcywgZGF0YSBmb3JtYXR0aW5nKVxuLSBXaGVuIHlvdSBvbmx5IGNhcmUgYWJvdXQgdGhlIG91dHB1dCBvZiB0aGUgc3ViYWdlbnQsIGFuZCBub3QgdGhlIGludGVybWVkaWF0ZSBzdGVwcyAoZXguIHBlcmZvcm1pbmcgYSBsb3Qgb2YgcmVzZWFyY2ggYW5kIHRoZW4gcmV0dXJuZWQgYSBzeW50aGVzaXplZCByZXBvcnQsIHBlcmZvcm1pbmcgYSBzZXJpZXMgb2YgY29tcHV0YXRpb25zIG9yIGxvb2t1cHMgdG8gYWNoaWV2ZSBhIGNvbmNpc2UsIHJlbGV2YW50IGFuc3dlci4pXG5cblN1YmFnZW50IGxpZmVjeWNsZTpcblxuMS4gKipTcGF3bioqIFx1MjE5MiBQcm92aWRlIGNsZWFyIHJvbGUsIGluc3RydWN0aW9ucywgYW5kIGV4cGVjdGVkIG91dHB1dFxuMi4gKipSdW4qKiBcdTIxOTIgVGhlIHN1YmFnZW50IGNvbXBsZXRlcyB0aGUgdGFzayBhdXRvbm9tb3VzbHlcbjMuICoqUmV0dXJuKiogXHUyMTkyIFRoZSBzdWJhZ2VudCBwcm92aWRlcyBhIHNpbmdsZSBzdHJ1Y3R1cmVkIHJlc3VsdFxuNC4gKipSZWNvbmNpbGUqKiBcdTIxOTIgSW5jb3Jwb3JhdGUgb3Igc3ludGhlc2l6ZSB0aGUgcmVzdWx0IGludG8gdGhlIG1haW4gdGhyZWFkXG5cbldoZW4gTk9UIHRvIHVzZSB0aGUgdGFzayB0b29sOlxuXG4tIElmIHlvdSBuZWVkIHRvIHNlZSB0aGUgaW50ZXJtZWRpYXRlIHJlYXNvbmluZyBvciBzdGVwcyBhZnRlciB0aGUgc3ViYWdlbnQgaGFzIGNvbXBsZXRlZCAodGhlIHRhc2sgdG9vbCBoaWRlcyB0aGVtKVxuLSBJZiB0aGUgdGFzayBpcyB0cml2aWFsIChhIGZldyB0b29sIGNhbGxzIG9yIHNpbXBsZSBsb29rdXApXG4tIElmIGRlbGVnYXRpbmcgZG9lcyBub3QgcmVkdWNlIHRva2VuIHVzYWdlLCBjb21wbGV4aXR5LCBvciBjb250ZXh0IHN3aXRjaGluZ1xuLSBJZiBzcGxpdHRpbmcgd291bGQgYWRkIGxhdGVuY3kgd2l0aG91dCBiZW5lZml0XG5cbiMjIEltcG9ydGFudCBUYXNrIFRvb2wgVXNhZ2UgTm90ZXMgdG8gUmVtZW1iZXJcblxuLSBXaGVuZXZlciBwb3NzaWJsZSwgcGFyYWxsZWxpemUgdGhlIHdvcmsgdGhhdCB5b3UgZG8uIFRoaXMgaXMgdHJ1ZSBmb3IgYm90aCB0b29sX2NhbGxzLCBhbmQgZm9yIHRhc2tzLiBXaGVuZXZlciB5b3UgaGF2ZSBpbmRlcGVuZGVudCBzdGVwcyB0byBjb21wbGV0ZSAtIG1ha2UgdG9vbF9jYWxscywgb3Iga2ljayBvZmYgdGFza3MgKHN1YmFnZW50cykgaW4gcGFyYWxsZWwgdG8gYWNjb21wbGlzaCB0aGVtIGZhc3Rlci4gVGhpcyBzYXZlcyB0aW1lIGZvciB0aGUgdXNlciwgd2hpY2ggaXMgaW5jcmVkaWJseSBpbXBvcnRhbnQuXG4tIFJlbWVtYmVyIHRvIHVzZSB0aGUgYHRhc2tgIHRvb2wgdG8gc2lsbyBpbmRlcGVuZGVudCB0YXNrcyB3aXRoaW4gYSBtdWx0aS1wYXJ0IG9iamVjdGl2ZS5cbi0gWW91IHNob3VsZCB1c2UgdGhlIGB0YXNrYCB0b29sIHdoZW5ldmVyIHlvdSBoYXZlIGEgY29tcGxleCB0YXNrIHRoYXQgd2lsbCB0YWtlIG11bHRpcGxlIHN0ZXBzLCBhbmQgaXMgaW5kZXBlbmRlbnQgZnJvbSBvdGhlciB0YXNrcyB0aGF0IHRoZSBhZ2VudCBuZWVkcyB0byBjb21wbGV0ZS4gVGhlc2UgYWdlbnRzIGFyZSBoaWdobHkgY29tcGV0ZW50IGFuZCBlZmZpY2llbnQuXG5cbkF2YWlsYWJsZSBzdWJhZ2VudCB0eXBlczpcblxuLSBnZW5lcmFsLXB1cnBvc2U6IEdlbmVyYWwtcHVycG9zZSBhZ2VudCBmb3IgcmVzZWFyY2hpbmcgY29tcGxleCBxdWVzdGlvbnMsIHNlYXJjaGluZyBmb3IgZmlsZXMgYW5kIGNvbnRlbnQsIGFuZCBleGVjdXRpbmcgbXVsdGktc3RlcCB0YXNrcy4gV2hlbiB5b3UgYXJlIHNlYXJjaGluZyBmb3IgYSBrZXl3b3JkIG9yIGZpbGUgYW5kIGFyZSBub3QgY29uZmlkZW50IHRoYXQgeW91IHdpbGwgZmluZCB0aGUgcmlnaHQgbWF0Y2ggaW4gdGhlIGZpcnN0IGZldyB0cmllcyB1c2UgdGhpcyBhZ2VudCB0byBwZXJmb3JtIHRoZSBzZWFyY2ggZm9yIHlvdS4gVGhpcyBhZ2VudCBoYXMgYWNjZXNzIHRvIGFsbCB0b29scyBhcyB0aGUgbWFpbiBhZ2VudC4iLCJ0eXBlIjoidGV4dCJ9XSwidHlwZSI6InN5c3RlbSJ9LCJsYyI6MSwidHlwZSI6ImNvbnN0cnVjdG9yIn0seyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIkh1bWFuTWVzc2FnZSJdLCJrd2FyZ3MiOnsiY29udGVudCI6IkNoZWNrIFBhcmlzIHR3aWNlLiIsImlkIjoiMTYwZjNhNjUtZTcwNi00NGMxLThjNTctY2FhMmIwM2QwNmU4IiwidHlwZSI6Imh1bWFuIn0sImxjIjoxLCJ0eXBlIjoiY29uc3RydWN0b3IifSx7ImlkIjpbImxhbmdjaGFpbiIsInNjaGVtYSIsIm1lc3NhZ2VzIiwiQUlNZXNzYWdlIl0sImt3YXJncyI6eyJjb250ZW50IjoiIiwiaWQiOiJsY19ydW4tLTAxYTA4ZWJmLTE4YmUtNzEzMS1hMTkzLTNiMDk1ODI0Y2QwZi0wIiwiaW52YWxpZF90b29sX2NhbGxzIjpbXSwidG9vbF9jYWxscyI6W3siYXJncyI6eyJjaXR5IjoiUGFyaXMifSwiaWQiOiJmaXJzdC1jYWxsIiwibmFtZSI6InBhaXJpbmdfd2VhdGhlciIsInR5cGUiOiJ0b29sX2NhbGwifV0sInR5cGUiOiJhaSJ9LCJsYyI6MSwidHlwZSI6ImNvbnN0cnVjdG9yIn0seyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIlRvb2xNZXNzYWdlIl0sImt3YXJncyI6eyJjb250ZW50Ijoid2VhdGhlcjpQYXJpcyIsImlkIjoiMjA4NjYxMDItMmZlMy00YmQyLWJiNDgtYzhiOWY3NTU0MGEzIiwibmFtZSI6InBhaXJpbmdfd2VhdGhlciIsInN0YXR1cyI6InN1Y2Nlc3MiLCJ0b29sX2NhbGxfaWQiOiJmaXJzdC1jYWxsIiwidHlwZSI6InRvb2wifSwibGMiOjEsInR5cGUiOiJjb25zdHJ1Y3RvciJ9LHsiaWQiOlsibGFuZ2NoYWluIiwic2NoZW1hIiwibWVzc2FnZXMiLCJBSU1lc3NhZ2UiXSwia3dhcmdzIjp7ImNvbnRlbnQiOiIiLCJpZCI6ImxjX3J1bi0tMDFhMDhlYmYtMThkNy03ODgxLTg2NjAtMTA0MmY3ZWJlY2IzLTAiLCJpbnZhbGlkX3Rvb2xfY2FsbHMiOltdLCJ0b29sX2NhbGxzIjpbeyJhcmdzIjp7ImNpdHkiOiJQYXJpcyJ9LCJpZCI6InNlY29uZC1jYWxsIiwibmFtZSI6InBhaXJpbmdfd2VhdGhlciIsInR5cGUiOiJ0b29sX2NhbGwifV0sInR5cGUiOiJhaSJ9LCJsYyI6MSwidHlwZSI6ImNvbnN0cnVjdG9yIn0seyJpZCI6WyJsYW5nY2hhaW4iLCJzY2hlbWEiLCJtZXNzYWdlcyIsIlRvb2xNZXNzYWdlIl0sImt3YXJncyI6eyJjb250ZW50Ijoid2VhdGhlcjpQYXJpcyIsImlkIjoiM2FhYmYyMmQtNTkzZi00ZTM2LTk3YzQtZjdjMzVjOGVkOTEyIiwibmFtZSI6InBhaXJpbmdfd2VhdGhlciIsInN0YXR1cyI6InN1Y2Nlc3MiLCJ0b29sX2NhbGxfaWQiOiJzZWNvbmQtY2FsbCIsInR5cGUiOiJ0b29sIn0sImxjIjoxLCJ0eXBlIjoiY29uc3RydWN0b3IifV0sIm1vZGVsX25hbWUiOiJmYWtlOm1vZGVsIiwic3RyZWFtaW5nX3RvcGljIjpudWxsLCJ0b29sX3NjaGVtYXMiOlt7ImZ1bmN0aW9uIjp7ImRlc2NyaXB0aW9uIjoiVXNlIHRoaXMgdG9vbCB0byBjcmVhdGUgYW5kIG1hbmFnZSBhIHN0cnVjdHVyZWQgdGFzayBsaXN0IGZvciB5b3VyIGN1cnJlbnQgd29yayBzZXNzaW9uLiBUaGlzIGhlbHBzIHlvdSB0cmFjayBwcm9ncmVzcyBhbmQgb3JnYW5pemUgY29tcGxleCB0YXNrcy5cblxuT25seSB1c2UgdGhpcyB0b29sIGlmIHlvdSB0aGluayBpdCB3aWxsIGJlIGhlbHBmdWwgaW4gc3RheWluZyBvcmdhbml6ZWQuIElmIHRoZSB1c2VyJ3MgcmVxdWVzdCBpcyB0cml2aWFsIGFuZCB0YWtlcyBsZXNzIHRoYW4gMyBzdGVwcywgaXQgaXMgYmV0dGVyIHRvIE5PVCB1c2UgdGhpcyB0b29sIGFuZCBqdXN0IGRvIHRoZSB0YXNrIGRpcmVjdGx5LlxuXG4jIyBXaGVuIHRvIFVzZSBUaGlzIFRvb2xcblxuVXNlIHRoaXMgdG9vbCBpbiB0aGVzZSBzY2VuYXJpb3M6XG5cbjEuIENvbXBsZXggbXVsdGktc3RlcCB0YXNrcyAtIFdoZW4gYSB0YXNrIHJlcXVpcmVzIDMgb3IgbW9yZSBkaXN0aW5jdCBzdGVwcyBvciBhY3Rpb25zXG4yLiBOb24tdHJpdmlhbCBhbmQgY29tcGxleCB0YXNrcyAtIFRhc2tzIHRoYXQgcmVxdWlyZSBjYXJlZnVsIHBsYW5uaW5nIG9yIG11bHRpcGxlIG9wZXJhdGlvbnNcbjMuIFVzZXIgZXhwbGljaXRseSByZXF1ZXN0cyB0b2RvIGxpc3QgLSBXaGVuIHRoZSB1c2VyIGRpcmVjdGx5IGFza3MgeW91IHRvIHVzZSB0aGUgdG9kbyBsaXN0XG40LiBVc2VyIHByb3ZpZGVzIG11bHRpcGxlIHRhc2tzIC0gV2hlbiB1c2VycyBwcm92aWRlIGEgbGlzdCBvZiB0aGluZ3MgdG8gYmUgZG9uZSAobnVtYmVyZWQgb3IgY29tbWEtc2VwYXJhdGVkKVxuNS4gVGhlIHBsYW4gbWF5IG5lZWQgZnV0dXJlIHJldmlzaW9ucyBvciB1cGRhdGVzIGJhc2VkIG9uIHJlc3VsdHMgZnJvbSB0aGUgZmlyc3QgZmV3IHN0ZXBzXG5cbiMjIEhvdyB0byBVc2UgVGhpcyBUb29sXG5cbjEuIFdoZW4geW91IHN0YXJ0IHdvcmtpbmcgb24gYSB0YXNrIC0gTWFyayBpdCBhcyBpbl9wcm9ncmVzcyBCRUZPUkUgYmVnaW5uaW5nIHdvcmsuXG4yLiBBZnRlciBjb21wbGV0aW5nIGEgdGFzayAtIE1hcmsgaXQgYXMgY29tcGxldGVkIGFuZCBhZGQgYW55IG5ldyBmb2xsb3ctdXAgdGFza3MgZGlzY292ZXJlZCBkdXJpbmcgaW1wbGVtZW50YXRpb24uXG4zLiBZb3UgY2FuIGFsc28gdXBkYXRlIGZ1dHVyZSB0YXNrcywgc3VjaCBhcyBkZWxldGluZyB0aGVtIGlmIHRoZXkgYXJlIG5vIGxvbmdlciBuZWNlc3NhcnksIG9yIGFkZGluZyBuZXcgdGFza3MgdGhhdCBhcmUgbmVjZXNzYXJ5LiBEb24ndCBjaGFuZ2UgcHJldmlvdXNseSBjb21wbGV0ZWQgdGFza3MuXG40LiBZb3UgY2FuIG1ha2Ugc2V2ZXJhbCB1cGRhdGVzIHRvIHRoZSB0b2RvIGxpc3QgYXQgb25jZS4gRm9yIGV4YW1wbGUsIHdoZW4geW91IGNvbXBsZXRlIGEgdGFzaywgeW91IGNhbiBtYXJrIHRoZSBuZXh0IHRhc2sgeW91IG5lZWQgdG8gc3RhcnQgYXMgaW5fcHJvZ3Jlc3MuXG5cbiMjIFdoZW4gTk9UIHRvIFVzZSBUaGlzIFRvb2xcblxuSXQgaXMgaW1wb3J0YW50IHRvIHNraXAgdXNpbmcgdGhpcyB0b29sIHdoZW46XG4xLiBUaGVyZSBpcyBvbmx5IGEgc2luZ2xlLCBzdHJhaWdodGZvcndhcmQgdGFza1xuMi4gVGhlIHRhc2sgaXMgdHJpdmlhbCBhbmQgdHJhY2tpbmcgaXQgcHJvdmlkZXMgbm8gYmVuZWZpdFxuMy4gVGhlIHRhc2sgY2FuIGJlIGNvbXBsZXRlZCBpbiBsZXNzIHRoYW4gMyB0cml2aWFsIHN0ZXBzXG40LiBUaGUgdGFzayBpcyBwdXJlbHkgY29udmVyc2F0aW9uYWwgb3IgaW5mb3JtYXRpb25hbFxuXG4jIyBUYXNrIFN0YXRlcyBhbmQgTWFuYWdlbWVudFxuXG4xLiAqKlRhc2sgU3RhdGVzKio6IFVzZSB0aGVzZSBzdGF0ZXMgdG8gdHJhY2sgcHJvZ3Jlc3M6XG4gICAgLSBwZW5kaW5nOiBUYXNrIG5vdCB5ZXQgc3RhcnRlZFxuICAgIC0gaW5fcHJvZ3Jlc3M6IEN1cnJlbnRseSB3b3JraW5nIG9uICh5b3UgY2FuIGhhdmUgbXVsdGlwbGUgdGFza3MgaW5fcHJvZ3Jlc3MgYXQgYSB0aW1lIGlmIHRoZXkgYXJlIG5vdCByZWxhdGVkIHRvIGVhY2ggb3RoZXIgYW5kIGNhbiBiZSBydW4gaW4gcGFyYWxsZWwpXG4gICAgLSBjb21wbGV0ZWQ6IFRhc2sgZmluaXNoZWQgc3VjY2Vzc2Z1bGx5XG5cbjIuICoqVGFzayBNYW5hZ2VtZW50Kio6XG4gICAgLSBVcGRhdGUgdGFzayBzdGF0dXMgaW4gcmVhbC10aW1lIGFzIHlvdSB3b3JrXG4gICAgLSBNYXJrIHRhc2tzIGNvbXBsZXRlIElNTUVESUFURUxZIGFmdGVyIGZpbmlzaGluZyAoZG9uJ3QgYmF0Y2ggY29tcGxldGlvbnMpXG4gICAgLSBDb21wbGV0ZSBjdXJyZW50IHRhc2tzIGJlZm9yZSBzdGFydGluZyBuZXcgb25lc1xuICAgIC0gUmVtb3ZlIHRhc2tzIHRoYXQgYXJlIG5vIGxvbmdlciByZWxldmFudCBmcm9tIHRoZSBsaXN0IGVudGlyZWx5XG4gICAgLSBJTVBPUlRBTlQ6IFdoZW4geW91IHdyaXRlIHRoaXMgdG9kbyBsaXN0LCB5b3Ugc2hvdWxkIG1hcmsgeW91ciBmaXJzdCB0YXNrIChvciB0YXNrcykgYXMgaW5fcHJvZ3Jlc3MgaW1tZWRpYXRlbHkhLlxuICAgIC0gSU1QT1JUQU5UOiBVbmxlc3MgYWxsIHRhc2tzIGFyZSBjb21wbGV0ZWQsIHlvdSBzaG91bGQgYWx3YXlzIGhhdmUgYXQgbGVhc3Qgb25lIHRhc2sgaW5fcHJvZ3Jlc3MuXG5cbjMuICoqVGFzayBDb21wbGV0aW9uIFJlcXVpcmVtZW50cyoqOlxuICAgIC0gT05MWSBtYXJrIGEgdGFzayBhcyBjb21wbGV0ZWQgd2hlbiB5b3UgaGF2ZSBGVUxMWSBhY2NvbXBsaXNoZWQgaXRcbiAgICAtIElmIHlvdSBlbmNvdW50ZXIgZXJyb3JzLCBibG9ja2Vycywgb3IgY2Fubm90IGZpbmlzaCwga2VlcCB0aGUgdGFzayBhcyBpbl9wcm9ncmVzc1xuICAgIC0gV2hlbiBibG9ja2VkLCBjcmVhdGUgYSBuZXcgdGFzayBkZXNjcmliaW5nIHdoYXQgbmVlZHMgdG8gYmUgcmVzb2x2ZWRcbiAgICAtIE5ldmVyIG1hcmsgYSB0YXNrIGFzIGNvbXBsZXRlZCBpZjpcbiAgICAgICAgLSBUaGVyZSBhcmUgdW5yZXNvbHZlZCBpc3N1ZXMgb3IgZXJyb3JzXG4gICAgICAgIC0gV29yayBpcyBwYXJ0aWFsIG9yIGluY29tcGxldGVcbiAgICAgICAgLSBZb3UgZW5jb3VudGVyZWQgYmxvY2tlcnMgdGhhdCBwcmV2ZW50IGNvbXBsZXRpb25cbiAgICAgICAgLSBZb3UgY291bGRuJ3QgZmluZCBuZWNlc3NhcnkgcmVzb3VyY2VzIG9yIGRlcGVuZGVuY2llc1xuICAgICAgICAtIFF1YWxpdHkgc3RhbmRhcmRzIGhhdmVuJ3QgYmVlbiBtZXRcblxuNC4gKipUYXNrIEJyZWFrZG93bioqOlxuICAgIC0gQ3JlYXRlIHNwZWNpZmljLCBhY3Rpb25hYmxlIGl0ZW1zXG4gICAgLSBCcmVhayBjb21wbGV4IHRhc2tzIGludG8gc21hbGxlciwgbWFuYWdlYWJsZSBzdGVwc1xuICAgIC0gVXNlIGNsZWFyLCBkZXNjcmlwdGl2ZSB0YXNrIG5hbWVzXG5cbkJlaW5nIHByb2FjdGl2ZSB3aXRoIHRhc2sgbWFuYWdlbWVudCBlbnN1cmVzIHlvdSBjb21wbGV0ZSBhbGwgcmVxdWlyZW1lbnRzIHN1Y2Nlc3NmdWxseVxuUmVtZW1iZXI6IElmIHlvdSBvbmx5IG5lZWQgdG8gbWFrZSBhIGZldyB0b29sIGNhbGxzIHRvIGNvbXBsZXRlIGEgdGFzaywgYW5kIGl0IGlzIGNsZWFyIHdoYXQgeW91IG5lZWQgdG8gZG8sIGl0IGlzIGJldHRlciB0byBqdXN0IGRvIHRoZSB0YXNrIGRpcmVjdGx5IGFuZCBOT1QgY2FsbCB0aGlzIHRvb2wgYXQgYWxsLlxuXG4jIyBXaGVuIFlvdSBGaW5pc2hcblxuYHdyaXRlX3RvZG9zYCB0cmFja3MgeW91ciB3b3JrOyBpdCBkb2VzIG5vdCBkZWxpdmVyIHRoZSBhbnN3ZXIuIFdoYXRldmVyIHRoZSB1c2VyIGFza2VkIGZvciBcdTIwMTQgY29tcHV0YXRpb25zLCBzdW1tYXJpZXMsIGNvbXBhcmlzb25zLCBkYXRhIFx1MjAxNCBtdXN0IGFwcGVhciBhcyB0ZXh0IGNvbnRlbnQgaW4gYSBtZXNzYWdlIGFmdGVyIHlvdXIgZmluYWwgYHdyaXRlX3RvZG9zYCBjYWxsLiBNYXJraW5nIHRoZSBsYXN0IHRvZG8gY29tcGxldGUgaXMgbm90IGl0c2VsZiBhbiBhbnN3ZXIgdG8gdGhlIHVzZXIuIiwibmFtZSI6IndyaXRlX3RvZG9zIiwicGFyYW1ldGVycyI6eyJwcm9wZXJ0aWVzIjp7InRvZG9zIjp7Iml0ZW1zIjp7ImRlc2NyaXB0aW9uIjoiQSBzaW5nbGUgdG9kbyBpdGVtIHdpdGggY29udGVudCBhbmQgc3RhdHVzLiIsInByb3BlcnRpZXMiOnsiY29udGVudCI6eyJ0eXBlIjoic3RyaW5nIn0sInN0YXR1cyI6eyJlbnVtIjpbInBlbmRpbmciLCJpbl9wcm9ncmVzcyIsImNvbXBsZXRlZCJdLCJ0eXBlIjoic3RyaW5nIn19LCJyZXF1aXJlZCI6WyJjb250ZW50Iiwic3RhdHVzIl0sInR5cGUiOiJvYmplY3QifSwidHlwZSI6ImFycmF5In19LCJyZXF1aXJlZCI6WyJ0b2RvcyJdLCJ0eXBlIjoib2JqZWN0In19LCJ0eXBlIjoiZnVuY3Rpb24ifSx7ImZ1bmN0aW9uIjp7ImRlc2NyaXB0aW9uIjoiTGlzdHMgYWxsIGZpbGVzIGluIGEgZGlyZWN0b3J5LlxuXG5UaGlzIGlzIHVzZWZ1bCBmb3IgZXhwbG9yaW5nIHRoZSBmaWxlc3lzdGVtIGFuZCBmaW5kaW5nIHRoZSByaWdodCBmaWxlIHRvIHJlYWQgb3IgZWRpdC5cbllvdSBzaG91bGQgYWxtb3N0IEFMV0FZUyB1c2UgdGhpcyB0b29sIGJlZm9yZSB1c2luZyB0aGUgcmVhZF9maWxlIG9yIGVkaXRfZmlsZSB0b29scy4iLCJuYW1lIjoibHMiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsicGF0aCI6eyJkZXNjcmlwdGlvbiI6IkFic29sdXRlIHBhdGggdG8gdGhlIGRpcmVjdG9yeSB0byBsaXN0LiBNdXN0IGJlIGFic29sdXRlLCBub3QgcmVsYXRpdmUuIiwidHlwZSI6InN0cmluZyJ9fSwicmVxdWlyZWQiOlsicGF0aCJdLCJ0eXBlIjoib2JqZWN0In19LCJ0eXBlIjoiZnVuY3Rpb24ifSx7ImZ1bmN0aW9uIjp7ImRlc2NyaXB0aW9uIjoiUmVhZHMgYSBmaWxlIGZyb20gdGhlIGZpbGVzeXN0ZW0uXG5cbkFzc3VtZSB0aGlzIHRvb2wgaXMgYWJsZSB0byByZWFkIGFsbCBmaWxlcy4gSWYgdGhlIFVzZXIgcHJvdmlkZXMgYSBwYXRoIHRvIGEgZmlsZSBhc3N1bWUgdGhhdCBwYXRoIGlzIHZhbGlkLiBJdCBpcyBva2F5IHRvIHJlYWQgYSBmaWxlIHRoYXQgZG9lcyBub3QgZXhpc3Q7IGFuIGVycm9yIHdpbGwgYmUgcmV0dXJuZWQuXG5cblVzYWdlOlxuLSBCeSBkZWZhdWx0LCBpdCByZWFkcyB1cCB0byAxMDAgbGluZXMgc3RhcnRpbmcgZnJvbSB0aGUgYmVnaW5uaW5nIG9mIHRoZSBmaWxlXG4tICoqSU1QT1JUQU5UIGZvciBsYXJnZSBmaWxlcyBhbmQgY29kZWJhc2UgZXhwbG9yYXRpb24qKjogVXNlIHBhZ2luYXRpb24gd2l0aCBvZmZzZXQgYW5kIGxpbWl0IHBhcmFtZXRlcnMgdG8gYXZvaWQgY29udGV4dCBvdmVyZmxvd1xuICAgIC0gRmlyc3Qgc2NhbjogcmVhZF9maWxlKGZpbGVfcGF0aD1cIi4uLlwiLCBsaW1pdD0xMDApIHRvIHNlZSBmaWxlIHN0cnVjdHVyZVxuICAgIC0gUmVhZCBtb3JlIHNlY3Rpb25zOiByZWFkX2ZpbGUoZmlsZV9wYXRoPVwiLi4uXCIsIG9mZnNldD0xMDAsIGxpbWl0PTIwMCkgZm9yIG5leHQgMjAwIGxpbmVzXG4gICAgLSBPbmx5IG9taXQgbGltaXQgKHJlYWQgZnVsbCBmaWxlKSB3aGVuIG5lY2Vzc2FyeSBmb3IgZWRpdGluZ1xuLSBTcGVjaWZ5IG9mZnNldCBhbmQgbGltaXQ6IHJlYWRfZmlsZShmaWxlX3BhdGg9XCIuLi5cIiwgb2Zmc2V0PTAsIGxpbWl0PTEwMCkgcmVhZHMgZmlyc3QgMTAwIGxpbmVzXG4tIFJlc3VsdHMgYXJlIHJldHVybmVkIHVzaW5nIGNhdCAtbiBmb3JtYXQsIHdpdGggbGluZSBudW1iZXJzIHN0YXJ0aW5nIGF0IDFcbi0gTGluZXMgbG9uZ2VyIHRoYW4gNSwwMDAgY2hhcmFjdGVycyB3aWxsIGJlIHNwbGl0IGludG8gbXVsdGlwbGUgbGluZXMgd2l0aCBjb250aW51YXRpb24gbWFya2VycyAoZS5nLiwgNS4xLCA1LjIsIGV0Yy4pLiBgbGltaXRgIGFwcGxpZXMgdG8gc291cmNlIGxpbmVzLCBzbyBjb250aW51YXRpb24gcm93cyBkbyBub3QgY29uc3VtZSB0aGUgYnVkZ2V0LlxuLSBZb3UgaGF2ZSB0aGUgY2FwYWJpbGl0eSB0byBjYWxsIG11bHRpcGxlIHRvb2xzIGluIGEgc2luZ2xlIHJlc3BvbnNlLiBJdCBpcyBhbHdheXMgYmV0dGVyIHRvIHNwZWN1bGF0aXZlbHkgcmVhZCBtdWx0aXBsZSBmaWxlcyBhcyBhIGJhdGNoIHRoYXQgYXJlIHBvdGVudGlhbGx5IHVzZWZ1bC5cbi0gSWYgeW91IHJlYWQgYSBmaWxlIHRoYXQgZXhpc3RzIGJ1dCBoYXMgZW1wdHkgY29udGVudHMgeW91IHdpbGwgcmVjZWl2ZSBhIHN5c3RlbSByZW1pbmRlciB3YXJuaW5nIGluIHBsYWNlIG9mIGZpbGUgY29udGVudHMuXG4tIEltYWdlIGZpbGVzIChgLnBuZ2AsIGAuanBnYCwgYC5qcGVnYCwgYC5naWZgLCBgLndlYnBgLCBldGMuKSwgYXVkaW8gYW5kIHZpZGVvIGZpbGVzLCBhbmQgUERGcyBhcmUgcmV0dXJuZWQgYXMgbXVsdGltb2RhbCBjb250ZW50IGJsb2NrcyAoc2VlIGh0dHBzOi8vZG9jcy5sYW5nY2hhaW4uY29tL29zcy9weXRob24vbGFuZ2NoYWluL21lc3NhZ2VzI211bHRpbW9kYWwpLlxuXG5Gb3IgbXVsdGltb2RhbCByZWFkcyAoaW1hZ2UsIGF1ZGlvLCB2aWRlbywgUERGLCBldGMuKTpcbi0gVXNlIGByZWFkX2ZpbGUoZmlsZV9wYXRoPS4uLilgXG4tIERvIE5PVCB1c2UgYG9mZnNldGAvYGxpbWl0YCBmb3IgaW1hZ2VzIChwYWdpbmF0aW9uIGlzIHRleHQtb25seSlcbi0gSWYgZmlsZSBkZXRhaWxzIHdlcmUgY29tcGFjdGVkIGZyb20gaGlzdG9yeSwgY2FsbCBgcmVhZF9maWxlYCBhZ2FpbiBvbiB0aGUgc2FtZSBwYXRoXG5cbi0gWW91IHNob3VsZCBBTFdBWVMgbWFrZSBzdXJlIGEgZmlsZSBoYXMgYmVlbiByZWFkIGJlZm9yZSBlZGl0aW5nIGl0LiIsIm5hbWUiOiJyZWFkX2ZpbGUiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsiZmlsZV9wYXRoIjp7ImRlc2NyaXB0aW9uIjoiQWJzb2x1dGUgcGF0aCB0byB0aGUgZmlsZSB0byByZWFkLiBNdXN0IGJlIGFic29sdXRlLCBub3QgcmVsYXRpdmUuIiwidHlwZSI6InN0cmluZyJ9LCJsaW1pdCI6eyJkZWZhdWx0IjoxMDAsImRlc2NyaXB0aW9uIjoiTWF4aW11bSBudW1iZXIgb2YgbGluZXMgdG8gcmVhZC4gVXNlIGZvciBwYWdpbmF0aW9uIG9mIGxhcmdlIGZpbGVzLiIsInR5cGUiOiJpbnRlZ2VyIn0sIm9mZnNldCI6eyJkZWZhdWx0IjowLCJkZXNjcmlwdGlvbiI6IkxpbmUgbnVtYmVyIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSAoMC1pbmRleGVkKS4gVXNlIGZvciBwYWdpbmF0aW9uIG9mIGxhcmdlIGZpbGVzLiIsInR5cGUiOiJpbnRlZ2VyIn19LCJyZXF1aXJlZCI6WyJmaWxlX3BhdGgiXSwidHlwZSI6Im9iamVjdCJ9fSwidHlwZSI6ImZ1bmN0aW9uIn0seyJmdW5jdGlvbiI6eyJkZXNjcmlwdGlvbiI6IldyaXRlcyB0byBhIG5ldyBmaWxlIGluIHRoZSBmaWxlc3lzdGVtLlxuXG5Vc2FnZTpcbi0gVGhlIHdyaXRlX2ZpbGUgdG9vbCB3aWxsIGNyZWF0ZSB0aGUgYSBuZXcgZmlsZS5cbi0gUHJlZmVyIHRvIGVkaXQgZXhpc3RpbmcgZmlsZXMgKHdpdGggdGhlIGVkaXRfZmlsZSB0b29sKSBvdmVyIGNyZWF0aW5nIG5ldyBvbmVzIHdoZW4gcG9zc2libGUuIiwibmFtZSI6IndyaXRlX2ZpbGUiLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsiY29udGVudCI6eyJkZXNjcmlwdGlvbiI6IlRoZSB0ZXh0IGNvbnRlbnQgdG8gd3JpdGUgdG8gdGhlIGZpbGUuIFRoaXMgcGFyYW1ldGVyIGlzIHJlcXVpcmVkLiIsInR5cGUiOiJzdHJpbmcifSwiZmlsZV9wYXRoIjp7ImRlc2NyaXB0aW9uIjoiQWJzb2x1dGUgcGF0aCB3aGVyZSB0aGUgZmlsZSBzaG91bGQgYmUgY3JlYXRlZC4gTXVzdCBiZSBhYnNvbHV0ZSwgbm90IHJlbGF0aXZlLiIsInR5cGUiOiJzdHJpbmcifX0sInJlcXVpcmVkIjpbImZpbGVfcGF0aCIsImNvbnRlbnQiXSwidHlwZSI6Im9iamVjdCJ9fSwidHlwZSI6ImZ1bmN0aW9uIn0seyJmdW5jdGlvbiI6eyJkZXNjcmlwdGlvbiI6IlBlcmZvcm1zIGV4YWN0IHN0cmluZyByZXBsYWNlbWVudHMgaW4gZmlsZXMuXG5cblVzYWdlOlxuLSBZb3UgbXVzdCByZWFkIHRoZSBmaWxlIGJlZm9yZSBlZGl0aW5nLiBUaGlzIHRvb2wgd2lsbCBlcnJvciBpZiB5b3UgYXR0ZW1wdCBhbiBlZGl0IHdpdGhvdXQgcmVhZGluZyB0aGUgZmlsZSBmaXJzdC5cbi0gV2hlbiBlZGl0aW5nLCBwcmVzZXJ2ZSB0aGUgZXhhY3QgaW5kZW50YXRpb24gKHRhYnMvc3BhY2VzKSBmcm9tIHRoZSByZWFkIG91dHB1dC4gTmV2ZXIgaW5jbHVkZSBsaW5lIG51bWJlciBwcmVmaXhlcyBpbiBvbGRfc3RyaW5nIG9yIG5ld19zdHJpbmcuXG4tIEFMV0FZUyBwcmVmZXIgZWRpdGluZyBleGlzdGluZyBmaWxlcyBvdmVyIGNyZWF0aW5nIG5ldyBvbmVzLlxuLSBPbmx5IHVzZSBlbW9qaXMgaWYgdGhlIHVzZXIgZXhwbGljaXRseSByZXF1ZXN0cyBpdC4iLCJuYW1lIjoiZWRpdF9maWxlIiwicGFyYW1ldGVycyI6eyJwcm9wZXJ0aWVzIjp7ImZpbGVfcGF0aCI6eyJkZXNjcmlwdGlvbiI6IkFic29sdXRlIHBhdGggdG8gdGhlIGZpbGUgdG8gZWRpdC4gTXVzdCBiZSBhYnNvbHV0ZSwgbm90IHJlbGF0aXZlLiIsInR5cGUiOiJzdHJpbmcifSwibmV3X3N0cmluZyI6eyJkZXNjcmlwdGlvbiI6IlRoZSB0ZXh0IHRvIHJlcGxhY2Ugb2xkX3N0cmluZyB3aXRoLiBNdXN0IGJlIGRpZmZlcmVudCBmcm9tIG9sZF9zdHJpbmcuIiwidHlwZSI6InN0cmluZyJ9LCJvbGRfc3RyaW5nIjp7ImRlc2NyaXB0aW9uIjoiVGhlIGV4YWN0IHRleHQgdG8gZmluZCBhbmQgcmVwbGFjZS4gTXVzdCBiZSB1bmlxdWUgaW4gdGhlIGZpbGUgdW5sZXNzIHJlcGxhY2VfYWxsIGlzIFRydWUuIiwidHlwZSI6InN0cmluZyJ9LCJyZXBsYWNlX2FsbCI6eyJkZWZhdWx0IjpmYWxzZSwiZGVzY3JpcHRpb24iOiJJZiBUcnVlLCByZXBsYWNlIGFsbCBvY2N1cnJlbmNlcyBvZiBvbGRfc3RyaW5nLiBJZiBGYWxzZSAoZGVmYXVsdCksIG9sZF9zdHJpbmcgbXVzdCBiZSB1bmlxdWUuIiwidHlwZSI6ImJvb2xlYW4ifX0sInJlcXVpcmVkIjpbImZpbGVfcGF0aCIsIm9sZF9zdHJpbmciLCJuZXdfc3RyaW5nIl0sInR5cGUiOiJvYmplY3QifX0sInR5cGUiOiJmdW5jdGlvbiJ9LHsiZnVuY3Rpb24iOnsiZGVzY3JpcHRpb24iOiJGaW5kIGZpbGVzIG1hdGNoaW5nIGEgZ2xvYiBwYXR0ZXJuLlxuXG5TdXBwb3J0cyBzdGFuZGFyZCBnbG9iIHBhdHRlcm5zOiBgKmAgKGFueSBjaGFyYWN0ZXJzKSwgYCoqYCAoYW55IGRpcmVjdG9yaWVzKSwgYD9gIChzaW5nbGUgY2hhcmFjdGVyKS5cblJldHVybnMgYSBsaXN0IG9mIGFic29sdXRlIGZpbGUgcGF0aHMgdGhhdCBtYXRjaCB0aGUgcGF0dGVybi5cblxuRXhhbXBsZXM6XG4tIGAqKi8qLnB5YCAtIEZpbmQgYWxsIFB5dGhvbiBmaWxlc1xuLSBgKi50eHRgIC0gRmluZCBhbGwgdGV4dCBmaWxlcyBpbiB0aGUgYmFja2VuZCdzIGRlZmF1bHQgcm9vdFxuLSBgL3N1YmRpci8qKi8qLm1kYCAtIEZpbmQgYWxsIG1hcmtkb3duIGZpbGVzIHVuZGVyIC9zdWJkaXIiLCJuYW1lIjoiZ2xvYiIsInBhcmFtZXRlcnMiOnsicHJvcGVydGllcyI6eyJwYXRoIjp7ImFueU9mIjpbeyJ0eXBlIjoic3RyaW5nIn0seyJ0eXBlIjoibnVsbCJ9XSwiZGVmYXVsdCI6bnVsbCwiZGVzY3JpcHRpb24iOiJCYXNlIGRpcmVjdG9yeSB0byBzZWFyY2ggZnJvbS4gRGVmYXVsdHMgdG8gdGhlIGJhY2tlbmQncyBkZWZhdWx0IHJvb3QuIn0sInBhdHRlcm4iOnsiZGVzY3JpcHRpb24iOiJHbG9iIHBhdHRlcm4gdG8gbWF0Y2ggZmlsZXMgKGUuZy4sICcqKi8qLnB5JywgJyoudHh0JywgJy9zdWJkaXIvKiovKi5tZCcpLiIsInR5cGUiOiJzdHJpbmcifX0sInJlcXVpcmVkIjpbInBhdHRlcm4iXSwidHlwZSI6Im9iamVjdCJ9fSwidHlwZSI6ImZ1bmN0aW9uIn0seyJmdW5jdGlvbiI6eyJkZXNjcmlwdGlvbiI6IlNlYXJjaCBmb3IgYSB0ZXh0IHBhdHRlcm4gYWNyb3NzIGZpbGVzLlxuXG5TZWFyY2hlcyBmb3IgbGl0ZXJhbCB0ZXh0IChub3QgcmVnZXgpIGFuZCByZXR1cm5zIG1hdGNoaW5nIGZpbGVzIG9yIGNvbnRlbnQgYmFzZWQgb24gb3V0cHV0X21vZGUuXG5TcGVjaWFsIGNoYXJhY3RlcnMgbGlrZSBwYXJlbnRoZXNlcywgYnJhY2tldHMsIHBpcGVzLCBldGMuIGFyZSB0cmVhdGVkIGFzIGxpdGVyYWwgY2hhcmFjdGVycywgbm90IHJlZ2V4IG9wZXJhdG9ycy5cblxuRXhhbXBsZXM6XG4tIFNlYXJjaCBhbGwgZmlsZXM6IGBncmVwKHBhdHRlcm49XCJUT0RPXCIpYFxuLSBTZWFyY2ggUHl0aG9uIGZpbGVzIG9ubHk6IGBncmVwKHBhdHRlcm49XCJpbXBvcnRcIiwgZ2xvYj1cIioucHlcIilgXG4tIFNob3cgbWF0Y2hpbmcgbGluZXM6IGBncmVwKHBhdHRlcm49XCJlcnJvclwiLCBvdXRwdXRfbW9kZT1cImNvbnRlbnRcIilgXG4tIFNlYXJjaCBmb3IgY29kZSB3aXRoIHNwZWNpYWwgY2hhcnM6IGBncmVwKHBhdHRlcm49XCJkZWYgX19pbml0X18oc2VsZik6XCIpYCIsIm5hbWUiOiJncmVwIiwicGFyYW1ldGVycyI6eyJwcm9wZXJ0aWVzIjp7Imdsb2IiOnsiYW55T2YiOlt7InR5cGUiOiJzdHJpbmcifSx7InR5cGUiOiJudWxsIn1dLCJkZWZhdWx0IjpudWxsLCJkZXNjcmlwdGlvbiI6Ikdsb2IgcGF0dGVybiB0byBmaWx0ZXIgd2hpY2ggZmlsZXMgdG8gc2VhcmNoIChlLmcuLCAnKi5weScpLiJ9LCJvdXRwdXRfbW9kZSI6eyJkZWZhdWx0IjoiZmlsZXNfd2l0aF9tYXRjaGVzIiwiZGVzY3JpcHRpb24iOiJPdXRwdXQgZm9ybWF0OiAnZmlsZXNfd2l0aF9tYXRjaGVzJyAoZmlsZSBwYXRocyBvbmx5LCBkZWZhdWx0KSwgJ2NvbnRlbnQnIChtYXRjaGluZyBsaW5lcyB3aXRoIGNvbnRleHQpLCAnY291bnQnIChtYXRjaCBjb3VudHMgcGVyIGZpbGUpLiIsImVudW0iOlsiZmlsZXNfd2l0aF9tYXRjaGVzIiwiY29udGVudCIsImNvdW50Il0sInR5cGUiOiJzdHJpbmcifSwicGF0aCI6eyJhbnlPZiI6W3sidHlwZSI6InN0cmluZyJ9LHsidHlwZSI6Im51bGwifV0sImRlZmF1bHQiOm51bGwsImRlc2NyaXB0aW9uIjoiRGlyZWN0b3J5IHRvIHNlYXJjaCBpbi4gRGVmYXVsdHMgdG8gY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4ifSwicGF0dGVybiI6eyJkZXNjcmlwdGlvbiI6IlRleHQgcGF0dGVybiB0byBzZWFyY2ggZm9yIChsaXRlcmFsIHN0cmluZywgbm90IHJlZ2V4KS4iLCJ0eXBlIjoic3RyaW5nIn19LCJyZXF1aXJlZCI6WyJwYXR0ZXJuIl0sInR5cGUiOiJvYmplY3QifX0sInR5cGUiOiJmdW5jdGlvbiJ9LHsiZnVuY3Rpb24iOnsiZGVzY3JpcHRpb24iOiJMYXVuY2ggYW4gZXBoZW1lcmFsIHN1YmFnZW50IHRvIGhhbmRsZSBjb21wbGV4LCBtdWx0aS1zdGVwIGluZGVwZW5kZW50IHRhc2tzIHdpdGggaXNvbGF0ZWQgY29udGV4dCB3aW5kb3dzLlxuXG5BdmFpbGFibGUgYWdlbnQgdHlwZXMgYW5kIHRoZSB0b29scyB0aGV5IGhhdmUgYWNjZXNzIHRvOlxuLSBnZW5lcmFsLXB1cnBvc2U6IEdlbmVyYWwtcHVycG9zZSBhZ2VudCBmb3IgcmVzZWFyY2hpbmcgY29tcGxleCBxdWVzdGlvbnMsIHNlYXJjaGluZyBmb3IgZmlsZXMgYW5kIGNvbnRlbnQsIGFuZCBleGVjdXRpbmcgbXVsdGktc3RlcCB0YXNrcy4gV2hlbiB5b3UgYXJlIHNlYXJjaGluZyBmb3IgYSBrZXl3b3JkIG9yIGZpbGUgYW5kIGFyZSBub3QgY29uZmlkZW50IHRoYXQgeW91IHdpbGwgZmluZCB0aGUgcmlnaHQgbWF0Y2ggaW4gdGhlIGZpcnN0IGZldyB0cmllcyB1c2UgdGhpcyBhZ2VudCB0byBwZXJmb3JtIHRoZSBzZWFyY2ggZm9yIHlvdS4gVGhpcyBhZ2VudCBoYXMgYWNjZXNzIHRvIGFsbCB0b29scyBhcyB0aGUgbWFpbiBhZ2VudC5cblxuV2hlbiB1c2luZyB0aGUgVGFzayB0b29sLCB5b3UgbXVzdCBzcGVjaWZ5IGEgc3ViYWdlbnRfdHlwZSBwYXJhbWV0ZXIgdG8gc2VsZWN0IHdoaWNoIGFnZW50IHR5cGUgdG8gdXNlLlxuXG4jIyBVc2FnZSBub3RlczpcbjEuIExhdW5jaCBtdWx0aXBsZSBhZ2VudHMgY29uY3VycmVudGx5IHdoZW5ldmVyIHBvc3NpYmxlLCB0byBtYXhpbWl6ZSBwZXJmb3JtYW5jZTsgdG8gZG8gdGhhdCwgdXNlIGEgc2luZ2xlIG1lc3NhZ2Ugd2l0aCBtdWx0aXBsZSB0b29sIHVzZXNcbjIuIFdoZW4gdGhlIGFnZW50IGlzIGRvbmUsIGl0IHdpbGwgcmV0dXJuIGEgc2luZ2xlIG1lc3NhZ2UgYmFjayB0byB5b3UuIFRoZSByZXN1bHQgcmV0dXJuZWQgYnkgdGhlIGFnZW50IGlzIG5vdCB2aXNpYmxlIHRvIHRoZSB1c2VyLiBUbyBzaG93IHRoZSB1c2VyIHRoZSByZXN1bHQsIHlvdSBzaG91bGQgc2VuZCBhIHRleHQgbWVzc2FnZSBiYWNrIHRvIHRoZSB1c2VyIHdpdGggYSBjb25jaXNlIHN1bW1hcnkgb2YgdGhlIHJlc3VsdC5cbjMuIEVhY2ggYWdlbnQgaW52b2NhdGlvbiBpcyBzdGF0ZWxlc3MuIFlvdSB3aWxsIG5vdCBiZSBhYmxlIHRvIHNlbmQgYWRkaXRpb25hbCBtZXNzYWdlcyB0byB0aGUgYWdlbnQsIG5vciB3aWxsIHRoZSBhZ2VudCBiZSBhYmxlIHRvIGNvbW11bmljYXRlIHdpdGggeW91IG91dHNpZGUgb2YgaXRzIGZpbmFsIHJlcG9ydC4gVGhlcmVmb3JlLCB5b3VyIHByb21wdCBzaG91bGQgY29udGFpbiBhIGhpZ2hseSBkZXRhaWxlZCB0YXNrIGRlc2NyaXB0aW9uIGZvciB0aGUgYWdlbnQgdG8gcGVyZm9ybSBhdXRvbm9tb3VzbHkgYW5kIHlvdSBzaG91bGQgc3BlY2lmeSBleGFjdGx5IHdoYXQgaW5mb3JtYXRpb24gdGhlIGFnZW50IHNob3VsZCByZXR1cm4gYmFjayB0byB5b3UgaW4gaXRzIGZpbmFsIGFuZCBvbmx5IG1lc3NhZ2UgdG8geW91LlxuNC4gVGhlIGFnZW50J3Mgb3V0cHV0cyBzaG91bGQgZ2VuZXJhbGx5IGJlIHRydXN0ZWRcbjUuIENsZWFybHkgdGVsbCB0aGUgYWdlbnQgd2hldGhlciB5b3UgZXhwZWN0IGl0IHRvIGNyZWF0ZSBjb250ZW50LCBwZXJmb3JtIGFuYWx5c2lzLCBvciBqdXN0IGRvIHJlc2VhcmNoIChzZWFyY2gsIGZpbGUgcmVhZHMsIHdlYiBmZXRjaGVzLCBldGMuKSwgc2luY2UgaXQgaXMgbm90IGF3YXJlIG9mIHRoZSB1c2VyJ3MgaW50ZW50XG42LiBJZiB0aGUgYWdlbnQgZGVzY3JpcHRpb24gbWVudGlvbnMgdGhhdCBpdCBzaG91bGQgYmUgdXNlZCBwcm9hY3RpdmVseSwgdGhlbiB5b3Ugc2hvdWxkIHRyeSB5b3VyIGJlc3QgdG8gdXNlIGl0IHdpdGhvdXQgdGhlIHVzZXIgaGF2aW5nIHRvIGFzayBmb3IgaXQgZmlyc3QuIFVzZSB5b3VyIGp1ZGdlbWVudC5cbjcuIFdoZW4gb25seSB0aGUgZ2VuZXJhbC1wdXJwb3NlIGFnZW50IGlzIHByb3ZpZGVkLCB5b3Ugc2hvdWxkIHVzZSBpdCBmb3IgYWxsIHRhc2tzLiBJdCBpcyBncmVhdCBmb3IgaXNvbGF0aW5nIGNvbnRleHQgYW5kIHRva2VuIHVzYWdlLCBhbmQgY29tcGxldGluZyBzcGVjaWZpYywgY29tcGxleCB0YXNrcywgYXMgaXQgaGFzIGFsbCB0aGUgc2FtZSBjYXBhYmlsaXRpZXMgYXMgdGhlIG1haW4gYWdlbnQuXG5cbiMjIyBFeGFtcGxlIHVzYWdlIG9mIHRoZSBnZW5lcmFsLXB1cnBvc2UgYWdlbnQ6XG5cbjxleGFtcGxlX2FnZW50X2Rlc2NyaXB0aW9ucz5cblwiZ2VuZXJhbC1wdXJwb3NlXCI6IHVzZSB0aGlzIGFnZW50IGZvciBnZW5lcmFsIHB1cnBvc2UgdGFza3MsIGl0IGhhcyBhY2Nlc3MgdG8gYWxsIHRvb2xzIGFzIHRoZSBtYWluIGFnZW50LlxuPC9leGFtcGxlX2FnZW50X2Rlc2NyaXB0aW9ucz5cblxuPGV4YW1wbGU+XG5Vc2VyOiBcIkkgd2FudCB0byBjb25kdWN0IHJlc2VhcmNoIG9uIHRoZSBhY2NvbXBsaXNobWVudHMgb2YgTGVicm9uIEphbWVzLCBNaWNoYWVsIEpvcmRhbiwgYW5kIEtvYmUgQnJ5YW50LCBhbmQgdGhlbiBjb21wYXJlIHRoZW0uXCJcbkFzc2lzdGFudDogKlVzZXMgdGhlIHRhc2sgdG9vbCBpbiBwYXJhbGxlbCB0byBjb25kdWN0IGlzb2xhdGVkIHJlc2VhcmNoIG9uIGVhY2ggb2YgdGhlIHRocmVlIHBsYXllcnMqXG5Bc3Npc3RhbnQ6ICpTeW50aGVzaXplcyB0aGUgcmVzdWx0cyBvZiB0aGUgdGhyZWUgaXNvbGF0ZWQgcmVzZWFyY2ggdGFza3MgYW5kIHJlc3BvbmRzIHRvIHRoZSBVc2VyKlxuPGNvbW1lbnRhcnk+XG5SZXNlYXJjaCBpcyBhIGNvbXBsZXgsIG11bHRpLXN0ZXAgdGFzayBpbiBpdCBvZiBpdHNlbGYuXG5UaGUgcmVzZWFyY2ggb2YgZWFjaCBpbmRpdmlkdWFsIHBsYXllciBpcyBub3QgZGVwZW5kZW50IG9uIHRoZSByZXNlYXJjaCBvZiB0aGUgb3RoZXIgcGxheWVycy5cblRoZSBhc3Npc3RhbnQgdXNlcyB0aGUgdGFzayB0b29sIHRvIGJyZWFrIGRvd24gdGhlIGNvbXBsZXggb2JqZWN0aXZlIGludG8gdGhyZWUgaXNvbGF0ZWQgdGFza3MuXG5FYWNoIHJlc2VhcmNoIHRhc2sgb25seSBuZWVkcyB0byB3b3JyeSBhYm91dCBjb250ZXh0IGFuZCB0b2tlbnMgYWJvdXQgb25lIHBsYXllciwgdGhlbiByZXR1cm5zIHN5bnRoZXNpemVkIGluZm9ybWF0aW9uIGFib3V0IGVhY2ggcGxheWVyIGFzIHRoZSBUb29sIFJlc3VsdC5cblRoaXMgbWVhbnMgZWFjaCByZXNlYXJjaCB0YXNrIGNhbiBkaXZlIGRlZXAgYW5kIHNwZW5kIHRva2VucyBhbmQgY29udGV4dCBkZWVwbHkgcmVzZWFyY2hpbmcgZWFjaCBwbGF5ZXIsIGJ1dCB0aGUgZmluYWwgcmVzdWx0IGlzIHN5bnRoZXNpemVkIGluZm9ybWF0aW9uLCBhbmQgc2F2ZXMgdXMgdG9rZW5zIGluIHRoZSBsb25nIHJ1biB3aGVuIGNvbXBhcmluZyB0aGUgcGxheWVycyB0byBlYWNoIG90aGVyLlxuPC9jb21tZW50YXJ5PlxuPC9leGFtcGxlPlxuXG48ZXhhbXBsZT5cblVzZXI6IFwiQW5hbHl6ZSBhIHNpbmdsZSBsYXJnZSBjb2RlIHJlcG9zaXRvcnkgZm9yIHNlY3VyaXR5IHZ1bG5lcmFiaWxpdGllcyBhbmQgZ2VuZXJhdGUgYSByZXBvcnQuXCJcbkFzc2lzdGFudDogKkxhdW5jaGVzIGEgc2luZ2xlIGB0YXNrYCBzdWJhZ2VudCBmb3IgdGhlIHJlcG9zaXRvcnkgYW5hbHlzaXMqXG5Bc3Npc3RhbnQ6ICpSZWNlaXZlcyByZXBvcnQgYW5kIGludGVncmF0ZXMgcmVzdWx0cyBpbnRvIGZpbmFsIHN1bW1hcnkqXG48Y29tbWVudGFyeT5cblN1YmFnZW50IGlzIHVzZWQgdG8gaXNvbGF0ZSBhIGxhcmdlLCBjb250ZXh0LWhlYXZ5IHRhc2ssIGV2ZW4gdGhvdWdoIHRoZXJlIGlzIG9ubHkgb25lLiBUaGlzIHByZXZlbnRzIHRoZSBtYWluIHRocmVhZCBmcm9tIGJlaW5nIG92ZXJsb2FkZWQgd2l0aCBkZXRhaWxzLlxuSWYgdGhlIHVzZXIgdGhlbiBhc2tzIGZvbGxvd3VwIHF1ZXN0aW9ucywgd2UgaGF2ZSBhIGNvbmNpc2UgcmVwb3J0IHRvIHJlZmVyZW5jZSBpbnN0ZWFkIG9mIHRoZSBlbnRpcmUgaGlzdG9yeSBvZiBhbmFseXNpcyBhbmQgdG9vbCBjYWxscywgd2hpY2ggaXMgZ29vZCBhbmQgc2F2ZXMgdXMgdGltZSBhbmQgbW9uZXkuXG48L2NvbW1lbnRhcnk+XG48L2V4YW1wbGU+XG5cbjxleGFtcGxlPlxuVXNlcjogXCJTY2hlZHVsZSB0d28gbWVldGluZ3MgZm9yIG1lIGFuZCBwcmVwYXJlIGFnZW5kYXMgZm9yIGVhY2guXCJcbkFzc2lzdGFudDogKkNhbGxzIHRoZSB0YXNrIHRvb2wgaW4gcGFyYWxsZWwgdG8gbGF1bmNoIHR3byBgdGFza2Agc3ViYWdlbnRzIChvbmUgcGVyIG1lZXRpbmcpIHRvIHByZXBhcmUgYWdlbmRhcypcbkFzc2lzdGFudDogKlJldHVybnMgZmluYWwgc2NoZWR1bGVzIGFuZCBhZ2VuZGFzKlxuPGNvbW1lbnRhcnk+XG5UYXNrcyBhcmUgc2ltcGxlIGluZGl2aWR1YWxseSwgYnV0IHN1YmFnZW50cyBoZWxwIHNpbG8gYWdlbmRhIHByZXBhcmF0aW9uLlxuRWFjaCBzdWJhZ2VudCBvbmx5IG5lZWRzIHRvIHdvcnJ5IGFib3V0IHRoZSBhZ2VuZGEgZm9yIG9uZSBtZWV0aW5nLlxuPC9jb21tZW50YXJ5PlxuPC9leGFtcGxlPlxuXG48ZXhhbXBsZT5cblVzZXI6IFwiSSB3YW50IHRvIG9yZGVyIGEgcGl6emEgZnJvbSBEb21pbm9zLCBvcmRlciBhIGJ1cmdlciBmcm9tIE1jRG9uYWxkJ3MsIGFuZCBvcmRlciBhIHNhbGFkIGZyb20gU3Vid2F5LlwiXG5Bc3Npc3RhbnQ6ICpDYWxscyB0b29scyBkaXJlY3RseSBpbiBwYXJhbGxlbCB0byBvcmRlciBhIHBpenphIGZyb20gRG9taW5vcywgYSBidXJnZXIgZnJvbSBNY0RvbmFsZCdzLCBhbmQgYSBzYWxhZCBmcm9tIFN1YndheSpcbjxjb21tZW50YXJ5PlxuVGhlIGFzc2lzdGFudCBkaWQgbm90IHVzZSB0aGUgdGFzayB0b29sIGJlY2F1c2UgdGhlIG9iamVjdGl2ZSBpcyBzdXBlciBzaW1wbGUgYW5kIGNsZWFyIGFuZCBvbmx5IHJlcXVpcmVzIGEgZmV3IHRyaXZpYWwgdG9vbCBjYWxscy5cbkl0IGlzIGJldHRlciB0byBqdXN0IGNvbXBsZXRlIHRoZSB0YXNrIGRpcmVjdGx5IGFuZCBOT1QgdXNlIHRoZSBgdGFza2AgdG9vbC5cbjwvY29tbWVudGFyeT5cbjwvZXhhbXBsZT5cblxuIyMjIEV4YW1wbGUgdXNhZ2Ugd2l0aCBjdXN0b20gYWdlbnRzOlxuXG48ZXhhbXBsZV9hZ2VudF9kZXNjcmlwdGlvbnM+XG5cImNvbnRlbnQtcmV2aWV3ZXJcIjogdXNlIHRoaXMgYWdlbnQgYWZ0ZXIgeW91IGFyZSBkb25lIGNyZWF0aW5nIHNpZ25pZmljYW50IGNvbnRlbnQgb3IgZG9jdW1lbnRzXG5cImdyZWV0aW5nLXJlc3BvbmRlclwiOiB1c2UgdGhpcyBhZ2VudCB3aGVuIHRvIHJlc3BvbmQgdG8gdXNlciBncmVldGluZ3Mgd2l0aCBhIGZyaWVuZGx5IGpva2VcblwicmVzZWFyY2gtYW5hbHlzdFwiOiB1c2UgdGhpcyBhZ2VudCB0byBjb25kdWN0IHRob3JvdWdoIHJlc2VhcmNoIG9uIGNvbXBsZXggdG9waWNzXG48L2V4YW1wbGVfYWdlbnRfZGVzY3JpcHRpb25zPlxuXG48ZXhhbXBsZT5cbnVzZXI6IFwiUGxlYXNlIHdyaXRlIGEgZnVuY3Rpb24gdGhhdCBjaGVja3MgaWYgYSBudW1iZXIgaXMgcHJpbWVcIlxuYXNzaXN0YW50OiBTdXJlIGxldCBtZSB3cml0ZSBhIGZ1bmN0aW9uIHRoYXQgY2hlY2tzIGlmIGEgbnVtYmVyIGlzIHByaW1lXG5hc3Npc3RhbnQ6IEZpcnN0IGxldCBtZSB1c2UgdGhlIFdyaXRlIHRvb2wgdG8gd3JpdGUgYSBmdW5jdGlvbiB0aGF0IGNoZWNrcyBpZiBhIG51bWJlciBpcyBwcmltZVxuYXNzaXN0YW50OiBJJ20gZ29pbmcgdG8gdXNlIHRoZSBXcml0ZSB0b29sIHRvIHdyaXRlIHRoZSBmb2xsb3dpbmcgY29kZTpcbjxjb2RlPlxuZnVuY3Rpb24gaXNQcmltZShuKSB7XG4gIGlmIChuIDw9IDEpIHJldHVybiBmYWxzZVxuICBmb3IgKGxldCBpID0gMjsgaSAqIGkgPD0gbjsgaSsrKSB7XG4gICAgaWYgKG4gJSBpID09PSAwKSByZXR1cm4gZmFsc2VcbiAgfVxuICByZXR1cm4gdHJ1ZVxufVxuPC9jb2RlPlxuPGNvbW1lbnRhcnk+XG5TaW5jZSBzaWduaWZpY2FudCBjb250ZW50IHdhcyBjcmVhdGVkIGFuZCB0aGUgdGFzayB3YXMgY29tcGxldGVkLCBub3cgdXNlIHRoZSBjb250ZW50LXJldmlld2VyIGFnZW50IHRvIHJldmlldyB0aGUgd29ya1xuPC9jb21tZW50YXJ5PlxuYXNzaXN0YW50OiBOb3cgbGV0IG1lIHVzZSB0aGUgY29udGVudC1yZXZpZXdlciBhZ2VudCB0byByZXZpZXcgdGhlIGNvZGVcbmFzc2lzdGFudDogVXNlcyB0aGUgVGFzayB0b29sIHRvIGxhdW5jaCB3aXRoIHRoZSBjb250ZW50LXJldmlld2VyIGFnZW50XG48L2V4YW1wbGU+XG5cbjxleGFtcGxlPlxudXNlcjogXCJDYW4geW91IGhlbHAgbWUgcmVzZWFyY2ggdGhlIGVudmlyb25tZW50YWwgaW1wYWN0IG9mIGRpZmZlcmVudCByZW5ld2FibGUgZW5lcmd5IHNvdXJjZXMgYW5kIGNyZWF0ZSBhIGNvbXByZWhlbnNpdmUgcmVwb3J0P1wiXG48Y29tbWVudGFyeT5cblRoaXMgaXMgYSBjb21wbGV4IHJlc2VhcmNoIHRhc2sgdGhhdCB3b3VsZCBiZW5lZml0IGZyb20gdXNpbmcgdGhlIHJlc2VhcmNoLWFuYWx5c3QgYWdlbnQgdG8gY29uZHVjdCB0aG9yb3VnaCBhbmFseXNpc1xuPC9jb21tZW50YXJ5PlxuYXNzaXN0YW50OiBJJ2xsIGhlbHAgeW91IHJlc2VhcmNoIHRoZSBlbnZpcm9ubWVudGFsIGltcGFjdCBvZiByZW5ld2FibGUgZW5lcmd5IHNvdXJjZXMuIExldCBtZSB1c2UgdGhlIHJlc2VhcmNoLWFuYWx5c3QgYWdlbnQgdG8gY29uZHVjdCBjb21wcmVoZW5zaXZlIHJlc2VhcmNoIG9uIHRoaXMgdG9waWMuXG5hc3Npc3RhbnQ6IFVzZXMgdGhlIFRhc2sgdG9vbCB0byBsYXVuY2ggd2l0aCB0aGUgcmVzZWFyY2gtYW5hbHlzdCBhZ2VudCwgcHJvdmlkaW5nIGRldGFpbGVkIGluc3RydWN0aW9ucyBhYm91dCB3aGF0IHJlc2VhcmNoIHRvIGNvbmR1Y3QgYW5kIHdoYXQgZm9ybWF0IHRoZSByZXBvcnQgc2hvdWxkIHRha2VcbjwvZXhhbXBsZT5cblxuPGV4YW1wbGU+XG51c2VyOiBcIkhlbGxvXCJcbjxjb21tZW50YXJ5PlxuU2luY2UgdGhlIHVzZXIgaXMgZ3JlZXRpbmcsIHVzZSB0aGUgZ3JlZXRpbmctcmVzcG9uZGVyIGFnZW50IHRvIHJlc3BvbmQgd2l0aCBhIGZyaWVuZGx5IGpva2VcbjwvY29tbWVudGFyeT5cbmFzc2lzdGFudDogXCJJJ20gZ29pbmcgdG8gdXNlIHRoZSBUYXNrIHRvb2wgdG8gbGF1bmNoIHdpdGggdGhlIGdyZWV0aW5nLXJlc3BvbmRlciBhZ2VudFwiXG48L2V4YW1wbGU+IiwibmFtZSI6InRhc2siLCJwYXJhbWV0ZXJzIjp7InByb3BlcnRpZXMiOnsiZGVzY3JpcHRpb24iOnsiZGVzY3JpcHRpb24iOiJBIGRldGFpbGVkIGRlc2NyaXB0aW9uIG9mIHRoZSB0YXNrIGZvciB0aGUgc3ViYWdlbnQgdG8gcGVyZm9ybSBhdXRvbm9tb3VzbHkuIEluY2x1ZGUgYWxsIG5lY2Vzc2FyeSBjb250ZXh0IGFuZCBzcGVjaWZ5IHRoZSBleHBlY3RlZCBvdXRwdXQgZm9ybWF0LiIsInR5cGUiOiJzdHJpbmcifSwic3ViYWdlbnRfdHlwZSI6eyJkZXNjcmlwdGlvbiI6IlRoZSB0eXBlIG9mIHN1YmFnZW50IHRvIHVzZS4gTXVzdCBiZSBvbmUgb2YgdGhlIGF2YWlsYWJsZSBhZ2VudCB0eXBlcyBsaXN0ZWQgaW4gdGhlIHRvb2wgZGVzY3JpcHRpb24uIiwidHlwZSI6InN0cmluZyJ9fSwicmVxdWlyZWQiOlsiZGVzY3JpcHRpb24iLCJzdWJhZ2VudF90eXBlIl0sInR5cGUiOiJvYmplY3QifX0sInR5cGUiOiJmdW5jdGlvbiJ9LHsiZnVuY3Rpb24iOnsiZGVzY3JpcHRpb24iOiJSZXR1cm4gdGhlIHdlYXRoZXIgZm9yIGEgY2l0eS4iLCJuYW1lIjoicGFpcmluZ193ZWF0aGVyIiwicGFyYW1ldGVycyI6eyJwcm9wZXJ0aWVzIjp7ImNpdHkiOnsidHlwZSI6InN0cmluZyJ9fSwicmVxdWlyZWQiOlsiY2l0eSJdLCJ0eXBlIjoib2JqZWN0In19LCJ0eXBlIjoiZnVuY3Rpb24ifV19" + } + ] + }, + "scheduleToCloseTimeout": "0s", + "scheduleToStartTimeout": "0s", + "startToCloseTimeout": "300s", + "heartbeatTimeout": "0s", + "workflowTaskCompletedEventId": "22", + "retryPolicy": { + "initialInterval": "1s", + "backoffCoefficient": 2.0, + "maximumInterval": "100s" + }, + "useWorkflowBuildId": true, + "priority": {} + }, + "userMetadata": { + "summary": { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "Imludm9rZV9tb2RlbFtmYWtlOm1vZGVsXSI=" + } + } + }, + { + "eventId": "24", + "eventTime": "2026-09-11T04:34:43.555140Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_STARTED", + "taskId": "1048652", + "activityTaskStartedEventAttributes": { + "scheduledEventId": "23", + "identity": "29727@Davids-MacBook-Pro.local", + "requestId": "f8bdca57-c5cc-42bb-8a2a-fd4e451b3851", + "attempt": 1, + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + } + } + }, + { + "eventId": "25", + "eventTime": "2026-09-11T04:34:43.558376Z", + "eventType": "EVENT_TYPE_ACTIVITY_TASK_COMPLETED", + "taskId": "1048653", + "activityTaskCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "eyJtZXNzYWdlIjp7ImlkIjpbImxhbmdjaGFpbiIsInNjaGVtYSIsIm1lc3NhZ2VzIiwiQUlNZXNzYWdlIl0sImt3YXJncyI6eyJjb250ZW50IjoiZG9uZSIsImlkIjoibGNfcnVuLS0wMWEwOGViZi0xOGU1LTdlNDEtYTczYy05NzQ1OGNlZGM3YmEtMCIsImludmFsaWRfdG9vbF9jYWxscyI6W10sInRvb2xfY2FsbHMiOltdLCJ0eXBlIjoiYWkifSwibGMiOjEsInR5cGUiOiJjb25zdHJ1Y3RvciJ9fQ==" + } + ] + }, + "scheduledEventId": "23", + "startedEventId": "24", + "identity": "29727@Davids-MacBook-Pro.local" + } + }, + { + "eventId": "26", + "eventTime": "2026-09-11T04:34:43.558380Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED", + "taskId": "1048654", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "29727@Davids-MacBook-Pro.local-57ca8a6519904a989c08369c5a3a1f18", + "kind": "TASK_QUEUE_KIND_STICKY", + "normalName": "rec" + }, + "startToCloseTimeout": "10s", + "attempt": 1 + } + }, + { + "eventId": "27", + "eventTime": "2026-09-11T04:34:43.558916Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED", + "taskId": "1048658", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "26", + "identity": "29727@Davids-MacBook-Pro.local", + "requestId": "800853e5-b122-4698-b88b-6ada286fafeb", + "historySizeBytes": "86854", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + } + } + }, + { + "eventId": "28", + "eventTime": "2026-09-11T04:34:43.562674Z", + "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED", + "taskId": "1048662", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "26", + "startedEventId": "27", + "identity": "29727@Davids-MacBook-Pro.local", + "workerVersion": { + "buildId": "30ee10c204132c0d80cfd2d5c5e13fbe" + }, + "sdkMetadata": {}, + "meteringMetadata": {} + } + }, + { + "eventId": "29", + "eventTime": "2026-09-11T04:34:43.562716Z", + "eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED", + "taskId": "1048663", + "workflowExecutionCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "ImRvbmUi" + } + ] + }, + "workflowTaskCompletedEventId": "28" + } + } + ] +} \ No newline at end of file diff --git a/tests/contrib/deepagents/test_backends.py b/tests/contrib/deepagents/test_backends.py index b32a6f12b..d21f812a0 100644 --- a/tests/contrib/deepagents/test_backends.py +++ b/tests/contrib/deepagents/test_backends.py @@ -17,6 +17,7 @@ import uuid from datetime import timedelta from pathlib import Path +from typing import Any import pytest @@ -29,8 +30,10 @@ pytest.importorskip("langchain_core") from temporalio import workflow +from temporalio.common import RetryPolicy from temporalio.contrib.deepagents import DeepAgentsPlugin, TemporalBackend from temporalio.contrib.deepagents._tools import ( + lookup_backend, register_backend, registered_backends, ) @@ -152,6 +155,21 @@ def test_temporal_backend_unregisters_on_gc() -> None: assert ref not in registered_backends() +def test_temporal_backend_gc_keeps_ref_resolvable_for_inflight_activity() -> None: + # A backend_op activity scheduled just before a cache eviction can start + # AFTER the evicted wrapper is collected, and the replay that would + # re-register the ref only happens once that activity completes. The + # activity-side lookup must therefore still resolve a retired ref. + inner = RecordingBackend() + before = set(registered_backends()) + wrapper = TemporalBackend(inner) + (ref,) = set(registered_backends()) - before + del wrapper + gc.collect() + assert ref not in registered_backends() + assert lookup_backend(ref) is inner + + def test_temporal_backend_gc_keeps_reregistered_ref() -> None: # Refs are deterministic per run: after a cache eviction, a replay # re-registers the SAME ref with a fresh inner backend. The evicted @@ -313,3 +331,92 @@ async def test_builtin_tool_on_default_backend_runs_in_workflow( # The state-backend op stays in-workflow: model turns are the ONLY activities. assert counts[BACKEND_OP] == 0, counts assert counts["deepagents.invoke_model"] == 2, counts + + +class MutatingBackend: + """Read result depends on op order: each read returns the write count so a + served-stale-cache regression is observable. + + State lives on DISK, like a real backend's. In-memory state (instance or + class level) cannot work here: the workflow re-constructs and re-registers + the fake from a FRESH sandbox on every replayed activation under + ``max_cached_workflows=0``, so a replay landing between the write and the + second read swaps in a new module copy with reset in-memory state. + """ + + def __init__(self, root: str) -> None: + self._log = Path(root) / "writes.log" + + def _count(self) -> int: + return len(self._log.read_text().splitlines()) if self._log.exists() else 0 + + def write(self, _file_path: str, _content: str) -> str: + with self._log.open("a") as f: + f.write("w\n") + return f"wrote:{self._count()}" + + def read(self, _file_path: str) -> str: + return f"read-at-write-count:{self._count()}" + + +class _RepeatedOpsAgent: + """ainvoke-shaped driver: read, write, read the SAME path — under + run_deep_agent so the continue-as-new result cache is active.""" + + def __init__(self, backend: Any) -> None: + self._backend = backend + + async def ainvoke(self, _input: Any) -> dict: + first = await self._backend.read("a.txt") + await self._backend.write("a.txt", "x") + second = await self._backend.read("a.txt") + return {"messages": [f"{first}|{second}"], "todos": []} + + +@workflow.defn +class RepeatedBackendOpWorkflow: + @workflow.run + async def run(self, input: dict, state_snapshot: dict | None = None) -> str: + from temporalio.contrib.deepagents import run_deep_agent + + backend = TemporalBackend( + MutatingBackend(input["root"]), + # No retries: the disk log grows per activity ATTEMPT and the + # assertions are exact counts. + activity_options={ + "start_to_close_timeout": timedelta(seconds=30), + "retry_policy": RetryPolicy(maximum_attempts=1), + }, + ) + result = await run_deep_agent( + _RepeatedOpsAgent(backend), input, state_snapshot=state_snapshot + ) + return str(result["messages"][-1]) + + +@pytest.mark.asyncio +async def test_repeated_backend_op_sees_fresh_state( + env: WorkflowEnvironment, tmp_path: Path +) -> None: + """A repeated identical read after an intervening write runs its own + Activity and sees the write — under the active CAN cache, the old + payload-only key served the FIRST read's stale result.""" + plugin = DeepAgentsPlugin() + async with Worker( + env.client, + task_queue="da-repeated-backend-op", + workflows=[RepeatedBackendOpWorkflow], + plugins=[plugin], + max_cached_workflows=0, + ): + handle = await env.client.start_workflow( + RepeatedBackendOpWorkflow.run, + {"messages": [], "root": str(tmp_path)}, + id=f"da-repeated-backend-op-{uuid.uuid4()}", + task_queue="da-repeated-backend-op", + ) + out = await handle.result() + + assert out == "read-at-write-count:0|read-at-write-count:1", out + counts = await count_scheduled_activities(handle) + assert counts[BACKEND_OP] == 3, counts diff --git a/tests/contrib/deepagents/test_continue_as_new.py b/tests/contrib/deepagents/test_continue_as_new.py index c5add7cf7..a66f95827 100644 --- a/tests/contrib/deepagents/test_continue_as_new.py +++ b/tests/contrib/deepagents/test_continue_as_new.py @@ -2,8 +2,10 @@ ``run_deep_agent(continue_as_new_after=...)`` keeps a long conversation from bloating workflow history: once the current turn finishes past the threshold and -there is still pending work, it snapshots the accumulated messages plus the -model/tool result cache and continues into a fresh run. These tests use a plain +there is still pending work, it snapshots the accumulated messages and continues +into a fresh run. (The legacy result cache is retired for new executions — +see ``deepagents.retire-result-cache``; ``test_state_snapshot_roundtrip`` below +covers the _serde plumbing that only the legacy replay branch still uses.) These tests use a plain fake agent (no LangChain needed) so they boot a real Temporal server and exercise the continue-as-new machinery end to end. """ @@ -12,10 +14,14 @@ import sys import uuid +from datetime import timedelta +from pathlib import Path from typing import Any import pytest +from temporalio.client import WorkflowExecutionStatus +from temporalio.common import RetryPolicy from temporalio.testing import WorkflowEnvironment pytestmark = pytest.mark.skipif( @@ -84,8 +90,9 @@ async def test_can_threshold_and_cache(env: WorkflowEnvironment) -> None: def test_state_snapshot_roundtrip() -> None: - # The result cache carried in a snapshot rehydrates to the same hits, so work - # done before a continue-as-new is reused, not recomputed, afterwards. + # LEGACY-branch plumbing (deepagents.retire-result-cache unpatched): a + # carried cache rehydrates to the same hits during replay of pre-change + # histories. Delete alongside the patch's deprecate_patch cleanup. _serde.set_result_cache({}) key = _serde.cache_key("model", "fake:model", [["m"], []]) _serde.cache_put(key, {"dumped": "message"}) @@ -165,3 +172,94 @@ async def test_can_defaults_to_server_suggestion( assert desc.status is not None and desc.status.name == "CONTINUED_AS_NEW", ( desc.status ) + + +class DiskCountingBackend: + """Each read appends to a log and reports the total — disk state, so the + count survives sandbox re-imports, replays, and continue-as-new.""" + + def __init__(self, root: str) -> None: + self._log = Path(root) / "reads.log" + + def read(self, _file_path: str) -> str: + with self._log.open("a") as f: + f.write("r\n") + return f"read:{len(self._log.read_text().splitlines())}" + + +class _CrossBoundaryAgent: + """ainvoke-shaped driver issuing the SAME read every run; reports pending + until the second read has observably executed.""" + + def __init__(self, backend: Any) -> None: + self._backend = backend + + async def ainvoke(self, input: Any) -> dict: + out = await self._backend.read("state.txt") + done = int(out.split(":")[1]) >= 2 + return { + "messages": [*list(input.get("messages", [])), out], + "todos": [ + {"content": "work", "status": "completed" if done else "pending"} + ], + } + + +@workflow.defn +class CrossBoundaryOpWorkflow: + @workflow.run + async def run(self, input: dict, state_snapshot: dict | None = None) -> dict: + from temporalio.contrib.deepagents import TemporalBackend + + backend = TemporalBackend( + DiskCountingBackend(input["root"]), + # No retries: the disk counter increments per activity ATTEMPT, so + # a retry would skew the exact read-count assertions. + activity_options={ + "start_to_close_timeout": timedelta(seconds=30), + "retry_policy": RetryPolicy(maximum_attempts=1), + }, + ) + return await run_deep_agent( + _CrossBoundaryAgent(backend), + input, + continue_as_new_after=1, + state_snapshot=state_snapshot, + ) + + +@pytest.mark.asyncio +async def test_identical_op_reruns_across_continue_as_new( + env: WorkflowEnvironment, tmp_path: Any +) -> None: + """An identical backend op issued on BOTH sides of a continue-as-new + boundary executes on both sides. Under the legacy carried cache the + post-boundary call was served the pre-boundary result (the continued run + resumes from the transcript — it never re-executes prior dispatches, so + a carried hit could only ever be stale).""" + plugin = DeepAgentsPlugin() + async with Worker( + env.client, + task_queue="da-cross-boundary", + workflows=[CrossBoundaryOpWorkflow], + plugins=[plugin], + max_cached_workflows=0, + ): + handle = await env.client.start_workflow( + CrossBoundaryOpWorkflow.run, + {"messages": [], "root": str(tmp_path)}, + id=f"da-cross-boundary-{uuid.uuid4()}", + task_queue="da-cross-boundary", + ) + result = await handle.result() + + # The read really executed in the continued run: disk shows two reads and + # the carried transcript holds each run's distinct observation. + assert (tmp_path / "reads.log").read_text().splitlines() == ["r", "r"] + assert result["messages"][-2:] == ["read:1", "read:2"], result + # The chain really crossed a boundary. + first = env.client.get_workflow_handle( + handle.id, run_id=handle.first_execution_run_id + ) + desc = await first.describe() + assert desc.status == WorkflowExecutionStatus.CONTINUED_AS_NEW, desc.status diff --git a/tests/contrib/deepagents/test_legacy_cache_replay.py b/tests/contrib/deepagents/test_legacy_cache_replay.py new file mode 100644 index 000000000..d0cc230af --- /dev/null +++ b/tests/contrib/deepagents/test_legacy_cache_replay.py @@ -0,0 +1,178 @@ +"""The retired legacy cache still replays pre-change histories. + +The checked-in history was recorded before this change: two model-issued tool +calls with identical name+args, deduped by the legacy result cache to ONE +scheduled ``deepagents.invoke_tool`` activity. Its replay exercises the +unpatched branch of ``deepagents.retire-result-cache`` end to end — the only +executable coverage that branch has, and the tripwire that keeps it from +being "simplified" away while pre-change workflows are still in flight. + +Fixture provenance: recorded on sdk-python main (pre-#1806) by driving a +scripted two-identical-tool-call agent through ``run_deep_agent`` on a local +dev server. Delete this test and the fixture together when the patch id goes +through ``workflow.deprecate_patch``. +""" + +from __future__ import annotations + +import sys +from datetime import timedelta +from pathlib import Path +from typing import Any + +import pytest + +pytestmark = pytest.mark.skipif( + sys.version_info < (3, 11), reason="deepagents requires Python >= 3.11" +) +pytest.importorskip("deepagents") +pytest.importorskip("langchain_core") + +from temporalio import workflow +from temporalio.client import WorkflowHistory +from temporalio.contrib.deepagents import ( + DeepAgentsPlugin, + run_deep_agent, + tool_as_activity, +) +from temporalio.contrib.deepagents.testing import mock_model_provider +from temporalio.worker import Replayer + +with workflow.unsafe.imports_passed_through(): + from langchain_core.messages import AIMessage + from langchain_core.tools import tool + +# Bind deepagents symbols off the module importorskip returns: a static +# `from deepagents import ...` cannot resolve on Python 3.10 (deepagents +# needs >= 3.11), and with the package absent the type checkers mis-resolve +# the name against this same-named test directory. +create_deep_agent = pytest.importorskip("deepagents").create_deep_agent + +_HISTORY = Path(__file__).parent / "histories" / "legacy_dedup_repeated_tool_calls.json" + + +@tool("pairing_weather") +def legacy_replay_pairing_weather(city: str) -> str: + """Return the weather for a city.""" + return f"weather:{city}" + + +# Distinct Python symbols from test_tools.py's same-named definitions; the +# DEFN name must match the workflow type recorded in the fixture history. +@workflow.defn(name="RepeatedToolCallWorkflow") +class LegacyReplayToolCallWorkflow: + @workflow.run + async def run(self) -> str: + t = tool_as_activity( + legacy_replay_pairing_weather, start_to_close_timeout=timedelta(seconds=10) + ) + agent = create_deep_agent(model="fake:model", tools=[t]) + result = await run_deep_agent( + agent, + {"messages": [{"role": "user", "content": "Check Paris twice."}]}, + continue_as_new_after=10_000, + ) + return str(result["messages"][-1].content) + + +RESPONSES: list[Any] = [ + AIMessage( + content="", + tool_calls=[ + {"name": "pairing_weather", "args": {"city": "Paris"}, "id": "first-call"} + ], + ), + AIMessage( + content="", + tool_calls=[ + {"name": "pairing_weather", "args": {"city": "Paris"}, "id": "second-call"} + ], + ), + AIMessage(content="done"), +] + + +@pytest.mark.asyncio +async def test_legacy_dedup_history_replays() -> None: + plugin = DeepAgentsPlugin(model_provider=mock_model_provider(RESPONSES)) + replayer = Replayer(workflows=[LegacyReplayToolCallWorkflow], plugins=[plugin]) + history = WorkflowHistory.from_json("legacy-replay", _HISTORY.read_text()) + await replayer.replay_workflow(history) + + +with workflow.unsafe.imports_passed_through(): + from langchain_core.tools import tool as _lc_tool + +from temporalio.contrib.deepagents import _activity +from temporalio.contrib.deepagents._tools import register_tool +from temporalio.contrib.deepagents.workflow import call_tool + +_CAN_HISTORY = ( + Path(__file__).parent / "histories" / "legacy_cache_carried_across_can.json" +) + + +@_lc_tool("legacy_echo") +def legacy_replay_echo(x: int) -> str: + """Echo a number.""" + return f"echo:{x}" + + +register_tool(legacy_replay_echo) + + +class _SameCallAgent: + async def ainvoke(self, input: Any) -> dict: + messages = list(input.get("messages", [])) if isinstance(input, dict) else [] + await call_tool( + _activity.ToolActivityInput( + tool_name="legacy_echo", tool_call_id="tc-1", args={"x": 1} + ), + summary="tool:legacy_echo", + start_to_close_timeout=timedelta(seconds=10), + ) + done = len(messages) >= 1 + return { + "messages": [*messages, "turn"], + "todos": [{"content": "w", "status": "completed" if done else "pending"}], + } + + +@workflow.defn(name="LegacyCanDedupWorkflow") +class LegacyReplayCanDedupWorkflow: + @workflow.run + async def run(self, input: dict, state_snapshot: dict | None = None) -> dict: + from temporalio.contrib.deepagents import run_deep_agent + + return await run_deep_agent( + _SameCallAgent(), + input, + continue_as_new_after=1, + state_snapshot=state_snapshot, + ) + + +@pytest.mark.asyncio +async def test_legacy_carried_cache_history_replays() -> None: + """The legacy rehydrate-and-hit path replays: this continued-run history + was recorded pre-change with the SAME tool call re-issued after the + boundary and served from the CARRIED cache — it contains zero + invoke_tool activities, so replay only succeeds if the unpatched branch + seeds the cache from the inbound snapshot and serves the hit.""" + import json + + events = json.loads(_CAN_HISTORY.read_text())["events"] + scheduled = [ + e + for e in events + if e.get("activityTaskScheduledEventAttributes", {}) + .get("activityType", {}) + .get("name") + == "deepagents.invoke_tool" + ] + assert scheduled == [], "fixture must contain a fully cache-served run" + + plugin = DeepAgentsPlugin() + replayer = Replayer(workflows=[LegacyReplayCanDedupWorkflow], plugins=[plugin]) + history = WorkflowHistory.from_json("legacy-can-replay", _CAN_HISTORY.read_text()) + await replayer.replay_workflow(history) diff --git a/tests/contrib/deepagents/test_model_activity.py b/tests/contrib/deepagents/test_model_activity.py index 37a98ef00..5a71a663d 100644 --- a/tests/contrib/deepagents/test_model_activity.py +++ b/tests/contrib/deepagents/test_model_activity.py @@ -9,6 +9,7 @@ import sys import uuid from datetime import timedelta +from typing import Any import pytest @@ -101,3 +102,62 @@ async def test_temporal_model_explicit(env: WorkflowEnvironment) -> None: assert out == "Bonjour." counts = await count_scheduled_activities(handle) assert counts[INVOKE_MODEL] == 1, counts + + +class _ResampleAgent: + """ainvoke-shaped driver: the SAME prompt sent twice through a + TemporalModel — deliberate resampling — under run_deep_agent so the + continue-as-new result cache is active.""" + + def __init__(self) -> None: + self.model = TemporalModel(model="fake:model") + + async def ainvoke(self, _input: Any) -> dict: + first = await self.model.ainvoke([HumanMessage(content="same prompt")]) + second = await self.model.ainvoke([HumanMessage(content="same prompt")]) + return { + "messages": [f"{first.content}|{second.content}"], + "todos": [], + } + + +@workflow.defn +class ResampleWorkflow: + @workflow.run + async def run(self, input: dict, state_snapshot: dict | None = None) -> str: + from temporalio.contrib.deepagents import run_deep_agent + + result = await run_deep_agent( + _ResampleAgent(), input, state_snapshot=state_snapshot + ) + return str(result["messages"][-1]) + + +@pytest.mark.asyncio +async def test_repeated_identical_model_call_resamples( + env: WorkflowEnvironment, +) -> None: + """Two identical live model calls each run their own Activity and can + return different responses (deliberate resampling) — under the active + CAN cache, the old input-only key served the FIRST response twice.""" + plugin = DeepAgentsPlugin( + model_provider=mock_model_provider(["first answer", "second answer"]), + ) + async with Worker( + env.client, + task_queue="da-model-resample", + workflows=[ResampleWorkflow], + plugins=[plugin], + max_cached_workflows=0, + ): + handle = await env.client.start_workflow( + ResampleWorkflow.run, + {"messages": []}, + id=f"da-model-resample-{uuid.uuid4()}", + task_queue="da-model-resample", + ) + out = await handle.result() + + assert out == "first answer|second answer", out + counts = await count_scheduled_activities(handle) + assert counts["deepagents.invoke_model"] == 2, counts diff --git a/tests/contrib/deepagents/test_tools.py b/tests/contrib/deepagents/test_tools.py index 1fc1ff212..d1eac8b05 100644 --- a/tests/contrib/deepagents/test_tools.py +++ b/tests/contrib/deepagents/test_tools.py @@ -32,9 +32,11 @@ from temporalio.contrib.deepagents import ( # noqa: E402 DeepAgentsPlugin, activity_as_tool, + run_deep_agent, tool_as_activity, ) from temporalio.contrib.deepagents._tools import warn_unwrapped_tools # noqa: E402 + from temporalio.contrib.deepagents.testing import mock_model_provider # noqa: E402 INVOKE_TOOL = "deepagents.invoke_tool" @@ -159,6 +161,23 @@ async def run(self, city: str) -> str: return str(result["messages"][-1].content) +@workflow.defn +class RepeatedToolCallWorkflow: + @workflow.run + async def run(self, input: dict, state_snapshot: dict | None = None) -> str: + tool = tool_as_activity( + pairing_weather, start_to_close_timeout=timedelta(seconds=10) + ) + agent = create_deep_agent(model="fake:model", tools=[tool]) + result = await run_deep_agent( + agent, + input, + continue_as_new_after=10_000, + state_snapshot=state_snapshot, + ) + return str(result["messages"][-1].content) + + @pytest.mark.asyncio async def test_wrapped_tool_result_pairs_with_model_tool_call_id( env: WorkflowEnvironment, @@ -236,3 +255,51 @@ def provider(_model_name: str) -> RecordingModel: 0 ].tool_call_id assert "weather:Paris" in str(tool_messages[0].content) + + +@pytest.mark.asyncio +async def test_repeated_tool_calls_with_same_args_both_run( + env: WorkflowEnvironment, +) -> None: + from langchain_core.messages import AIMessage + + responses = [ + AIMessage( + content="", + tool_calls=[ + { + "name": "pairing_weather", + "args": {"city": "Paris"}, + "id": "first-call", + } + ], + ), + AIMessage( + content="", + tool_calls=[ + { + "name": "pairing_weather", + "args": {"city": "Paris"}, + "id": "second-call", + } + ], + ), + AIMessage(content="done"), + ] + plugin = DeepAgentsPlugin(model_provider=mock_model_provider(responses)) + async with Worker( + env.client, + task_queue="da-repeated-tool-calls", + workflows=[RepeatedToolCallWorkflow], + plugins=[plugin], + ): + handle = await env.client.start_workflow( + RepeatedToolCallWorkflow.run, + {"messages": [{"role": "user", "content": "Check Paris twice."}]}, + id=f"da-repeated-tool-calls-{uuid.uuid4()}", + task_queue="da-repeated-tool-calls", + ) + assert await handle.result() == "done" + + counts = await count_scheduled_activities(handle) + assert counts[INVOKE_TOOL] == 2, counts